@htmlplus/element 2.12.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +2 -2
  2. package/bundlers.d.ts +20 -0
  3. package/{bundlers/vite.js → bundlers.js} +39 -3
  4. package/client-5FqNUiuz.d.ts +309 -0
  5. package/client-Dse96R-O.js +1805 -0
  6. package/client.d.ts +1 -0
  7. package/client.js +3 -0
  8. package/constants.d.ts +48 -0
  9. package/constants.js +60 -0
  10. package/internal.d.ts +1 -0
  11. package/internal.js +3 -0
  12. package/package.json +8 -4
  13. package/transformer.d.ts +139 -0
  14. package/transformer.js +1277 -0
  15. package/bundlers/rollup.d.ts +0 -7
  16. package/bundlers/rollup.js +0 -23
  17. package/bundlers/vite.d.ts +0 -8
  18. package/client/decorators/bind.d.ts +0 -8
  19. package/client/decorators/bind.js +0 -21
  20. package/client/decorators/context.d.ts +0 -3
  21. package/client/decorators/context.js +0 -121
  22. package/client/decorators/direction.d.ts +0 -5
  23. package/client/decorators/direction.js +0 -8
  24. package/client/decorators/element.d.ts +0 -7
  25. package/client/decorators/element.js +0 -65
  26. package/client/decorators/event.d.ts +0 -35
  27. package/client/decorators/event.js +0 -53
  28. package/client/decorators/host.d.ts +0 -4
  29. package/client/decorators/host.js +0 -7
  30. package/client/decorators/index.d.ts +0 -15
  31. package/client/decorators/index.js +0 -15
  32. package/client/decorators/isRTL.d.ts +0 -4
  33. package/client/decorators/isRTL.js +0 -7
  34. package/client/decorators/listen.d.ts +0 -52
  35. package/client/decorators/listen.js +0 -37
  36. package/client/decorators/method.d.ts +0 -6
  37. package/client/decorators/method.js +0 -15
  38. package/client/decorators/property.d.ts +0 -25
  39. package/client/decorators/property.js +0 -94
  40. package/client/decorators/query.d.ts +0 -9
  41. package/client/decorators/query.js +0 -12
  42. package/client/decorators/queryAll.d.ts +0 -12
  43. package/client/decorators/queryAll.js +0 -15
  44. package/client/decorators/slots.d.ts +0 -4
  45. package/client/decorators/slots.js +0 -7
  46. package/client/decorators/state.d.ts +0 -6
  47. package/client/decorators/state.js +0 -23
  48. package/client/decorators/watch.d.ts +0 -11
  49. package/client/decorators/watch.js +0 -31
  50. package/client/index.d.ts +0 -2
  51. package/client/index.js +0 -2
  52. package/client/utils/appendToMethod.d.ts +0 -1
  53. package/client/utils/appendToMethod.js +0 -15
  54. package/client/utils/attributes.d.ts +0 -2
  55. package/client/utils/attributes.js +0 -33
  56. package/client/utils/call.d.ts +0 -1
  57. package/client/utils/call.js +0 -3
  58. package/client/utils/classes.d.ts +0 -4
  59. package/client/utils/classes.js +0 -45
  60. package/client/utils/config.d.ts +0 -39
  61. package/client/utils/config.js +0 -28
  62. package/client/utils/defineProperty.d.ts +0 -1
  63. package/client/utils/defineProperty.js +0 -1
  64. package/client/utils/direction.d.ts +0 -6
  65. package/client/utils/direction.js +0 -8
  66. package/client/utils/event.d.ts +0 -13
  67. package/client/utils/event.js +0 -48
  68. package/client/utils/getFramework.d.ts +0 -2
  69. package/client/utils/getFramework.js +0 -20
  70. package/client/utils/getStyles.d.ts +0 -2
  71. package/client/utils/getStyles.js +0 -4
  72. package/client/utils/getTag.d.ts +0 -2
  73. package/client/utils/getTag.js +0 -4
  74. package/client/utils/host.d.ts +0 -5
  75. package/client/utils/host.js +0 -12
  76. package/client/utils/index.d.ts +0 -32
  77. package/client/utils/index.js +0 -32
  78. package/client/utils/isCSSColor.d.ts +0 -5
  79. package/client/utils/isCSSColor.js +0 -9
  80. package/client/utils/isEvent.d.ts +0 -1
  81. package/client/utils/isEvent.js +0 -3
  82. package/client/utils/isRTL.d.ts +0 -5
  83. package/client/utils/isRTL.js +0 -5
  84. package/client/utils/isServer.d.ts +0 -4
  85. package/client/utils/isServer.js +0 -6
  86. package/client/utils/merge.d.ts +0 -1
  87. package/client/utils/merge.js +0 -22
  88. package/client/utils/query.d.ts +0 -5
  89. package/client/utils/query.js +0 -7
  90. package/client/utils/queryAll.d.ts +0 -5
  91. package/client/utils/queryAll.js +0 -7
  92. package/client/utils/request.d.ts +0 -9
  93. package/client/utils/request.js +0 -106
  94. package/client/utils/shadowRoot.d.ts +0 -2
  95. package/client/utils/shadowRoot.js +0 -4
  96. package/client/utils/slots.d.ts +0 -9
  97. package/client/utils/slots.js +0 -18
  98. package/client/utils/styles.d.ts +0 -4
  99. package/client/utils/styles.js +0 -10
  100. package/client/utils/task.d.ts +0 -6
  101. package/client/utils/task.js +0 -34
  102. package/client/utils/toBoolean.d.ts +0 -1
  103. package/client/utils/toBoolean.js +0 -3
  104. package/client/utils/toDecorator.d.ts +0 -2
  105. package/client/utils/toDecorator.js +0 -10
  106. package/client/utils/toEvent.d.ts +0 -1
  107. package/client/utils/toEvent.js +0 -3
  108. package/client/utils/toProperty.d.ts +0 -1
  109. package/client/utils/toProperty.js +0 -55
  110. package/client/utils/toUnit.d.ts +0 -4
  111. package/client/utils/toUnit.js +0 -10
  112. package/client/utils/typeOf.d.ts +0 -3
  113. package/client/utils/typeOf.js +0 -6
  114. package/client/utils/uhtml.d.ts +0 -22
  115. package/client/utils/uhtml.js +0 -703
  116. package/client/utils/updateAttribute.d.ts +0 -2
  117. package/client/utils/updateAttribute.js +0 -10
  118. package/constants/index.d.ts +0 -48
  119. package/constants/index.js +0 -60
  120. package/transformer/index.d.ts +0 -3
  121. package/transformer/index.js +0 -3
  122. package/transformer/plugins/assets.d.ts +0 -7
  123. package/transformer/plugins/assets.js +0 -26
  124. package/transformer/plugins/copy.d.ts +0 -9
  125. package/transformer/plugins/copy.js +0 -29
  126. package/transformer/plugins/customElement.d.ts +0 -7
  127. package/transformer/plugins/customElement.js +0 -392
  128. package/transformer/plugins/document.d.ts +0 -7
  129. package/transformer/plugins/document.js +0 -206
  130. package/transformer/plugins/extract.d.ts +0 -2
  131. package/transformer/plugins/extract.js +0 -22
  132. package/transformer/plugins/index.d.ts +0 -12
  133. package/transformer/plugins/index.js +0 -12
  134. package/transformer/plugins/parse.d.ts +0 -6
  135. package/transformer/plugins/parse.js +0 -13
  136. package/transformer/plugins/read.d.ts +0 -7
  137. package/transformer/plugins/read.js +0 -19
  138. package/transformer/plugins/readme.d.ts +0 -6
  139. package/transformer/plugins/readme.js +0 -24
  140. package/transformer/plugins/style.d.ts +0 -6
  141. package/transformer/plugins/style.js +0 -42
  142. package/transformer/plugins/validate.d.ts +0 -2
  143. package/transformer/plugins/validate.js +0 -40
  144. package/transformer/plugins/visualStudioCode.d.ts +0 -8
  145. package/transformer/plugins/visualStudioCode.js +0 -73
  146. package/transformer/plugins/webTypes.d.ts +0 -10
  147. package/transformer/plugins/webTypes.js +0 -74
  148. package/transformer/transformer.d.ts +0 -8
  149. package/transformer/transformer.js +0 -78
  150. package/transformer/transformer.types.d.ts +0 -52
  151. package/transformer/transformer.types.js +0 -1
  152. package/transformer/utils/addDependency.d.ts +0 -7
  153. package/transformer/utils/addDependency.js +0 -64
  154. package/transformer/utils/extractAttribute.d.ts +0 -2
  155. package/transformer/utils/extractAttribute.js +0 -10
  156. package/transformer/utils/extractFromComment.d.ts +0 -4
  157. package/transformer/utils/extractFromComment.js +0 -51
  158. package/transformer/utils/getInitializer.d.ts +0 -2
  159. package/transformer/utils/getInitializer.js +0 -3
  160. package/transformer/utils/getType.d.ts +0 -2
  161. package/transformer/utils/getType.js +0 -89
  162. package/transformer/utils/getTypeReference.d.ts +0 -2
  163. package/transformer/utils/getTypeReference.js +0 -33
  164. package/transformer/utils/hasDecorator.d.ts +0 -1
  165. package/transformer/utils/hasDecorator.js +0 -5
  166. package/transformer/utils/index.d.ts +0 -10
  167. package/transformer/utils/index.js +0 -10
  168. package/transformer/utils/print.d.ts +0 -2
  169. package/transformer/utils/print.js +0 -5
  170. package/transformer/utils/printType.d.ts +0 -1
  171. package/transformer/utils/printType.js +0 -69
  172. package/transformer/utils/visitor.d.ts +0 -2
  173. package/transformer/utils/visitor.js +0 -5
  174. package/types/index.d.ts +0 -2
  175. package/types/index.js +0 -1
