@mpxjs/webpack-plugin 2.7.52 → 2.8.0-beta.2

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 (71) hide show
  1. package/lib/config.js +24 -24
  2. package/lib/dependencies/CommonJsVariableDependency.js +1 -1
  3. package/lib/dependencies/DynamicEntryDependency.js +18 -11
  4. package/lib/extractor.js +1 -1
  5. package/lib/helpers.js +3 -1
  6. package/lib/index.js +24 -21
  7. package/lib/json-compiler/helper.js +1 -1
  8. package/lib/json-compiler/index.js +17 -17
  9. package/lib/json-compiler/plugin.js +3 -2
  10. package/lib/json-compiler/theme.js +1 -1
  11. package/lib/loader.js +3 -3
  12. package/lib/native-loader.js +1 -1
  13. package/lib/platform/json/normalize-test.js +3 -1
  14. package/lib/platform/run-rules.js +2 -2
  15. package/lib/platform/template/wx/component-config/camera.js +3 -3
  16. package/lib/platform/template/wx/component-config/canvas.js +5 -5
  17. package/lib/platform/template/wx/component-config/map.js +5 -5
  18. package/lib/platform/template/wx/component-config/navigator.js +7 -7
  19. package/lib/platform/template/wx/component-config/progress.js +4 -4
  20. package/lib/platform/template/wx/component-config/scroll-view.js +3 -3
  21. package/lib/platform/template/wx/component-config/slider.js +6 -6
  22. package/lib/platform/template/wx/component-config/swiper.js +2 -2
  23. package/lib/platform/template/wx/component-config/video.js +4 -4
  24. package/lib/platform/template/wx/component-config/view.js +4 -4
  25. package/lib/platform/template/wx/index.js +45 -13
  26. package/lib/resolver/PackageEntryPlugin.js +1 -1
  27. package/lib/runtime/components/web/filterTag.js +6 -6
  28. package/lib/runtime/components/web/getInnerListeners.js +1 -1
  29. package/lib/runtime/components/web/mpx-button.vue +0 -1
  30. package/lib/runtime/components/web/mpx-icon.vue +1 -1
  31. package/lib/runtime/components/web/mpx-keep-alive.vue +2 -2
  32. package/lib/runtime/components/web/mpx-picker.vue +1 -1
  33. package/lib/runtime/components/web/mpx-progress.vue +1 -1
  34. package/lib/runtime/components/web/mpx-scroll-view.vue +1 -1
  35. package/lib/runtime/env.js +1 -0
  36. package/lib/runtime/i18n.wxs +44 -81
  37. package/lib/runtime/optionProcessor.d.ts +0 -4
  38. package/lib/runtime/optionProcessor.js +15 -13
  39. package/lib/runtime/stringify.wxs +3 -3
  40. package/lib/runtime/swanHelper.wxs +2 -2
  41. package/lib/runtime/{components/web/util.js → utils.js} +8 -5
  42. package/lib/script-setup-compiler/index.js +1163 -0
  43. package/lib/style-compiler/index.js +1 -1
  44. package/lib/style-compiler/plugins/rpx.js +1 -1
  45. package/lib/style-compiler/plugins/vw.js +6 -4
  46. package/lib/template-compiler/bind-this.js +5 -5
  47. package/lib/template-compiler/compiler.js +122 -179
  48. package/lib/template-compiler/index.js +3 -3
  49. package/lib/utils/add-query.js +2 -1
  50. package/lib/utils/gen-component-tag.js +1 -1
  51. package/lib/utils/has-own.js +5 -0
  52. package/lib/utils/is-empty-object.js +2 -1
  53. package/lib/utils/parse-request.js +3 -3
  54. package/lib/utils/{index.js → process-defs.js} +3 -10
  55. package/lib/utils/stringify-query.js +23 -21
  56. package/lib/web/processJSON.js +5 -5
  57. package/lib/web/processScript.js +16 -19
  58. package/lib/web/processTemplate.js +1 -1
  59. package/lib/wxml/loader.js +3 -3
  60. package/lib/wxs/i18n-loader.js +4 -11
  61. package/lib/wxs/pre-loader.js +51 -44
  62. package/lib/wxss/compile-exports.js +4 -4
  63. package/lib/wxss/createResolver.js +3 -3
  64. package/lib/wxss/css-base.js +13 -13
  65. package/lib/wxss/getLocalIdent.js +5 -4
  66. package/lib/wxss/loader.js +1 -1
  67. package/lib/wxss/localsLoader.js +14 -14
  68. package/lib/wxss/processCss.js +10 -7
  69. package/package.json +4 -3
  70. package/lib/utils/env.js +0 -4
  71. package/lib/utils/parse-asset.js +0 -195
