@mpxjs/webpack-plugin 2.10.19 → 2.10.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/lib/dependencies/ResolveDependency.js +2 -2
  2. package/lib/index.js +38 -7
  3. package/lib/json-compiler/helper.js +11 -10
  4. package/lib/json-compiler/index.js +7 -4
  5. package/lib/json-compiler/plugin.js +4 -4
  6. package/lib/loader.js +4 -4
  7. package/lib/native-loader.js +4 -4
  8. package/lib/parser.js +1 -1
  9. package/lib/platform/create-diagnostic.js +168 -0
  10. package/lib/platform/index.js +16 -3
  11. package/lib/platform/json/wx/index.js +66 -17
  12. package/lib/platform/run-rules.js +9 -5
  13. package/lib/platform/style/wx/index.js +82 -33
  14. package/lib/platform/template/normalize-component-rules.js +7 -9
  15. package/lib/platform/template/wx/component-config/block.js +2 -1
  16. package/lib/platform/template/wx/component-config/custom-built-in-component.js +34 -0
  17. package/lib/platform/template/wx/component-config/index.js +18 -3
  18. package/lib/platform/template/wx/component-config/input.js +1 -7
  19. package/lib/platform/template/wx/component-config/movable-view.js +1 -7
  20. package/lib/platform/template/wx/component-config/text.js +1 -1
  21. package/lib/platform/template/wx/component-config/textarea.js +1 -25
  22. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  23. package/lib/platform/template/wx/index.js +48 -34
  24. package/lib/react/processJSON.js +7 -4
  25. package/lib/react/processStyles.js +22 -8
  26. package/lib/react/processTemplate.js +98 -41
  27. package/lib/react/style-helper.js +121 -86
  28. package/lib/react/template-loader.js +161 -0
  29. package/lib/runtime/components/react/context.ts +8 -1
  30. package/lib/runtime/components/react/dist/context.d.ts +6 -1
  31. package/lib/runtime/components/react/dist/context.js +1 -0
  32. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -0
  33. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +1 -1
  34. package/lib/runtime/components/react/dist/mpx-button.d.ts +1 -1
  35. package/lib/runtime/components/react/dist/mpx-button.jsx +6 -5
  36. package/lib/runtime/components/react/dist/mpx-camera.jsx +1 -0
  37. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +4 -1
  38. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -1
  39. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +6 -4
  40. package/lib/runtime/components/react/dist/mpx-form.jsx +3 -3
  41. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +5 -1
  42. package/lib/runtime/components/react/dist/mpx-image.d.ts +3 -3
  43. package/lib/runtime/components/react/dist/mpx-image.jsx +45 -12
  44. package/lib/runtime/components/react/dist/mpx-inline-text.jsx +10 -6
  45. package/lib/runtime/components/react/dist/mpx-input.jsx +17 -4
  46. package/lib/runtime/components/react/dist/mpx-label.jsx +6 -4
  47. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +19 -4
  48. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +12 -2
  49. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +1 -1
  50. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +7 -4
  51. package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
  52. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +4 -1
  53. package/lib/runtime/components/react/dist/mpx-radio.jsx +5 -4
  54. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -1
  55. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +13 -4
  56. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +52 -6
  57. package/lib/runtime/components/react/dist/mpx-simple-view.jsx +36 -6
  58. package/lib/runtime/components/react/dist/mpx-slider.jsx +2 -1
  59. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +8 -4
  60. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +6 -4
  61. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +7 -4
  62. package/lib/runtime/components/react/dist/mpx-swiper.jsx +15 -4
  63. package/lib/runtime/components/react/dist/mpx-switch.jsx +4 -1
  64. package/lib/runtime/components/react/dist/mpx-text.jsx +57 -12
  65. package/lib/runtime/components/react/dist/mpx-video.d.ts +2 -1
  66. package/lib/runtime/components/react/dist/mpx-video.jsx +10 -4
  67. package/lib/runtime/components/react/dist/mpx-view.jsx +42 -7
  68. package/lib/runtime/components/react/dist/utils.d.ts +21 -11
  69. package/lib/runtime/components/react/dist/utils.jsx +105 -35
  70. package/lib/runtime/components/react/getInnerListeners.ts +1 -0
  71. package/lib/runtime/components/react/mpx-async-suspense.tsx +2 -1
  72. package/lib/runtime/components/react/mpx-button.tsx +6 -5
  73. package/lib/runtime/components/react/mpx-camera.tsx +1 -0
  74. package/lib/runtime/components/react/mpx-canvas/index.tsx +4 -1
  75. package/lib/runtime/components/react/mpx-checkbox-group.tsx +2 -1
  76. package/lib/runtime/components/react/mpx-checkbox.tsx +6 -4
  77. package/lib/runtime/components/react/mpx-form.tsx +3 -3
  78. package/lib/runtime/components/react/mpx-icon/index.tsx +5 -1
  79. package/lib/runtime/components/react/mpx-image.tsx +57 -20
  80. package/lib/runtime/components/react/mpx-inline-text.tsx +12 -7
  81. package/lib/runtime/components/react/mpx-input.tsx +17 -4
  82. package/lib/runtime/components/react/mpx-label.tsx +6 -4
  83. package/lib/runtime/components/react/mpx-movable-view.tsx +20 -4
  84. package/lib/runtime/components/react/mpx-picker/index.tsx +12 -2
  85. package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
  86. package/lib/runtime/components/react/mpx-picker-view/index.tsx +8 -4
  87. package/lib/runtime/components/react/mpx-portal/index.tsx +5 -1
  88. package/lib/runtime/components/react/mpx-radio-group.tsx +4 -1
  89. package/lib/runtime/components/react/mpx-radio.tsx +5 -4
  90. package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -1
  91. package/lib/runtime/components/react/mpx-scroll-view.tsx +13 -4
  92. package/lib/runtime/components/react/mpx-simple-text.tsx +55 -8
  93. package/lib/runtime/components/react/mpx-simple-view.tsx +30 -6
  94. package/lib/runtime/components/react/mpx-slider.tsx +2 -1
  95. package/lib/runtime/components/react/mpx-sticky-header.tsx +8 -4
  96. package/lib/runtime/components/react/mpx-sticky-section.tsx +6 -4
  97. package/lib/runtime/components/react/mpx-swiper-item.tsx +7 -4
  98. package/lib/runtime/components/react/mpx-swiper.tsx +16 -4
  99. package/lib/runtime/components/react/mpx-switch.tsx +4 -1
  100. package/lib/runtime/components/react/mpx-text.tsx +55 -15
  101. package/lib/runtime/components/react/mpx-video.tsx +11 -5
  102. package/lib/runtime/components/react/mpx-view.tsx +35 -7
  103. package/lib/runtime/components/react/types/global.d.ts +4 -0
  104. package/lib/runtime/components/react/utils.tsx +126 -45
  105. package/lib/runtime/components/wx/default-component.mpx +9 -0
  106. package/lib/runtime/components/wx/default-page.mpx +3 -11
  107. package/lib/runtime/optionProcessor.d.ts +2 -0
  108. package/lib/runtime/optionProcessor.js +77 -1
  109. package/lib/runtime/optionProcessorReact.js +5 -0
  110. package/lib/script-setup-compiler/index.js +1 -1
  111. package/lib/style-compiler/index.js +2 -0
  112. package/lib/style-compiler/plugins/remove-strip-conditional-comments.js +14 -0
  113. package/lib/style-compiler/plugins/trans-special.js +1 -1
  114. package/lib/style-compiler/strip-conditional.js +40 -26
  115. package/lib/template-compiler/compiler.js +306 -125
  116. package/lib/template-compiler/gen-node-react.js +35 -7
  117. package/lib/template-compiler/index.js +9 -7
  118. package/lib/utils/const.js +4 -1
  119. package/lib/utils/gen-component-tag.js +1 -5
  120. package/lib/utils/normalize-perf-options.js +47 -0
  121. package/lib/utils/partial-compile-rules.js +27 -0
  122. package/lib/utils/pre-process-json.js +3 -0
  123. package/lib/utils/source-location.js +96 -0
  124. package/lib/web/compile-wx-template-fragment.js +68 -0
  125. package/lib/web/index.js +3 -0
  126. package/lib/web/processJSON.js +7 -4
  127. package/lib/web/processMainScript.js +3 -7
  128. package/lib/web/processScript.js +43 -8
  129. package/lib/web/processStyles.js +12 -3
  130. package/lib/web/processTemplate.js +61 -19
  131. package/lib/web/template-loader.js +123 -0
  132. package/lib/web/template-shared.js +48 -0
  133. package/lib/wxml/loader.js +4 -3
  134. package/lib/wxss/loader.js +1 -1
  135. package/lib/wxss/utils.js +6 -4
  136. package/package.json +12 -4
  137. package/lib/platform/template/wx/component-config/component.js +0 -41
