@htmlplus/element 3.3.0 → 3.3.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/dist/bundlers.d.ts +5 -5
- package/dist/bundlers.js +4 -4
- package/dist/client.d.ts +36 -18
- package/dist/client.js +674 -626
- package/dist/jsx-runtime.d.ts +183 -183
- package/dist/transformer.d.ts +45 -40
- package/dist/transformer.js +359 -276
- package/package.json +96 -92
package/dist/transformer.js
CHANGED
|
@@ -1,99 +1,29 @@
|
|
|
1
|
-
import generator from '@babel/generator';
|
|
2
1
|
import t from '@babel/types';
|
|
3
|
-
import traverse from '@babel/traverse';
|
|
4
2
|
import { parse as parse$1 } from '@babel/parser';
|
|
5
3
|
import fs from 'fs-extra';
|
|
6
4
|
import { glob } from 'glob';
|
|
7
5
|
import template from '@babel/template';
|
|
8
6
|
import { pascalCase, kebabCase, camelCase, capitalCase } from 'change-case';
|
|
9
|
-
import ora from 'ora';
|
|
10
7
|
import path, { join, resolve, dirname } from 'node:path';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
});
|
|
16
|
-
const log = (message, persist) => {
|
|
17
|
-
const content = `${new Date().toLocaleTimeString()} [${KEY}] ${message}`;
|
|
18
|
-
const log = logger.start(content);
|
|
19
|
-
if (!persist)
|
|
20
|
-
return;
|
|
21
|
-
log.succeed();
|
|
22
|
-
};
|
|
23
|
-
const transformer = (...plugins) => {
|
|
24
|
-
let global = {
|
|
25
|
-
contexts: []
|
|
26
|
-
};
|
|
27
|
-
const start = async () => {
|
|
28
|
-
log(`Started.`, true);
|
|
29
|
-
log(`${plugins.length} plugins detected.`, true);
|
|
30
|
-
log(`Plugins are starting.`, true);
|
|
31
|
-
for (const plugin of plugins) {
|
|
32
|
-
if (!plugin.start)
|
|
33
|
-
continue;
|
|
34
|
-
log(`Plugin '${plugin.name}' is starting.`);
|
|
35
|
-
global = (await plugin.start(global)) || global;
|
|
36
|
-
log(`Plugin '${plugin.name}' started successfully.`);
|
|
37
|
-
}
|
|
38
|
-
log(`Plugins have been successfully started.`, true);
|
|
39
|
-
};
|
|
40
|
-
const run = async (filePath) => {
|
|
41
|
-
path.join(filePath).split(path.sep).pop();
|
|
42
|
-
let context = {
|
|
43
|
-
filePath
|
|
44
|
-
};
|
|
45
|
-
const parsed = path.parse(filePath);
|
|
46
|
-
for (const plugin of plugins) {
|
|
47
|
-
if (!plugin.run)
|
|
48
|
-
continue;
|
|
49
|
-
const source = path.join(parsed.dir).split(path.sep).slice(-2).concat(parsed.base).join('/');
|
|
50
|
-
log(`Plugin '${plugin.name}' is executing on '${source}' file.`);
|
|
51
|
-
try {
|
|
52
|
-
context = (await plugin.run(context, global)) || context;
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
log(`Error in '${plugin.name}' plugin on '${source}' file.\n`, true);
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
global.contexts = global.contexts
|
|
59
|
-
.filter((current) => {
|
|
60
|
-
return current.filePath != context.filePath;
|
|
61
|
-
})
|
|
62
|
-
.concat(context);
|
|
63
|
-
log(`Plugin '${plugin.name}' executed successfully on '${source}' file.`);
|
|
64
|
-
}
|
|
65
|
-
logger.stop();
|
|
66
|
-
return context;
|
|
67
|
-
};
|
|
68
|
-
const finish = async () => {
|
|
69
|
-
log(`Plugins are finishing.`, true);
|
|
70
|
-
for (const plugin of plugins) {
|
|
71
|
-
if (!plugin.finish)
|
|
72
|
-
continue;
|
|
73
|
-
log(`Plugin '${plugin.name}' is finishing.`);
|
|
74
|
-
global = (await plugin.finish(global)) || global;
|
|
75
|
-
log(`Plugin '${plugin.name}' finished successfully.`);
|
|
76
|
-
}
|
|
77
|
-
log(`Plugins have been successfully finished.`, true);
|
|
78
|
-
log(`Finished.`, true);
|
|
79
|
-
};
|
|
80
|
-
return { global, start, run, finish };
|
|
81
|
-
};
|
|
8
|
+
import { COMMENT_AUTO_ADDED, DECORATOR_PROPERTY, STATIC_TAG, DECORATOR_PROPERTY_TYPE, UTILS_STYLES_IMPORTED, UTILS_STYLES_LOCAL, UTILS_PATH, UTILS_HTML_IMPORTED, UTILS_HTML_LOCAL, ELEMENT_HOST_NAME, TYPE_OBJECT, TYPE_NULL, TYPE_ARRAY, TYPE_STRING, TYPE_ENUM, TYPE_NUMBER, TYPE_DATE, TYPE_BOOLEAN, UTILS_ATTRIBUTES_IMPORTED, UTILS_ATTRIBUTES_LOCAL, DECORATOR_CSS_VARIABLE, DECORATOR_EVENT, DECORATOR_METHOD, DECORATOR_STATE, STATIC_STYLE, STYLE_IMPORTED, PACKAGE_NAME, DECORATOR_ELEMENT, KEY } from './constants.js';
|
|
9
|
+
import core from '@babel/traverse';
|
|
10
|
+
import core$1 from '@babel/generator';
|
|
11
|
+
import ora from 'ora';
|
|
82
12
|
|
|
83
13
|
const ASSETS_OPTIONS = {
|
|
84
14
|
destination(context) {
|
|
85
|
-
return path.join('dist', 'assets', context.fileName);
|
|
15
|
+
return path.join('dist', 'assets', context.fileName || '');
|
|
86
16
|
},
|
|
87
17
|
source(context) {
|
|
88
|
-
return path.join(context.directoryPath, 'assets');
|
|
18
|
+
return path.join(context.directoryPath || '', 'assets');
|
|
89
19
|
},
|
|
90
20
|
json(context) {
|
|
91
|
-
return path.join('dist', 'assets', context.fileName
|
|
21
|
+
return path.join('dist', 'assets', `${context.fileName || ''}.json`);
|
|
92
22
|
}
|
|
93
23
|
};
|
|
94
|
-
const assets = (
|
|
24
|
+
const assets = (userOptions) => {
|
|
95
25
|
const name = 'assets';
|
|
96
|
-
options = Object.assign({}, ASSETS_OPTIONS,
|
|
26
|
+
const options = Object.assign({}, ASSETS_OPTIONS, userOptions);
|
|
97
27
|
const finish = (global) => {
|
|
98
28
|
for (const context of global.contexts) {
|
|
99
29
|
context.assetsDestination = options.destination(context);
|
|
@@ -115,16 +45,16 @@ const assets = (options) => {
|
|
|
115
45
|
};
|
|
116
46
|
|
|
117
47
|
const COPY_OPTIONS = {
|
|
118
|
-
at: 'start'
|
|
48
|
+
at: 'start',
|
|
49
|
+
transformer: (content) => content
|
|
119
50
|
};
|
|
120
|
-
const copy = (
|
|
51
|
+
const copy = (userOptions) => {
|
|
121
52
|
const name = 'copy';
|
|
122
|
-
options = Object.assign({}, COPY_OPTIONS,
|
|
53
|
+
const options = Object.assign({}, COPY_OPTIONS, userOptions);
|
|
123
54
|
const copy = (caller) => {
|
|
124
|
-
if (options.at
|
|
55
|
+
if (options.at !== caller)
|
|
125
56
|
return;
|
|
126
|
-
let content;
|
|
127
|
-
content = fs.readFileSync(options.source, 'utf8');
|
|
57
|
+
let content = fs.readFileSync(options.source, 'utf8');
|
|
128
58
|
if (options.transformer)
|
|
129
59
|
content = options.transformer(content);
|
|
130
60
|
fs.ensureDirSync(path.dirname(options.destination));
|
|
@@ -142,11 +72,10 @@ const copy = (options) => {
|
|
|
142
72
|
return { name, start, run, finish };
|
|
143
73
|
};
|
|
144
74
|
|
|
145
|
-
|
|
146
|
-
const visitor =
|
|
147
|
-
(traverse.default || traverse)(ast, options);
|
|
148
|
-
};
|
|
75
|
+
const traverse = (core.default || core);
|
|
76
|
+
const visitor = traverse;
|
|
149
77
|
|
|
78
|
+
// biome-ignore-all lint: TODO
|
|
150
79
|
function addDependency(path, source, local, imported, comment) {
|
|
151
80
|
const isDefault = local && !imported;
|
|
152
81
|
const isImport = local && imported;
|
|
@@ -158,7 +87,7 @@ function addDependency(path, source, local, imported, comment) {
|
|
|
158
87
|
file = file.node || file;
|
|
159
88
|
visitor(file, {
|
|
160
89
|
ImportDeclaration(path) {
|
|
161
|
-
if (path.node.source.value
|
|
90
|
+
if (path.node.source.value !== source)
|
|
162
91
|
return;
|
|
163
92
|
declaration = path.node;
|
|
164
93
|
}
|
|
@@ -169,10 +98,10 @@ function addDependency(path, source, local, imported, comment) {
|
|
|
169
98
|
};
|
|
170
99
|
let specifier = declaration?.specifiers.find((specifier) => {
|
|
171
100
|
if (isDefault) {
|
|
172
|
-
return specifier.type
|
|
101
|
+
return specifier.type === 'ImportDefaultSpecifier';
|
|
173
102
|
}
|
|
174
103
|
else if (isImport) {
|
|
175
|
-
return specifier.imported?.name
|
|
104
|
+
return specifier.imported?.name === imported;
|
|
176
105
|
}
|
|
177
106
|
});
|
|
178
107
|
if (specifier)
|
|
@@ -211,10 +140,11 @@ function addDependency(path, source, local, imported, comment) {
|
|
|
211
140
|
|
|
212
141
|
const extractAttribute = (property) => {
|
|
213
142
|
try {
|
|
143
|
+
// biome-ignore lint: Keep using `any` type because of complexity
|
|
214
144
|
return property.decorators
|
|
215
|
-
.find((decorator) => decorator.expression.callee.name
|
|
216
|
-
.expression.arguments
|
|
217
|
-
.value;
|
|
145
|
+
.find((decorator) => decorator.expression.callee.name === DECORATOR_PROPERTY)
|
|
146
|
+
.expression.arguments.at(0)
|
|
147
|
+
.properties.find((property) => property.key.name === 'attribute').value.value;
|
|
218
148
|
}
|
|
219
149
|
catch { }
|
|
220
150
|
};
|
|
@@ -225,12 +155,12 @@ const extractFromComment = (node, whitelist) => {
|
|
|
225
155
|
description: ''
|
|
226
156
|
};
|
|
227
157
|
const lines = node.leadingComments
|
|
228
|
-
?.
|
|
229
|
-
if (comment.type
|
|
158
|
+
?.flatMap((comment) => {
|
|
159
|
+
if (comment.type === 'CommentLine') {
|
|
230
160
|
return comment.value;
|
|
161
|
+
}
|
|
231
162
|
return comment.value.split('\n');
|
|
232
163
|
})
|
|
233
|
-
?.flat()
|
|
234
164
|
?.map((line) => line.trim().replace(/^\*/, '').trim())
|
|
235
165
|
?.filter((line) => line.trim());
|
|
236
166
|
for (const line of lines || []) {
|
|
@@ -240,7 +170,7 @@ const extractFromComment = (node, whitelist) => {
|
|
|
240
170
|
}
|
|
241
171
|
if (!normalized.length)
|
|
242
172
|
normalized.push('');
|
|
243
|
-
normalized[normalized.length - 1] +=
|
|
173
|
+
normalized[normalized.length - 1] += ` ${line}`;
|
|
244
174
|
}
|
|
245
175
|
for (const line of normalized) {
|
|
246
176
|
if (!line.startsWith('@')) {
|
|
@@ -255,11 +185,14 @@ const extractFromComment = (node, whitelist) => {
|
|
|
255
185
|
const type = groups[2]?.trim().slice(1, -1);
|
|
256
186
|
const name = groups[3]?.trim();
|
|
257
187
|
const description = groups[4]?.trim();
|
|
188
|
+
// TODO
|
|
189
|
+
// const [, tag, type, name, description] = groups.map((g) => g?.trim() || '');
|
|
258
190
|
if (name && description) {
|
|
259
|
-
const key = tag
|
|
191
|
+
const key = `${tag}s`;
|
|
260
192
|
if (whitelist && !whitelist.includes(key))
|
|
261
193
|
continue;
|
|
262
|
-
|
|
194
|
+
result[key] ||= [];
|
|
195
|
+
result[key].push({ name, type, description });
|
|
263
196
|
}
|
|
264
197
|
else {
|
|
265
198
|
const key = tag;
|
|
@@ -272,18 +205,30 @@ const extractFromComment = (node, whitelist) => {
|
|
|
272
205
|
};
|
|
273
206
|
|
|
274
207
|
const getInitializer = (node) => {
|
|
208
|
+
// biome-ignore lint: Keep using `any` type because of complexity
|
|
275
209
|
return node?.extra?.raw || node?.['value'];
|
|
276
210
|
};
|
|
277
211
|
|
|
212
|
+
const getTypeReferenceName = (ref) => {
|
|
213
|
+
switch (ref.typeName.type) {
|
|
214
|
+
case 'Identifier':
|
|
215
|
+
return ref.typeName.name;
|
|
216
|
+
default:
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
278
220
|
const getType = (directory, file, node) => {
|
|
279
221
|
if (!node)
|
|
280
222
|
return node;
|
|
281
|
-
if (node.type
|
|
223
|
+
if (node.type !== 'TSTypeReference')
|
|
282
224
|
return node;
|
|
283
225
|
let result;
|
|
226
|
+
const typeName = getTypeReferenceName(node);
|
|
227
|
+
if (!typeName)
|
|
228
|
+
return node;
|
|
284
229
|
visitor(file, {
|
|
285
230
|
ClassDeclaration(path) {
|
|
286
|
-
if (path.node.id
|
|
231
|
+
if (path.node.id?.name !== typeName)
|
|
287
232
|
return;
|
|
288
233
|
result = path.node;
|
|
289
234
|
path.stop();
|
|
@@ -291,31 +236,25 @@ const getType = (directory, file, node) => {
|
|
|
291
236
|
ImportDeclaration(path) {
|
|
292
237
|
for (const specifier of path.node.specifiers) {
|
|
293
238
|
const alias = specifier.local.name;
|
|
294
|
-
if (alias
|
|
239
|
+
if (alias !== typeName)
|
|
295
240
|
continue;
|
|
296
|
-
switch (specifier.type) {
|
|
297
|
-
case 'ImportNamespaceSpecifier':
|
|
298
|
-
break;
|
|
299
|
-
case 'ImportDefaultSpecifier':
|
|
300
|
-
break;
|
|
301
|
-
case 'ImportSpecifier':
|
|
302
|
-
specifier.imported.name;
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
241
|
try {
|
|
306
242
|
const reference = glob
|
|
307
243
|
.sync(['.ts*', '/index.ts*'].map((key) => {
|
|
308
244
|
return join(directory, path.node.source.value).replace(/\\/g, '/') + key;
|
|
309
245
|
}))
|
|
310
|
-
.find((reference) => fs.existsSync(reference));
|
|
246
|
+
.find((reference) => reference && fs.existsSync(reference));
|
|
247
|
+
if (!reference)
|
|
248
|
+
continue;
|
|
311
249
|
const content = fs.readFileSync(reference, 'utf8');
|
|
312
|
-
const filePath = resolve(directory, path.node.source.value
|
|
313
|
-
|
|
250
|
+
const filePath = resolve(directory, `${path.node.source.value}.ts`);
|
|
251
|
+
const pathWithAst = path;
|
|
252
|
+
pathWithAst.$ast ||= parse$1(content, {
|
|
314
253
|
allowImportExportEverywhere: true,
|
|
315
254
|
plugins: ['typescript'],
|
|
316
255
|
ranges: false
|
|
317
256
|
});
|
|
318
|
-
result = getType(dirname(filePath),
|
|
257
|
+
result = getType(dirname(filePath), pathWithAst.$ast, node);
|
|
319
258
|
}
|
|
320
259
|
catch { }
|
|
321
260
|
path.stop();
|
|
@@ -323,32 +262,35 @@ const getType = (directory, file, node) => {
|
|
|
323
262
|
}
|
|
324
263
|
},
|
|
325
264
|
TSInterfaceDeclaration(path) {
|
|
326
|
-
if (path.node.id.name
|
|
265
|
+
if (path.node.id.name !== typeName)
|
|
327
266
|
return;
|
|
328
267
|
result = path.node;
|
|
329
268
|
path.stop();
|
|
330
269
|
},
|
|
331
270
|
TSTypeAliasDeclaration(path) {
|
|
332
|
-
if (path.node.id.name
|
|
271
|
+
if (path.node.id.name !== typeName)
|
|
333
272
|
return;
|
|
334
|
-
|
|
335
|
-
switch (
|
|
336
|
-
case 'TSUnionType':
|
|
273
|
+
const typeAnnotation = path.node.typeAnnotation;
|
|
274
|
+
switch (typeAnnotation.type) {
|
|
275
|
+
case 'TSUnionType': {
|
|
337
276
|
const types = [];
|
|
338
|
-
for (const prev of
|
|
277
|
+
for (const prev of typeAnnotation.types) {
|
|
339
278
|
const next = getType(directory, file, prev);
|
|
340
|
-
if (next.type
|
|
341
|
-
|
|
279
|
+
if (next.type === 'TSUnionType') {
|
|
280
|
+
types.push(...next.types);
|
|
342
281
|
}
|
|
343
282
|
else {
|
|
344
283
|
types.push(next);
|
|
345
284
|
}
|
|
346
285
|
}
|
|
347
|
-
|
|
286
|
+
typeAnnotation.types = types;
|
|
287
|
+
result = typeAnnotation;
|
|
348
288
|
break;
|
|
349
|
-
|
|
350
|
-
|
|
289
|
+
}
|
|
290
|
+
default: {
|
|
291
|
+
result = getType(directory, file, typeAnnotation);
|
|
351
292
|
break;
|
|
293
|
+
}
|
|
352
294
|
}
|
|
353
295
|
path.stop();
|
|
354
296
|
}
|
|
@@ -359,24 +301,17 @@ const getType = (directory, file, node) => {
|
|
|
359
301
|
const getTypeReference = (file, node) => {
|
|
360
302
|
if (!node)
|
|
361
303
|
return;
|
|
362
|
-
if (node.type
|
|
304
|
+
if (node.type !== 'TSTypeReference')
|
|
363
305
|
return;
|
|
364
306
|
let result;
|
|
365
307
|
visitor(file, {
|
|
366
308
|
ImportDeclaration(path) {
|
|
367
309
|
for (const specifier of path.node.specifiers) {
|
|
368
310
|
const alias = specifier.local.name;
|
|
369
|
-
if (
|
|
311
|
+
if (node.typeName.type !== 'Identifier')
|
|
312
|
+
continue;
|
|
313
|
+
if (alias !== node.typeName.name)
|
|
370
314
|
continue;
|
|
371
|
-
switch (specifier.type) {
|
|
372
|
-
case 'ImportNamespaceSpecifier':
|
|
373
|
-
break;
|
|
374
|
-
case 'ImportDefaultSpecifier':
|
|
375
|
-
break;
|
|
376
|
-
case 'ImportSpecifier':
|
|
377
|
-
specifier.imported.name;
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
380
315
|
result = path.node.source.value;
|
|
381
316
|
path.stop();
|
|
382
317
|
break;
|
|
@@ -387,38 +322,51 @@ const getTypeReference = (file, node) => {
|
|
|
387
322
|
};
|
|
388
323
|
|
|
389
324
|
const hasDecorator = (node, name) => {
|
|
325
|
+
if ('decorators' in node === false)
|
|
326
|
+
return false;
|
|
390
327
|
if (!node.decorators)
|
|
391
328
|
return false;
|
|
392
|
-
|
|
329
|
+
for (const decorator of node.decorators) {
|
|
330
|
+
const expression = decorator.expression;
|
|
331
|
+
if (!t.isCallExpression(expression))
|
|
332
|
+
continue;
|
|
333
|
+
if (!t.isIdentifier(expression.callee))
|
|
334
|
+
continue;
|
|
335
|
+
if (expression.callee.name === name) {
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
393
340
|
};
|
|
394
341
|
|
|
395
|
-
|
|
342
|
+
const generator = (core$1.default || core$1);
|
|
396
343
|
const print = (ast) => {
|
|
397
|
-
// TODO: the `ast` should not be undefined
|
|
398
344
|
if (!ast)
|
|
399
345
|
return '';
|
|
400
|
-
return
|
|
346
|
+
return generator(ast, { decoratorsBeforeExport: true }).code;
|
|
401
347
|
};
|
|
402
348
|
|
|
403
349
|
const CUSTOM_ELEMENT_OPTIONS = {
|
|
404
|
-
prefix:
|
|
350
|
+
prefix: '',
|
|
405
351
|
typings: true
|
|
406
352
|
};
|
|
407
353
|
// TODO: support {variable && jsxElement}
|
|
408
|
-
const customElement = (
|
|
354
|
+
const customElement = (userOptions) => {
|
|
409
355
|
const name = 'customElement';
|
|
410
|
-
options = Object.assign({}, CUSTOM_ELEMENT_OPTIONS,
|
|
356
|
+
const options = Object.assign({}, CUSTOM_ELEMENT_OPTIONS, userOptions);
|
|
411
357
|
const run = (context) => {
|
|
358
|
+
if (!context.fileAST)
|
|
359
|
+
return;
|
|
412
360
|
const ast = t.cloneNode(context.fileAST, true);
|
|
413
|
-
context.elementTagName = `${options.prefix
|
|
361
|
+
context.elementTagName = `${options.prefix}${context.elementKey}`;
|
|
414
362
|
context.elementInterfaceName = `HTML${pascalCase(context.elementTagName)}Element`;
|
|
415
363
|
// attach tag name
|
|
416
364
|
visitor(ast, {
|
|
417
365
|
ClassDeclaration(path) {
|
|
418
366
|
const { body, id } = path.node;
|
|
419
|
-
if (id
|
|
367
|
+
if (id?.name !== context.className)
|
|
420
368
|
return;
|
|
421
|
-
const node = t.classProperty(t.identifier(STATIC_TAG), t.stringLiteral(context.elementTagName), undefined, undefined, undefined, true);
|
|
369
|
+
const node = t.classProperty(t.identifier(STATIC_TAG), t.stringLiteral(context.elementTagName || ''), undefined, undefined, undefined, true);
|
|
422
370
|
t.addComment(node, 'leading', COMMENT_AUTO_ADDED, true);
|
|
423
371
|
body.body.unshift(node);
|
|
424
372
|
}
|
|
@@ -427,15 +375,18 @@ const customElement = (options) => {
|
|
|
427
375
|
visitor(ast, {
|
|
428
376
|
JSXAttribute(path) {
|
|
429
377
|
const { name, value } = path.node;
|
|
430
|
-
if (name.name
|
|
378
|
+
if (name.name !== 'style')
|
|
431
379
|
return;
|
|
432
380
|
if (!value)
|
|
433
381
|
return;
|
|
434
|
-
if (value.type
|
|
382
|
+
if (value.type !== 'JSXExpressionContainer')
|
|
383
|
+
return;
|
|
384
|
+
if (!value.expression)
|
|
385
|
+
return;
|
|
386
|
+
if (value.expression.type === 'JSXEmptyExpression')
|
|
435
387
|
return;
|
|
436
388
|
const { local } = addDependency(path, UTILS_PATH, UTILS_STYLES_LOCAL, UTILS_STYLES_IMPORTED);
|
|
437
|
-
|
|
438
|
-
path.replaceWith(t.jsxAttribute(t.jsxIdentifier('style'), t.jsxExpressionContainer(t.callExpression(t.identifier(local), [value.expression]))));
|
|
389
|
+
path.replaceWith(t.jsxAttribute(t.jsxIdentifier('style'), t.jsxExpressionContainer(t.callExpression(t.identifier(local || ''), [value.expression]))));
|
|
439
390
|
path.skip();
|
|
440
391
|
}
|
|
441
392
|
});
|
|
@@ -443,10 +394,14 @@ const customElement = (options) => {
|
|
|
443
394
|
visitor(ast, {
|
|
444
395
|
JSXAttribute(path) {
|
|
445
396
|
const { name, value } = path.node;
|
|
446
|
-
if (name.name
|
|
397
|
+
if (name.name !== 'className')
|
|
447
398
|
return;
|
|
448
|
-
|
|
449
|
-
return
|
|
399
|
+
if (!value)
|
|
400
|
+
return;
|
|
401
|
+
if (!t.isJSXOpeningElement(path.parent))
|
|
402
|
+
return;
|
|
403
|
+
const hasClass = path.parent.attributes.some((attribute) => {
|
|
404
|
+
return t.isJSXAttribute(attribute) && attribute.name.name === 'class';
|
|
450
405
|
});
|
|
451
406
|
if (hasClass)
|
|
452
407
|
return path.remove();
|
|
@@ -457,12 +412,14 @@ const customElement = (options) => {
|
|
|
457
412
|
visitor(ast, {
|
|
458
413
|
JSXAttribute(path) {
|
|
459
414
|
const { name, value } = path.node;
|
|
460
|
-
if (
|
|
461
|
-
|
|
415
|
+
if (!t.isJSXIdentifier(name))
|
|
416
|
+
return;
|
|
417
|
+
if (name.name === 'value') {
|
|
418
|
+
name.name = `.${name.name}`;
|
|
462
419
|
return;
|
|
463
420
|
}
|
|
464
|
-
if (name.name
|
|
465
|
-
name.name =
|
|
421
|
+
if (name.name === 'disabled') {
|
|
422
|
+
name.name = `.${name.name}`;
|
|
466
423
|
return;
|
|
467
424
|
}
|
|
468
425
|
const key = ['tabIndex', 'viewBox'];
|
|
@@ -480,7 +437,7 @@ const customElement = (options) => {
|
|
|
480
437
|
return;
|
|
481
438
|
const TODO = (node, attributes) => {
|
|
482
439
|
const { local } = addDependency(path, UTILS_PATH, UTILS_ATTRIBUTES_LOCAL, UTILS_ATTRIBUTES_IMPORTED);
|
|
483
|
-
return t.callExpression(t.identifier(local), [
|
|
440
|
+
return t.callExpression(t.identifier(local || ''), [
|
|
484
441
|
node,
|
|
485
442
|
t.arrayExpression(attributes.map((attribute) => {
|
|
486
443
|
switch (attribute.type) {
|
|
@@ -488,7 +445,7 @@ const customElement = (options) => {
|
|
|
488
445
|
return attribute.argument;
|
|
489
446
|
default:
|
|
490
447
|
return t.objectExpression([
|
|
491
|
-
t.objectProperty(t.stringLiteral(attribute.name.name), attribute.value?.type
|
|
448
|
+
t.objectProperty(t.stringLiteral(attribute.name.name), attribute.value?.type === 'JSXExpressionContainer'
|
|
492
449
|
? attribute.value.expression
|
|
493
450
|
: attribute.value || t.booleanLiteral(true))
|
|
494
451
|
]);
|
|
@@ -498,22 +455,22 @@ const customElement = (options) => {
|
|
|
498
455
|
};
|
|
499
456
|
const render = (node) => {
|
|
500
457
|
switch (node.type) {
|
|
501
|
-
case 'JSXElement':
|
|
458
|
+
case 'JSXElement': {
|
|
502
459
|
const attributes = node.openingElement.attributes;
|
|
503
|
-
const isHost = node.openingElement.name.name
|
|
460
|
+
const isHost = node.openingElement.name.name === ELEMENT_HOST_NAME;
|
|
504
461
|
// TODO
|
|
505
462
|
if (isHost) {
|
|
506
|
-
const children = node.children.
|
|
463
|
+
const children = node.children.flatMap(render);
|
|
507
464
|
if (!attributes.length)
|
|
508
465
|
return children;
|
|
509
466
|
return [TODO(t.thisExpression(), attributes), ...children];
|
|
510
467
|
}
|
|
511
468
|
const name = node.openingElement.name.name;
|
|
512
|
-
const children = node.children.
|
|
469
|
+
const children = node.children.flatMap(render);
|
|
513
470
|
const parts = [];
|
|
514
471
|
parts.push('<', name);
|
|
515
472
|
const hasSpreadAttribute = attributes.some((attribute) => {
|
|
516
|
-
return attribute.type
|
|
473
|
+
return attribute.type === 'JSXSpreadAttribute';
|
|
517
474
|
});
|
|
518
475
|
if (hasSpreadAttribute) {
|
|
519
476
|
parts.push(' ', 'ref=', t.arrowFunctionExpression([t.identifier('$element')], TODO(t.identifier('$element'), attributes)));
|
|
@@ -522,7 +479,7 @@ const customElement = (options) => {
|
|
|
522
479
|
for (const attribute of attributes) {
|
|
523
480
|
switch (attribute.type) {
|
|
524
481
|
case 'JSXAttribute':
|
|
525
|
-
if (attribute.name.name
|
|
482
|
+
if (attribute.name.name === 'dangerouslySetInnerHTML') {
|
|
526
483
|
try {
|
|
527
484
|
parts.push(' ', '.innerHTML');
|
|
528
485
|
parts.push('=');
|
|
@@ -556,12 +513,13 @@ const customElement = (options) => {
|
|
|
556
513
|
parts.push('<', '/', name, '>');
|
|
557
514
|
}
|
|
558
515
|
return parts;
|
|
516
|
+
}
|
|
559
517
|
case 'JSXFragment':
|
|
560
|
-
return node.children.
|
|
518
|
+
return node.children.flatMap(render);
|
|
561
519
|
case 'JSXText':
|
|
562
520
|
return [node.extra.raw];
|
|
563
521
|
case 'JSXExpressionContainer':
|
|
564
|
-
if (node.expression.type
|
|
522
|
+
if (node.expression.type === 'JSXEmptyExpression')
|
|
565
523
|
return [];
|
|
566
524
|
return [node.expression];
|
|
567
525
|
}
|
|
@@ -572,7 +530,7 @@ const customElement = (options) => {
|
|
|
572
530
|
let i = 0;
|
|
573
531
|
while (i < parts.length + 1) {
|
|
574
532
|
let quasi = '';
|
|
575
|
-
while (typeof parts[i]
|
|
533
|
+
while (typeof parts[i] === 'string') {
|
|
576
534
|
quasi += parts[i].replace(/[\\`]/g, (s) => `\\${s}`);
|
|
577
535
|
i += 1;
|
|
578
536
|
}
|
|
@@ -585,7 +543,7 @@ const customElement = (options) => {
|
|
|
585
543
|
// TODO
|
|
586
544
|
// if (!expressions.length) return template;
|
|
587
545
|
const { local } = addDependency(path, UTILS_PATH, UTILS_HTML_LOCAL, UTILS_HTML_IMPORTED, true);
|
|
588
|
-
return t.taggedTemplateExpression(t.identifier(local), templateLiteral);
|
|
546
|
+
return t.taggedTemplateExpression(t.identifier(local || ''), templateLiteral);
|
|
589
547
|
};
|
|
590
548
|
path.replaceWith(transform(render(path.node)));
|
|
591
549
|
}
|
|
@@ -594,14 +552,22 @@ const customElement = (options) => {
|
|
|
594
552
|
visitor(ast, {
|
|
595
553
|
Decorator(path) {
|
|
596
554
|
const { expression } = path.node;
|
|
597
|
-
if (expression
|
|
555
|
+
if (!t.isCallExpression(expression))
|
|
556
|
+
return;
|
|
557
|
+
if (!t.isIdentifier(expression.callee))
|
|
558
|
+
return;
|
|
559
|
+
if (expression.callee.name !== DECORATOR_PROPERTY)
|
|
598
560
|
return;
|
|
599
561
|
if (!expression.arguments.length) {
|
|
600
562
|
expression.arguments.push(t.objectExpression([]));
|
|
601
563
|
}
|
|
602
564
|
const [argument] = expression.arguments;
|
|
565
|
+
if (!t.isObjectExpression(argument))
|
|
566
|
+
return;
|
|
603
567
|
const property = argument.properties.find((property) => {
|
|
604
|
-
return property
|
|
568
|
+
return (t.isObjectProperty(property) &&
|
|
569
|
+
t.isIdentifier(property.key) &&
|
|
570
|
+
property.key.name === DECORATOR_PROPERTY_TYPE);
|
|
605
571
|
});
|
|
606
572
|
if (property)
|
|
607
573
|
return;
|
|
@@ -652,20 +618,25 @@ const customElement = (options) => {
|
|
|
652
618
|
input.types.forEach(extract);
|
|
653
619
|
break;
|
|
654
620
|
// TODO
|
|
655
|
-
case 'TSParenthesizedType':
|
|
656
|
-
if (input?.typeAnnotation?.type
|
|
621
|
+
case 'TSParenthesizedType': {
|
|
622
|
+
if (input?.typeAnnotation?.type !== 'TSIntersectionType')
|
|
657
623
|
break;
|
|
658
624
|
let types = input.types || input.typeAnnotation.types;
|
|
659
|
-
if (types.length
|
|
625
|
+
if (types.length !== 2)
|
|
660
626
|
return;
|
|
661
|
-
types = types.filter((type) => type.type
|
|
662
|
-
if (types.length
|
|
627
|
+
types = types.filter((type) => type.type !== 'TSTypeLiteral');
|
|
628
|
+
if (types.length !== 1)
|
|
663
629
|
return;
|
|
664
630
|
extract(types[0]);
|
|
665
631
|
break;
|
|
632
|
+
}
|
|
666
633
|
}
|
|
667
634
|
};
|
|
668
|
-
|
|
635
|
+
if (context.directoryPath) {
|
|
636
|
+
extract(
|
|
637
|
+
// biome-ignore lint: TODO
|
|
638
|
+
getType(context.directoryPath, ast, path.parent['typeAnnotation']?.typeAnnotation));
|
|
639
|
+
}
|
|
669
640
|
argument.properties.push(t.objectProperty(t.identifier(DECORATOR_PROPERTY_TYPE), t.numericLiteral(type)));
|
|
670
641
|
}
|
|
671
642
|
});
|
|
@@ -673,49 +644,62 @@ const customElement = (options) => {
|
|
|
673
644
|
if (options.typings) {
|
|
674
645
|
visitor(ast, {
|
|
675
646
|
Program(path) {
|
|
676
|
-
const attributes = context
|
|
677
|
-
.
|
|
647
|
+
const attributes = (context.classProperties || [])
|
|
648
|
+
.filter((property) => !t.isClassMethod(property))
|
|
678
649
|
.map((property) => {
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
650
|
+
const keyName = extractAttribute(property) ??
|
|
651
|
+
(t.isIdentifier(property.key) ? kebabCase(property.key.name) : '');
|
|
652
|
+
const typeAnnotation = property.typeAnnotation
|
|
653
|
+
? property.typeAnnotation
|
|
654
|
+
: undefined;
|
|
655
|
+
const signature = t.tSPropertySignature(t.stringLiteral(kebabCase(keyName)), typeAnnotation);
|
|
656
|
+
signature.optional = property.optional ?? false;
|
|
657
|
+
signature.leadingComments = t.cloneNode(property, true).leadingComments;
|
|
658
|
+
return signature;
|
|
685
659
|
});
|
|
686
|
-
const events = context.classEvents
|
|
660
|
+
const events = (context.classEvents ?? [])
|
|
661
|
+
.map((event) => {
|
|
662
|
+
if (!t.isIdentifier(event.key))
|
|
663
|
+
return null;
|
|
687
664
|
const key = event.key;
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
})
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
method
|
|
701
|
-
)
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
665
|
+
const parameter = t.identifier('event');
|
|
666
|
+
parameter.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CustomEvent'),
|
|
667
|
+
// biome-ignore lint: TODO
|
|
668
|
+
event.typeAnnotation?.['typeAnnotation']?.typeParameters));
|
|
669
|
+
const functionType = t.tsFunctionType(undefined, [parameter], t.tsTypeAnnotation(t.tsVoidKeyword()));
|
|
670
|
+
const signature = t.tSPropertySignature(t.identifier(camelCase(`on-${key.name}`)), t.tsTypeAnnotation(functionType));
|
|
671
|
+
signature.optional = true;
|
|
672
|
+
signature.leadingComments = t.cloneNode(event, true).leadingComments;
|
|
673
|
+
return signature;
|
|
674
|
+
})
|
|
675
|
+
.filter((event) => !!event);
|
|
676
|
+
const methods = (context.classMethods ?? [])
|
|
677
|
+
.map((method) => {
|
|
678
|
+
if (!t.isIdentifier(method.key))
|
|
679
|
+
return null;
|
|
680
|
+
const parameters = (method.params ?? []);
|
|
681
|
+
const returnType = method.returnType;
|
|
682
|
+
const signature = t.tsMethodSignature(method.key, undefined, parameters, returnType);
|
|
683
|
+
signature.leadingComments = t.cloneNode(method, true).leadingComments;
|
|
684
|
+
return signature;
|
|
685
|
+
})
|
|
686
|
+
.filter((method) => !!method);
|
|
687
|
+
const properties = (context.classProperties ?? [])
|
|
688
|
+
.map((property) => {
|
|
689
|
+
if (!t.isIdentifier(property.key))
|
|
690
|
+
return null;
|
|
706
691
|
const key = property.key;
|
|
707
|
-
// TODO
|
|
692
|
+
// biome-ignore lint: TODO
|
|
708
693
|
const readonly = property.readonly || !!property['returnType'];
|
|
709
|
-
// TODO
|
|
710
|
-
const typeAnnotation =
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
// prettier-ignore
|
|
694
|
+
// biome-ignore lint: TODO
|
|
695
|
+
const typeAnnotation = property.typeAnnotation || property['returnType'];
|
|
696
|
+
const signature = t.tsPropertySignature(t.identifier(key.name), typeAnnotation);
|
|
697
|
+
signature.readonly = readonly;
|
|
698
|
+
signature.optional = property.optional ?? false;
|
|
699
|
+
signature.leadingComments = t.cloneNode(property, true).leadingComments;
|
|
700
|
+
return signature;
|
|
701
|
+
})
|
|
702
|
+
.filter((property) => !!property);
|
|
719
703
|
const ast = template.default.ast(`
|
|
720
704
|
// THE FOLLOWING TYPES HAVE BEEN ADDED AUTOMATICALLY
|
|
721
705
|
|
|
@@ -773,12 +757,19 @@ const customElement = (options) => {
|
|
|
773
757
|
},
|
|
774
758
|
// TODO
|
|
775
759
|
TSTypeReference(path) {
|
|
776
|
-
if (path.node.typeName
|
|
760
|
+
if (!t.isIdentifier(path.node.typeName))
|
|
777
761
|
return;
|
|
778
|
-
|
|
762
|
+
if (path.node.typeName.name !== 'OverridesConfig')
|
|
763
|
+
return;
|
|
764
|
+
const property = path.findParent((p) => p.isTSPropertySignature());
|
|
779
765
|
if (!property)
|
|
780
766
|
return;
|
|
767
|
+
if (!t.isTSPropertySignature(property.node))
|
|
768
|
+
return;
|
|
769
|
+
// biome-ignore lint: TODO
|
|
781
770
|
const name = property.node.key.name || property.node.key.extra.rawValue;
|
|
771
|
+
if (!name)
|
|
772
|
+
return;
|
|
782
773
|
if (!path.node.typeParameters?.params)
|
|
783
774
|
return;
|
|
784
775
|
path.node.typeParameters.params[1] = t.tsTypeReference(t.identifier('Omit'), t.tsTypeParameterInstantiation([
|
|
@@ -794,12 +785,14 @@ const customElement = (options) => {
|
|
|
794
785
|
return { name, run };
|
|
795
786
|
};
|
|
796
787
|
|
|
788
|
+
// biome-ignore-all lint: TODO
|
|
797
789
|
const DOCUMENT_OPTIONS = {
|
|
798
|
-
destination: path.join('dist', 'document.json')
|
|
790
|
+
destination: path.join('dist', 'document.json'),
|
|
791
|
+
transformer: (_context, element) => element
|
|
799
792
|
};
|
|
800
|
-
const document = (
|
|
793
|
+
const document = (userOptions) => {
|
|
801
794
|
const name = 'document';
|
|
802
|
-
options = Object.assign({}, DOCUMENT_OPTIONS,
|
|
795
|
+
const options = Object.assign({}, DOCUMENT_OPTIONS, userOptions);
|
|
803
796
|
const finish = (global) => {
|
|
804
797
|
const json = {
|
|
805
798
|
elements: []
|
|
@@ -813,9 +806,9 @@ const document = (options) => {
|
|
|
813
806
|
for (const decorator of event.decorators) {
|
|
814
807
|
for (const argument of decorator.expression['arguments']) {
|
|
815
808
|
for (const property of argument.properties) {
|
|
816
|
-
if (property.key.name
|
|
809
|
+
if (property.key.name !== 'cancelable')
|
|
817
810
|
continue;
|
|
818
|
-
if (property.value.type
|
|
811
|
+
if (property.value.type !== 'BooleanLiteral')
|
|
819
812
|
continue;
|
|
820
813
|
if (!property.value.value)
|
|
821
814
|
continue;
|
|
@@ -848,7 +841,8 @@ const document = (options) => {
|
|
|
848
841
|
const comments = extractFromComment(method);
|
|
849
842
|
// TODO
|
|
850
843
|
const parameters = method.params.map((param) => ({
|
|
851
|
-
description: comments.params?.find((item) => item.name
|
|
844
|
+
description: comments.params?.find((item) => item.name === param['name'])
|
|
845
|
+
?.description,
|
|
852
846
|
required: !param['optional'],
|
|
853
847
|
name: param['name'],
|
|
854
848
|
type: print(param?.['typeAnnotation']?.typeAnnotation) || undefined,
|
|
@@ -888,7 +882,7 @@ const document = (options) => {
|
|
|
888
882
|
returns
|
|
889
883
|
},
|
|
890
884
|
// TODO
|
|
891
|
-
returns
|
|
885
|
+
returns !== 'void' &&
|
|
892
886
|
comments.returns && {
|
|
893
887
|
tags: [
|
|
894
888
|
{
|
|
@@ -903,7 +897,7 @@ const document = (options) => {
|
|
|
903
897
|
// TODO
|
|
904
898
|
const initializer = getInitializer(property.value);
|
|
905
899
|
const name = property.key['name'];
|
|
906
|
-
const readonly = property['kind']
|
|
900
|
+
const readonly = property['kind'] === 'get';
|
|
907
901
|
// TODO
|
|
908
902
|
const reflects = (() => {
|
|
909
903
|
if (!property.decorators)
|
|
@@ -912,9 +906,9 @@ const document = (options) => {
|
|
|
912
906
|
for (const decorator of property.decorators) {
|
|
913
907
|
for (const argument of decorator.expression['arguments']) {
|
|
914
908
|
for (const property of argument.properties) {
|
|
915
|
-
if (property.key.name
|
|
909
|
+
if (property.key.name !== 'reflect')
|
|
916
910
|
continue;
|
|
917
|
-
if (property.value.type
|
|
911
|
+
if (property.value.type !== 'BooleanLiteral')
|
|
918
912
|
continue;
|
|
919
913
|
if (!property.value.value)
|
|
920
914
|
continue;
|
|
@@ -990,7 +984,10 @@ const document = (options) => {
|
|
|
990
984
|
json.elements = json.elements.sort((a, b) => (a.title > b.title ? 1 : -1));
|
|
991
985
|
const dirname = path.dirname(options.destination);
|
|
992
986
|
fs.ensureDirSync(dirname);
|
|
993
|
-
fs.writeJSONSync(options.destination, json, {
|
|
987
|
+
fs.writeJSONSync(options.destination, json, {
|
|
988
|
+
encoding: 'utf8',
|
|
989
|
+
spaces: 2
|
|
990
|
+
});
|
|
994
991
|
};
|
|
995
992
|
return { name, finish };
|
|
996
993
|
};
|
|
@@ -998,11 +995,13 @@ const document = (options) => {
|
|
|
998
995
|
const extract = () => {
|
|
999
996
|
const name = 'extract';
|
|
1000
997
|
const run = (context) => {
|
|
1001
|
-
const
|
|
998
|
+
const body = context.fileAST?.program.body.find((child) => {
|
|
1002
999
|
return t.isExportNamedDeclaration(child);
|
|
1003
1000
|
});
|
|
1004
|
-
context.class = declaration;
|
|
1005
|
-
context.class
|
|
1001
|
+
context.class = body?.declaration;
|
|
1002
|
+
if (context.class) {
|
|
1003
|
+
context.class.leadingComments = body?.leadingComments; // TODO
|
|
1004
|
+
}
|
|
1006
1005
|
context.classMembers = context.class?.body?.body || [];
|
|
1007
1006
|
context.className = context.class?.id?.name;
|
|
1008
1007
|
context.elementKey = kebabCase(context.className || '');
|
|
@@ -1018,11 +1017,11 @@ const PARSE_OPTIONS = {
|
|
|
1018
1017
|
sourceType: 'module',
|
|
1019
1018
|
plugins: [['decorators', { decoratorsBeforeExport: true }], 'jsx', 'typescript']
|
|
1020
1019
|
};
|
|
1021
|
-
const parse = (
|
|
1020
|
+
const parse = (userOptions) => {
|
|
1022
1021
|
const name = 'parse';
|
|
1023
|
-
options = Object.assign({}, PARSE_OPTIONS,
|
|
1022
|
+
const options = Object.assign({}, PARSE_OPTIONS, userOptions);
|
|
1024
1023
|
const run = (context) => {
|
|
1025
|
-
context.fileAST = parse$1(context.fileContent, options);
|
|
1024
|
+
context.fileAST = parse$1(context.fileContent || '', options);
|
|
1026
1025
|
};
|
|
1027
1026
|
return { name, run };
|
|
1028
1027
|
};
|
|
@@ -1043,12 +1042,12 @@ const read = () => {
|
|
|
1043
1042
|
|
|
1044
1043
|
const README_OPTIONS = {
|
|
1045
1044
|
source(context) {
|
|
1046
|
-
return path.join(context.directoryPath, `${context.fileName}.md`);
|
|
1045
|
+
return path.join(context.directoryPath || '', `${context.fileName}.md`);
|
|
1047
1046
|
}
|
|
1048
1047
|
};
|
|
1049
|
-
const readme = (
|
|
1048
|
+
const readme = (userOptions) => {
|
|
1050
1049
|
const name = 'readme';
|
|
1051
|
-
options = Object.assign({}, README_OPTIONS,
|
|
1050
|
+
const options = Object.assign({}, README_OPTIONS, userOptions);
|
|
1052
1051
|
const finish = (global) => {
|
|
1053
1052
|
for (const context of global.contexts) {
|
|
1054
1053
|
context.readmePath = options.source(context);
|
|
@@ -1066,18 +1065,14 @@ const readme = (options) => {
|
|
|
1066
1065
|
|
|
1067
1066
|
const STYLE_OPTIONS = {
|
|
1068
1067
|
source(context) {
|
|
1069
|
-
return [
|
|
1070
|
-
path.join(context.directoryPath, `${context.fileName}
|
|
1071
|
-
|
|
1072
|
-
path.join(context.directoryPath, `${context.fileName}.sass`),
|
|
1073
|
-
path.join(context.directoryPath, `${context.fileName}.scss`),
|
|
1074
|
-
path.join(context.directoryPath, `${context.fileName}.styl`)
|
|
1075
|
-
];
|
|
1068
|
+
return ['css', 'less', 'sass', 'scss', 'styl'].map((key) => {
|
|
1069
|
+
return path.join(context.directoryPath || '', `${context.fileName}.${key}`);
|
|
1070
|
+
});
|
|
1076
1071
|
}
|
|
1077
1072
|
};
|
|
1078
|
-
const style = (
|
|
1073
|
+
const style = (userOptions) => {
|
|
1079
1074
|
const name = 'style';
|
|
1080
|
-
options = Object.assign({}, STYLE_OPTIONS,
|
|
1075
|
+
const options = Object.assign({}, STYLE_OPTIONS, userOptions);
|
|
1081
1076
|
const run = (context) => {
|
|
1082
1077
|
const sources = [options.source(context)].flat();
|
|
1083
1078
|
for (const source of sources) {
|
|
@@ -1093,11 +1088,12 @@ const style = (options) => {
|
|
|
1093
1088
|
context.styleContent = fs.readFileSync(context.stylePath, 'utf8');
|
|
1094
1089
|
context.styleExtension = path.extname(context.stylePath);
|
|
1095
1090
|
context.styleName = path.basename(context.stylePath, context.styleExtension);
|
|
1091
|
+
if (!context.fileAST)
|
|
1092
|
+
return;
|
|
1096
1093
|
const { local } = addDependency(context.fileAST, context.stylePath, STYLE_IMPORTED, undefined, true);
|
|
1097
|
-
|
|
1098
|
-
const property = t.classProperty(t.identifier(STATIC_STYLE), t.identifier(local), undefined, null, undefined, true);
|
|
1094
|
+
const property = t.classProperty(t.identifier(STATIC_STYLE), t.identifier(local || ''), undefined, null, undefined, true);
|
|
1099
1095
|
t.addComment(property, 'leading', COMMENT_AUTO_ADDED, true);
|
|
1100
|
-
context.class
|
|
1096
|
+
context.class?.body.body.unshift(property);
|
|
1101
1097
|
};
|
|
1102
1098
|
return { name, run };
|
|
1103
1099
|
};
|
|
@@ -1106,30 +1102,36 @@ const validate = () => {
|
|
|
1106
1102
|
const name = 'validate';
|
|
1107
1103
|
const run = (context) => {
|
|
1108
1104
|
context.skipped = true;
|
|
1105
|
+
if (!context.fileAST)
|
|
1106
|
+
return;
|
|
1109
1107
|
visitor(context.fileAST, {
|
|
1110
1108
|
ImportDeclaration(path) {
|
|
1111
1109
|
if (path.node.source?.value !== PACKAGE_NAME)
|
|
1112
1110
|
return;
|
|
1113
1111
|
for (const specifier of path.node.specifiers) {
|
|
1114
|
-
if (specifier
|
|
1112
|
+
if (!t.isImportSpecifier(specifier) ||
|
|
1113
|
+
!t.isIdentifier(specifier.imported) ||
|
|
1114
|
+
specifier.imported.name !== DECORATOR_ELEMENT) {
|
|
1115
1115
|
continue;
|
|
1116
|
+
}
|
|
1116
1117
|
const binding = path.scope.getBinding(specifier.imported.name);
|
|
1117
|
-
if (binding.references
|
|
1118
|
-
|
|
1118
|
+
if (!binding || binding.references === 0) {
|
|
1119
|
+
continue;
|
|
1120
|
+
}
|
|
1119
1121
|
const referencePaths = binding.referencePaths.filter((referencePath) => {
|
|
1120
|
-
|
|
1121
|
-
t.isDecorator(referencePath.parentPath
|
|
1122
|
-
t.isClassDeclaration(referencePath.parentPath.parentPath
|
|
1123
|
-
t.isExportNamedDeclaration(referencePath.parentPath.parentPath.parentPath
|
|
1124
|
-
return true;
|
|
1122
|
+
return (t.isCallExpression(referencePath.parent) &&
|
|
1123
|
+
t.isDecorator(referencePath.parentPath?.parent) &&
|
|
1124
|
+
t.isClassDeclaration(referencePath.parentPath.parentPath?.parent) &&
|
|
1125
|
+
t.isExportNamedDeclaration(referencePath.parentPath.parentPath.parentPath?.parent));
|
|
1125
1126
|
});
|
|
1126
1127
|
if (referencePaths.length > 1) {
|
|
1127
1128
|
throw new Error('In each file, only one custom element can be defined. \n' +
|
|
1128
1129
|
'If more than one @Element() decorator is used in the file, it will result in an error.\n');
|
|
1129
1130
|
}
|
|
1130
1131
|
context.skipped = false;
|
|
1131
|
-
if (referencePaths.length
|
|
1132
|
+
if (referencePaths.length === 1) {
|
|
1132
1133
|
break;
|
|
1134
|
+
}
|
|
1133
1135
|
throw new Error('It appears that the class annotated with the @Element() decorator is not being exported correctly.');
|
|
1134
1136
|
}
|
|
1135
1137
|
path.stop();
|
|
@@ -1140,12 +1142,15 @@ const validate = () => {
|
|
|
1140
1142
|
return { name, run };
|
|
1141
1143
|
};
|
|
1142
1144
|
|
|
1145
|
+
// biome-ignore-all lint: TODO
|
|
1143
1146
|
const VISUAL_STUDIO_CODE_OPTIONS = {
|
|
1144
|
-
destination: path.join('dist', 'visual-studio-code.json')
|
|
1147
|
+
destination: path.join('dist', 'visual-studio-code.json'),
|
|
1148
|
+
reference: () => '',
|
|
1149
|
+
transformer: (_context, element) => element
|
|
1145
1150
|
};
|
|
1146
|
-
const visualStudioCode = (
|
|
1151
|
+
const visualStudioCode = (userOptions) => {
|
|
1147
1152
|
const name = 'visualStudioCode';
|
|
1148
|
-
options = Object.assign({}, VISUAL_STUDIO_CODE_OPTIONS,
|
|
1153
|
+
const options = Object.assign({}, VISUAL_STUDIO_CODE_OPTIONS, userOptions);
|
|
1149
1154
|
const finish = (global) => {
|
|
1150
1155
|
const contexts = global.contexts.sort((a, b) => {
|
|
1151
1156
|
return a.elementKey.toUpperCase() > b.elementKey.toUpperCase() ? 1 : -1;
|
|
@@ -1205,34 +1210,40 @@ const visualStudioCode = (options) => {
|
|
|
1205
1210
|
}
|
|
1206
1211
|
const dirname = path.dirname(options.destination);
|
|
1207
1212
|
fs.ensureDirSync(dirname);
|
|
1208
|
-
fs.writeJSONSync(options.destination, json, {
|
|
1213
|
+
fs.writeJSONSync(options.destination, json, {
|
|
1214
|
+
encoding: 'utf8',
|
|
1215
|
+
spaces: 2
|
|
1216
|
+
});
|
|
1209
1217
|
};
|
|
1210
1218
|
return { name, finish };
|
|
1211
1219
|
};
|
|
1212
1220
|
|
|
1221
|
+
// biome-ignore-all lint: TODO
|
|
1213
1222
|
const WEB_TYPES_OPTIONS = {
|
|
1214
1223
|
destination: path.join('dist', 'web-types.json'),
|
|
1215
1224
|
packageName: '',
|
|
1216
|
-
packageVersion: ''
|
|
1225
|
+
packageVersion: '',
|
|
1226
|
+
reference: () => '',
|
|
1227
|
+
transformer: (_context, element) => element
|
|
1217
1228
|
};
|
|
1218
|
-
const webTypes = (
|
|
1229
|
+
const webTypes = (userOptions) => {
|
|
1219
1230
|
const name = 'webTypes';
|
|
1220
|
-
options = Object.assign({}, WEB_TYPES_OPTIONS,
|
|
1231
|
+
const options = Object.assign({}, WEB_TYPES_OPTIONS, userOptions);
|
|
1221
1232
|
const finish = (global) => {
|
|
1222
1233
|
const contexts = global.contexts.sort((a, b) => {
|
|
1223
|
-
return a.elementKey.toUpperCase()
|
|
1234
|
+
return (a.elementKey ?? '').toUpperCase().localeCompare((b.elementKey ?? '').toUpperCase());
|
|
1224
1235
|
});
|
|
1225
1236
|
const json = {
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1237
|
+
$schema: 'http://json.schemastore.org/web-types',
|
|
1238
|
+
name: options.packageName,
|
|
1239
|
+
version: options.packageVersion,
|
|
1229
1240
|
'description-markup': 'markdown',
|
|
1230
1241
|
'framework-config': {
|
|
1231
1242
|
'enable-when': {
|
|
1232
1243
|
'node-packages': [options.packageName]
|
|
1233
1244
|
}
|
|
1234
1245
|
},
|
|
1235
|
-
|
|
1246
|
+
contributions: {
|
|
1236
1247
|
html: {
|
|
1237
1248
|
elements: []
|
|
1238
1249
|
}
|
|
@@ -1263,9 +1274,9 @@ const webTypes = (options) => {
|
|
|
1263
1274
|
default: getInitializer(property.value)
|
|
1264
1275
|
}, extractFromComment(property, ['description', 'deprecated', 'experimental'])));
|
|
1265
1276
|
const element = Object.assign({
|
|
1266
|
-
|
|
1277
|
+
name: context.elementKey,
|
|
1267
1278
|
'doc-url': options.reference?.(context),
|
|
1268
|
-
|
|
1279
|
+
js: {
|
|
1269
1280
|
events,
|
|
1270
1281
|
properties: [].concat(properties, methods)
|
|
1271
1282
|
},
|
|
@@ -1276,9 +1287,81 @@ const webTypes = (options) => {
|
|
|
1276
1287
|
}
|
|
1277
1288
|
const dirname = path.dirname(options.destination);
|
|
1278
1289
|
fs.ensureDirSync(dirname);
|
|
1279
|
-
fs.writeJSONSync(options.destination, json, {
|
|
1290
|
+
fs.writeJSONSync(options.destination, json, {
|
|
1291
|
+
encoding: 'utf8',
|
|
1292
|
+
spaces: 2
|
|
1293
|
+
});
|
|
1280
1294
|
};
|
|
1281
1295
|
return { name, finish };
|
|
1282
1296
|
};
|
|
1283
1297
|
|
|
1298
|
+
const logger = ora({
|
|
1299
|
+
color: 'yellow'
|
|
1300
|
+
});
|
|
1301
|
+
const log = (message, persist) => {
|
|
1302
|
+
const content = `${new Date().toLocaleTimeString()} [${KEY}] ${message}`;
|
|
1303
|
+
const log = logger.start(content);
|
|
1304
|
+
if (!persist)
|
|
1305
|
+
return;
|
|
1306
|
+
log.succeed();
|
|
1307
|
+
};
|
|
1308
|
+
const transformer = (...plugins) => {
|
|
1309
|
+
let global = {
|
|
1310
|
+
contexts: []
|
|
1311
|
+
};
|
|
1312
|
+
const start = async () => {
|
|
1313
|
+
log(`Started.`, true);
|
|
1314
|
+
log(`${plugins.length} plugins detected.`, true);
|
|
1315
|
+
log(`Plugins are starting.`, true);
|
|
1316
|
+
for (const plugin of plugins) {
|
|
1317
|
+
if (!plugin.start)
|
|
1318
|
+
continue;
|
|
1319
|
+
log(`Plugin '${plugin.name}' is starting.`);
|
|
1320
|
+
global = (await plugin.start(global)) || global;
|
|
1321
|
+
log(`Plugin '${plugin.name}' started successfully.`);
|
|
1322
|
+
}
|
|
1323
|
+
log(`Plugins have been successfully started.`, true);
|
|
1324
|
+
};
|
|
1325
|
+
const run = async (filePath) => {
|
|
1326
|
+
let context = {
|
|
1327
|
+
filePath
|
|
1328
|
+
};
|
|
1329
|
+
const parsed = path.parse(filePath);
|
|
1330
|
+
for (const plugin of plugins) {
|
|
1331
|
+
if (!plugin.run)
|
|
1332
|
+
continue;
|
|
1333
|
+
const source = path.join(parsed.dir).split(path.sep).slice(-2).concat(parsed.base).join('/');
|
|
1334
|
+
log(`Plugin '${plugin.name}' is executing on '${source}' file.`);
|
|
1335
|
+
try {
|
|
1336
|
+
context = (await plugin.run(context, global)) || context;
|
|
1337
|
+
}
|
|
1338
|
+
catch (error) {
|
|
1339
|
+
log(`Error in '${plugin.name}' plugin on '${source}' file.\n`, true);
|
|
1340
|
+
throw error;
|
|
1341
|
+
}
|
|
1342
|
+
global.contexts = global.contexts
|
|
1343
|
+
.filter((current) => {
|
|
1344
|
+
return current.filePath !== context.filePath;
|
|
1345
|
+
})
|
|
1346
|
+
.concat(context);
|
|
1347
|
+
log(`Plugin '${plugin.name}' executed successfully on '${source}' file.`);
|
|
1348
|
+
}
|
|
1349
|
+
logger.stop();
|
|
1350
|
+
return context;
|
|
1351
|
+
};
|
|
1352
|
+
const finish = async () => {
|
|
1353
|
+
log(`Plugins are finishing.`, true);
|
|
1354
|
+
for (const plugin of plugins) {
|
|
1355
|
+
if (!plugin.finish)
|
|
1356
|
+
continue;
|
|
1357
|
+
log(`Plugin '${plugin.name}' is finishing.`);
|
|
1358
|
+
global = (await plugin.finish(global)) || global;
|
|
1359
|
+
log(`Plugin '${plugin.name}' finished successfully.`);
|
|
1360
|
+
}
|
|
1361
|
+
log(`Plugins have been successfully finished.`, true);
|
|
1362
|
+
log(`Finished.`, true);
|
|
1363
|
+
};
|
|
1364
|
+
return { global, start, run, finish };
|
|
1365
|
+
};
|
|
1366
|
+
|
|
1284
1367
|
export { ASSETS_OPTIONS, COPY_OPTIONS, CUSTOM_ELEMENT_OPTIONS, DOCUMENT_OPTIONS, PARSE_OPTIONS, README_OPTIONS, STYLE_OPTIONS, VISUAL_STUDIO_CODE_OPTIONS, WEB_TYPES_OPTIONS, assets, copy, customElement, document, extract, parse, read, readme, style, transformer, validate, visualStudioCode, webTypes };
|