@@ -0,0 +1,1163 @@
1
+ const babylon = require('@babel/parser')
2
+ const MagicString = require('magic-string')
3
+ const traverse = require('@babel/traverse').default
4
+ const t = require('@babel/types')
5
+ const formatCodeFrame = require('@babel/code-frame')
6
+ const parseRequest = require('../utils/parse-request')
7
+
8
+ // Special compiler macros
9
+ const DEFINE_PROPS = 'defineProps'
10
+ const DEFINE_OPTIONS = 'defineOptions'
11
+ const DEFINE_EXPOSE = 'defineExpose'
12
+ const WITH_DEFAULTS = 'withDefaults'
13
+
14
+ const MPX_CORE = '@mpxjs/core'
15
+
16
+ const BindingTypes = {
17
+ /**
18
+ * declared as a prop
19
+ */
20
+ PROPS: 'props',
21
+ /**
22
+ * a local alias of a `<script setup>` destructured prop.
23
+ * the original is stored in __propsAliases of the bindingMetadata object.
24
+ */
25
+ PROPS_ALIASED: 'props-aliased',
26
+ /**
27
+ * a let binding (may or may not be a ref)
28
+ */
29
+ SETUP_LET: 'setup-let',
30
+ /**
31
+ * a const binding that can never be a ref.
32
+ * these bindings don't need `unref()` calls when processed in inlined
33
+ * template expressions.
34
+ */
35
+ SETUP_CONST: 'setup-const',
36
+ /**
37
+ * a const binding that does not need `unref()`, but may be mutated.
38
+ */
39
+ SETUP_REACTIVE_CONST: 'setup-reactive-const',
40
+ /**
41
+ * a const binding that may be a ref.
42
+ */
43
+ SETUP_MAYBE_REF: 'setup-maybe-ref',
44
+ /**
45
+ * bindings that are guaranteed to be refs
46
+ */
47
+ SETUP_REF: 'setup-ref',
48
+ /**
49
+ * declared by other options, e.g. computed, inject
50
+ */
51
+ OPTIONS: 'options'
52
+ }
53
+
54
+ function compileScriptSetup (
55
+ scriptSetup,
56
+ ctorType,
57
+ filePath
58
+ ) {
59
+ const content = scriptSetup.content
60
+ const _s = new MagicString(content)
61
+ const scriptBindings = Object.create(null)
62
+ const setupBindings = Object.create(null)
63
+ const userImportAlias = Object.create(null)
64
+ const userImports = Object.create(null)
65
+ // const genSourceMap = false
66
+
67
+ let startOffset = 0
68
+ let endOffset = 0
69
+ let hasDefinePropsCall = false
70
+ let hasDefineOptionsCall = false
71
+ let hasDefineExposeCall = false
72
+
73
+ let propsRuntimeDecl
74
+ let propsRuntimeDefaults
75
+ let propsTypeDeclRaw
76
+ let propsTypeDecl
77
+ let propsIdentifier
78
+ let optionsRuntimeDecl
79
+ let exposeRuntimeDecl
80
+
81
+ const scriptSetupLang = scriptSetup && scriptSetup.lang
82
+ const isTS =
83
+ scriptSetupLang === 'ts' ||
84
+ scriptSetupLang === 'tsx'
85
+ const plugins = []
86
+
87
+ if (isTS) plugins.push('typescript', 'decorators-legacy')
88
+
89
+ // props/emits declared via types
90
+ const typeDeclaredProps = {}
91
+ const declaredTypes = {}
92
+
93
+ function error (
94
+ msg,
95
+ node,
96
+ end
97
+ ) {
98
+ throw new Error(
99
+ `[@mpxjs/webpack-plugin script-setup-compiler] ${msg}\n\n${filePath}\n${formatCodeFrame(
100
+ content,
101
+ node.start + startOffset,
102
+ end
103
+ )}`
104
+ )
105
+ }
106
+
107
+ function registerUserImport (
108
+ source,
109
+ local,
110
+ imported = false,
111
+ isType,
112
+ isFromSetup = true,
113
+ needTemplateUsageCheck
114
+ ) {
115
+ if (source === MPX_CORE && imported) {
116
+ userImportAlias[imported] = local
117
+ }
118
+
119
+ userImports[local] = {
120
+ isType,
121
+ imported: imported || 'default',
122
+ source,
123
+ isFromSetup
124
+ }
125
+ }
126
+
127
+ function processDefineExpose (node, declId) {
128
+ if (!isCallOf(node, DEFINE_EXPOSE)) {
129
+ return false
130
+ }
131
+ if (hasDefineExposeCall) {
132
+ error(`duplicate ${DEFINE_EXPOSE}() call`, node)
133
+ }
134
+ hasDefineExposeCall = true
135
+ exposeRuntimeDecl = node.arguments[0]
136
+
137
+ if (node.typeParameters) {
138
+ error(`${DEFINE_EXPOSE} is not support type parameters`, node)
139
+ }
140
+
141
+ if (declId) {
142
+ console.warn(`${DEFINE_OPTIONS} no return value, please check it`, declId)
143
+ }
144
+
145
+ return true
146
+ }
147
+
148
+ function processDefineOptions (node, declId) {
149
+ if (!isCallOf(node, DEFINE_OPTIONS)) {
150
+ return false
151
+ }
152
+ if (hasDefineOptionsCall) {
153
+ error(`duplicate ${DEFINE_OPTIONS}() call`, node)
154
+ }
155
+ hasDefineOptionsCall = true
156
+ const arg0 = node.arguments[0]
157
+ if (arg0.type === 'ObjectExpression') {
158
+ optionsRuntimeDecl = arg0.properties
159
+ } else {
160
+ error(`${DEFINE_OPTIONS} input parameter must be an object`)
161
+ }
162
+
163
+ if (node.typeParameters) {
164
+ error(`${DEFINE_OPTIONS} is not support type parameters`, node)
165
+ }
166
+
167
+ if (declId) {
168
+ console.warn(`${DEFINE_OPTIONS} no return value, please check it`, declId)
169
+ }
170
+ return true
171
+ }
172
+
173
+ function processDefineProps (node, declId) {
174
+ if (!isCallOf(node, DEFINE_PROPS)) {
175
+ return false
176
+ }
177
+ if (hasDefinePropsCall) {
178
+ error(`duplicate ${DEFINE_PROPS}() call`, node)
179
+ }
180
+ hasDefinePropsCall = true
181
+ propsRuntimeDecl = node.arguments[0]
182
+
183
+ /**
184
+ * defineProps<{
185
+ * foo: string
186
+ * bar?: number
187
+ * }>()
188
+ */
189
+ if (node.typeParameters) {
190
+ if (propsRuntimeDecl) {
191
+ error(
192
+ `${DEFINE_PROPS}() cannot accept both type and non-type arguments ` +
193
+ 'at the same time. Use one or the other.',
194
+ node
195
+ )
196
+ }
197
+
198
+ propsTypeDeclRaw = node.typeParameters.params[0]
199
+ propsTypeDecl = resolveQualifiedType(
200
+ propsTypeDeclRaw,
201
+ node => node.type === 'TSFunctionType' || node.type === 'TSTypeLiteral'
202
+ )
203
+
204
+ if (!propsTypeDecl) {
205
+ error(
206
+ `type argument passed to ${DEFINE_PROPS}() must be a literal type, ` +
207
+ 'or a reference to an interface or literal type.',
208
+ propsTypeDeclRaw
209
+ )
210
+ }
211
+ }
212
+
213
+ // 处理 VariableDeclaration declarations id
214
+ if (declId) {
215
+ propsIdentifier = content.slice(declId.start, declId.end)
216
+ }
217
+ return true
218
+ }
219
+
220
+ function processWithDefaults (node, declId) {
221
+ if (!isCallOf(node, WITH_DEFAULTS)) {
222
+ return false
223
+ }
224
+ if (processDefineProps(node.arguments[0], declId)) {
225
+ if (propsRuntimeDecl) {
226
+ error(
227
+ `${WITH_DEFAULTS} can only be used with type-based ` +
228
+ `${DEFINE_PROPS} declaration.`,
229
+ node
230
+ )
231
+ }
232
+ propsRuntimeDefaults = node.arguments[1]
233
+ if (
234
+ !propsRuntimeDefaults ||
235
+ propsRuntimeDefaults.type !== 'ObjectExpression'
236
+ ) {
237
+ error(
238
+ `The 2nd argument of ${WITH_DEFAULTS} must be an object literal.`,
239
+ propsRuntimeDefaults || node
240
+ )
241
+ }
242
+ } else {
243
+ error(
244
+ `${WITH_DEFAULTS}' first argument must be a ${DEFINE_PROPS} call.`,
245
+ node.arguments[0] || node
246
+ )
247
+ }
248
+ return true
249
+ }
250
+
251
+ function resolveQualifiedType (node, qualifier) {
252
+ if (qualifier(node)) {
253
+ return node
254
+ }
255
+ // TSTypeReference defineProps<Props>()
256
+ if (node.type === 'TSTypeReference' && node.typeName.type === 'Identifier') {
257
+ const refName = node.typeName.name
258
+ const isQualifiedType = (node) => {
259
+ // interface Props TSInterfaceDeclaration
260
+ if (node.type === 'TSInterfaceDeclaration' && node.id.name === refName) {
261
+ return node.body
262
+ }
263
+ // type Props TSTypeAliasDeclaration
264
+ if (node.type === 'TSTypeAliasDeclaration' && node.id.name === refName && qualifier(node.typeAnnotation)) {
265
+ return node.typeAnnotation
266
+ }
267
+ // export type Props
268
+ if (node.type === 'ExportNamedDeclaration' && node.declaration) {
269
+ return isQualifiedType(node.declaration)
270
+ }
271
+ }
272
+ const body = scriptSetupAst.program.body
273
+ for (const node of body) {
274
+ const qualified = isQualifiedType(node)
275
+ if (qualified) {
276
+ return qualified
277
+ }
278
+ }
279
+ }
280
+ }
281
+
282
+ function hasStaticWithDefaults () {
283
+ return (
284
+ propsRuntimeDefaults &&
285
+ propsRuntimeDefaults.type === 'ObjectExpression' &&
286
+ propsRuntimeDefaults.properties.every(
287
+ node =>
288
+ (node.type === 'ObjectProperty' && !node.computed) ||
289
+ node.type === 'ObjectMethod'
290
+ )
291
+ )
292
+ }
293
+
294
+ function genRuntimeProps (props) {
295
+ const keys = Object.keys(props)
296
+ if (!keys.length) {
297
+ return ''
298
+ }
299
+ const hasStaticDefaults = hasStaticWithDefaults()
300
+ const scriptSetupSource = content
301
+ const propsDecls = `{
302
+ ${keys.map(key => {
303
+ let defaultString
304
+ if (hasStaticDefaults) {
305
+ const prop = propsRuntimeDefaults.properties.find(
306
+ node => node.key.name === key
307
+ )
308
+ if (prop) {
309
+ if (prop.type === 'ObjectProperty') {
310
+ defaultString = `value: ${scriptSetupSource.slice(
311
+ prop.value.start,
312
+ prop.value.end
313
+ )}`
314
+ }
315
+ }
316
+ }
317
+ const { type } = props[key]
318
+ const propRuntimeTypes = toRuntimeTypeString(type)
319
+ if (propRuntimeTypes.optionalTypes) {
320
+ return `${key}: { type: ${propRuntimeTypes.type}, optionalTypes: ${propRuntimeTypes.optionalTypes}${
321
+ defaultString ? `, ${defaultString}` : ''
322
+ } }`
323
+ } else {
324
+ return `${key}: { type: ${propRuntimeTypes.type}${
325
+ defaultString ? `, ${defaultString}` : null
326
+ } }`
327
+ }
328
+ }).join(',\n ')}
329
+ }`
330
+
331
+ return `\n properties: ${propsDecls},`
332
+ }
333
+
334
+ function checkInvalidScopeReference (node, method) {
335
+ if (!node) return
336
+ walkIdentifiers(node, id => {
337
+ if (setupBindings[id.name]) {
338
+ error(
339
+ `\`${method}()\` in <script setup> cannot reference locally ` +
340
+ 'declared variables because it will be hoisted outside of the ' +
341
+ 'setup() function.',
342
+ id
343
+ )
344
+ }
345
+ })
346
+ }
347
+
348
+ // 1. parse <script setup> and walk over top level statements
349
+ const scriptSetupAst = babylon.parse(content, {
350
+ plugins: [
351
+ ...plugins,
352
+ 'topLevelAwait'
353
+ ],
354
+ sourceType: 'module'
355
+ })
356
+ for (const node of scriptSetupAst.program.body) {
357
+ const start = node.start + startOffset
358
+ let end = node.end + startOffset
359
+
360
+ // 定位comment,例如 var a= 1; // a为属性
361
+ if (node.trailingComments && node.trailingComments.length > 0) {
362
+ const lastCommentNode =
363
+ node.trailingComments[node.trailingComments.length - 1]
364
+ end = lastCommentNode.end + startOffset
365
+ }
366
+
367
+ // locate the end of whitespace between this statement and the next
368
+ while (end <= content.length) {
369
+ if (!/\s/.test(content.charAt(end))) {
370
+ break
371
+ }
372
+ end++
373
+ }
374
+
375
+ if (node.type === 'ImportDeclaration') {
376
+ // import declarations are moved to top
377
+ _s.move(start, end, 0)
378
+ // dedupe imports
379
+ let removed = 0
380
+ const removeSpecifier = (i) => {
381
+ const removeLeft = i > removed
382
+ removed++
383
+ const current = node.specifiers[i]
384
+ const next = node.specifiers[i + 1]
385
+ _s.remove(
386
+ removeLeft ? node.specifiers[i - 1].end + startOffset : current.start + startOffset,
387
+ next && !removeLeft ? next.start + startOffset : current.end + startOffset
388
+ )
389
+ }
390
+ // 判断defineProps等是否有被引入
391
+ // record imports for dedupe
392
+ for (let i = 0; i < node.specifiers.length; i++) {
393
+ const specifier = node.specifiers[i]
394
+ let imported = specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name
395
+ if (specifier.type === 'ImportNamespaceSpecifier') {
396
+ imported = '*'
397
+ }
398
+ const local = specifier.local.name
399
+ const source = node.source.value
400
+ const existing = userImports[local]
401
+ if (source === MPX_CORE && isCompilerMacro(imported)) {
402
+ console.warn(`${imported} is a compiler macro and no longer needs to be imported.`)
403
+ // 不需要经过
404
+ removeSpecifier(i)
405
+ } else if (existing) {
406
+ if (existing.source === source && existing.imported === imported) {
407
+ // already imported in <script setup>, dedupe
408
+ removeSpecifier(i)
409
+ } else {
410
+ error('different imports aliased to same local name.', specifier)
411
+ }
412
+ } else {
413
+ registerUserImport(
414
+ node.source.value,
415
+ specifier.local.name,
416
+ imported,
417
+ node.importKind === 'type' ||
418
+ (specifier.type === 'ImportSpecifier' &&
419
+ specifier.importKind === 'type'),
420
+ true
421
+ )
422
+ }
423
+ }
424
+ if (node.specifiers.length && removed === node.specifiers.length) {
425
+ _s.remove(node.start, node.end)
426
+ }
427
+ startOffset = node.loc.end.index
428
+ }
429
+
430
+ // process defineProps defineOptions 等编译宏
431
+ if (node.type === 'ExpressionStatement') {
432
+ if (
433
+ processDefineProps(node.expression) ||
434
+ processDefineOptions(node.expression) ||
435
+ processDefineExpose(node.expression) ||
436
+ processWithDefaults(node.expression)
437
+ ) {
438
+ _s.remove(node.start, node.end)
439
+ }
440
+ }
441
+
442
+ if (node.type === 'VariableDeclaration' && !node.declare) {
443
+ const total = node.declarations.length
444
+ let left = total
445
+ for (let i = 0; i < total; i++) {
446
+ const decl = node.declarations[i]
447
+ if (decl.init) {
448
+ const isDefineProps = processDefineProps(decl.init, decl.id) || processWithDefaults(decl.init, decl.id)
449
+ const isDefineOptions = processDefineOptions(decl.init, decl.id)
450
+ if (isDefineProps || isDefineOptions) {
451
+ if (left === 1) {
452
+ _s.remove(node.start, node.end)
453
+ } else {
454
+ // let a,b = defineProps({})
455
+ let start = decl.start
456
+ let end = decl.end
457
+ if (i < total - 1) {
458
+ // not the last one, locate the start of the next
459
+ end = node.declarations[i + 1].start
460
+ } else {
461
+ // last one, locate the end of the prev
462
+ start = node.declarations[i - 1].end
463
+ }
464
+ _s.remove(start, end)
465
+ left--
466
+ }
467
+ }
468
+ }
469
+ }
470
+ }
471
+
472
+ // walk declarations to record declared bindings
473
+ if (
474
+ (node.type === 'VariableDeclaration' ||
475
+ node.type === 'FunctionDeclaration' ||
476
+ node.type === 'ClassDeclaration') &&
477
+ !node.declare
478
+ ) {
479
+ walkDeclaration(node, setupBindings, userImportAlias)
480
+ }
481
+
482
+ // walk statements & named exports / variable declarations for top level
483
+ // await,when find await will throw error
484
+ // { await someFunc ()}
485
+ if (
486
+ (node.type === 'VariableDeclaration' && !node.declare) ||
487
+ node.type.endsWith('Statement')
488
+ ) {
489
+ const scope = [scriptSetupAst.body]
490
+ traverse(node, {
491
+ enter (path) {
492
+ if (isFunctionType(path.node)) {
493
+ path.skip()
494
+ }
495
+ if (t.isBlockStatement(path.node)) {
496
+ scope.push(path.node.body)
497
+ }
498
+ if (t.isAwaitExpression(path.node)) {
499
+ // error
500
+ error('if the await expression is an expression statement and is in the root scope or is not the first statement in a nested block scope, this is not support in miniprogram')
501
+ }
502
+ },
503
+ exit (path) {
504
+ if (t.isBlockStatement(path.node)) scope.pop()
505
+ },
506
+ noScope: true
507
+ })
508
+ }
509
+
510
+ if (
511
+ (node.type === 'ExportNamedDeclaration' && node.exportKind !== 'type') ||
512
+ node.type === 'ExportAllDeclaration' ||
513
+ node.type === 'ExportDefaultDeclaration'
514
+ ) {
515
+ error(
516
+ '<script setup> cannot contain ES module exports. ',
517
+ node
518
+ )
519
+ }
520
+
521
+ // working with TS code
522
+ if (isTS) {
523
+ if (
524
+ node.type.startsWith('TS') ||
525
+ (node.type === 'ExportNamedDeclaration' &&
526
+ node.exportKind === 'type') ||
527
+ (node.type === 'VariableDeclaration' && node.declare)
528
+ ) {
529
+ recordType(node, declaredTypes)
530
+ _s.move(node.start, node.end, 0)
531
+ }
532
+ }
533
+
534
+ endOffset = node.loc.end.index
535
+ }
536
+
537
+ // 2. extract runtime props code from setup context type
538
+ if (propsTypeDecl) {
539
+ // TS defineProps 提取Props
540
+ extractRuntimeProps(propsTypeDecl, typeDeclaredProps, declaredTypes)
541
+ }
542
+
543
+ // 3. check useOptions args to make sure it doesn't reference setup scope
544
+ checkInvalidScopeReference(propsRuntimeDecl, DEFINE_PROPS)
545
+ checkInvalidScopeReference(optionsRuntimeDecl, DEFINE_OPTIONS)
546
+
547
+ // 4. finalize setup() argument signature
548
+ let args = '__props'
549
+ if (propsTypeDecl) {
550
+ args += ': any'
551
+ }
552
+ // inject user assignment of props
553
+ if (propsIdentifier) {
554
+ _s.prependLeft(
555
+ startOffset,
556
+ `\nconst ${propsIdentifier} = __props${
557
+ propsTypeDecl ? ' as any' : ''
558
+ }\n`)
559
+ }
560
+ // args 添加 __context
561
+ args += `, __context${isTS ? ': any' : ''}`
562
+
563
+ // 5. generate return statement
564
+ let returned
565
+ if (hasDefineExposeCall && exposeRuntimeDecl) {
566
+ const declCode = content.slice(exposeRuntimeDecl.start, exposeRuntimeDecl.end).trim()
567
+ returned = `${declCode}`
568
+ } else {
569
+ const allBindings = {
570
+ ...scriptBindings,
571
+ ...setupBindings
572
+ }
573
+ for (const key in userImports) {
574
+ // import 进的的变量或方法,非mpxjs/core中的,暂时都进行return
575
+ if (!userImports[key].isType && !userImportAlias[key]) {
576
+ allBindings[key] = true
577
+ }
578
+ }
579
+ returned = `{ ${Object.keys(allBindings).join(', ')} }`
580
+ }
581
+ _s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
582
+
583
+ // 6. finalize default export
584
+ let runtimeOptions = ''
585
+ if (propsRuntimeDecl) {
586
+ const declCode = content.slice(propsRuntimeDecl.start, propsRuntimeDecl.end).trim()
587
+ runtimeOptions += `\n properties: ${declCode},`
588
+ } else if (propsTypeDecl) {
589
+ runtimeOptions += genRuntimeProps(typeDeclaredProps)
590
+ }
591
+
592
+ if (optionsRuntimeDecl) {
593
+ for (const node of optionsRuntimeDecl) {
594
+ if (node.key.name === 'properties' && hasDefinePropsCall) {
595
+ console.warn(`${DEFINE_PROPS} has been called, ${DEFINE_OPTIONS} set properties will be ignored`)
596
+ } else {
597
+ const declCode = content.slice(node.value.start, node.value.end).trim()
598
+ runtimeOptions += `\n ${node.key.name}: ${declCode},`
599
+ }
600
+ }
601
+ }
602
+
603
+ // import {createComponent} from '@mpxjs/core' 添加是否已有import判断
604
+ const ctor = getCtor(ctorType)
605
+ _s.prependLeft(
606
+ startOffset,
607
+ `\nimport {${ctor}} from '${MPX_CORE}'\n${getCtor(ctorType)} ({${runtimeOptions}\n ` +
608
+ `setup(${args}) {\n const useContext = () => { return __context }`
609
+ )
610
+ _s.appendRight(endOffset, '})')
611
+
612
+ return {
613
+ content: _s.toString()
614
+ }
615
+ }
616
+
617
+ function isCallOf (
618
+ node,
619
+ test
620
+ ) {
621
+ return !!(
622
+ node &&
623
+ node.type === 'CallExpression' &&
624
+ node.callee.type === 'Identifier' &&
625
+ (typeof test === 'string'
626
+ ? node.callee.name === test
627
+ : test(node.callee.name))
628
+ )
629
+ }
630
+
631
+ function canNeverBeRef (
632
+ node,
633
+ userReactiveImport
634
+ ) {
635
+ if (isCallOf(node, userReactiveImport)) {
636
+ return true
637
+ }
638
+ switch (node.type) {
639
+ case 'UnaryExpression':
640
+ case 'BinaryExpression':
641
+ case 'ArrayExpression':
642
+ case 'ObjectExpression':
643
+ case 'FunctionExpression':
644
+ case 'ArrowFunctionExpression':
645
+ case 'UpdateExpression':
646
+ case 'ClassExpression':
647
+ case 'TaggedTemplateExpression':
648
+ return true
649
+ case 'SequenceExpression':
650
+ return canNeverBeRef(
651
+ node.expressions[node.expressions.length - 1],
652
+ userReactiveImport
653
+ )
654
+ default:
655
+ if (node.type.endsWith('Literal')) {
656
+ return true
657
+ }
658
+ return false
659
+ }
660
+ }
661
+
662
+ function isCompilerMacro (c) {
663
+ return c === DEFINE_PROPS || c === DEFINE_OPTIONS || c === DEFINE_EXPOSE
664
+ }
665
+
666
+ function registerBinding (
667
+ bindings,
668
+ node,
669
+ type
670
+ ) {
671
+ bindings[node.name] = type
672
+ }
673
+
674
+ function walkDeclaration (
675
+ node,
676
+ bindings,
677
+ userImportAlias
678
+ ) {
679
+ if (node.type === 'VariableDeclaration') {
680
+ const isConst = node.kind === 'const'
681
+ for (const { id, init } of node.declarations) {
682
+ const isDefineCall = !!(
683
+ isConst &&
684
+ isCallOf(
685
+ init,
686
+ isCompilerMacro
687
+ )
688
+ )
689
+ if (id.type === 'Identifier') {
690
+ let bindingType
691
+ const userReactiveBinding = userImportAlias.reactive || 'reactive'
692
+ // 是否是 reactive init
693
+ if (isCallOf(init, userReactiveBinding)) {
694
+ bindingType = isConst
695
+ ? BindingTypes.SETUP_REACTIVE_CONST
696
+ : BindingTypes.SETUP_LET
697
+ } else if (
698
+ isDefineCall ||
699
+ (isConst && canNeverBeRef(init, userReactiveBinding))
700
+ ) {
701
+ bindingType = isCallOf(init, DEFINE_PROPS)
702
+ ? BindingTypes.SETUP_REACTIVE_CONST
703
+ : BindingTypes.SETUP_CONST
704
+ } else if (isConst) {
705
+ if (isCallOf(init, userImportAlias.ref || 'ref')) {
706
+ bindingType = BindingTypes.SETUP_REF
707
+ } else {
708
+ bindingType = BindingTypes.SETUP_MAYBE_REF
709
+ }
710
+ } else {
711
+ bindingType = BindingTypes.SETUP_LET
712
+ }
713
+ registerBinding(bindings, id, bindingType)
714
+ } else {
715
+ if (isCallOf(init, DEFINE_PROPS)) {
716
+ // skip walking props destructure
717
+ return
718
+ }
719
+ if (id.type === 'ObjectPattern') {
720
+ walkObjectPattern(id, bindings, isConst, isDefineCall)
721
+ } else if (id.type === 'ArrayPattern') {
722
+ walkArrayPattern(id, bindings, isConst, isDefineCall)
723
+ }
724
+ }
725
+ }
726
+ } else if (
727
+ node.type === 'TSEnumDeclaration' ||
728
+ node.type === 'FunctionDeclaration' ||
729
+ node.type === 'ClassDeclaration'
730
+ ) {
731
+ bindings[node.id.name] = BindingTypes.SETUP_CONST
732
+ }
733
+ }
734
+
735
+ function walkObjectPattern (
736
+ node,
737
+ bindings,
738
+ isConst,
739
+ isDefineCall = false
740
+ ) {
741
+ for (const p of node.properties) {
742
+ if (p.type === 'ObjectProperty') {
743
+ if (p.key.type === 'Identifier' && p.key === p.value) {
744
+ // shorthand: const { x } = ...
745
+ const type = isDefineCall ? BindingTypes.SETUP_CONST : isConst ? BindingTypes.SETUP_MAYBE_REF : BindingTypes.SETUP_LET
746
+ registerBinding(bindings, p.key, type)
747
+ } else {
748
+ walkPattern(p.value, bindings, isConst, isDefineCall)
749
+ }
750
+ } else {
751
+ // ...rest
752
+ const type = isConst ? BindingTypes.SETUP_CONST : BindingTypes.SETUP_LET
753
+ registerBinding(bindings, p.argument, type)
754
+ }
755
+ }
756
+ }
757
+
758
+ function walkArrayPattern (
759
+ node,
760
+ bindings,
761
+ isConst,
762
+ isDefineCall = false
763
+ ) {
764
+ for (const e of node.elements) {
765
+ e && walkPattern(e, bindings, isConst, isDefineCall)
766
+ }
767
+ }
768
+
769
+ function walkPattern (
770
+ node,
771
+ bindings,
772
+ isConst,
773
+ isDefineCall = false
774
+ ) {
775
+ if (node.type === 'Identifier') {
776
+ const type = isDefineCall
777
+ ? BindingTypes.SETUP_CONST
778
+ : isConst
779
+ ? BindingTypes.SETUP_MAYBE_REF
780
+ : BindingTypes.SETUP_LET
781
+ registerBinding(bindings, node, type)
782
+ } else if (node.type === 'RestElement') {
783
+ const type = isConst ? BindingTypes.SETUP_CONST : BindingTypes.SETUP_LET
784
+ registerBinding(bindings, node.argument, type)
785
+ } else if (node.type === 'ObjectPattern') {
786
+ walkObjectPattern(node, bindings, isConst)
787
+ } else if (node.type === 'ArrayPattern') {
788
+ walkArrayPattern(node, bindings, isConst)
789
+ } else if (node.type === 'AssignmentPattern') {
790
+ // const {propsA:c=2} = defineProps
791
+ if (node.left.type === 'Identifier') {
792
+ const type = isDefineCall
793
+ ? BindingTypes.SETUP_CONST
794
+ : isConst
795
+ ? BindingTypes.SETUP_MAYBE_REF
796
+ : BindingTypes.SETUP_LET
797
+ registerBinding(bindings, node.left, type)
798
+ } else {
799
+ walkPattern(node.left, bindings, isConst)
800
+ }
801
+ }
802
+ }
803
+
804
+ function recordType (node, declaredTypes) {
805
+ if (node.type === 'TSInterfaceDeclaration') {
806
+ declaredTypes[node.id.name] = ['Object']
807
+ } else if (node.type === 'TSTypeAliasDeclaration') {
808
+ declaredTypes[node.id.name] = inferRuntimeType(
809
+ node.typeAnnotation,
810
+ declaredTypes
811
+ )
812
+ } else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
813
+ recordType(node.declaration, declaredTypes)
814
+ }
815
+ }
816
+
817
+ function toRuntimeTypeString (types) {
818
+ return {
819
+ type: types[0],
820
+ optionalTypes: types.length > 1 ? `[${types.slice(1).join(', ')}]` : undefined
821
+ }
822
+ }
823
+
824
+ // extract runtime props from ts types
825
+ function extractRuntimeProps (
826
+ node,
827
+ props,
828
+ declaredTypes
829
+ ) {
830
+ const members = node.type === 'TSTypeLiteral' ? node.members : node.body
831
+ for (const m of members) {
832
+ if (
833
+ (m.type === 'TSPropertySignature' || m.type === 'TSMethodSignature') &&
834
+ m.key.type === 'Identifier'
835
+ ) {
836
+ let type
837
+ if (m.type === 'TSMethodSignature') {
838
+ type = ['Function']
839
+ } else if (m.typeAnnotation) {
840
+ type = inferRuntimeType(m.typeAnnotation.typeAnnotation, declaredTypes)
841
+ }
842
+ props[m.key.name] = {
843
+ key: m.key.name,
844
+ required: !m.optional,
845
+ type: type || ['null']
846
+ }
847
+ }
848
+ }
849
+ }
850
+
851
+ function inferRuntimeType (
852
+ node,
853
+ declaredTypes
854
+ ) {
855
+ switch (node.type) {
856
+ case 'TSStringKeyword':
857
+ return ['String']
858
+ case 'TSNumberKeyword':
859
+ return ['Number']
860
+ case 'TSBooleanKeyword':
861
+ return ['Boolean']
862
+ case 'TSObjectKeyword':
863
+ return ['Object']
864
+ case 'TSFunctionType':
865
+ return ['Function']
866
+ case 'TSArrayType':
867
+ case 'TSTupleType':
868
+ return ['Array']
869
+ case 'TSLiteralType':
870
+ switch (node.literal.type) {
871
+ case 'StringLiteral':
872
+ return ['String']
873
+ case 'BooleanLiteral':
874
+ return ['Boolean']
875
+ case 'NumericLiteral':
876
+ case 'BigIntLiteral':
877
+ return ['Number']
878
+ default:
879
+ return ['null']
880
+ }
881
+
882
+ case 'TSTypeReference':
883
+ if (node.typeName.type === 'Identifier') {
884
+ if (declaredTypes[node.typeName.name]) {
885
+ return declaredTypes[node.typeName.name]
886
+ }
887
+ switch (node.typeName.name) {
888
+ case 'Array':
889
+ case 'Function':
890
+ case 'Object':
891
+ case 'Set':
892
+ case 'Map':
893
+ case 'WeakSet':
894
+ case 'WeakMap':
895
+ case 'Date':
896
+ case 'Promise':
897
+ return [node.typeName.name]
898
+ case 'Record':
899
+ case 'Partial':
900
+ case 'Readonly':
901
+ case 'Pick':
902
+ case 'Omit':
903
+ case 'Exclude':
904
+ case 'Extract':
905
+ case 'Required':
906
+ case 'InstanceType':
907
+ return ['Object']
908
+ }
909
+ }
910
+ return ['null']
911
+
912
+ case 'TSParenthesizedType':
913
+ return inferRuntimeType(node.typeAnnotation, declaredTypes)
914
+
915
+ case 'TSUnionType':
916
+ return [
917
+ ...new Set(
918
+ [].concat(
919
+ ...(node.types.map(t => inferRuntimeType(t, declaredTypes)))
920
+ )
921
+ )
922
+ ]
923
+ case 'TSIntersectionType':
924
+ return ['Object']
925
+
926
+ default:
927
+ return ['null']
928
+ }
929
+ }
930
+
931
+ function walkIdentifiers (
932
+ root,
933
+ onIdentifier,
934
+ parentStack = [],
935
+ knownIds = Object.create(null)
936
+ ) {
937
+ const rootExp =
938
+ root.type === 'Program' &&
939
+ root.body[0].type === 'ExpressionStatement' &&
940
+ root.body[0].expression
941
+ traverse(root, {
942
+ enter (path) {
943
+ const { node, parent } = path
944
+ if (
945
+ parent &&
946
+ parent.type.startsWith('TS') &&
947
+ parent.type !== 'TSAsExpression' &&
948
+ parent.type !== 'TSNonNullExpression' &&
949
+ parent.type !== 'TSTypeAssertion'
950
+ ) {
951
+ return path.skip()
952
+ }
953
+ if (node.type === 'Identifier') {
954
+ const isLocal = knownIds[node.name]
955
+ const isRefed = isReferencedIdentifier(node, parent, parentStack)
956
+ if (isRefed && !isLocal) {
957
+ onIdentifier(node, parent, parentStack, isRefed, isLocal)
958
+ }
959
+ } else if (
960
+ node.type === 'ObjectProperty' &&
961
+ parent.type === 'ObjectPattern'
962
+ ) {
963
+ node.inPattern = true
964
+ } else if (isFunctionType(node)) {
965
+ walkFunctionParams(node, id => markScopeIdentifier(node, id, knownIds))
966
+ } else if (node.type === 'BlockStatement') {
967
+ walkBlockDeclarations(node, id =>
968
+ markScopeIdentifier(node, id, knownIds)
969
+ )
970
+ }
971
+ },
972
+ exit (path) {
973
+ const { node, parent } = path
974
+ parent && parentStack.pop()
975
+ if (node !== rootExp && node.scopeIds) {
976
+ for (const id of node.scopeIds) {
977
+ knownIds[id]--
978
+ if (knownIds[id] === 0) {
979
+ delete knownIds[id]
980
+ }
981
+ }
982
+ }
983
+ },
984
+ noScope: true
985
+ })
986
+ }
987
+
988
+ function markScopeIdentifier (
989
+ node,
990
+ child,
991
+ knownIds
992
+ ) {
993
+ const { name } = child
994
+ if (node.scopeIds && node.scopeIds.has(name)) {
995
+ return
996
+ }
997
+ if (name in knownIds) {
998
+ knownIds[name]++
999
+ } else {
1000
+ knownIds[name] = 1
1001
+ }
1002
+ (node.scopeIds || (node.scopeIds = new Set())).add(name)
1003
+ }
1004
+
1005
+ function walkFunctionParams (
1006
+ node,
1007
+ onIdent
1008
+ ) {
1009
+ for (const p of node.params) {
1010
+ for (const id of extractIdentifiers(p)) {
1011
+ onIdent(id)
1012
+ }
1013
+ }
1014
+ }
1015
+
1016
+ function walkBlockDeclarations (
1017
+ block,
1018
+ onIndent
1019
+ ) {
1020
+ for (const stmt of block.body) {
1021
+ if (stmt.type === 'VariableDeclaration') {
1022
+ if (stmt.declare) continue
1023
+ for (const decl of stmt.declarations) {
1024
+ for (const id of extractIdentifiers(decl.id)) {
1025
+ onIndent(id)
1026
+ }
1027
+ }
1028
+ } else if (
1029
+ stmt.type === 'FunctionDeclaration' ||
1030
+ stmt.type === 'ClassDeclaration'
1031
+ ) {
1032
+ if (stmt.declare || !stmt.id) continue
1033
+ onIndent(stmt.id)
1034
+ }
1035
+ }
1036
+ }
1037
+
1038
+ function isReferencedIdentifier (
1039
+ id,
1040
+ parent,
1041
+ parentStack
1042
+ ) {
1043
+ if (!parent) {
1044
+ return true
1045
+ }
1046
+
1047
+ // is a special keyword but parsed as identifier
1048
+ if (id.name === 'arguments') {
1049
+ return false
1050
+ }
1051
+
1052
+ if (t.isReferenced(id, parent)) {
1053
+ return true
1054
+ }
1055
+
1056
+ // babel's isReferenced check returns false for ids being assigned to, so we
1057
+ // need to cover those cases here
1058
+ switch (parent.type) {
1059
+ case 'AssignmentExpression':
1060
+ case 'AssignmentPattern':
1061
+ return true
1062
+ case 'ObjectPattern':
1063
+ case 'ArrayPattern':
1064
+ return isInDestructureAssignment(parent, parentStack)
1065
+ }
1066
+ return false
1067
+ }
1068
+
1069
+ function extractIdentifiers (
1070
+ param,
1071
+ nodes
1072
+ ) {
1073
+ switch (param.type) {
1074
+ case 'Identifier':
1075
+ nodes.push(param)
1076
+ break
1077
+
1078
+ case 'MemberExpression': {
1079
+ let object = param
1080
+ while (object.type === 'MemberExpression') {
1081
+ object = object.object
1082
+ }
1083
+ nodes.push(object)
1084
+ break
1085
+ }
1086
+
1087
+ case 'ObjectPattern':
1088
+ for (const prop of param.properties) {
1089
+ if (prop.type === 'RestElement') {
1090
+ extractIdentifiers(prop.argument, nodes)
1091
+ } else {
1092
+ extractIdentifiers(prop.value, nodes)
1093
+ }
1094
+ }
1095
+ break
1096
+
1097
+ case 'ArrayPattern':
1098
+ param.elements.forEach(element => {
1099
+ if (element) extractIdentifiers(element, nodes)
1100
+ })
1101
+ break
1102
+
1103
+ case 'RestElement':
1104
+ extractIdentifiers(param.argument, nodes)
1105
+ break
1106
+
1107
+ case 'AssignmentPattern':
1108
+ extractIdentifiers(param.left, nodes)
1109
+ break
1110
+ }
1111
+
1112
+ return nodes
1113
+ }
1114
+
1115
+ function isInDestructureAssignment (
1116
+ parent,
1117
+ parentStack
1118
+ ) {
1119
+ if (
1120
+ parent &&
1121
+ (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')
1122
+ ) {
1123
+ let i = parentStack.length
1124
+ while (i--) {
1125
+ const p = parentStack[i]
1126
+ if (p.type === 'AssignmentExpression') {
1127
+ return true
1128
+ } else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
1129
+ break
1130
+ }
1131
+ }
1132
+ }
1133
+ return false
1134
+ }
1135
+
1136
+ function isFunctionType (node) {
1137
+ return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
1138
+ }
1139
+
1140
+ function getCtor (ctorType) {
1141
+ let ctor = 'createComponent'
1142
+ switch (ctorType) {
1143
+ case 'app':
1144
+ ctor = 'createApp'
1145
+ break
1146
+ case 'page':
1147
+ ctor = 'createPage'
1148
+ break
1149
+ }
1150
+ return ctor
1151
+ }
1152
+
1153
+ module.exports = function (content) {
1154
+ const { queryObj } = parseRequest(this.resource)
1155
+ const { ctorType, lang } = queryObj
1156
+ const filePath = this.resourcePath
1157
+ const { content: callbackContent } = compileScriptSetup({
1158
+ content,
1159
+ lang
1160
+ }, ctorType, filePath)
1161
+
1162
+ this.callback(null, callbackContent)
1163
+ }