• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20import path from 'path'
21import loaderUtils from 'loader-utils'
22import hash from 'hash-sum'
23import {
24  SourceMapGenerator,
25  SourceMapConsumer
26} from 'source-map'
27
28const { DEVICE_LEVEL } = require('./lite/lite-enum')
29
30export function getNameByPath (resourcePath) {
31  return path.basename(resourcePath).replace(/\..*$/, '')
32}
33
34export function getFileNameWithHash (resourcePath, content) {
35  const filename = path.relative('.', resourcePath)
36  const cacheKey = hash(filename + content)
37  return `./${filename}?${cacheKey}`
38}
39
40export function getFilenameByPath (filepath) {
41  return path.relative('.', filepath)
42}
43
44export const FUNC_START = '#####FUN_S#####'
45export const FUNC_START_REG = new RegExp('["\']' + FUNC_START, 'g')
46export const FUNC_END = '#####FUN_E#####'
47export const FUNC_END_REG = new RegExp(FUNC_END + '["\']', 'g')
48
49export function stringifyFunction (key, value) {
50  if (typeof value === 'function') {
51    return FUNC_START + value.toString() + FUNC_END
52  }
53  return value
54}
55
56export function logWarn (loader, logs) {
57  // add flag to determine if there is an error log
58  let flag = false
59  if (process.env.logLevel > 0) {
60    if (logs && logs.length) {
61      logs.forEach(log => {
62        if (log.reason.startsWith('NOTE') && parseInt(process.env.logLevel) <= 1) {
63          if (log.line && log.column) {
64            loader.emitWarning('noteStartNOTE File:' + loader.resourcePath + ':' +
65              log.line + ':' + log.column + '\n ' + log.reason.replace('NOTE: ', '') + 'noteEnd')
66          } else {
67            loader.emitWarning('noteStartNOTE File:' + loader.resourcePath +
68              '\n ' + log.reason.replace('NOTE: ', '') + 'noteEnd')
69          }
70        } else if (log.reason.startsWith('WARN') && parseInt(process.env.logLevel) <= 2) {
71          if (log.line && log.column) {
72            loader.emitWarning('warnStartWARNING File:' + loader.resourcePath + ':' +
73              log.line + ':' + log.column + '\n ' + log.reason.replace('WARNING: ', '') + 'warnEnd')
74          } else {
75            loader.emitWarning('warnStartWARNING File:' + loader.resourcePath +
76              '\n ' + log.reason.replace('WARNING: ', '') + 'warnEnd')
77          }
78        } else if (log.reason.startsWith('ERROR') && parseInt(process.env.logLevel) <= 3) {
79          flag = true
80          if (log.line && log.column) {
81            loader.emitError('errorStartERROR File:' + loader.resourcePath + ':' +
82              log.line + ':' + log.column + '\n ' + log.reason.replace('ERROR: ', '') + 'errorEnd')
83          } else {
84            loader.emitError('errorStartERROR File:' + loader.resourcePath +
85              '\n ' + log.reason.replace('ERROR: ', '') + 'errorEnd')
86          }
87        }
88      })
89    }
90  }
91  return flag
92}
93
94export function getRequireString (loaderContext, loader, filepath) {
95  return 'require(' +
96                loaderUtils.stringifyRequest(
97                  loaderContext,
98                  loader ?
99                    `!!${loader}!${filepath}` :
100                    `${filepath}`
101                ) +
102           ')\n'
103}
104
105export function stringifyLoaders (loaders) {
106  return loaders.map(loader => {
107    if (typeof loader === 'string') {
108      return loader
109    }
110    else {
111      const name = loader.name
112      const query = []
113      if (loader.query) {
114        for (const k in loader.query) {
115          const v = loader.query[k]
116          if (v != null) {
117            if (v === true) {
118              query.push(k)
119            }
120            else if (v instanceof Array) {
121              query.push(`${k}[]=${v.join(',')}`)
122            }
123            else {
124              query.push(`${k}=${v}`)
125            }
126          }
127        }
128      }
129      return `${name}${query.length ? ('?' + query.join('&')) : ''}`
130    }
131  }).join('!')
132}
133
134export function generateMap (loader, source, iterator) {
135  const filePath = loader.resourcePath
136
137  const fileNameWithHash = getFileNameWithHash(filePath)
138  const sourceRoot = path.resolve('.')
139
140  const map = new SourceMapGenerator({
141    sourceRoot,
142    skipValidation: true
143  })
144  map.setSourceContent(fileNameWithHash, source)
145
146  for (const { original, generated } of iterator) {
147    map.addMapping({
148      source: fileNameWithHash,
149      original,
150      generated
151    })
152  }
153
154  return map
155}
156
157export function consumeMap (loader, target, map) {
158  const smc = new SourceMapConsumer(map)
159  let source
160  const original = []
161  const generated = []
162  const mapping = {}
163
164  splitSourceLine(target)
165    .forEach((input, line) => {
166      const column = 0
167      line = line + 1
168
169      const pos = smc.originalPositionFor({
170        line,
171        column
172      })
173
174      if (pos.source) {
175        source = pos.source
176        original.push({
177          line: pos.line,
178          column: pos.column
179        })
180        generated.push({
181          line,
182          column
183        })
184        mapping[`line-${line}-column-${column}`] = {
185          line: pos.line,
186          column: pos.column
187        }
188      }
189    })
190
191  return {
192    source,
193    original,
194    generated,
195    mapping,
196    sourcesContent: smc.sourcesContent
197  }
198}
199
200const LINE_REG = /\r?\n/g
201export function splitSourceLine (source) {
202  return source.split(LINE_REG)
203}
204
205export function printSourceWithLine (source) {
206  console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
207  source = splitSourceLine(source)
208    .map((input, line) => {
209      console.log(line + 1 + ':', input)
210    })
211  console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
212}
213
214export function loadBabelModule (moduleName) {
215  try {
216    const filePath = require.resolve(moduleName)
217    return filePath.slice(0, filePath.indexOf(moduleName.replace(/\//g, path.sep)) + moduleName.length)
218  }
219  catch (e) {
220    return moduleName
221  }
222}
223
224const methodForLite =
225`
226function requireModule(moduleName) {
227  return requireNative(moduleName.slice(1));
228}
229`
230const methodForOthers =
231`
232function requireModule(moduleName) {
233  const systemList = ['system.router', 'system.app', 'system.prompt', 'system.configuration',
234  'system.image', 'system.device', 'system.mediaquery', 'ohos.animator', 'system.grid', 'system.resource']
235  var target = ''
236  if (systemList.includes(moduleName.replace('@', ''))) {
237    target = $app_require$('@app-module/' + moduleName.substring(1));
238    return target;
239  }
240  var shortName = moduleName.replace(/@[^.]+\.([^.]+)/, '$1');
241  target = requireNapi(shortName);
242  if (target !== 'undefined' && /@ohos/.test(moduleName)) {
243    return target;
244  }
245  if (typeof ohosplugin !== 'undefined' && /@ohos/.test(moduleName)) {
246    target = ohosplugin;
247    for (let key of shortName.split('.')) {
248      target = target[key];
249      if(!target) {
250        break;
251      }
252    }
253    if (typeof target !== 'undefined') {
254      return target;
255    }
256  }
257  if (typeof systemplugin !== 'undefined') {
258    target = systemplugin;
259    for (let key of shortName.split('.')) {
260      target = target[key];
261      if(!target) {
262        break;
263      }
264    }
265    if (typeof target !== 'undefined') {
266      return target;
267    }
268  }
269  return target;
270}
271`
272export function parseRequireModule (source) {
273  const requireMethod = process.env.DEVICE_LEVEL === DEVICE_LEVEL.LITE ? methodForLite : methodForOthers
274  source = `${source}\n${requireMethod}`
275  const requireReg = /require\(['"]([^()]+)['"]\)/g
276  const libReg = /^lib(.+)\.so$/
277  let requireStatements = source.match(requireReg)
278  if (requireStatements && requireStatements.length) {
279    for (let requireStatement of requireStatements) {
280      if (requireStatement.indexOf('@system') > 0 || requireStatement.indexOf('@ohos') > 0) {
281        source = source.replace(requireStatement, requireStatement.replace('require', 'requireModule'))
282      }
283    }
284  }
285  source = source.replace(requireReg, (item, item1) => {
286    if (libReg.test(item1)) {
287      item = `requireNapi("${item1.replace(libReg, '$1')}", true)`
288    }
289    return item
290  })
291  return source
292}
293
294export function jsonLoaders (type, customLoader, isVisual, queryType) {
295  let loaders = []
296
297  switch (type) {
298    case "template":
299      loaders = [{
300        name: path.resolve(__dirname, 'json.js')
301      }, {
302        name: path.resolve(__dirname, 'template.js')
303      }]
304      break
305    case "style":
306      loaders = [{
307        name: path.resolve(__dirname, 'json.js')
308      }, {
309        name: path.resolve(__dirname, 'style.js')
310      }]
311      break
312    case "json":
313      loaders = [{
314        name: path.resolve(__dirname, 'json.js')
315      }]
316      break
317    default:
318      break
319  }
320
321  if (customLoader) {
322    loaders.push({
323      name: path.resolve(__dirname, `../node_modules/${customLoader}`)
324    })
325  }
326
327  if (isVisual) {
328    loaders.push({
329      name: path.resolve(__dirname, 'extgen.js'),
330      query: {
331        type: queryType
332      }
333    })
334  }
335
336  return stringifyLoaders(loaders)
337}
338