@@ -1,7 +1,7 @@
1
1
  const NullDependency = require('webpack/lib/dependencies/NullDependency')
2
2
  const parseRequest = require('../utils/parse-request')
3
3
  const makeSerializable = require('webpack/lib/util/makeSerializable')
4
- const { matchCondition } = require('../utils/match-condition')
4
+ const { isPartialCompileExcluded } = require('../utils/partial-compile-rules')
5
5
 
6
6
  class ResolveDependency extends NullDependency {
7
7
  constructor (resource, packageName, issuerResource, range) {
@@ -35,7 +35,7 @@ class ResolveDependency extends NullDependency {
35
35
  const mainStaticResourcesMap = staticResourcesMap.main
36
36
  const resolveResult = pagesMap[resourcePath] || currentComponentsMap[resourcePath] || mainComponentsMap[resourcePath] || currentStaticResourcesMap[resourcePath] || mainStaticResourcesMap[resourcePath] || ''
37
37
  if (!resolveResult) {
38
- if (!partialCompileRules || matchCondition(resourcePath, partialCompileRules)) {
38
+ if (!isPartialCompileExcluded(resourcePath, partialCompileRules, 'page') && !isPartialCompileExcluded(resourcePath, partialCompileRules, 'component')) {
39
39
  compilation.errors.push(new Error(`[Mpx json error]:Path ${resource} is not a page/component/static resource, which is resolved from ${issuerResource}!`))
40
40
  }
41
41
  }
package/lib/index.js CHANGED
@@ -51,7 +51,9 @@ const fixRelative = require('./utils/fix-relative')
51
51
  const parseRequest = require('./utils/parse-request')
52
52
  const { transSubpackage } = require('./utils/trans-async-sub-rules')
53
53
  const { matchCondition } = require('./utils/match-condition')
54
+ const { getPartialCompileRules } = require('./utils/partial-compile-rules')
54
55
  const processDefs = require('./utils/process-defs')
56
+ const { PERF_GROUPS, normalizePerfOptions } = require('./utils/normalize-perf-options')
55
57
  const config = require('./config')
56
58
  const hash = require('hash-sum')
57
59
  const nativeLoaderPath = normalize.lib('native-loader')
@@ -163,13 +165,24 @@ class MpxWebpackPlugin {
163
165
  options.transMpxRules = options.transMpxRules || {
164
166
  include: () => true
165
167
  }
168
+ // 归一化 perf 配置:{ enable, probes: [...] } → { enable, framework, user, ... }
169
+ // 分组未知 / typo 在此直接抛错,避免静默失效。
170
+ const perf = normalizePerfOptions(options.perf)
171
+ options.perf = perf
166
172
  // 通过默认defs配置实现mode及srcMode的注入,简化内部处理逻辑
167
173
  options.defs = Object.assign({}, options.defs, {
168
174
  __mpx_mode__: options.mode,
169
175
  __mpx_src_mode__: options.srcMode,
170
176
  __mpx_env__: options.env,
171
- __mpx_dynamic_runtime__: options.dynamicRuntime
177
+ __mpx_dynamic_runtime__: options.dynamicRuntime,
178
+ // 总开关:@mpxjs/perf 包内部使用,决定 impl 是否进入 bundle。
179
+ __mpx_perf__: perf.enable
172
180
  })
181
+ // 分组开关:调用方点缀代码使用。开关粒度独立、产物 DCE 独立。
182
+ for (let i = 0; i < PERF_GROUPS.length; i++) {
183
+ const k = PERF_GROUPS[i]
184
+ options.defs[`__mpx_perf_${k}__`] = perf[k]
185
+ }
173
186
  // 批量指定源码mode
174
187
  options.modeRules = options.modeRules || {}
175
188
  options.generateBuildMap = options.generateBuildMap || false
@@ -494,13 +507,31 @@ class MpxWebpackPlugin {
494
507
 
495
508
  let mpx
496
509
 
497
- if (this.options.partialCompileRules) {
510
+ const pagePartialCompileRules = getPartialCompileRules(this.options.partialCompileRules, 'page')
511
+ const componentPartialCompileRules = getPartialCompileRules(this.options.partialCompileRules, 'component')
512
+
513
+ if (pagePartialCompileRules || componentPartialCompileRules) {
498
514
  function isResolvingPage (obj) {
499
515
  // valid query should start with '?'
500
516
  const query = parseQuery(obj.query || '?')
501
517
  return query.isPage && !query.type
502
518
  }
503
519
 
520
+ function isResolvingComponent (obj) {
521
+ // valid query should start with '?'
522
+ const query = parseQuery(obj.query || '?')
523
+ return query.isComponent && !query.type
524
+ }
525
+
526
+ const replaceResource = (obj, target) => {
527
+ const infix = obj.query ? '&' : '?'
528
+ obj.query += `${infix}resourcePath=${obj.path}`
529
+ obj.path = target
530
+ }
531
+
532
+ const defaultPagePath = require.resolve('./runtime/components/wx/default-page.mpx')
533
+ const defaultComponentPath = require.resolve('./runtime/components/wx/default-component.mpx')
534
+
504
535
  // new PartialCompilePlugin(this.options.partialCompile).apply(compiler)
505
536
  compiler.resolverFactory.hooks.resolver.intercept({
506
537
  factory: (type, hook) => {
@@ -509,13 +540,13 @@ class MpxWebpackPlugin {
509
540
  name: 'MpxPartialCompilePlugin',
510
541
  stage: -100
511
542
  }, (obj, resolverContext, callback) => {
512
- if (obj.path.startsWith(require.resolve('./runtime/components/wx/default-page.mpx'))) {
543
+ if (obj.path.startsWith(defaultPagePath) || obj.path.startsWith(defaultComponentPath)) {
513
544
  return callback(null, obj)
514
545
  }
515
- if (isResolvingPage(obj) && !matchCondition(obj.path, this.options.partialCompileRules)) {
516
- const infix = obj.query ? '&' : '?'
517
- obj.query += `${infix}resourcePath=${obj.path}`
518
- obj.path = require.resolve('./runtime/components/wx/default-page.mpx')
546
+ if (pagePartialCompileRules && isResolvingPage(obj) && !matchCondition(obj.path, pagePartialCompileRules)) {
547
+ replaceResource(obj, defaultPagePath)
548
+ } else if (componentPartialCompileRules && isResolvingComponent(obj) && !matchCondition(obj.path, componentPartialCompileRules)) {
549
+ replaceResource(obj, defaultComponentPath)
519
550
  }
520
551
  callback(null, obj)
521
552
  })
@@ -51,6 +51,8 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom
51
51
  if (resolveMode === 'native') {
52
52
  component = urlToRequest(component)
53
53
  }
54
+ // 增加 component 标识,与 page 的 partialCompile 处理保持一致
55
+ component = addQuery(component, { isComponent: true })
54
56
  resolve(context, component, loaderContext, (err, resource, info) => {
55
57
  if (err) return callback(err)
56
58
  const { resourcePath, queryObj } = parseRequest(resource)
@@ -168,14 +170,14 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom
168
170
  })
169
171
  }
170
172
 
171
- const fillInComponentPlaceholder = ({ jsonObj, name: componentName, placeholder, placeholderEntry, resolveResourcePathMap }, callback) => {
173
+ const fillInComponentPlaceholder = ({ jsonObj, name: componentName, placeholder, placeholderEntry, resolveResourcePathMap }) => {
172
174
  let placeholderComponentName = placeholder.name
173
175
  const componentPlaceholder = jsonObj.componentPlaceholder || {}
174
176
  if (componentPlaceholder[componentName]) {
175
- callback()
176
177
  return
177
178
  }
178
179
  jsonObj.componentPlaceholder = componentPlaceholder
180
+ componentPlaceholder[componentName] = placeholderComponentName
179
181
  if (placeholderEntry) {
180
182
  if (resolveResourcePathMap.has(placeholderComponentName) && resolveResourcePathMap.get(placeholderComponentName) !== placeholder.resourcePath) {
181
183
  // 如果存在placeholder与已有usingComponents冲突, 重新生成一个组件名,在当前组件后增加一个数字
@@ -184,16 +186,15 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom
184
186
  while (jsonObj.usingComponents[newPlaceholder]) {
185
187
  newPlaceholder = placeholderComponentName + ++i
186
188
  }
187
- placeholderComponentName = newPlaceholder
189
+ componentPlaceholder[componentName] = placeholderComponentName = newPlaceholder
188
190
  }
189
191
  jsonObj.usingComponents[placeholderComponentName] = placeholderEntry
190
192
  resolveResourcePathMap.set(placeholderComponentName, placeholder.resourcePath)
193
+ return {
194
+ name: placeholderComponentName,
195
+ entry: placeholderEntry
196
+ }
191
197
  }
192
- componentPlaceholder[componentName] = placeholderComponentName
193
- callback(null, {
194
- name: placeholderComponentName,
195
- entry: placeholderEntry
196
- })
197
198
  }
198
199
 
199
200
  const getNormalizePlaceholder = (placeholder) => {
@@ -218,10 +219,10 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom
218
219
  processComponent(placeholder.resource, context, { relativePath }, (err, entry, { resourcePath }) => {
219
220
  if (err) return callback(err)
220
221
  placeholder.resourcePath = resourcePath
221
- fillInComponentPlaceholder({ jsonObj, name, placeholder, placeholderEntry: entry, resolveResourcePathMap }, callback)
222
+ callback(null, fillInComponentPlaceholder({ jsonObj, name, placeholder, placeholderEntry: entry, resolveResourcePathMap }))
222
223
  })
223
224
  } else {
224
- fillInComponentPlaceholder({ jsonObj, name, placeholder }, callback)
225
+ callback(null, fillInComponentPlaceholder({ jsonObj, name, placeholder }))
225
226
  }
226
227
  } else {
227
228
  if (!jsonObj.componentPlaceholder || !jsonObj.componentPlaceholder[name]) {
@@ -46,15 +46,15 @@ module.exports = function (content) {
46
46
  const fs = this._compiler.inputFileSystem
47
47
  const runtimeCompile = queryObj.isDynamic
48
48
 
49
- const emitWarning = (msg) => {
49
+ const emitWarning = (msg, loc) => {
50
50
  this.emitWarning(
51
- new Error('[Mpx json error][' + this.resource + ']: ' + msg)
51
+ new Error('[Mpx json error][' + (loc || this.resourcePath) + ']: ' + msg)
52
52
  )
53
53
  }
54
54
 
55
- const emitError = (msg) => {
55
+ const emitError = (msg, loc) => {
56
56
  this.emitError(
57
- new Error('[Mpx json error][' + this.resource + ']: ' + msg)
57
+ new Error('[Mpx json error][' + (loc || this.resourcePath) + ']: ' + msg)
58
58
  )
59
59
  }
60
60
 
@@ -180,6 +180,9 @@ module.exports = function (content) {
180
180
  waterfall: true,
181
181
  warn: emitWarning,
182
182
  error: emitError,
183
+ diagnostic: {
184
+ file: resourcePath
185
+ },
183
186
  data: {
184
187
  // polyfill global usingComponents
185
188
  globalComponents: mpx.globalComponents
@@ -21,15 +21,15 @@ module.exports = function (source) {
21
21
 
22
22
  this._module.addPresentationalDependency(new FlagPluginDependency())
23
23
 
24
- const emitWarning = (msg) => {
24
+ const emitWarning = (msg, loc) => {
25
25
  this.emitWarning(
26
- new Error('[Mpx json warning][' + this.resource + ']: ' + msg)
26
+ new Error('[Mpx json warning][' + (loc || this.resourcePath) + ']: ' + msg)
27
27
  )
28
28
  }
29
29
 
30
- const emitError = (msg) => {
30
+ const emitError = (msg, loc) => {
31
31
  this.emitError(
32
- new Error('[Mpx json error][' + this.resource + ']: ' + msg)
32
+ new Error('[Mpx json error][' + (loc || this.resourcePath) + ']: ' + msg)
33
33
  )
34
34
  }
35
35
 
package/lib/loader.js CHANGED
@@ -53,15 +53,15 @@ module.exports = function (content) {
53
53
  const autoScope = matchCondition(resourcePath, mpx.autoScopeRules)
54
54
  const isRuntimeMode = queryObj.isDynamic
55
55
 
56
- const emitWarning = (msg) => {
56
+ const emitWarning = (msg, loc) => {
57
57
  this.emitWarning(
58
- new Error('[Mpx json warning][' + this.resource + ']: ' + msg)
58
+ new Error('[Mpx json warning][' + (loc || this.resourcePath) + ']: ' + msg)
59
59
  )
60
60
  }
61
61
 
62
- const emitError = (msg) => {
62
+ const emitError = (msg, loc) => {
63
63
  this.emitError(
64
- new Error('[Mpx json error][' + this.resource + ']: ' + msg)
64
+ new Error('[Mpx json error][' + (loc || this.resourcePath) + ']: ' + msg)
65
65
  )
66
66
  }
67
67
 
@@ -105,15 +105,15 @@ module.exports = function (content) {
105
105
  })
106
106
  }
107
107
 
108
- const emitWarning = (msg) => {
108
+ const emitWarning = (msg, loc) => {
109
109
  this.emitWarning(
110
- new Error('[Mpx json warning][native-loader][' + this.resource + ']: ' + msg)
110
+ new Error('[Mpx json warning][native-loader][' + (loc || this.resourcePath) + ']: ' + msg)
111
111
  )
112
112
  }
113
113
 
114
- const emitError = (msg) => {
114
+ const emitError = (msg, loc) => {
115
115
  this.emitError(
116
- new Error('[Mpx json error][native-loader][' + this.resource + ']: ' + msg)
116
+ new Error('[Mpx json error][native-loader][' + (loc || this.resourcePath) + ']: ' + msg)
117
117
  )
118
118
  }
119
119
  let ctorType = pagesMap[resourcePath]
package/lib/parser.js CHANGED
@@ -14,7 +14,7 @@ module.exports = (content, { filePath, needMap, mode, env }) => {
14
14
  output = compiler.parseComponent(content, {
15
15
  mode,
16
16
  filePath,
17
- pad: 'line',
17
+ pad: mode !== 'web' && 'line',
18
18
  env
19
19
  })
20
20
  if (needMap) {
@@ -0,0 +1,168 @@
1
+ const {
2
+ normalizeLoc,
3
+ createCodeFrame,
4
+ originalPositionFor,
5
+ readSource
6
+ } = require('../utils/source-location')
7
+
8
+ function formatAttr (attr) {
9
+ if (!attr) return ''
10
+ if (attr.value === true || attr.value == null) return attr.name
11
+ return `${attr.name}="${attr.value}"`
12
+ }
13
+
14
+ function formatTarget (context, extra) {
15
+ const target = extra && extra.target
16
+ if (target) {
17
+ if (target.kind === 'css-decl') return `${target.prop}: ${target.value}`
18
+ if (target.kind === 'css-atrule') return `@${target.name}${target.params ? ' ' + target.params : ''}`
19
+ if (target.kind === 'selector') return target.value
20
+ if (target.kind === 'event') return target.name
21
+ }
22
+ const input = context && context.input
23
+ const data = context && context.data
24
+ if (data && data.attr) {
25
+ return `<${data.el && data.el.tag}${formatAttr(data.attr) ? ' ' + formatAttr(data.attr) : ''}>`
26
+ }
27
+ if (input && input.prop) {
28
+ return `${input.prop}: ${input.value}`
29
+ }
30
+ if (input && input.selector) {
31
+ return input.selector
32
+ }
33
+ return ''
34
+ }
35
+
36
+ function inferPath (context, extra) {
37
+ if (extra && extra.path) {
38
+ return Array.isArray(extra.path) ? extra.path.join('.') : extra.path
39
+ }
40
+ const data = context && context.data
41
+ const meta = context && context.meta
42
+ if (data && meta && Array.isArray(meta.paths)) {
43
+ const paths = meta.paths.join('|')
44
+ return (data.pathArr || []).concat(paths).filter(Boolean).join('.')
45
+ }
46
+ }
47
+
48
+ function formatValue (value) {
49
+ if (value === undefined) return 'undefined'
50
+ let result
51
+ try {
52
+ result = JSON.stringify(value)
53
+ } catch (e) {
54
+ result = String(value)
55
+ }
56
+ if (result === undefined) result = String(value)
57
+ return result.length > 120 ? result.slice(0, 117) + '...' : result
58
+ }
59
+
60
+ function inferJsonTarget (context, extra) {
61
+ const path = inferPath(context, extra)
62
+ if (!path) return ''
63
+ if (extra && Object.prototype.hasOwnProperty.call(extra, 'value')) {
64
+ return `${path}: ${formatValue(extra.value)}`
65
+ }
66
+ return path
67
+ }
68
+
69
+ function inferLoc (context, extra) {
70
+ if (extra) {
71
+ if (extra.loc) return normalizeLoc(extra.loc)
72
+ if (extra.node && extra.node.source) return normalizeLoc(extra.node.source.start)
73
+ if (extra.decl && extra.decl.source) return normalizeLoc(extra.decl.source.start)
74
+ if (extra.attr) return normalizeLoc(extra.attr.loc)
75
+ if (extra.el) return normalizeLoc(extra.el.loc)
76
+ }
77
+ const input = context && context.input
78
+ const data = context && context.data
79
+ if (data) {
80
+ if (data.attr && data.attr.loc) return normalizeLoc(data.attr.loc)
81
+ if (data.el && data.el.loc) return normalizeLoc(data.el.loc)
82
+ }
83
+ if (input) {
84
+ if (input.decl && input.decl.source) return normalizeLoc(input.decl.source.start)
85
+ if (input.rule && input.rule.source) return normalizeLoc(input.rule.source.start)
86
+ if (input.loc) return normalizeLoc(input.loc)
87
+ }
88
+ }
89
+
90
+ function inferSourceMap (context, extra, base) {
91
+ if (extra && extra.sourceMap) return extra.sourceMap
92
+ if (context && context.input && context.input.sourceMap) return context.input.sourceMap
93
+ return base && base.sourceMap
94
+ }
95
+
96
+ function createDiagnostic ({
97
+ type,
98
+ mode,
99
+ srcMode,
100
+ warn,
101
+ error,
102
+ diagnostic = {}
103
+ }) {
104
+ const stack = []
105
+ const file = diagnostic.file
106
+ const source = diagnostic.source
107
+ const inputFileSystem = diagnostic.inputFileSystem
108
+
109
+ function withContext (context, fn) {
110
+ stack.push(context)
111
+ try {
112
+ return fn()
113
+ } finally {
114
+ stack.pop()
115
+ }
116
+ }
117
+
118
+ function format (msg, extra) {
119
+ msg = msg && msg.message ? msg.message : String(msg)
120
+ const context = stack[stack.length - 1]
121
+ const lines = []
122
+ const loc = inferLoc(context, extra)
123
+ const sourceMap = inferSourceMap(context, extra, diagnostic)
124
+ let finalFile = file
125
+ let finalLoc = loc
126
+ let finalSource = source
127
+ let original
128
+ if (sourceMap && loc) {
129
+ original = originalPositionFor(sourceMap, loc)
130
+ if (original) {
131
+ finalFile = original.file
132
+ finalLoc = original.loc
133
+ finalSource = original.source || readSource(original.file, inputFileSystem)
134
+ }
135
+ }
136
+ const hasLoc = finalLoc && finalLoc.start
137
+ const locText = finalFile && hasLoc
138
+ ? `${finalFile}:${finalLoc.start.line}:${finalLoc.start.column}`
139
+ : ''
140
+ lines.push(msg)
141
+ const target = formatTarget(context, extra) || (type === 'json' ? inferJsonTarget(context, extra) : inferPath(context, extra))
142
+ if (target) lines.push(`Target: ${target}`)
143
+ if (srcMode || mode) lines.push(`Mode: ${srcMode || ''}${srcMode && mode ? ' -> ' : ''}${mode || ''}`)
144
+ const frame = createCodeFrame(finalSource, finalLoc)
145
+ if (frame) {
146
+ lines.push('')
147
+ lines.push(frame)
148
+ }
149
+ return {
150
+ message: lines.join('\n'),
151
+ loc: locText || undefined
152
+ }
153
+ }
154
+
155
+ return {
156
+ warn (msg, extra) {
157
+ const result = format(msg, extra)
158
+ warn && warn(result.message, result.loc)
159
+ },
160
+ error (msg, extra) {
161
+ const result = format(msg, extra)
162
+ error && error(result.message, result.loc)
163
+ },
164
+ withContext
165
+ }
166
+ }
167
+
168
+ module.exports = createDiagnostic
@@ -1,4 +1,5 @@
1
1
  const runRules = require('./run-rules')
2
+ const createDiagnostic = require('./create-diagnostic')
2
3
 
3
4
  module.exports = function getRulesRunner ({
4
5
  type,
@@ -10,7 +11,8 @@ module.exports = function getRulesRunner ({
10
11
  mainKey,
11
12
  waterfall,
12
13
  warn,
13
- error
14
+ error,
15
+ diagnostic
14
16
  }) {
15
17
  const specMap = {
16
18
  template: {
@@ -23,13 +25,24 @@ module.exports = function getRulesRunner ({
23
25
  wx: require('./json/wx')
24
26
  }
25
27
  }
26
- const spec = specMap[type] && specMap[type][srcMode] && specMap[type][srcMode]({ warn, error })
28
+ diagnostic = createDiagnostic({
29
+ type,
30
+ mode,
31
+ srcMode,
32
+ warn,
33
+ error,
34
+ diagnostic
35
+ })
36
+ const spec = specMap[type] && specMap[type][srcMode] && specMap[type][srcMode]({
37
+ warn: diagnostic.warn,
38
+ error: diagnostic.error
39
+ })
27
40
  if (spec && spec.supportedModes.indexOf(mode) > -1) {
28
41
  const normalizeTest = spec.normalizeTest
29
42
  const mainRules = mainKey ? spec[mainKey] : spec
30
43
  if (mainRules) {
31
44
  return function (input) {
32
- return runRules(mainRules, input, { mode, data, meta, testKey, waterfall, normalizeTest })
45
+ return runRules(mainRules, input, { mode, data, meta, testKey, waterfall, normalizeTest, diagnostic })
33
46
  }
34
47
  }
35
48
  }