@cfp-studio/plugin-vue3 16.0.1
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.
- package/LICENSE +21 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +656 -0
- package/package.json +51 -0
- package/preview/index.ts +141 -0
- package/preview/modules/@vue/compiler-core/LICENSE +21 -0
- package/preview/modules/@vue/compiler-core/README.md +1 -0
- package/preview/modules/@vue/compiler-core/dist/compiler-core.cjs.js +6813 -0
- package/preview/modules/@vue/compiler-core/dist/compiler-core.cjs.prod.js +6690 -0
- package/preview/modules/@vue/compiler-core/dist/compiler-core.d.ts +1091 -0
- package/preview/modules/@vue/compiler-core/dist/compiler-core.esm-bundler.js +5790 -0
- package/preview/modules/@vue/compiler-core/index.js +7 -0
- package/preview/modules/@vue/compiler-core/node_modules/.bin/parser +17 -0
- package/preview/modules/@vue/compiler-core/package.json +58 -0
- package/preview/modules/@vue/compiler-sfc/LICENSE +21 -0
- package/preview/modules/@vue/compiler-sfc/README.md +80 -0
- package/preview/modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js +24970 -0
- package/preview/modules/@vue/compiler-sfc/dist/compiler-sfc.d.ts +484 -0
- package/preview/modules/@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js +53043 -0
- package/preview/modules/@vue/compiler-sfc/node_modules/.bin/parser +17 -0
- package/preview/modules/@vue/compiler-sfc/package.json +67 -0
- package/preview/modules/@vue/reactivity/LICENSE +21 -0
- package/preview/modules/@vue/reactivity/README.md +19 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.cjs.js +1939 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.cjs.prod.js +1789 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.d.ts +754 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.esm-browser.js +1938 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.esm-browser.prod.js +5 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.esm-bundler.js +1896 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.global.js +1994 -0
- package/preview/modules/@vue/reactivity/dist/reactivity.global.prod.js +5 -0
- package/preview/modules/@vue/reactivity/index.js +7 -0
- package/preview/modules/@vue/reactivity/package.json +55 -0
- package/preview/modules/@vue/runtime-core/LICENSE +21 -0
- package/preview/modules/@vue/runtime-core/README.md +28 -0
- package/preview/modules/@vue/runtime-core/dist/runtime-core.cjs.js +8493 -0
- package/preview/modules/@vue/runtime-core/dist/runtime-core.cjs.prod.js +6654 -0
- package/preview/modules/@vue/runtime-core/dist/runtime-core.d.ts +1832 -0
- package/preview/modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js +8419 -0
- package/preview/modules/@vue/runtime-core/index.js +7 -0
- package/preview/modules/@vue/runtime-core/package.json +52 -0
- package/preview/modules/@vue/runtime-dom/LICENSE +21 -0
- package/preview/modules/@vue/runtime-dom/README.md +13 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.cjs.js +1820 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.cjs.prod.js +1669 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.d.ts +1395 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.esm-browser.js +12332 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.esm-browser.prod.js +5 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js +1860 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.global.js +12383 -0
- package/preview/modules/@vue/runtime-dom/dist/runtime-dom.global.prod.js +5 -0
- package/preview/modules/@vue/runtime-dom/index.js +7 -0
- package/preview/modules/@vue/runtime-dom/package.json +60 -0
- package/preview/modules/@vue/shared/LICENSE +21 -0
- package/preview/modules/@vue/shared/README.md +3 -0
- package/preview/modules/@vue/shared/dist/shared.cjs.js +594 -0
- package/preview/modules/@vue/shared/dist/shared.cjs.prod.js +594 -0
- package/preview/modules/@vue/shared/dist/shared.d.ts +328 -0
- package/preview/modules/@vue/shared/dist/shared.esm-bundler.js +519 -0
- package/preview/modules/@vue/shared/index.js +7 -0
- package/preview/modules/@vue/shared/package.json +47 -0
- package/preview/modules/vue/LICENSE +21 -0
- package/preview/modules/vue/README.md +62 -0
- package/preview/modules/vue/compiler-sfc/index.browser.js +1 -0
- package/preview/modules/vue/compiler-sfc/index.browser.mjs +1 -0
- package/preview/modules/vue/compiler-sfc/index.d.mts +1 -0
- package/preview/modules/vue/compiler-sfc/index.d.ts +1 -0
- package/preview/modules/vue/compiler-sfc/index.js +3 -0
- package/preview/modules/vue/compiler-sfc/index.mjs +3 -0
- package/preview/modules/vue/compiler-sfc/package.json +4 -0
- package/preview/modules/vue/compiler-sfc/register-ts.js +3 -0
- package/preview/modules/vue/dist/vue.cjs.js +80 -0
- package/preview/modules/vue/dist/vue.cjs.prod.js +66 -0
- package/preview/modules/vue/dist/vue.d.mts +7 -0
- package/preview/modules/vue/dist/vue.d.ts +7 -0
- package/preview/modules/vue/dist/vue.esm-browser.js +18216 -0
- package/preview/modules/vue/dist/vue.esm-browser.prod.js +9 -0
- package/preview/modules/vue/dist/vue.esm-bundler.js +71 -0
- package/preview/modules/vue/dist/vue.global.js +18096 -0
- package/preview/modules/vue/dist/vue.global.prod.js +9 -0
- package/preview/modules/vue/dist/vue.runtime.esm-browser.js +12355 -0
- package/preview/modules/vue/dist/vue.runtime.esm-browser.prod.js +5 -0
- package/preview/modules/vue/dist/vue.runtime.esm-bundler.js +26 -0
- package/preview/modules/vue/dist/vue.runtime.global.js +12407 -0
- package/preview/modules/vue/dist/vue.runtime.global.prod.js +5 -0
- package/preview/modules/vue/index.js +7 -0
- package/preview/modules/vue/index.mjs +1 -0
- package/preview/modules/vue/jsx-runtime/index.d.ts +25 -0
- package/preview/modules/vue/jsx-runtime/index.js +15 -0
- package/preview/modules/vue/jsx-runtime/index.mjs +12 -0
- package/preview/modules/vue/jsx-runtime/package.json +5 -0
- package/preview/modules/vue/jsx.d.ts +22 -0
- package/preview/modules/vue/node_modules/.bin/tsc +17 -0
- package/preview/modules/vue/node_modules/.bin/tsserver +17 -0
- package/preview/modules/vue/package.json +112 -0
- package/preview/modules/vue/server-renderer/index.d.mts +1 -0
- package/preview/modules/vue/server-renderer/index.d.ts +1 -0
- package/preview/modules/vue/server-renderer/index.js +1 -0
- package/preview/modules/vue/server-renderer/index.mjs +1 -0
- package/preview/modules/vue/server-renderer/package.json +4 -0
- package/preview/tsconfig.json +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Zenc Labs Pty Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.mts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
import { intersectionType, objectType, NODE_TYPE, maybeOptionalType, UNKNOWN_TYPE, helpers, createTypeAnalyzer } from '@cfp-studio/type-analyzer';
|
|
2
|
+
import { ReaderListeners, createStackedReader, createFileSystemReader } from '@cfp-studio/vfs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import url from 'url';
|
|
5
|
+
import { generatePreviewableId, decodePreviewableId } from '@cfp-studio/analyzer-api';
|
|
6
|
+
import { parseSerializableValue } from '@cfp-studio/serializable-values';
|
|
7
|
+
import { extractStoriesInfo, extractArgs, extractCsf3Stories, resolvePreviewableId } from '@cfp-studio/storybook-helpers';
|
|
8
|
+
import ts from 'typescript';
|
|
9
|
+
import { parse } from '@vue/compiler-sfc';
|
|
10
|
+
|
|
11
|
+
function analyzeFromTemplate(resolver, virtualVueTsAbsoluteFilePath) {
|
|
12
|
+
const sourceFile = resolver.sourceFile(virtualVueTsAbsoluteFilePath);
|
|
13
|
+
let props = UNKNOWN_TYPE;
|
|
14
|
+
let types = {};
|
|
15
|
+
let slots = [];
|
|
16
|
+
for (const statement of sourceFile?.statements || []) {
|
|
17
|
+
const definedProps = extractDefinePropsFromStatement(resolver, statement);
|
|
18
|
+
if (definedProps) {
|
|
19
|
+
return {
|
|
20
|
+
props: definedProps.type,
|
|
21
|
+
types: definedProps.collected
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (ts.isTypeAliasDeclaration(statement)) {
|
|
25
|
+
if (statement.name.text === "PJS_Props") {
|
|
26
|
+
const type = resolver.checker.getTypeAtLocation(statement);
|
|
27
|
+
const defineComponentProps = resolver.resolveType(type);
|
|
28
|
+
props = defineComponentProps.type;
|
|
29
|
+
types = defineComponentProps.collected;
|
|
30
|
+
} else if (statement.name.text === "PJS_Slots") {
|
|
31
|
+
const slotsType = resolver.checker.getTypeAtLocation(statement);
|
|
32
|
+
const resolvedSlotsTypeName = resolver.resolveType(slotsType);
|
|
33
|
+
if (resolvedSlotsTypeName.type.kind === "name") {
|
|
34
|
+
const resolvedSlotsType = resolvedSlotsTypeName.collected[resolvedSlotsTypeName.type.name];
|
|
35
|
+
if (resolvedSlotsType?.type.kind === "tuple") {
|
|
36
|
+
for (const item of resolvedSlotsType.type.items) {
|
|
37
|
+
if (item.kind === "literal" && typeof item.value === "string") {
|
|
38
|
+
slots.push(item.value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
props: intersectionType([
|
|
48
|
+
props,
|
|
49
|
+
objectType(
|
|
50
|
+
Object.fromEntries(
|
|
51
|
+
slots.map((slotName) => [`slot:${slotName}`, NODE_TYPE])
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
]),
|
|
55
|
+
types
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function extractDefinePropsFromStatement(resolver, statement) {
|
|
59
|
+
if (ts.isExpressionStatement(statement)) {
|
|
60
|
+
const definedProps = extractDefinePropsFromExpression(
|
|
61
|
+
resolver,
|
|
62
|
+
statement.expression
|
|
63
|
+
);
|
|
64
|
+
if (definedProps) {
|
|
65
|
+
return definedProps;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (ts.isVariableStatement(statement)) {
|
|
69
|
+
for (const variableDeclaration of statement.declarationList.declarations) {
|
|
70
|
+
if (!variableDeclaration.initializer) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const definedProps = extractDefinePropsFromExpression(
|
|
74
|
+
resolver,
|
|
75
|
+
variableDeclaration.initializer
|
|
76
|
+
);
|
|
77
|
+
if (definedProps) {
|
|
78
|
+
return definedProps;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function extractDefinePropsFromExpression(resolver, expression) {
|
|
85
|
+
if (ts.isBinaryExpression(expression) && expression.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
86
|
+
return extractDefinePropsFromExpression(resolver, expression.right);
|
|
87
|
+
}
|
|
88
|
+
if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression)) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const functionName = expression.expression.text;
|
|
92
|
+
if (functionName === "defineProps") {
|
|
93
|
+
const signature = resolver.checker.getResolvedSignature(expression);
|
|
94
|
+
if (signature) {
|
|
95
|
+
return resolver.resolveType(signature.getReturnType());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (functionName === "withDefaults") {
|
|
99
|
+
const [firstArgument, secondArgument] = expression.arguments;
|
|
100
|
+
if (!firstArgument || !secondArgument) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const definePropsType = extractDefinePropsFromExpression(
|
|
104
|
+
resolver,
|
|
105
|
+
firstArgument
|
|
106
|
+
);
|
|
107
|
+
if (!definePropsType) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const defaultsType = resolver.resolveType(
|
|
111
|
+
resolver.checker.getTypeAtLocation(secondArgument)
|
|
112
|
+
);
|
|
113
|
+
if (defaultsType.type.kind !== "object" || definePropsType.type.kind !== "object") {
|
|
114
|
+
return definePropsType;
|
|
115
|
+
}
|
|
116
|
+
const fieldsWithDefaultValue = new Set(
|
|
117
|
+
Object.keys(defaultsType.type.fields)
|
|
118
|
+
);
|
|
119
|
+
return {
|
|
120
|
+
type: objectType(
|
|
121
|
+
Object.fromEntries(
|
|
122
|
+
Object.entries(definePropsType.type.fields).map(
|
|
123
|
+
([fieldKey, fieldType]) => [
|
|
124
|
+
fieldKey,
|
|
125
|
+
maybeOptionalType(
|
|
126
|
+
fieldType,
|
|
127
|
+
fieldsWithDefaultValue.has(fieldKey)
|
|
128
|
+
)
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
),
|
|
133
|
+
collected: definePropsType.collected
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function inferComponentNameFromVuePath(filePath) {
|
|
140
|
+
return path.basename(filePath, path.extname(filePath));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function crawlFile(reader, resolver, rootDir, absoluteFilePath) {
|
|
144
|
+
const vueAbsoluteFilePath = extractVueFilePath(absoluteFilePath);
|
|
145
|
+
if (vueAbsoluteFilePath) {
|
|
146
|
+
const virtualVueTsAbsoluteFilePath = vueAbsoluteFilePath + ".ts";
|
|
147
|
+
const fileEntry = reader.readSync(vueAbsoluteFilePath);
|
|
148
|
+
if (fileEntry?.kind !== "file") {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
return [
|
|
152
|
+
{
|
|
153
|
+
id: generatePreviewableId({
|
|
154
|
+
filePath: path.relative(rootDir, vueAbsoluteFilePath),
|
|
155
|
+
name: inferComponentNameFromVuePath(vueAbsoluteFilePath)
|
|
156
|
+
}),
|
|
157
|
+
sourcePosition: {
|
|
158
|
+
start: 0,
|
|
159
|
+
end: fileEntry.size()
|
|
160
|
+
},
|
|
161
|
+
exported: true,
|
|
162
|
+
analyze: async () => analyzeFromTemplate(resolver, virtualVueTsAbsoluteFilePath)
|
|
163
|
+
}
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
const sourceFile = resolver.sourceFile(absoluteFilePath);
|
|
167
|
+
if (!sourceFile) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
const functions = [];
|
|
171
|
+
for (const statement of sourceFile.statements) {
|
|
172
|
+
if (ts.isExportAssignment(statement)) {
|
|
173
|
+
if (ts.isIdentifier(statement.expression)) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
functions.push(["default", statement, statement.expression]);
|
|
177
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
178
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
179
|
+
if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
functions.push([
|
|
183
|
+
declaration.name.text,
|
|
184
|
+
statement,
|
|
185
|
+
declaration.initializer
|
|
186
|
+
]);
|
|
187
|
+
}
|
|
188
|
+
} else if (ts.isFunctionDeclaration(statement)) {
|
|
189
|
+
const isDefaultExport = !!statement.modifiers?.find(
|
|
190
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
191
|
+
) && !!statement.modifiers?.find(
|
|
192
|
+
(m) => m.kind === ts.SyntaxKind.DefaultKeyword
|
|
193
|
+
);
|
|
194
|
+
const name = statement.name?.text;
|
|
195
|
+
if (isDefaultExport || name) {
|
|
196
|
+
functions.push([name || "default", statement, statement]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const storiesInfo = extractStoriesInfo(sourceFile);
|
|
201
|
+
const previewables = [];
|
|
202
|
+
const nameToExportedName = helpers.extractExportedNames(sourceFile);
|
|
203
|
+
const args = extractArgs(sourceFile);
|
|
204
|
+
async function extractPreviewable(basePreviewable, node, name) {
|
|
205
|
+
const storyArgs = args[name];
|
|
206
|
+
const isExported = name === "default" || !!nameToExportedName[name];
|
|
207
|
+
if (storiesInfo && storyArgs && isExported) {
|
|
208
|
+
const associatedComponent = extractStoryAssociatedComponent(
|
|
209
|
+
rootDir,
|
|
210
|
+
resolver,
|
|
211
|
+
storiesInfo.component
|
|
212
|
+
);
|
|
213
|
+
return {
|
|
214
|
+
...basePreviewable,
|
|
215
|
+
analyze: async () => ({
|
|
216
|
+
args: {
|
|
217
|
+
sourcePosition: {
|
|
218
|
+
start: storyArgs.getStart(),
|
|
219
|
+
end: storyArgs.getEnd()
|
|
220
|
+
},
|
|
221
|
+
value: await parseSerializableValue(storyArgs)
|
|
222
|
+
}
|
|
223
|
+
}),
|
|
224
|
+
associatedComponent
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const type = resolver.checker.getTypeAtLocation(node);
|
|
228
|
+
for (const callSignature of type.getCallSignatures()) {
|
|
229
|
+
const returnType = callSignature.getReturnType();
|
|
230
|
+
if (isJsxElement(returnType)) {
|
|
231
|
+
return {
|
|
232
|
+
...basePreviewable,
|
|
233
|
+
exported: isExported,
|
|
234
|
+
analyze: async () => ({
|
|
235
|
+
// TODO: Handle JSX properties.
|
|
236
|
+
props: UNKNOWN_TYPE,
|
|
237
|
+
types: {}
|
|
238
|
+
})
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (storiesInfo && isExported && returnType.getProperty("template")) {
|
|
242
|
+
const associatedComponent = extractStoryAssociatedComponent(
|
|
243
|
+
rootDir,
|
|
244
|
+
resolver,
|
|
245
|
+
storiesInfo.component
|
|
246
|
+
);
|
|
247
|
+
return {
|
|
248
|
+
...basePreviewable,
|
|
249
|
+
analyze: async () => ({ args: null }),
|
|
250
|
+
associatedComponent
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
for (const [name, statement, node] of functions) {
|
|
257
|
+
const previewable = await extractPreviewable(
|
|
258
|
+
{
|
|
259
|
+
id: generatePreviewableId({
|
|
260
|
+
filePath: path.relative(rootDir, absoluteFilePath),
|
|
261
|
+
name
|
|
262
|
+
}),
|
|
263
|
+
sourcePosition: {
|
|
264
|
+
start: statement.getStart(),
|
|
265
|
+
end: statement.getEnd()
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
node,
|
|
269
|
+
name
|
|
270
|
+
);
|
|
271
|
+
if (previewable) {
|
|
272
|
+
previewables.push(previewable);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return [
|
|
276
|
+
...previewables,
|
|
277
|
+
...(await extractCsf3Stories(rootDir, resolver, sourceFile, async (id) => {
|
|
278
|
+
const { filePath } = decodePreviewableId(id);
|
|
279
|
+
const absoluteFilePath2 = path.join(rootDir, filePath);
|
|
280
|
+
const vueComponents = await crawlFile(
|
|
281
|
+
reader,
|
|
282
|
+
resolver,
|
|
283
|
+
rootDir,
|
|
284
|
+
absoluteFilePath2
|
|
285
|
+
);
|
|
286
|
+
const component = absoluteFilePath2.endsWith(".vue.ts") ? vueComponents[0] : vueComponents.find((c) => c.id === id);
|
|
287
|
+
if (!component || !("exported" in component)) {
|
|
288
|
+
return {
|
|
289
|
+
props: UNKNOWN_TYPE,
|
|
290
|
+
types: {}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
return component.analyze();
|
|
294
|
+
})).map((story) => {
|
|
295
|
+
if (!story.associatedComponent?.id.includes(".vue.ts:")) {
|
|
296
|
+
return story;
|
|
297
|
+
}
|
|
298
|
+
const { filePath: associatedComponentFilePath } = decodePreviewableId(
|
|
299
|
+
story.associatedComponent.id
|
|
300
|
+
);
|
|
301
|
+
const associatedComponentVueFilePath = stripTsExtension(
|
|
302
|
+
associatedComponentFilePath
|
|
303
|
+
);
|
|
304
|
+
return {
|
|
305
|
+
...story,
|
|
306
|
+
associatedComponent: {
|
|
307
|
+
...story.associatedComponent,
|
|
308
|
+
id: generatePreviewableId({
|
|
309
|
+
filePath: associatedComponentVueFilePath,
|
|
310
|
+
name: inferComponentNameFromVuePath(associatedComponentVueFilePath)
|
|
311
|
+
})
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
})
|
|
315
|
+
];
|
|
316
|
+
}
|
|
317
|
+
function stripTsExtension(filePath) {
|
|
318
|
+
return filePath.substring(0, filePath.length - 3);
|
|
319
|
+
}
|
|
320
|
+
function extractVueFilePath(filePath) {
|
|
321
|
+
if (filePath.endsWith(".vue")) {
|
|
322
|
+
return filePath;
|
|
323
|
+
}
|
|
324
|
+
if (filePath.endsWith(".vue.ts")) {
|
|
325
|
+
return filePath.substring(0, filePath.length - 3);
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
function extractStoryAssociatedComponent(rootDir, resolver, component) {
|
|
330
|
+
const resolvedStoriesPreviewableId = resolvePreviewableId(
|
|
331
|
+
rootDir,
|
|
332
|
+
resolver.checker,
|
|
333
|
+
component
|
|
334
|
+
);
|
|
335
|
+
if (!resolvedStoriesPreviewableId) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
const { filePath } = decodePreviewableId(resolvedStoriesPreviewableId);
|
|
339
|
+
const vueFilePath = extractVueFilePath(filePath);
|
|
340
|
+
if (vueFilePath) {
|
|
341
|
+
return {
|
|
342
|
+
id: generatePreviewableId({
|
|
343
|
+
filePath: vueFilePath,
|
|
344
|
+
name: inferComponentNameFromVuePath(vueFilePath)
|
|
345
|
+
}),
|
|
346
|
+
analyze: async () => analyzeFromTemplate(resolver, vueFilePath + ".ts")
|
|
347
|
+
};
|
|
348
|
+
} else {
|
|
349
|
+
return {
|
|
350
|
+
id: resolvedStoriesPreviewableId,
|
|
351
|
+
analyze: async () => (
|
|
352
|
+
// TODO: Handle JSX properties.
|
|
353
|
+
{
|
|
354
|
+
props: UNKNOWN_TYPE,
|
|
355
|
+
types: {}
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const jsxElementTypes = /* @__PURE__ */ new Set(["Element"]);
|
|
362
|
+
function isJsxElement(type) {
|
|
363
|
+
if (type.isUnion()) {
|
|
364
|
+
for (const subtype of type.types) {
|
|
365
|
+
if (isJsxElement(subtype)) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return jsxElementTypes.has(type.symbol?.getEscapedName().toString());
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
var __defProp = Object.defineProperty;
|
|
374
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
375
|
+
var __publicField = (obj, key, value) => {
|
|
376
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
377
|
+
return value;
|
|
378
|
+
};
|
|
379
|
+
function createVueTypeScriptReader(reader) {
|
|
380
|
+
return new VueTypeScriptReader(reader);
|
|
381
|
+
}
|
|
382
|
+
class VueTypeScriptReader {
|
|
383
|
+
constructor(reader) {
|
|
384
|
+
this.reader = reader;
|
|
385
|
+
__publicField(this, "listeners", new ReaderListeners());
|
|
386
|
+
reader.listeners.add({
|
|
387
|
+
onChange: (absoluteFilePath, info) => {
|
|
388
|
+
this.listeners.notify(absoluteFilePath, info);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
this.observe = reader.observe?.bind(reader);
|
|
392
|
+
}
|
|
393
|
+
async read(absoluteFilePath) {
|
|
394
|
+
if (absoluteFilePath.endsWith(".vue.ts")) {
|
|
395
|
+
const source = await this.reader.read(
|
|
396
|
+
absoluteFilePath.substr(0, absoluteFilePath.length - 3)
|
|
397
|
+
);
|
|
398
|
+
if (source?.kind !== "file") {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
const name = path.basename(absoluteFilePath);
|
|
402
|
+
return {
|
|
403
|
+
kind: "file",
|
|
404
|
+
name,
|
|
405
|
+
realPath: async () => null,
|
|
406
|
+
lastModifiedMillis: () => source.lastModifiedMillis(),
|
|
407
|
+
read: async () => convertToTypeScript(await source.read(), name),
|
|
408
|
+
size: () => source.size()
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return this.reader.read(absoluteFilePath);
|
|
412
|
+
}
|
|
413
|
+
readSync(absoluteFilePath) {
|
|
414
|
+
if (absoluteFilePath.endsWith(".vue.ts")) {
|
|
415
|
+
const source = this.reader.readSync(
|
|
416
|
+
absoluteFilePath.substr(0, absoluteFilePath.length - 3)
|
|
417
|
+
);
|
|
418
|
+
if (source?.kind !== "file") {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
const name = path.basename(absoluteFilePath);
|
|
422
|
+
return {
|
|
423
|
+
kind: "file",
|
|
424
|
+
name,
|
|
425
|
+
realPath: () => null,
|
|
426
|
+
lastModifiedMillis: () => source.lastModifiedMillis(),
|
|
427
|
+
read: () => convertToTypeScript(source.read(), name),
|
|
428
|
+
size: () => source.size()
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
const entry = this.reader.readSync(absoluteFilePath);
|
|
432
|
+
if (entry?.kind === "file" && (entry.name.endsWith(".jsx") || entry.name.endsWith(".tsx"))) {
|
|
433
|
+
return {
|
|
434
|
+
...entry,
|
|
435
|
+
read: () => `/// <reference types="@vue/runtime-dom" />
|
|
436
|
+
${entry.read()}`
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
return entry;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function convertToTypeScript(vueTemplateSource, name) {
|
|
443
|
+
const parsed = parse(vueTemplateSource);
|
|
444
|
+
let pjsSlotsType = "[]";
|
|
445
|
+
if (parsed.descriptor.template?.ast) {
|
|
446
|
+
const slots = extractSlots(parsed.descriptor.template.ast);
|
|
447
|
+
pjsSlotsType = `[${slots.map((slotName) => JSON.stringify(slotName)).join(", ")}]`;
|
|
448
|
+
}
|
|
449
|
+
const pjsSlotsTypeDeclaration = `type PJS_Slots = ${pjsSlotsType};`;
|
|
450
|
+
if (parsed.descriptor.scriptSetup) {
|
|
451
|
+
return `import { defineProps } from '@vue/runtime-core';
|
|
452
|
+
${parsed.descriptor.scriptSetup.content}
|
|
453
|
+
export default {};${pjsSlotsTypeDeclaration}`;
|
|
454
|
+
} else if (parsed.descriptor.script) {
|
|
455
|
+
const lang = parsed.descriptor.script.lang;
|
|
456
|
+
if (lang && !["js", "javascript", "ts", "typescript"].includes(lang)) {
|
|
457
|
+
return "export default {}";
|
|
458
|
+
}
|
|
459
|
+
const scriptContent = parsed.descriptor.script.content;
|
|
460
|
+
const sourceFile = ts.createSourceFile(
|
|
461
|
+
`${name}.vue.ts`,
|
|
462
|
+
scriptContent,
|
|
463
|
+
ts.ScriptTarget.Latest
|
|
464
|
+
);
|
|
465
|
+
let component = null;
|
|
466
|
+
for (const node of sourceFile.statements) {
|
|
467
|
+
if (ts.isExportAssignment(node)) {
|
|
468
|
+
component = extractDefineComponentArgument(node.expression);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
let pjsComponentDeclaration = "const pjs_component = null;";
|
|
472
|
+
if (component) {
|
|
473
|
+
pjsComponentDeclaration = ts.createPrinter().printFile(
|
|
474
|
+
ts.factory.createSourceFile(
|
|
475
|
+
[
|
|
476
|
+
ts.factory.createVariableStatement(
|
|
477
|
+
[],
|
|
478
|
+
ts.factory.createVariableDeclarationList(
|
|
479
|
+
[
|
|
480
|
+
ts.factory.createVariableDeclaration(
|
|
481
|
+
"pjs_component",
|
|
482
|
+
void 0,
|
|
483
|
+
void 0,
|
|
484
|
+
ts.isObjectLiteralExpression(component) ? ts.factory.createAsExpression(
|
|
485
|
+
component,
|
|
486
|
+
ts.factory.createTypeReferenceNode("const")
|
|
487
|
+
) : component
|
|
488
|
+
)
|
|
489
|
+
],
|
|
490
|
+
ts.NodeFlags.Const
|
|
491
|
+
)
|
|
492
|
+
)
|
|
493
|
+
],
|
|
494
|
+
ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
|
|
495
|
+
0
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
return `
|
|
500
|
+
${scriptContent}
|
|
501
|
+
${pjsComponentDeclaration}
|
|
502
|
+
|
|
503
|
+
import type { PropType as PJS_PropType } from "@vue/runtime-core";
|
|
504
|
+
|
|
505
|
+
type PJS_TypeOrUnion<T> = PJS_PropType<T> | ReadonlyArray<PJS_PropType<T>>;
|
|
506
|
+
type PJS_OptionalPropType<T> = PJS_TypeOrUnion<T> | {type: PJS_TypeOrUnion<T>; required?: false};
|
|
507
|
+
type PJS_RequiredPropType<T> = {type: PJS_TypeOrUnion<T>; required: true};
|
|
508
|
+
type PJS_OptionalPropsKeys<T> = {
|
|
509
|
+
[K in keyof T]: T[K] extends PJS_OptionalPropType<any> ? K : never;
|
|
510
|
+
}[keyof T];
|
|
511
|
+
type PJS_RequiredPropsKeys<T> = {
|
|
512
|
+
[K in keyof T]: T[K] extends PJS_RequiredPropType<any> ? K : never;
|
|
513
|
+
}[keyof T];
|
|
514
|
+
type PJS_CombinedProps<T> = T extends readonly [...any] ? {
|
|
515
|
+
[K in T[number]]: unknown
|
|
516
|
+
} : ({
|
|
517
|
+
[K in PJS_OptionalPropsKeys<T>]?: T[K] extends PJS_OptionalPropType<infer S> ? S : never;
|
|
518
|
+
} & {
|
|
519
|
+
[K in PJS_RequiredPropsKeys<T>]: T[K] extends PJS_RequiredPropType<infer S> ? S : never;
|
|
520
|
+
});
|
|
521
|
+
type PJS_ExtractProps<T> = T extends { props: any } ? PJS_CombinedProps<T['props']> : {}
|
|
522
|
+
type PJS_Props = PJS_ExtractProps<typeof pjs_component>;
|
|
523
|
+
${pjsSlotsTypeDeclaration}
|
|
524
|
+
`;
|
|
525
|
+
} else {
|
|
526
|
+
return `export default {};${pjsSlotsTypeDeclaration}`;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function extractDefineComponentArgument(node) {
|
|
530
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineComponent" && node.arguments.length > 0) {
|
|
531
|
+
return node.arguments[0];
|
|
532
|
+
}
|
|
533
|
+
return node;
|
|
534
|
+
}
|
|
535
|
+
function extractSlots(element) {
|
|
536
|
+
namedSlot:
|
|
537
|
+
if ("tag" in element && element.tag === "slot") {
|
|
538
|
+
let slotName = "default";
|
|
539
|
+
for (const prop of element.props) {
|
|
540
|
+
if (prop.name === "name" && prop.type === 6 && prop.value) {
|
|
541
|
+
slotName = prop.value.content;
|
|
542
|
+
}
|
|
543
|
+
if (prop.name === "bind" && prop.type === 7 && prop.arg?.type === 4 && prop.arg.content === "name") {
|
|
544
|
+
break namedSlot;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return [slotName];
|
|
548
|
+
}
|
|
549
|
+
const result = [];
|
|
550
|
+
for (const child of element.children) {
|
|
551
|
+
if (child.type === 1) {
|
|
552
|
+
result.push(...extractSlots(child));
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return result;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const vue3FrameworkPlugin = {
|
|
559
|
+
info: {
|
|
560
|
+
apiVersion: 5,
|
|
561
|
+
name: "@cfp-studio/plugin-vue3"
|
|
562
|
+
},
|
|
563
|
+
isCompatible: async (dependencies) => {
|
|
564
|
+
const version = await dependencies["vue"]?.readInstalledVersion() || await dependencies["nuxt"]?.readInstalledVersion() || await dependencies["nuxt3"]?.readInstalledVersion();
|
|
565
|
+
if (!version) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
return parseInt(version) === 3;
|
|
569
|
+
},
|
|
570
|
+
async create({ rootDir, reader }) {
|
|
571
|
+
const { default: createVuePlugin } = await import('@vitejs/plugin-vue');
|
|
572
|
+
const { default: vueJsxPlugin } = await import('@vitejs/plugin-vue-jsx');
|
|
573
|
+
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
574
|
+
const previewDirPath = path.resolve(__dirname, "..", "preview");
|
|
575
|
+
const typeAnalyzer = createTypeAnalyzer({
|
|
576
|
+
rootDir,
|
|
577
|
+
reader: createStackedReader([
|
|
578
|
+
createVueTypeScriptReader(reader),
|
|
579
|
+
createFileSystemReader({
|
|
580
|
+
mapping: {
|
|
581
|
+
from: path.join(previewDirPath, "modules"),
|
|
582
|
+
to: path.join(rootDir, "node_modules")
|
|
583
|
+
},
|
|
584
|
+
watch: false
|
|
585
|
+
})
|
|
586
|
+
]),
|
|
587
|
+
tsCompilerOptions: {
|
|
588
|
+
types: ["vue/jsx"]
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
return {
|
|
592
|
+
defaultWrapperPath: "__previewjs__/Wrapper.vue",
|
|
593
|
+
previewDirPath,
|
|
594
|
+
typeAnalyzer,
|
|
595
|
+
crawlFiles: async (filePaths) => {
|
|
596
|
+
const absoluteFilePaths = filePaths.map(
|
|
597
|
+
(f) => path.isAbsolute(f) ? f : path.join(rootDir, f)
|
|
598
|
+
);
|
|
599
|
+
const resolver = typeAnalyzer.analyze(
|
|
600
|
+
absoluteFilePaths.map((p) => p.endsWith(".vue") ? p + ".ts" : p)
|
|
601
|
+
);
|
|
602
|
+
const components = [];
|
|
603
|
+
const stories = [];
|
|
604
|
+
for (const absoluteFilePath of absoluteFilePaths) {
|
|
605
|
+
for (const previewable of await crawlFile(
|
|
606
|
+
reader,
|
|
607
|
+
resolver,
|
|
608
|
+
rootDir,
|
|
609
|
+
absoluteFilePath
|
|
610
|
+
)) {
|
|
611
|
+
if ("exported" in previewable) {
|
|
612
|
+
components.push(previewable);
|
|
613
|
+
} else {
|
|
614
|
+
stories.push(previewable);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return {
|
|
619
|
+
components,
|
|
620
|
+
stories
|
|
621
|
+
};
|
|
622
|
+
},
|
|
623
|
+
viteConfig: (configuredPlugins) => {
|
|
624
|
+
return {
|
|
625
|
+
plugins: [
|
|
626
|
+
...configuredPlugins,
|
|
627
|
+
configuredPlugins.find((plugin) => plugin.name === "vite:vue") ? null : createVuePlugin(),
|
|
628
|
+
configuredPlugins.find((plugin) => plugin.name.includes("jsx")) ? null : vueJsxPlugin(),
|
|
629
|
+
{
|
|
630
|
+
name: "previewjs:optimize-deps",
|
|
631
|
+
config: () => ({
|
|
632
|
+
optimizeDeps: {
|
|
633
|
+
include: ["vue"]
|
|
634
|
+
}
|
|
635
|
+
})
|
|
636
|
+
}
|
|
637
|
+
],
|
|
638
|
+
esbuild: {
|
|
639
|
+
banner: `import { h } from 'vue';`,
|
|
640
|
+
jsxFactory: "h"
|
|
641
|
+
},
|
|
642
|
+
resolve: {
|
|
643
|
+
alias: {
|
|
644
|
+
vue: "vue/dist/vue.esm-bundler.js"
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
},
|
|
649
|
+
dispose: () => {
|
|
650
|
+
typeAnalyzer.dispose();
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
export { vue3FrameworkPlugin as default };
|