-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathjsonUsingComponents.ts
More file actions
122 lines (106 loc) · 3.6 KB
/
jsonUsingComponents.ts
File metadata and controls
122 lines (106 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import type { Code } from '../../types'
import type { ScriptCodegenOptions } from './index'
import type { ScriptCodegenContext } from './context'
import { camelize, capitalize } from '@mpxjs/language-shared'
import { endOfLine, newLine } from '../utils'
import { identifierRegex } from '../utils'
export function* generateJsonUsingComponents(
options: ScriptCodegenOptions,
_ctx: ScriptCodegenContext,
): Generator<Code> {
const usingComponents = options.sfc.json?.usingComponents
if (!usingComponents?.size) {
yield `const __MPX_jsonComponents = {}${endOfLine}`
return
}
yield `const __MPX_jsonComponents = {${newLine}`
for (const [componentName, componentPaths] of usingComponents) {
const firstImportName = getUsingComponentImportName(componentName, 0)
yield `${firstImportName}`
if (componentPaths.length > 1) {
// Multiple resolved paths still need a single runtime value, so keep the
// first import as the value and widen its type to all candidate imports.
yield `: ${firstImportName} as `
for (let i = 0; i < componentPaths.length; i++) {
if (i) {
yield ` | `
}
yield `typeof ${getUsingComponentImportName(componentName, i)}`
}
}
yield `,${newLine}`
}
yield `}${endOfLine}`
}
export function* generateJsonPathCompletionImports(
options: ScriptCodegenOptions,
_ctx: ScriptCodegenContext,
): Generator<Code> {
const usingComponents = options.sfc.json?.usingComponents
const jsonStart = (options.sfc.json?.startTagEnd || 0) + 1
const pages = options.sfc.json?.pages
// 生成虚拟的 import 语句用于路径补全
yield `// Virtual imports for JSON path completion${newLine}`
// 为 usingComponents 生成虚拟 import
if (usingComponents?.size) {
for (const [componentName, componentPaths] of usingComponents) {
for (let i = 0; i < componentPaths.length; i++) {
const componentPathInfo = componentPaths[i]!
const importName = getUsingComponentImportName(componentName, i)
// Generate a virtual import with a stable identifier so the generated
// component map reads like normal source imports instead of index-based
// placeholders.
yield `import ${importName} from '`
// 传递原始路径及位置信息
yield [
componentPathInfo.text,
'json_import',
jsonStart + componentPathInfo.offset,
{
// 仅启用补全功能,不参与语义分析等
completion: true,
navigation: false,
semantic: false,
verification: false,
structure: false,
format: false,
},
]
yield `'${newLine}`
}
}
}
// todo:为 pages 生成虚拟 import,留窗口
if (pages?.length) {
for (let i = 0; i < pages.length; i++) {
const page = pages[i]
yield `import __mpx_page_path_completion_${i} from '`
yield [
page.text,
'json_import',
jsonStart + page.offset,
{
completion: true,
navigation: false,
semantic: false,
verification: false,
structure: false,
format: false,
},
]
yield `'${newLine}`
}
}
yield `${newLine}`
}
export function getUsingComponentImportName(
componentName: string,
index: number,
) {
const camelizedName = capitalize(camelize(componentName))
const baseName =
camelizedName && identifierRegex.test(camelizedName)
? camelizedName
: `component_${index}`
return index && baseName === camelizedName ? `${baseName}_${index}` : baseName
}