package/transformer.js ADDED
@@ -0,0 +1,1277 @@
1
+ import generator from '@babel/generator';
2
+ import t from '@babel/types';
3
+ import traverse from '@babel/traverse';
4
+ import { parse as parse$1 } from '@babel/parser';
5
+ import fs from 'fs-extra';
6
+ import { glob } from 'glob';
7
+ import template from '@babel/template';
8
+ import { pascalCase, kebabCase, camelCase, capitalCase } from 'change-case';
9
+ import ora from 'ora';
10
+ import path, { join, resolve, dirname } from 'node:path';
11
+ import { COMMENT_AUTO_ADDED, DECORATOR_PROPERTY, STATIC_TAG, UTILS_STYLES_LOCAL, UTILS_PATH, DECORATOR_PROPERTY_TYPE, UTILS_STYLES_IMPORTED, ELEMENT_HOST_NAME, UTILS_HTML_IMPORTED, UTILS_HTML_LOCAL, TYPE_OBJECT, TYPE_NUMBER, TYPE_DATE, TYPE_BOOLEAN, TYPE_ARRAY, TYPE_STRING, TYPE_NULL, TYPE_ENUM, UTILS_ATTRIBUTES_IMPORTED, UTILS_ATTRIBUTES_LOCAL, DECORATOR_CSS_VARIABLE, DECORATOR_EVENT, DECORATOR_METHOD, DECORATOR_STATE, STATIC_STYLE, STYLE_IMPORTED, PACKAGE_NAME, DECORATOR_ELEMENT } from './constants.js';
12
+
13
+ const logger = ora({
14
+ color: 'yellow'
15
+ });
16
+ const log = (message, persist) => {
17
+ const content = `${new Date().toLocaleTimeString()} [HTMLPLUS] ${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 found.`, 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 started successfully.`, 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 finished successfully.`, true);
78
+ log(`Finished.`, true);
79
+ };
80
+ const write = async () => {
81
+ for (const plugin of plugins) {
82
+ if (!plugin.write)
83
+ continue;
84
+ global = (await plugin.write(global)) || global;
85
+ }
86
+ };
87
+ return { global, start, run, finish, write };
88
+ };
89
+
90
+ const ASSETS_OPTIONS = {
91
+ destination(context) {
92
+ return path.join('dist', 'assets', context.fileName);
93
+ },
94
+ source(context) {
95
+ return path.join(context.directoryPath, 'assets');
96
+ }
97
+ };
98
+ const assets = (options) => {
99
+ const name = 'assets';
100
+ options = Object.assign({}, ASSETS_OPTIONS, options);
101
+ const finish = (global) => {
102
+ for (const context of global.contexts) {
103
+ context.assetsDestination = options.destination(context);
104
+ context.assetsSource = options.source(context);
105
+ if (!context.assetsSource)
106
+ continue;
107
+ if (!fs.existsSync(context.assetsSource))
108
+ continue;
109
+ fs.copySync(context.assetsSource, context.assetsDestination);
110
+ }
111
+ };
112
+ return { name, finish };
113
+ };
114
+
115
+ const COPY_OPTIONS = {
116
+ at: 'start'
117
+ };
118
+ const copy = (options) => {
119
+ const name = 'copy';
120
+ options = Object.assign({}, COPY_OPTIONS, options);
121
+ const copy = (caller) => {
122
+ if (options.at != caller)
123
+ return;
124
+ let content;
125
+ content = fs.readFileSync(options.source, 'utf8');
126
+ if (options.transformer)
127
+ content = options.transformer(content);
128
+ fs.ensureDirSync(path.dirname(options.destination));
129
+ fs.writeFileSync(options.destination, content, 'utf8');
130
+ };
131
+ const start = () => {
132
+ copy('start');
133
+ };
134
+ const run = () => {
135
+ copy('run');
136
+ };
137
+ const finish = () => {
138
+ copy('finish');
139
+ };
140
+ return { name, start, run, finish };
141
+ };
142
+
143
+ // TODO: options type
144
+ const visitor = (ast, options) => {
145
+ (traverse.default || traverse)(ast, options);
146
+ };
147
+
148
+ function addDependency(path, source, local, imported, comment) {
149
+ const isDefault = local && !imported;
150
+ const isImport = local && imported;
151
+ const isNormal = !local && !imported;
152
+ let declaration;
153
+ let file = path;
154
+ while (file.parentPath)
155
+ file = file.parentPath;
156
+ file = file.node || file;
157
+ visitor(file, {
158
+ ImportDeclaration(path) {
159
+ if (path.node.source.value != source)
160
+ return;
161
+ declaration = path.node;
162
+ }
163
+ });
164
+ if (isNormal && declaration)
165
+ return {
166
+ node: declaration
167
+ };
168
+ let specifier = declaration?.specifiers.find((specifier) => {
169
+ if (isDefault) {
170
+ return specifier.type == 'ImportDefaultSpecifier';
171
+ }
172
+ else if (isImport) {
173
+ return specifier.imported?.name == imported;
174
+ }
175
+ });
176
+ if (specifier)
177
+ return {
178
+ local: specifier.local.name,
179
+ node: declaration
180
+ };
181
+ if (isDefault) {
182
+ specifier = t.importDefaultSpecifier(t.identifier(local));
183
+ }
184
+ else if (isImport) {
185
+ specifier = t.importSpecifier(t.identifier(local), t.identifier(imported));
186
+ }
187
+ if (declaration) {
188
+ if (isDefault) {
189
+ declaration.specifiers.unshift(specifier);
190
+ }
191
+ else if (isImport) {
192
+ declaration.specifiers.push(specifier);
193
+ }
194
+ }
195
+ else {
196
+ declaration = t.importDeclaration(specifier ? [specifier] : [], t.stringLiteral(source));
197
+ // TODO
198
+ (file.program || file).body.unshift(declaration);
199
+ // TODO
200
+ if (comment) {
201
+ t.addComment(declaration, 'leading', COMMENT_AUTO_ADDED, true);
202
+ }
203
+ }
204
+ return {
205
+ local,
206
+ node: declaration
207
+ };
208
+ }
209
+
210
+ const extractAttribute = (property) => {
211
+ try {
212
+ return property.decorators
213
+ .find((decorator) => decorator.expression.callee.name == DECORATOR_PROPERTY)
214
+ .expression.arguments[0].properties.find((property) => property.key.name == 'attribute').value
215
+ .value;
216
+ }
217
+ catch { }
218
+ };
219
+
220
+ const extractFromComment = (node, whitelist) => {
221
+ const normalized = [];
222
+ const result = {
223
+ description: ''
224
+ };
225
+ const lines = node.leadingComments
226
+ ?.map((comment) => {
227
+ if (comment.type == 'CommentLine')
228
+ return comment.value;
229
+ return comment.value.split('\n');
230
+ })
231
+ ?.flat()
232
+ ?.map((line) => line.trim().replace(/^\*/, '').trim())
233
+ ?.filter((line) => line.trim());
234
+ for (const line of lines || []) {
235
+ if (line.startsWith('@')) {
236
+ normalized.push(line);
237
+ continue;
238
+ }
239
+ if (!normalized.length)
240
+ normalized.push('');
241
+ normalized[normalized.length - 1] += ' ' + line;
242
+ }
243
+ for (const line of normalized) {
244
+ if (!line.startsWith('@')) {
245
+ result.description = line.trim();
246
+ continue;
247
+ }
248
+ const regex = /@(\w+)(?:\s*({\w+})\s*)?(?:\s*([-a-zA-Z\s]+)\s*-\s*)?(.*)/;
249
+ const groups = regex.exec(line);
250
+ if (!groups)
251
+ continue;
252
+ const tag = groups[1]?.trim();
253
+ const type = groups[2]?.trim().slice(1, -1);
254
+ const name = groups[3]?.trim();
255
+ const description = groups[4]?.trim();
256
+ if (name && description) {
257
+ const key = tag + 's';
258
+ if (whitelist && !whitelist.includes(key))
259
+ continue;
260
+ (result[key] ||= []).push({ name, type, description });
261
+ }
262
+ else {
263
+ const key = tag;
264
+ if (whitelist && !whitelist.includes(key))
265
+ continue;
266
+ result[key] = description || true;
267
+ }
268
+ }
269
+ return result;
270
+ };
271
+
272
+ const getInitializer = (node) => {
273
+ return node?.extra?.raw || node?.['value'];
274
+ };
275
+
276
+ const getType = (directory, file, node) => {
277
+ if (!node)
278
+ return node;
279
+ if (node.type != 'TSTypeReference')
280
+ return node;
281
+ let result;
282
+ visitor(file, {
283
+ ClassDeclaration(path) {
284
+ if (path.node.id.name != node.typeName['name'])
285
+ return;
286
+ result = path.node;
287
+ path.stop();
288
+ },
289
+ ImportDeclaration(path) {
290
+ for (const specifier of path.node.specifiers) {
291
+ const alias = specifier.local.name;
292
+ if (alias != node.typeName['name'])
293
+ continue;
294
+ switch (specifier.type) {
295
+ case 'ImportNamespaceSpecifier':
296
+ break;
297
+ case 'ImportDefaultSpecifier':
298
+ break;
299
+ case 'ImportSpecifier':
300
+ specifier.imported.name;
301
+ break;
302
+ }
303
+ try {
304
+ const reference = glob
305
+ .sync(['.ts*', '/index.ts*'].map((key) => {
306
+ return join(directory, path.node.source.value).replace(/\\/g, '/') + key;
307
+ }))
308
+ .find((reference) => fs.existsSync(reference));
309
+ const content = fs.readFileSync(reference, 'utf8');
310
+ const filePath = resolve(directory, path.node.source.value + '.ts');
311
+ path.$ast ||= parse$1(content, {
312
+ allowImportExportEverywhere: true,
313
+ plugins: ['typescript'],
314
+ ranges: false
315
+ });
316
+ result = getType(dirname(filePath), path.$ast, node);
317
+ }
318
+ catch { }
319
+ path.stop();
320
+ break;
321
+ }
322
+ },
323
+ TSInterfaceDeclaration(path) {
324
+ if (path.node.id.name != node.typeName['name'])
325
+ return;
326
+ result = path.node;
327
+ path.stop();
328
+ },
329
+ TSTypeAliasDeclaration(path) {
330
+ if (path.node.id.name != node.typeName['name'])
331
+ return;
332
+ result = path.node.typeAnnotation;
333
+ switch (result.type) {
334
+ case 'TSUnionType':
335
+ const types = [];
336
+ for (const prev of result.types) {
337
+ const next = getType(directory, file, prev);
338
+ if (next.type == 'TSUnionType') {
339
+ next.types.forEach((type) => types.push(type));
340
+ }
341
+ else {
342
+ types.push(next);
343
+ }
344
+ }
345
+ result.types = types;
346
+ break;
347
+ default:
348
+ result = getType(directory, file, result);
349
+ break;
350
+ }
351
+ path.stop();
352
+ }
353
+ });
354
+ return result || node;
355
+ };
356
+
357
+ const getTypeReference = (file, node) => {
358
+ if (!node)
359
+ return;
360
+ if (node.type != 'TSTypeReference')
361
+ return;
362
+ let result;
363
+ visitor(file, {
364
+ ImportDeclaration(path) {
365
+ for (const specifier of path.node.specifiers) {
366
+ const alias = specifier.local.name;
367
+ if (alias != node.typeName['name'])
368
+ continue;
369
+ switch (specifier.type) {
370
+ case 'ImportNamespaceSpecifier':
371
+ break;
372
+ case 'ImportDefaultSpecifier':
373
+ break;
374
+ case 'ImportSpecifier':
375
+ specifier.imported.name;
376
+ break;
377
+ }
378
+ result = path.node.source.value;
379
+ path.stop();
380
+ break;
381
+ }
382
+ }
383
+ });
384
+ return result;
385
+ };
386
+
387
+ const hasDecorator = (node, name) => {
388
+ if (!node.decorators)
389
+ return false;
390
+ return !!node.decorators.some((decorator) => decorator.expression.callee?.name == name);
391
+ };
392
+
393
+ // TODO: add options
394
+ const print = (ast) => {
395
+ return (generator.default || generator)(ast, { decoratorsBeforeExport: true }).code;
396
+ };
397
+
398
+ const CUSTOM_ELEMENT_OPTIONS = {
399
+ prefix: undefined,
400
+ typings: true
401
+ };
402
+ // TODO: support {variable && jsxElement}
403
+ const customElement = (options) => {
404
+ const name = 'customElement';
405
+ options = Object.assign({}, CUSTOM_ELEMENT_OPTIONS, options);
406
+ const run = (context) => {
407
+ const ast = t.cloneNode(context.fileAST, true);
408
+ context.elementTagName = `${options.prefix || ''}${context.elementKey}`;
409
+ context.elementInterfaceName = `HTML${pascalCase(context.elementTagName)}Element`;
410
+ // attach tag name
411
+ visitor(ast, {
412
+ ClassDeclaration(path) {
413
+ const { body, id } = path.node;
414
+ if (id.name != context.className)
415
+ return;
416
+ const node = t.classProperty(t.identifier(STATIC_TAG), t.stringLiteral(context.elementTagName), undefined, undefined, undefined, true);
417
+ t.addComment(node, 'leading', COMMENT_AUTO_ADDED, true);
418
+ body.body.unshift(node);
419
+ }
420
+ });
421
+ // attach style mapper for 'style' attribute
422
+ visitor(ast, {
423
+ JSXAttribute(path) {
424
+ const { name, value } = path.node;
425
+ if (name.name != 'style')
426
+ return;
427
+ if (!value)
428
+ return;
429
+ if (value.type != 'JSXExpressionContainer')
430
+ return;
431
+ const { local } = addDependency(path, UTILS_PATH, UTILS_STYLES_LOCAL, UTILS_STYLES_IMPORTED);
432
+ // TODO: remove 'local!'
433
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier('style'), t.jsxExpressionContainer(t.callExpression(t.identifier(local), [value.expression]))));
434
+ path.skip();
435
+ }
436
+ });
437
+ // replace 'className' attribute with 'class'
438
+ visitor(ast, {
439
+ JSXAttribute(path) {
440
+ const { name, value } = path.node;
441
+ if (name.name != 'className')
442
+ return;
443
+ const hasClass = path.parentPath.node.attributes.some((attribute) => {
444
+ return attribute.name?.name == 'class';
445
+ });
446
+ if (hasClass)
447
+ return path.remove();
448
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier('class'), value));
449
+ }
450
+ });
451
+ // TODO
452
+ visitor(ast, {
453
+ JSXAttribute(path) {
454
+ const { name, value } = path.node;
455
+ if (name.name == 'value') {
456
+ name.name = '.' + name.name;
457
+ return;
458
+ }
459
+ const key = ['tabIndex', 'viewBox'];
460
+ if (!key.includes(name.name))
461
+ return;
462
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier(name.name.toLowerCase()), value));
463
+ }
464
+ });
465
+ // TODO
466
+ // convert 'jsx' to 'uhtml' syntax
467
+ visitor(ast, {
468
+ enter(path) {
469
+ const { type } = path.node;
470
+ if (!['JSXElement', 'JSXFragment'].includes(type))
471
+ return;
472
+ const TODO = (node, attributes) => {
473
+ const { local } = addDependency(path, UTILS_PATH, UTILS_ATTRIBUTES_LOCAL, UTILS_ATTRIBUTES_IMPORTED);
474
+ return t.callExpression(t.identifier(local), [
475
+ node,
476
+ t.arrayExpression(attributes.map((attribute) => {
477
+ switch (attribute.type) {
478
+ case 'JSXSpreadAttribute':
479
+ return attribute.argument;
480
+ default:
481
+ return t.objectExpression([
482
+ t.objectProperty(t.stringLiteral(attribute.name.name), attribute.value?.type == 'JSXExpressionContainer'
483
+ ? attribute.value.expression
484
+ : attribute.value || t.booleanLiteral(true))
485
+ ]);
486
+ }
487
+ }))
488
+ ]);
489
+ };
490
+ const render = (node) => {
491
+ switch (node.type) {
492
+ case 'JSXElement':
493
+ const attributes = node.openingElement.attributes;
494
+ const isHost = node.openingElement.name.name == ELEMENT_HOST_NAME;
495
+ // TODO
496
+ if (isHost) {
497
+ const children = node.children.map(render).flat();
498
+ if (!attributes.length)
499
+ return children;
500
+ return [TODO(t.thisExpression(), attributes), ...children];
501
+ }
502
+ const name = node.openingElement.name.name;
503
+ const children = node.children.map(render).flat();
504
+ const parts = [];
505
+ parts.push('<', name);
506
+ const hasSpreadAttribute = attributes.some((attribute) => {
507
+ return attribute.type == 'JSXSpreadAttribute';
508
+ });
509
+ if (hasSpreadAttribute) {
510
+ parts.push(' ', TODO(t.identifier('TODO'), attributes));
511
+ }
512
+ else {
513
+ for (const attribute of attributes) {
514
+ switch (attribute.type) {
515
+ case 'JSXAttribute':
516
+ if (attribute.name.name == 'dangerouslySetInnerHTML') {
517
+ try {
518
+ parts.push(' ', '.innerHTML');
519
+ parts.push('=');
520
+ parts.push(attribute.value.expression.properties.at(0).value);
521
+ }
522
+ catch { }
523
+ continue;
524
+ }
525
+ parts.push(' ', attribute.name.name);
526
+ if (!attribute.value)
527
+ continue;
528
+ parts.push('=');
529
+ switch (attribute.value.type) {
530
+ case 'JSXExpressionContainer':
531
+ parts.push(attribute.value.expression);
532
+ break;
533
+ default:
534
+ parts.push(attribute.value.extra.raw);
535
+ break;
536
+ }
537
+ break;
538
+ default:
539
+ parts.push(' ', attribute);
540
+ break;
541
+ }
542
+ }
543
+ }
544
+ parts.push(node.closingElement ? '>' : ' />');
545
+ parts.push(...children);
546
+ if (node.closingElement) {
547
+ parts.push('<', '/', name, '>');
548
+ }
549
+ return parts;
550
+ case 'JSXFragment':
551
+ return node.children.map(render).flat();
552
+ case 'JSXText':
553
+ return [node.extra.raw];
554
+ case 'JSXExpressionContainer':
555
+ if (node.expression.type == 'JSXEmptyExpression')
556
+ return [];
557
+ return [node.expression];
558
+ }
559
+ };
560
+ const transform = (parts) => {
561
+ const quasis = [];
562
+ const expressions = [];
563
+ let i = 0;
564
+ while (i < parts.length + 1) {
565
+ let quasi = '';
566
+ while (typeof parts[i] == 'string') {
567
+ quasi += parts[i].replace(/[\\`]/g, (s) => `\\${s}`);
568
+ i += 1;
569
+ }
570
+ quasis.push(t.templateElement({ raw: quasi }));
571
+ if (parts[i] != null)
572
+ expressions.push(parts[i]);
573
+ i += 1;
574
+ }
575
+ const templateLiteral = t.templateLiteral(quasis, expressions);
576
+ // TODO
577
+ // if (!expressions.length) return template;
578
+ const { local } = addDependency(path, UTILS_PATH, UTILS_HTML_LOCAL, UTILS_HTML_IMPORTED, true);
579
+ return t.taggedTemplateExpression(t.identifier(local), templateLiteral);
580
+ };
581
+ path.replaceWith(transform(render(path.node)));
582
+ }
583
+ });
584
+ // add type to properties
585
+ visitor(ast, {
586
+ Decorator(path) {
587
+ const { expression } = path.node;
588
+ if (expression.callee?.name != DECORATOR_PROPERTY)
589
+ return;
590
+ if (!expression.arguments.length) {
591
+ expression.arguments.push(t.objectExpression([]));
592
+ }
593
+ const [argument] = expression.arguments;
594
+ const filtered = argument.properties.filter((property) => {
595
+ return property.key.name != DECORATOR_PROPERTY_TYPE;
596
+ });
597
+ if (argument.properties.length != filtered.length)
598
+ return;
599
+ argument.properties = filtered;
600
+ let type = 0;
601
+ const extract = (input) => {
602
+ switch (input?.type) {
603
+ case 'BooleanLiteral':
604
+ type |= TYPE_BOOLEAN;
605
+ break;
606
+ case 'NumericLiteral':
607
+ type |= TYPE_NUMBER;
608
+ break;
609
+ case 'StringLiteral':
610
+ type |= TYPE_ENUM;
611
+ break;
612
+ case 'TSArrayType':
613
+ type |= TYPE_ARRAY;
614
+ break;
615
+ case 'TSBooleanKeyword':
616
+ type |= TYPE_BOOLEAN;
617
+ break;
618
+ case 'TSLiteralType':
619
+ extract(input.literal);
620
+ break;
621
+ case 'TSNullKeyword':
622
+ type |= TYPE_NULL;
623
+ break;
624
+ case 'TSNumberKeyword':
625
+ type |= TYPE_NUMBER;
626
+ break;
627
+ case 'TSObjectKeyword':
628
+ type |= TYPE_OBJECT;
629
+ break;
630
+ case 'TSStringKeyword':
631
+ type |= TYPE_STRING;
632
+ break;
633
+ case 'TSTupleType':
634
+ type |= TYPE_ARRAY;
635
+ break;
636
+ case 'TSTypeLiteral':
637
+ type |= TYPE_OBJECT;
638
+ break;
639
+ case 'TSTypeReference':
640
+ if (!input.typeName)
641
+ break;
642
+ switch (input.typeName.name) {
643
+ case 'Array':
644
+ type |= TYPE_ARRAY;
645
+ break;
646
+ case 'Boolean':
647
+ type |= TYPE_BOOLEAN;
648
+ break;
649
+ case 'bool':
650
+ type |= TYPE_BOOLEAN;
651
+ break;
652
+ case 'Date':
653
+ type |= TYPE_DATE;
654
+ break;
655
+ case 'Number':
656
+ type |= TYPE_NUMBER;
657
+ break;
658
+ case 'Object':
659
+ type |= TYPE_OBJECT;
660
+ break;
661
+ }
662
+ break;
663
+ case 'TSUnionType':
664
+ input.types.forEach(extract);
665
+ break;
666
+ }
667
+ // TODO
668
+ if (input?.type == 'TSParenthesizedType' &&
669
+ input?.typeAnnotation?.type == 'TSIntersectionType') {
670
+ let types = input.types || input.typeAnnotation.types;
671
+ if (types.length != 2)
672
+ return;
673
+ types = types.filter((type) => type.type != 'TSTypeLiteral');
674
+ if (types.length != 1)
675
+ return;
676
+ extract(types[0]);
677
+ }
678
+ };
679
+ extract(getType(context.directoryPath, ast, path.parentPath.node.typeAnnotation?.typeAnnotation));
680
+ argument.properties.push(t.objectProperty(t.identifier(DECORATOR_PROPERTY_TYPE), t.numericLiteral(type)));
681
+ }
682
+ });
683
+ // attach typings
684
+ if (options.typings) {
685
+ visitor(ast, {
686
+ Program(path) {
687
+ const attributes = context
688
+ .classProperties.filter((property) => !t.isClassMethod(property))
689
+ .map((property) => {
690
+ const key = extractAttribute(property) || kebabCase(property.key['name']);
691
+ const typeAnnotation = property.typeAnnotation;
692
+ return Object.assign(t.tSPropertySignature(t.stringLiteral(kebabCase(key)), typeAnnotation), {
693
+ optional: property.optional,
694
+ leadingComments: t.cloneNode(property, true).leadingComments
695
+ });
696
+ });
697
+ const events = context.classEvents.map((event) => {
698
+ const key = event.key;
699
+ const typeAnnotation = event.typeAnnotation;
700
+ return Object.assign(t.tSPropertySignature(t.identifier(camelCase('on-' + key.name)), t.tsTypeAnnotation(t.tsFunctionType(undefined, [
701
+ Object.assign({}, t.identifier('event'), {
702
+ typeAnnotation: t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CustomEvent'), typeAnnotation?.['typeAnnotation']?.typeParameters))
703
+ })
704
+ ], t.tsTypeAnnotation(t.tsVoidKeyword())))), {
705
+ optional: true,
706
+ leadingComments: t.cloneNode(event, true).leadingComments
707
+ });
708
+ });
709
+ const methods = context.classMethods.map((method) => {
710
+ return Object.assign(t.tsMethodSignature(method.key, undefined, method.params, // TODO
711
+ method.returnType // TODO
712
+ ), {
713
+ leadingComments: t.cloneNode(method, true).leadingComments
714
+ });
715
+ });
716
+ const properties = context.classProperties.map((property) => {
717
+ const key = property.key;
718
+ // TODO
719
+ const readonly = property.readonly || !!property['returnType'];
720
+ // TODO
721
+ const typeAnnotation = (property.typeAnnotation ||
722
+ property['returnType']);
723
+ return Object.assign(t.tsPropertySignature(t.identifier(key.name), typeAnnotation), {
724
+ readonly,
725
+ optional: property.optional,
726
+ leadingComments: t.cloneNode(property, true).leadingComments
727
+ });
728
+ });
729
+ // prettier-ignore
730
+ const ast = template.default.ast(`
731
+ // THE FOLLOWING TYPES HAVE BEEN ADDED AUTOMATICALLY
732
+
733
+ export interface ${context.className}Attributes {
734
+ ${attributes.map(print).join('')}
735
+ }
736
+
737
+ export interface ${context.className}Events {
738
+ ${events.map(print).join('')}
739
+ }
740
+
741
+ export interface ${context.className}Methods {
742
+ ${methods.map(print).join('')}
743
+ }
744
+
745
+ export interface ${context.className}Properties {
746
+ ${properties.map(print).join('')}
747
+ }
748
+
749
+ export interface ${context.className}JSX extends ${context.className}Events, ${context.className}Properties { }
750
+
751
+ declare global {
752
+ interface ${context.elementInterfaceName} extends HTMLElement, ${context.className}Methods, ${context.className}Properties { }
753
+
754
+ var ${context.elementInterfaceName}: {
755
+ prototype: ${context.elementInterfaceName};
756
+ new (): ${context.elementInterfaceName};
757
+ };
758
+
759
+ interface HTMLElementTagNameMap {
760
+ "${context.elementTagName}": ${context.elementInterfaceName};
761
+ }
762
+
763
+ namespace JSX {
764
+ interface IntrinsicElements {
765
+ "${context.elementTagName}": ${context.className}Events & ${context.className}Attributes & {
766
+ [key: string]: any;
767
+ };
768
+ }
769
+ }
770
+ }
771
+
772
+ export type ${context.className}Element = globalThis.${context.elementInterfaceName}
773
+ `, {
774
+ plugins: ['typescript'],
775
+ preserveComments: true
776
+ });
777
+ path.node.body.push(...ast);
778
+ }
779
+ });
780
+ }
781
+ context.script = print(ast);
782
+ };
783
+ return { name, run };
784
+ };
785
+
786
+ const DOCUMENT_OPTIONS = {
787
+ destination: path.join('dist', 'document.json')
788
+ };
789
+ const document = (options) => {
790
+ const name = 'document';
791
+ options = Object.assign({}, DOCUMENT_OPTIONS, options);
792
+ const write = (global) => {
793
+ const json = {
794
+ elements: []
795
+ };
796
+ for (const context of global.contexts) {
797
+ const events = context.classEvents.map((event) => {
798
+ const cancelable = (() => {
799
+ if (!event.decorators)
800
+ return false;
801
+ try {
802
+ for (const decorator of event.decorators) {
803
+ for (const argument of decorator.expression['arguments']) {
804
+ for (const property of argument.properties) {
805
+ if (property.key.name != 'cancelable')
806
+ continue;
807
+ if (property.value.type != 'BooleanLiteral')
808
+ continue;
809
+ if (!property.value.value)
810
+ continue;
811
+ return true;
812
+ }
813
+ }
814
+ }
815
+ }
816
+ catch { }
817
+ return false;
818
+ })();
819
+ const detail = print(event.typeAnnotation?.['typeAnnotation']);
820
+ const detailReference = getTypeReference(context.fileAST, event.typeAnnotation?.['typeAnnotation'].typeParameters.params[0]);
821
+ const name = event.key['name'];
822
+ return Object.assign({
823
+ cancelable,
824
+ detail,
825
+ detailReference,
826
+ name
827
+ }, extractFromComment(event));
828
+ });
829
+ const lastModified = glob
830
+ .sync('**/*.*', { cwd: context.directoryPath })
831
+ .map((file) => fs.statSync(path.join(context.directoryPath, file)).mtime)
832
+ .sort((a, b) => (a > b ? 1 : -1))
833
+ .pop();
834
+ const methods = context.classMethods.map((method) => {
835
+ const async = method.async;
836
+ const name = method.key['name'];
837
+ const comments = extractFromComment(method);
838
+ // TODO
839
+ const parameters = method.params.map((param) => ({
840
+ description: comments.params?.find((item) => item.name == param['name'])?.description,
841
+ required: !param['optional'],
842
+ name: param['name'],
843
+ type: print(param?.['typeAnnotation']?.typeAnnotation) || undefined,
844
+ typeReference: getTypeReference(context.fileAST, param?.['typeAnnotation']?.typeAnnotation)
845
+ }));
846
+ // TODO
847
+ delete comments.params;
848
+ const returns = print(method.returnType?.['typeAnnotation']) || 'void';
849
+ const returnsReference = getTypeReference(context.fileAST, method.returnType?.['typeAnnotation']);
850
+ const signature = [
851
+ method.key['name'],
852
+ '(',
853
+ parameters
854
+ .map((parameter) => {
855
+ let string = '';
856
+ string += parameter.name;
857
+ string += parameter.required ? '' : '?';
858
+ string += parameter.type ? ': ' : '';
859
+ string += parameter.type ?? '';
860
+ return string;
861
+ })
862
+ .join(', '),
863
+ ')',
864
+ ' => ',
865
+ returns
866
+ ].join('');
867
+ return Object.assign({
868
+ async,
869
+ name,
870
+ parameters,
871
+ returns,
872
+ returnsReference,
873
+ signature
874
+ }, comments,
875
+ // TODO
876
+ {
877
+ returns
878
+ },
879
+ // TODO
880
+ returns != 'void' &&
881
+ comments.returns && {
882
+ tags: [
883
+ {
884
+ key: 'returns',
885
+ value: `${comments.returns}`
886
+ }
887
+ ]
888
+ });
889
+ });
890
+ const properties = context.classProperties.map((property) => {
891
+ const attribute = extractAttribute(property) || kebabCase(property.key['name']);
892
+ // TODO
893
+ const initializer = getInitializer(property.value);
894
+ const name = property.key['name'];
895
+ const readonly = property['kind'] == 'get';
896
+ // TODO
897
+ const reflects = (() => {
898
+ if (!property.decorators)
899
+ return false;
900
+ try {
901
+ for (const decorator of property.decorators) {
902
+ for (const argument of decorator.expression['arguments']) {
903
+ for (const property of argument.properties) {
904
+ if (property.key.name != 'reflect')
905
+ continue;
906
+ if (property.value.type != 'BooleanLiteral')
907
+ continue;
908
+ if (!property.value.value)
909
+ continue;
910
+ return true;
911
+ }
912
+ }
913
+ }
914
+ }
915
+ catch { }
916
+ return false;
917
+ })();
918
+ const required = 'optional' in property && !property.optional;
919
+ // TODO
920
+ const type = property['returnType']
921
+ ? print(property['returnType']?.['typeAnnotation'])
922
+ : print(property.typeAnnotation?.['typeAnnotation']);
923
+ const typeReference = getTypeReference(context.fileAST, property.typeAnnotation?.['typeAnnotation']);
924
+ return Object.assign({
925
+ attribute,
926
+ initializer,
927
+ name,
928
+ readonly,
929
+ reflects,
930
+ required,
931
+ type,
932
+ typeReference
933
+ }, extractFromComment(property));
934
+ });
935
+ // TODO
936
+ const styles = (() => {
937
+ if (!context.styleContent)
938
+ return [];
939
+ return context.styleContent
940
+ .split(DECORATOR_CSS_VARIABLE)
941
+ .slice(1)
942
+ .map((section) => {
943
+ const [first, second] = section.split(/\n/);
944
+ const description = first.replace('*/', '').trim();
945
+ const name = second.split(':')[0].trim();
946
+ const initializerDefault = second.split(':').slice(1).join(':').replace(';', '').trim();
947
+ // TODO
948
+ const initializerTransformed = context.styleContentTransformed
949
+ ?.split(name)
950
+ ?.at(1)
951
+ ?.split(':')
952
+ ?.filter((section) => !!section)
953
+ ?.at(0)
954
+ ?.split(/;|}/)
955
+ ?.at(0)
956
+ ?.trim();
957
+ const initializer = initializerTransformed || initializerDefault;
958
+ return {
959
+ description,
960
+ initializer,
961
+ name
962
+ };
963
+ });
964
+ })();
965
+ const title = capitalCase(context.elementKey);
966
+ const element = Object.assign({
967
+ events,
968
+ key: context.elementKey,
969
+ lastModified,
970
+ methods,
971
+ properties,
972
+ readmeContent: context.readmeContent,
973
+ styles,
974
+ title
975
+ }, extractFromComment(context.class));
976
+ const transformed = options.transformer?.(context, element) || element;
977
+ json.elements.push(transformed);
978
+ }
979
+ json.elements = json.elements.sort((a, b) => (a.title > b.title ? 1 : -1));
980
+ const dirname = path.dirname(options.destination);
981
+ fs.ensureDirSync(dirname);
982
+ fs.writeJSONSync(options.destination, json, { encoding: 'utf8', spaces: 2 });
983
+ };
984
+ return { name, write };
985
+ };
986
+
987
+ const extract = () => {
988
+ const name = 'extract';
989
+ const run = (context) => {
990
+ const { declaration, leadingComments } = context.fileAST?.program.body.find((child) => {
991
+ return t.isExportNamedDeclaration(child);
992
+ });
993
+ context.class = declaration;
994
+ context.class.leadingComments = leadingComments; // TODO
995
+ context.classMembers = context.class?.body?.body || [];
996
+ context.className = context.class?.id?.name;
997
+ context.elementKey = kebabCase(context.className || '');
998
+ context.classEvents = context.classMembers.filter((member) => hasDecorator(member, DECORATOR_EVENT));
999
+ context.classMethods = context.classMembers.filter((member) => hasDecorator(member, DECORATOR_METHOD));
1000
+ context.classProperties = context.classMembers.filter((member) => hasDecorator(member, DECORATOR_PROPERTY));
1001
+ context.classStates = context.classMembers.filter((member) => hasDecorator(member, DECORATOR_STATE));
1002
+ };
1003
+ return { name, run };
1004
+ };
1005
+
1006
+ const PARSE_OPTIONS = {
1007
+ sourceType: 'module',
1008
+ plugins: [['decorators', { decoratorsBeforeExport: true }], 'jsx', 'typescript']
1009
+ };
1010
+ const parse = (options) => {
1011
+ const name = 'parse';
1012
+ options = Object.assign({}, PARSE_OPTIONS, options);
1013
+ const run = (context) => {
1014
+ context.fileAST = parse$1(context.fileContent, options);
1015
+ };
1016
+ return { name, run };
1017
+ };
1018
+
1019
+ const READ_OPTIONS = {
1020
+ encoding: 'utf8'
1021
+ };
1022
+ const read = (options) => {
1023
+ const name = 'read';
1024
+ options = Object.assign({}, READ_OPTIONS, options);
1025
+ const run = (context) => {
1026
+ if (!context.filePath)
1027
+ return;
1028
+ context.fileContent = fs.readFileSync(context.filePath, options);
1029
+ context.fileExtension = path.extname(context.filePath);
1030
+ context.fileName = path.basename(context.filePath, context.fileExtension);
1031
+ context.directoryPath = path.dirname(context.filePath);
1032
+ context.directoryName = path.basename(context.directoryPath);
1033
+ };
1034
+ return { name, run };
1035
+ };
1036
+
1037
+ const README_OPTIONS = {
1038
+ source(context) {
1039
+ return path.join(context.directoryPath, `${context.fileName}.md`);
1040
+ }
1041
+ };
1042
+ const readme = (options) => {
1043
+ const name = 'readme';
1044
+ options = Object.assign({}, README_OPTIONS, options);
1045
+ const finish = (global) => {
1046
+ for (const context of global.contexts) {
1047
+ context.readmePath = options.source(context);
1048
+ if (!context.readmePath)
1049
+ continue;
1050
+ if (!fs.existsSync(context.readmePath))
1051
+ continue;
1052
+ context.readmeContent = fs.readFileSync(context.readmePath, 'utf8');
1053
+ context.readmeExtension = path.extname(context.readmePath);
1054
+ context.readmeName = path.basename(context.readmePath, context.readmeExtension);
1055
+ }
1056
+ };
1057
+ return { name, finish };
1058
+ };
1059
+
1060
+ const STYLE_OPTIONS = {
1061
+ source(context) {
1062
+ return [
1063
+ path.join(context.directoryPath, `${context.fileName}.css`),
1064
+ path.join(context.directoryPath, `${context.fileName}.less`),
1065
+ path.join(context.directoryPath, `${context.fileName}.sass`),
1066
+ path.join(context.directoryPath, `${context.fileName}.scss`),
1067
+ path.join(context.directoryPath, `${context.fileName}.styl`)
1068
+ ];
1069
+ }
1070
+ };
1071
+ const style = (options) => {
1072
+ const name = 'style';
1073
+ options = Object.assign({}, STYLE_OPTIONS, options);
1074
+ const run = (context) => {
1075
+ const sources = [options.source(context)].flat();
1076
+ for (const source of sources) {
1077
+ if (!source)
1078
+ continue;
1079
+ if (!fs.existsSync(source))
1080
+ continue;
1081
+ context.stylePath = source;
1082
+ break;
1083
+ }
1084
+ if (!context.stylePath)
1085
+ return;
1086
+ context.styleContent = fs.readFileSync(context.stylePath, 'utf8');
1087
+ context.styleExtension = path.extname(context.stylePath);
1088
+ context.styleName = path.basename(context.stylePath, context.styleExtension);
1089
+ const { local } = addDependency(context.fileAST, context.stylePath, STYLE_IMPORTED, undefined, true);
1090
+ // TODO: remove 'local!'
1091
+ const property = t.classProperty(t.identifier(STATIC_STYLE), t.identifier(local), undefined, null, undefined, true);
1092
+ t.addComment(property, 'leading', COMMENT_AUTO_ADDED, true);
1093
+ context.class.body.body.unshift(property);
1094
+ };
1095
+ return { name, run };
1096
+ };
1097
+
1098
+ const validate = () => {
1099
+ const name = 'validate';
1100
+ const run = (context) => {
1101
+ context.skipped = true;
1102
+ visitor(context.fileAST, {
1103
+ ImportDeclaration(path) {
1104
+ if (path.node.source?.value !== PACKAGE_NAME)
1105
+ return;
1106
+ for (const specifier of path.node.specifiers) {
1107
+ if (specifier.imported.name !== DECORATOR_ELEMENT)
1108
+ continue;
1109
+ const binding = path.scope.getBinding(specifier.imported.name);
1110
+ if (binding.references == 0)
1111
+ break;
1112
+ const referencePaths = binding.referencePaths.filter((referencePath) => {
1113
+ if (t.isCallExpression(referencePath.parent) &&
1114
+ t.isDecorator(referencePath.parentPath.parent) &&
1115
+ t.isClassDeclaration(referencePath.parentPath.parentPath.parent) &&
1116
+ t.isExportNamedDeclaration(referencePath.parentPath.parentPath.parentPath.parent))
1117
+ return true;
1118
+ });
1119
+ if (referencePaths.length > 1) {
1120
+ throw new Error('In each file, only one custom element can be defined. \n' +
1121
+ 'If more than one @Element() decorator is used in the file, it will result in an error.\n');
1122
+ }
1123
+ context.skipped = false;
1124
+ if (referencePaths.length == 1)
1125
+ break;
1126
+ throw new Error('It appears that the class annotated with the @Element() decorator is not being exported correctly.');
1127
+ }
1128
+ path.stop();
1129
+ }
1130
+ });
1131
+ context.skipped;
1132
+ };
1133
+ return { name, run };
1134
+ };
1135
+
1136
+ const VISUAL_STUDIO_CODE_OPTIONS = {
1137
+ destination: path.join('dist', 'visual-studio-code.json')
1138
+ };
1139
+ const visualStudioCode = (options) => {
1140
+ const name = 'visualStudioCode';
1141
+ options = Object.assign({}, VISUAL_STUDIO_CODE_OPTIONS, options);
1142
+ const finish = (global) => {
1143
+ const contexts = global.contexts.sort((a, b) => {
1144
+ return a.elementKey.toUpperCase() > b.elementKey.toUpperCase() ? +1 : -1;
1145
+ });
1146
+ const json = {
1147
+ $schema: 'TODO',
1148
+ version: 1.1,
1149
+ tags: []
1150
+ };
1151
+ for (const context of contexts) {
1152
+ const tag = Object.assign({
1153
+ name: context.elementKey,
1154
+ attributes: [],
1155
+ references: [
1156
+ {
1157
+ name: 'Source code',
1158
+ url: options.reference?.(context)
1159
+ }
1160
+ ]
1161
+ }, extractFromComment(context.class, ['description']));
1162
+ for (const property of context.classProperties || []) {
1163
+ const attribute = Object.assign({
1164
+ name: extractAttribute(property) || kebabCase(property.key['name']),
1165
+ values: []
1166
+ }, extractFromComment(property, ['description']));
1167
+ const type = print(getType(context.directoryPath, context.fileAST, property.typeAnnotation?.['typeAnnotation']));
1168
+ const sections = type.split('|');
1169
+ for (const section of sections) {
1170
+ const trimmed = section.trim();
1171
+ if (!trimmed)
1172
+ continue;
1173
+ const isBoolean = /bool|boolean|Boolean/.test(trimmed);
1174
+ const isNumber = !isNaN(trimmed);
1175
+ const isString = /^("|'|`)/.test(trimmed);
1176
+ if (isBoolean) {
1177
+ attribute.values.push({
1178
+ name: 'false'
1179
+ }, {
1180
+ name: 'true'
1181
+ });
1182
+ }
1183
+ else if (isNumber) {
1184
+ attribute.values.push({
1185
+ name: trimmed
1186
+ });
1187
+ }
1188
+ else if (isString) {
1189
+ attribute.values.push({
1190
+ name: trimmed.slice(1, -1)
1191
+ });
1192
+ }
1193
+ }
1194
+ tag.attributes.push(attribute);
1195
+ }
1196
+ const transformed = options.transformer?.(context, tag) || tag;
1197
+ json.tags.push(transformed);
1198
+ }
1199
+ const dirname = path.dirname(options.destination);
1200
+ fs.ensureDirSync(dirname);
1201
+ fs.writeJSONSync(options.destination, json, { encoding: 'utf8', spaces: 2 });
1202
+ };
1203
+ return { name, finish };
1204
+ };
1205
+
1206
+ const WEB_TYPES_OPTIONS = {
1207
+ destination: path.join('dist', 'web-types.json'),
1208
+ packageName: '',
1209
+ packageVersion: ''
1210
+ };
1211
+ const webTypes = (options) => {
1212
+ const name = 'webTypes';
1213
+ options = Object.assign({}, WEB_TYPES_OPTIONS, options);
1214
+ const finish = (global) => {
1215
+ const contexts = global.contexts.sort((a, b) => {
1216
+ return a.elementKey.toUpperCase() > b.elementKey.toUpperCase() ? +1 : -1;
1217
+ });
1218
+ const json = {
1219
+ '$schema': 'http://json.schemastore.org/web-types',
1220
+ 'name': options.packageName,
1221
+ 'version': options.packageVersion,
1222
+ 'description-markup': 'markdown',
1223
+ 'framework-config': {
1224
+ 'enable-when': {
1225
+ 'node-packages': [options.packageName]
1226
+ }
1227
+ },
1228
+ 'contributions': {
1229
+ html: {
1230
+ elements: []
1231
+ }
1232
+ }
1233
+ };
1234
+ for (const context of contexts) {
1235
+ const attributes = context.classProperties?.map((property) => Object.assign({
1236
+ name: extractAttribute(property) || kebabCase(property.key['name']),
1237
+ value: {
1238
+ // kind: TODO
1239
+ type: print(getType(context.directoryPath, context.fileAST, property.typeAnnotation?.['typeAnnotation']))
1240
+ // required: TODO
1241
+ // default: TODO
1242
+ },
1243
+ default: getInitializer(property.value)
1244
+ }, extractFromComment(property, ['description', 'deprecated', 'experimental'])));
1245
+ const events = context.classEvents?.map((event) => Object.assign({
1246
+ name: kebabCase(event.key['name']) // TODO
1247
+ // 'value': TODO
1248
+ }, extractFromComment(event, ['description', 'deprecated', 'experimental'])));
1249
+ const methods = context.classMethods?.map((method) => Object.assign({
1250
+ name: method.key['name']
1251
+ // 'value': TODO
1252
+ }, extractFromComment(method, ['description', 'deprecated', 'experimental'])));
1253
+ const properties = context.classProperties?.map((property) => Object.assign({
1254
+ name: property.key['name'],
1255
+ // 'value': TODO
1256
+ default: getInitializer(property.value)
1257
+ }, extractFromComment(property, ['description', 'deprecated', 'experimental'])));
1258
+ const element = Object.assign({
1259
+ 'name': context.elementKey,
1260
+ 'doc-url': options.reference?.(context),
1261
+ 'js': {
1262
+ events,
1263
+ properties: [].concat(properties, methods)
1264
+ },
1265
+ attributes
1266
+ }, extractFromComment(context.class, ['description', 'deprecated', 'experimental', 'slots']));
1267
+ const transformed = options.transformer?.(context, element) || element;
1268
+ json.contributions.html.elements.push(transformed);
1269
+ }
1270
+ const dirname = path.dirname(options.destination);
1271
+ fs.ensureDirSync(dirname);
1272
+ fs.writeJSONSync(options.destination, json, { encoding: 'utf8', spaces: 2 });
1273
+ };
1274
+ return { name, finish };
1275
+ };
1276
+
1277
+ export { ASSETS_OPTIONS, COPY_OPTIONS, CUSTOM_ELEMENT_OPTIONS, DOCUMENT_OPTIONS, PARSE_OPTIONS, README_OPTIONS, READ_OPTIONS, STYLE_OPTIONS, VISUAL_STUDIO_CODE_OPTIONS, WEB_TYPES_OPTIONS, assets, copy, customElement, document, extract, parse, read, readme, style, transformer, validate, visualStudioCode, webTypes };