@htmlplus/element 3.2.6 → 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 +71 -23
- package/dist/client.js +873 -624
- package/dist/jsx-runtime.d.ts +183 -183
- package/dist/transformer.d.ts +45 -40
- package/dist/transformer.js +375 -280
- 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')
|
|
398
|
+
return;
|
|
399
|
+
if (!value)
|
|
400
|
+
return;
|
|
401
|
+
if (!t.isJSXOpeningElement(path.parent))
|
|
447
402
|
return;
|
|
448
|
-
const hasClass = path.
|
|
449
|
-
return attribute.name
|
|
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
|
|
|
@@ -751,9 +735,7 @@ const customElement = (options) => {
|
|
|
751
735
|
|
|
752
736
|
namespace JSX {
|
|
753
737
|
interface IntrinsicElements {
|
|
754
|
-
"${context.elementTagName}": ${context.className}Events & ${context.className}Attributes &
|
|
755
|
-
[key: string]: any;
|
|
756
|
-
};
|
|
738
|
+
"${context.elementTagName}": ${context.className}Events & ${context.className}Attributes & React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
757
739
|
}
|
|
758
740
|
}
|
|
759
741
|
}
|
|
@@ -761,9 +743,7 @@ const customElement = (options) => {
|
|
|
761
743
|
declare module "react" {
|
|
762
744
|
namespace JSX {
|
|
763
745
|
interface IntrinsicElements {
|
|
764
|
-
"${context.elementTagName}": ${context.className}Events & ${context.className}Attributes &
|
|
765
|
-
[key: string]: any;
|
|
766
|
-
};
|
|
746
|
+
"${context.elementTagName}": ${context.className}Events & ${context.className}Attributes & React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
767
747
|
}
|
|
768
748
|
}
|
|
769
749
|
}
|
|
@@ -774,6 +754,29 @@ const customElement = (options) => {
|
|
|
774
754
|
preserveComments: true
|
|
775
755
|
});
|
|
776
756
|
path.node.body.push(...ast);
|
|
757
|
+
},
|
|
758
|
+
// TODO
|
|
759
|
+
TSTypeReference(path) {
|
|
760
|
+
if (!t.isIdentifier(path.node.typeName))
|
|
761
|
+
return;
|
|
762
|
+
if (path.node.typeName.name !== 'OverridesConfig')
|
|
763
|
+
return;
|
|
764
|
+
const property = path.findParent((p) => p.isTSPropertySignature());
|
|
765
|
+
if (!property)
|
|
766
|
+
return;
|
|
767
|
+
if (!t.isTSPropertySignature(property.node))
|
|
768
|
+
return;
|
|
769
|
+
// biome-ignore lint: TODO
|
|
770
|
+
const name = property.node.key.name || property.node.key.extra.rawValue;
|
|
771
|
+
if (!name)
|
|
772
|
+
return;
|
|
773
|
+
if (!path.node.typeParameters?.params)
|
|
774
|
+
return;
|
|
775
|
+
path.node.typeParameters.params[1] = t.tsTypeReference(t.identifier('Omit'), t.tsTypeParameterInstantiation([
|
|
776
|
+
t.tsTypeReference(t.identifier(`${context.className}Properties`)),
|
|
777
|
+
t.tsLiteralType(t.stringLiteral(name))
|
|
778
|
+
]));
|
|
779
|
+
path.skip();
|
|
777
780
|
}
|
|
778
781
|
});
|
|
779
782
|
}
|
|
@@ -782,12 +785,14 @@ const customElement = (options) => {
|
|
|
782
785
|
return { name, run };
|
|
783
786
|
};
|
|
784
787
|
|
|
788
|
+
// biome-ignore-all lint: TODO
|
|
785
789
|
const DOCUMENT_OPTIONS = {
|
|
786
|
-
destination: path.join('dist', 'document.json')
|
|
790
|
+
destination: path.join('dist', 'document.json'),
|
|
791
|
+
transformer: (_context, element) => element
|
|
787
792
|
};
|
|
788
|
-
const document = (
|
|
793
|
+
const document = (userOptions) => {
|
|
789
794
|
const name = 'document';
|
|
790
|
-
options = Object.assign({}, DOCUMENT_OPTIONS,
|
|
795
|
+
const options = Object.assign({}, DOCUMENT_OPTIONS, userOptions);
|
|
791
796
|
const finish = (global) => {
|
|
792
797
|
const json = {
|
|
793
798
|
elements: []
|
|
@@ -801,9 +806,9 @@ const document = (options) => {
|
|
|
801
806
|
for (const decorator of event.decorators) {
|
|
802
807
|
for (const argument of decorator.expression['arguments']) {
|
|
803
808
|
for (const property of argument.properties) {
|
|
804
|
-
if (property.key.name
|
|
809
|
+
if (property.key.name !== 'cancelable')
|
|
805
810
|
continue;
|
|
806
|
-
if (property.value.type
|
|
811
|
+
if (property.value.type !== 'BooleanLiteral')
|
|
807
812
|
continue;
|
|
808
813
|
if (!property.value.value)
|
|
809
814
|
continue;
|
|
@@ -836,7 +841,8 @@ const document = (options) => {
|
|
|
836
841
|
const comments = extractFromComment(method);
|
|
837
842
|
// TODO
|
|
838
843
|
const parameters = method.params.map((param) => ({
|
|
839
|
-
description: comments.params?.find((item) => item.name
|
|
844
|
+
description: comments.params?.find((item) => item.name === param['name'])
|
|
845
|
+
?.description,
|
|
840
846
|
required: !param['optional'],
|
|
841
847
|
name: param['name'],
|
|
842
848
|
type: print(param?.['typeAnnotation']?.typeAnnotation) || undefined,
|
|
@@ -876,7 +882,7 @@ const document = (options) => {
|
|
|
876
882
|
returns
|
|
877
883
|
},
|
|
878
884
|
// TODO
|
|
879
|
-
returns
|
|
885
|
+
returns !== 'void' &&
|
|
880
886
|
comments.returns && {
|
|
881
887
|
tags: [
|
|
882
888
|
{
|
|
@@ -891,7 +897,7 @@ const document = (options) => {
|
|
|
891
897
|
// TODO
|
|
892
898
|
const initializer = getInitializer(property.value);
|
|
893
899
|
const name = property.key['name'];
|
|
894
|
-
const readonly = property['kind']
|
|
900
|
+
const readonly = property['kind'] === 'get';
|
|
895
901
|
// TODO
|
|
896
902
|
const reflects = (() => {
|
|
897
903
|
if (!property.decorators)
|
|
@@ -900,9 +906,9 @@ const document = (options) => {
|
|
|
900
906
|
for (const decorator of property.decorators) {
|
|
901
907
|
for (const argument of decorator.expression['arguments']) {
|
|
902
908
|
for (const property of argument.properties) {
|
|
903
|
-
if (property.key.name
|
|
909
|
+
if (property.key.name !== 'reflect')
|
|
904
910
|
continue;
|
|
905
|
-
if (property.value.type
|
|
911
|
+
if (property.value.type !== 'BooleanLiteral')
|
|
906
912
|
continue;
|
|
907
913
|
if (!property.value.value)
|
|
908
914
|
continue;
|
|
@@ -978,7 +984,10 @@ const document = (options) => {
|
|
|
978
984
|
json.elements = json.elements.sort((a, b) => (a.title > b.title ? 1 : -1));
|
|
979
985
|
const dirname = path.dirname(options.destination);
|
|
980
986
|
fs.ensureDirSync(dirname);
|
|
981
|
-
fs.writeJSONSync(options.destination, json, {
|
|
987
|
+
fs.writeJSONSync(options.destination, json, {
|
|
988
|
+
encoding: 'utf8',
|
|
989
|
+
spaces: 2
|
|
990
|
+
});
|
|
982
991
|
};
|
|
983
992
|
return { name, finish };
|
|
984
993
|
};
|
|
@@ -986,11 +995,13 @@ const document = (options) => {
|
|
|
986
995
|
const extract = () => {
|
|
987
996
|
const name = 'extract';
|
|
988
997
|
const run = (context) => {
|
|
989
|
-
const
|
|
998
|
+
const body = context.fileAST?.program.body.find((child) => {
|
|
990
999
|
return t.isExportNamedDeclaration(child);
|
|
991
1000
|
});
|
|
992
|
-
context.class = declaration;
|
|
993
|
-
context.class
|
|
1001
|
+
context.class = body?.declaration;
|
|
1002
|
+
if (context.class) {
|
|
1003
|
+
context.class.leadingComments = body?.leadingComments; // TODO
|
|
1004
|
+
}
|
|
994
1005
|
context.classMembers = context.class?.body?.body || [];
|
|
995
1006
|
context.className = context.class?.id?.name;
|
|
996
1007
|
context.elementKey = kebabCase(context.className || '');
|
|
@@ -1006,11 +1017,11 @@ const PARSE_OPTIONS = {
|
|
|
1006
1017
|
sourceType: 'module',
|
|
1007
1018
|
plugins: [['decorators', { decoratorsBeforeExport: true }], 'jsx', 'typescript']
|
|
1008
1019
|
};
|
|
1009
|
-
const parse = (
|
|
1020
|
+
const parse = (userOptions) => {
|
|
1010
1021
|
const name = 'parse';
|
|
1011
|
-
options = Object.assign({}, PARSE_OPTIONS,
|
|
1022
|
+
const options = Object.assign({}, PARSE_OPTIONS, userOptions);
|
|
1012
1023
|
const run = (context) => {
|
|
1013
|
-
context.fileAST = parse$1(context.fileContent, options);
|
|
1024
|
+
context.fileAST = parse$1(context.fileContent || '', options);
|
|
1014
1025
|
};
|
|
1015
1026
|
return { name, run };
|
|
1016
1027
|
};
|
|
@@ -1031,12 +1042,12 @@ const read = () => {
|
|
|
1031
1042
|
|
|
1032
1043
|
const README_OPTIONS = {
|
|
1033
1044
|
source(context) {
|
|
1034
|
-
return path.join(context.directoryPath, `${context.fileName}.md`);
|
|
1045
|
+
return path.join(context.directoryPath || '', `${context.fileName}.md`);
|
|
1035
1046
|
}
|
|
1036
1047
|
};
|
|
1037
|
-
const readme = (
|
|
1048
|
+
const readme = (userOptions) => {
|
|
1038
1049
|
const name = 'readme';
|
|
1039
|
-
options = Object.assign({}, README_OPTIONS,
|
|
1050
|
+
const options = Object.assign({}, README_OPTIONS, userOptions);
|
|
1040
1051
|
const finish = (global) => {
|
|
1041
1052
|
for (const context of global.contexts) {
|
|
1042
1053
|
context.readmePath = options.source(context);
|
|
@@ -1054,18 +1065,14 @@ const readme = (options) => {
|
|
|
1054
1065
|
|
|
1055
1066
|
const STYLE_OPTIONS = {
|
|
1056
1067
|
source(context) {
|
|
1057
|
-
return [
|
|
1058
|
-
path.join(context.directoryPath, `${context.fileName}
|
|
1059
|
-
|
|
1060
|
-
path.join(context.directoryPath, `${context.fileName}.sass`),
|
|
1061
|
-
path.join(context.directoryPath, `${context.fileName}.scss`),
|
|
1062
|
-
path.join(context.directoryPath, `${context.fileName}.styl`)
|
|
1063
|
-
];
|
|
1068
|
+
return ['css', 'less', 'sass', 'scss', 'styl'].map((key) => {
|
|
1069
|
+
return path.join(context.directoryPath || '', `${context.fileName}.${key}`);
|
|
1070
|
+
});
|
|
1064
1071
|
}
|
|
1065
1072
|
};
|
|
1066
|
-
const style = (
|
|
1073
|
+
const style = (userOptions) => {
|
|
1067
1074
|
const name = 'style';
|
|
1068
|
-
options = Object.assign({}, STYLE_OPTIONS,
|
|
1075
|
+
const options = Object.assign({}, STYLE_OPTIONS, userOptions);
|
|
1069
1076
|
const run = (context) => {
|
|
1070
1077
|
const sources = [options.source(context)].flat();
|
|
1071
1078
|
for (const source of sources) {
|
|
@@ -1081,11 +1088,12 @@ const style = (options) => {
|
|
|
1081
1088
|
context.styleContent = fs.readFileSync(context.stylePath, 'utf8');
|
|
1082
1089
|
context.styleExtension = path.extname(context.stylePath);
|
|
1083
1090
|
context.styleName = path.basename(context.stylePath, context.styleExtension);
|
|
1091
|
+
if (!context.fileAST)
|
|
1092
|
+
return;
|
|
1084
1093
|
const { local } = addDependency(context.fileAST, context.stylePath, STYLE_IMPORTED, undefined, true);
|
|
1085
|
-
|
|
1086
|
-
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);
|
|
1087
1095
|
t.addComment(property, 'leading', COMMENT_AUTO_ADDED, true);
|
|
1088
|
-
context.class
|
|
1096
|
+
context.class?.body.body.unshift(property);
|
|
1089
1097
|
};
|
|
1090
1098
|
return { name, run };
|
|
1091
1099
|
};
|
|
@@ -1094,30 +1102,36 @@ const validate = () => {
|
|
|
1094
1102
|
const name = 'validate';
|
|
1095
1103
|
const run = (context) => {
|
|
1096
1104
|
context.skipped = true;
|
|
1105
|
+
if (!context.fileAST)
|
|
1106
|
+
return;
|
|
1097
1107
|
visitor(context.fileAST, {
|
|
1098
1108
|
ImportDeclaration(path) {
|
|
1099
1109
|
if (path.node.source?.value !== PACKAGE_NAME)
|
|
1100
1110
|
return;
|
|
1101
1111
|
for (const specifier of path.node.specifiers) {
|
|
1102
|
-
if (specifier
|
|
1112
|
+
if (!t.isImportSpecifier(specifier) ||
|
|
1113
|
+
!t.isIdentifier(specifier.imported) ||
|
|
1114
|
+
specifier.imported.name !== DECORATOR_ELEMENT) {
|
|
1103
1115
|
continue;
|
|
1116
|
+
}
|
|
1104
1117
|
const binding = path.scope.getBinding(specifier.imported.name);
|
|
1105
|
-
if (binding.references
|
|
1106
|
-
|
|
1118
|
+
if (!binding || binding.references === 0) {
|
|
1119
|
+
continue;
|
|
1120
|
+
}
|
|
1107
1121
|
const referencePaths = binding.referencePaths.filter((referencePath) => {
|
|
1108
|
-
|
|
1109
|
-
t.isDecorator(referencePath.parentPath
|
|
1110
|
-
t.isClassDeclaration(referencePath.parentPath.parentPath
|
|
1111
|
-
t.isExportNamedDeclaration(referencePath.parentPath.parentPath.parentPath
|
|
1112
|
-
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));
|
|
1113
1126
|
});
|
|
1114
1127
|
if (referencePaths.length > 1) {
|
|
1115
1128
|
throw new Error('In each file, only one custom element can be defined. \n' +
|
|
1116
1129
|
'If more than one @Element() decorator is used in the file, it will result in an error.\n');
|
|
1117
1130
|
}
|
|
1118
1131
|
context.skipped = false;
|
|
1119
|
-
if (referencePaths.length
|
|
1132
|
+
if (referencePaths.length === 1) {
|
|
1120
1133
|
break;
|
|
1134
|
+
}
|
|
1121
1135
|
throw new Error('It appears that the class annotated with the @Element() decorator is not being exported correctly.');
|
|
1122
1136
|
}
|
|
1123
1137
|
path.stop();
|
|
@@ -1128,12 +1142,15 @@ const validate = () => {
|
|
|
1128
1142
|
return { name, run };
|
|
1129
1143
|
};
|
|
1130
1144
|
|
|
1145
|
+
// biome-ignore-all lint: TODO
|
|
1131
1146
|
const VISUAL_STUDIO_CODE_OPTIONS = {
|
|
1132
|
-
destination: path.join('dist', 'visual-studio-code.json')
|
|
1147
|
+
destination: path.join('dist', 'visual-studio-code.json'),
|
|
1148
|
+
reference: () => '',
|
|
1149
|
+
transformer: (_context, element) => element
|
|
1133
1150
|
};
|
|
1134
|
-
const visualStudioCode = (
|
|
1151
|
+
const visualStudioCode = (userOptions) => {
|
|
1135
1152
|
const name = 'visualStudioCode';
|
|
1136
|
-
options = Object.assign({}, VISUAL_STUDIO_CODE_OPTIONS,
|
|
1153
|
+
const options = Object.assign({}, VISUAL_STUDIO_CODE_OPTIONS, userOptions);
|
|
1137
1154
|
const finish = (global) => {
|
|
1138
1155
|
const contexts = global.contexts.sort((a, b) => {
|
|
1139
1156
|
return a.elementKey.toUpperCase() > b.elementKey.toUpperCase() ? 1 : -1;
|
|
@@ -1193,34 +1210,40 @@ const visualStudioCode = (options) => {
|
|
|
1193
1210
|
}
|
|
1194
1211
|
const dirname = path.dirname(options.destination);
|
|
1195
1212
|
fs.ensureDirSync(dirname);
|
|
1196
|
-
fs.writeJSONSync(options.destination, json, {
|
|
1213
|
+
fs.writeJSONSync(options.destination, json, {
|
|
1214
|
+
encoding: 'utf8',
|
|
1215
|
+
spaces: 2
|
|
1216
|
+
});
|
|
1197
1217
|
};
|
|
1198
1218
|
return { name, finish };
|
|
1199
1219
|
};
|
|
1200
1220
|
|
|
1221
|
+
// biome-ignore-all lint: TODO
|
|
1201
1222
|
const WEB_TYPES_OPTIONS = {
|
|
1202
1223
|
destination: path.join('dist', 'web-types.json'),
|
|
1203
1224
|
packageName: '',
|
|
1204
|
-
packageVersion: ''
|
|
1225
|
+
packageVersion: '',
|
|
1226
|
+
reference: () => '',
|
|
1227
|
+
transformer: (_context, element) => element
|
|
1205
1228
|
};
|
|
1206
|
-
const webTypes = (
|
|
1229
|
+
const webTypes = (userOptions) => {
|
|
1207
1230
|
const name = 'webTypes';
|
|
1208
|
-
options = Object.assign({}, WEB_TYPES_OPTIONS,
|
|
1231
|
+
const options = Object.assign({}, WEB_TYPES_OPTIONS, userOptions);
|
|
1209
1232
|
const finish = (global) => {
|
|
1210
1233
|
const contexts = global.contexts.sort((a, b) => {
|
|
1211
|
-
return a.elementKey.toUpperCase()
|
|
1234
|
+
return (a.elementKey ?? '').toUpperCase().localeCompare((b.elementKey ?? '').toUpperCase());
|
|
1212
1235
|
});
|
|
1213
1236
|
const json = {
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1237
|
+
$schema: 'http://json.schemastore.org/web-types',
|
|
1238
|
+
name: options.packageName,
|
|
1239
|
+
version: options.packageVersion,
|
|
1217
1240
|
'description-markup': 'markdown',
|
|
1218
1241
|
'framework-config': {
|
|
1219
1242
|
'enable-when': {
|
|
1220
1243
|
'node-packages': [options.packageName]
|
|
1221
1244
|
}
|
|
1222
1245
|
},
|
|
1223
|
-
|
|
1246
|
+
contributions: {
|
|
1224
1247
|
html: {
|
|
1225
1248
|
elements: []
|
|
1226
1249
|
}
|
|
@@ -1251,9 +1274,9 @@ const webTypes = (options) => {
|
|
|
1251
1274
|
default: getInitializer(property.value)
|
|
1252
1275
|
}, extractFromComment(property, ['description', 'deprecated', 'experimental'])));
|
|
1253
1276
|
const element = Object.assign({
|
|
1254
|
-
|
|
1277
|
+
name: context.elementKey,
|
|
1255
1278
|
'doc-url': options.reference?.(context),
|
|
1256
|
-
|
|
1279
|
+
js: {
|
|
1257
1280
|
events,
|
|
1258
1281
|
properties: [].concat(properties, methods)
|
|
1259
1282
|
},
|
|
@@ -1264,9 +1287,81 @@ const webTypes = (options) => {
|
|
|
1264
1287
|
}
|
|
1265
1288
|
const dirname = path.dirname(options.destination);
|
|
1266
1289
|
fs.ensureDirSync(dirname);
|
|
1267
|
-
fs.writeJSONSync(options.destination, json, {
|
|
1290
|
+
fs.writeJSONSync(options.destination, json, {
|
|
1291
|
+
encoding: 'utf8',
|
|
1292
|
+
spaces: 2
|
|
1293
|
+
});
|
|
1268
1294
|
};
|
|
1269
1295
|
return { name, finish };
|
|
1270
1296
|
};
|
|
1271
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
|
+
|
|
1272
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 };
|