@htmlplus/element 0.1.8 → 0.3.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 (62) hide show
  1. package/README.md +30 -0
  2. package/dist/client/decorators/attributes.js +1 -1
  3. package/dist/client/decorators/element.js +10 -6
  4. package/dist/client/decorators/listen.js +1 -1
  5. package/dist/client/decorators/property.js +9 -3
  6. package/dist/client/decorators/watch.js +1 -1
  7. package/dist/client/utils/get-members.js +1 -1
  8. package/dist/client/utils/get-styles.js +1 -1
  9. package/dist/client/utils/host.js +1 -1
  10. package/dist/client/utils/index.d.ts +1 -0
  11. package/dist/client/utils/index.js +1 -0
  12. package/dist/client/utils/is-ready.d.ts +2 -0
  13. package/dist/client/utils/is-ready.js +4 -0
  14. package/dist/client/utils/on-ready.js +1 -1
  15. package/dist/client/utils/parse-value.js +1 -1
  16. package/dist/client/utils/render.js +4 -2
  17. package/dist/client/utils/request.js +6 -3
  18. package/dist/client/utils/task.js +3 -12
  19. package/dist/compiler/compiler.js +28 -29
  20. package/dist/compiler/plugins/componentDependencyResolver.d.ts +5 -0
  21. package/dist/compiler/plugins/componentDependencyResolver.js +40 -0
  22. package/dist/compiler/plugins/{print.d.ts → customElement.d.ts} +1 -1
  23. package/dist/compiler/plugins/customElement.js +138 -0
  24. package/dist/compiler/plugins/customElementReact/customElementReact.d.ts +12 -0
  25. package/dist/compiler/plugins/{react.proxy/react.proxy.js → customElementReact/customElementReact.js} +13 -9
  26. package/dist/compiler/plugins/customElementReact/index.d.ts +1 -0
  27. package/dist/compiler/plugins/customElementReact/index.js +1 -0
  28. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/README.md.hbs +0 -0
  29. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/_.gitignore.hbs +0 -0
  30. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/package.json.hbs +0 -0
  31. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/rollup.config.js.hbs +0 -0
  32. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/src/components/index.ts.hbs +0 -0
  33. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/src/components/{{fileName}}.compact.ts.hbs +0 -0
  34. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/src/components/{{fileName}}.ts.hbs +0 -0
  35. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/src/index.ts.hbs +0 -0
  36. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/src/proxy.ts.hbs +0 -0
  37. package/dist/compiler/plugins/{react.proxy → customElementReact}/templates/tsconfig.json.hbs +0 -0
  38. package/dist/compiler/plugins/extract.js +1 -8
  39. package/dist/compiler/plugins/index.d.ts +3 -7
  40. package/dist/compiler/plugins/index.js +3 -7
  41. package/dist/compiler/plugins/style.d.ts +12 -0
  42. package/dist/compiler/plugins/style.js +42 -0
  43. package/dist/compiler/plugins/validate.js +33 -1
  44. package/dist/{configs/constants.d.ts → constants/index.d.ts} +1 -0
  45. package/dist/{configs/constants.js → constants/index.js} +1 -0
  46. package/dist/types/context.d.ts +3 -0
  47. package/dist/types/global.d.ts +4 -0
  48. package/dist/types/global.js +1 -0
  49. package/dist/types/index.d.ts +1 -0
  50. package/dist/types/index.js +1 -0
  51. package/dist/types/plugin.d.ts +4 -3
  52. package/package.json +3 -3
  53. package/dist/compiler/plugins/attach.d.ts +0 -11
  54. package/dist/compiler/plugins/attach.js +0 -101
  55. package/dist/compiler/plugins/print.js +0 -11
  56. package/dist/compiler/plugins/react.proxy/index.d.ts +0 -1
  57. package/dist/compiler/plugins/react.proxy/index.js +0 -1
  58. package/dist/compiler/plugins/react.proxy/react.proxy.d.ts +0 -11
  59. package/dist/compiler/plugins/sass.d.ts +0 -6
  60. package/dist/compiler/plugins/sass.js +0 -15
  61. package/dist/compiler/plugins/uhtml.d.ts +0 -5
  62. package/dist/compiler/plugins/uhtml.js +0 -59
package/README.md CHANGED
@@ -258,6 +258,36 @@ export class MyCounter {
258
258
 
259
259
  </details>
260
260
 
261
+ <details>
262
+ <summary>Attributes</summary>
263
+
264
+ TODO
265
+
266
+ ```tsx
267
+ import { Attributes, Element } from '@htmlplus/element';
268
+
269
+ @Element('my-button')
270
+ export class MyButton {
271
+
272
+ @Attributes()
273
+ get attributes() {
274
+ return {
275
+ role: 'button'
276
+ }
277
+ }
278
+
279
+ render() {
280
+ return <button><slot /></button>
281
+ }
282
+ }
283
+ ```
284
+
285
+ ```html
286
+ <my-button role="button"></my-button>
287
+ ```
288
+
289
+ </details>
290
+
261
291
  <details>
262
292
  <summary>Watch</summary>
263
293
 
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  import { appendToMethod, host, sync } from '../utils/index.js';
3
3
  export function Attributes() {
4
4
  return function (target, propertyKey) {
@@ -1,10 +1,11 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
2
- import { call, isServer, parseValue, request } from '../utils/index.js';
1
+ import { camelCase, paramCase } from 'change-case';
2
+ import * as CONSTANTS from '../../constants/index.js';
3
+ import { call, getMembers, isServer, parseValue, request } from '../utils/index.js';
3
4
  export function Element(tag) {
4
5
  return function (constructor) {
5
6
  if (isServer())
6
7
  return;
7
- const members = constructor[CONSTANTS.STATIC_MEMBERS];
8
+ const members = getMembers(constructor);
8
9
  class Plus extends HTMLElement {
9
10
  constructor() {
10
11
  var _a;
@@ -15,15 +16,18 @@ export function Element(tag) {
15
16
  this.attachShadow({ mode: 'open' });
16
17
  }
17
18
  static get observedAttributes() {
18
- return Object.keys(members).filter((key) => members[key][0] != CONSTANTS.TYPE_FUNCTION);
19
+ return Object.keys(members)
20
+ .filter((key) => members[key][0] != CONSTANTS.TYPE_FUNCTION)
21
+ .map((key) => paramCase(key));
19
22
  }
20
23
  adoptedCallback() {
21
24
  call(this.plus, CONSTANTS.LIFECYCLE_ADOPTED);
22
25
  }
23
26
  attributeChangedCallback(name, prev, next) {
24
- const [type] = members[name];
27
+ const key = camelCase(name);
28
+ const [type] = members[key];
25
29
  const parsed = parseValue(next, type);
26
- this.plus[name] = parsed;
30
+ this.plus[key] = parsed;
27
31
  }
28
32
  connectedCallback() {
29
33
  this.plus[CONSTANTS.API_READY] = true;
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  import { appendToMethod, host, on, off } from '../utils/index.js';
3
3
  import { Bind } from './bind.js';
4
4
  const defaults = {
@@ -1,4 +1,4 @@
1
- import { defineProperty, getMembers, host, parseValue, request, updateAttribute, onReady } from '../utils/index.js';
1
+ import { defineProperty, getMembers, host, isReady, parseValue, request, updateAttribute, onReady } from '../utils/index.js';
2
2
  export function Property(options) {
3
3
  return function (target, propertyKey) {
4
4
  const values = new Map();
@@ -11,14 +11,20 @@ export function Property(options) {
11
11
  if (value === input)
12
12
  return;
13
13
  values.set(this, input);
14
+ // TODO
15
+ const ready = isReady(this);
14
16
  request(this, { [propertyKey]: [input, value] })
15
17
  .then((renderd) => {
18
+ const name = String(propertyKey);
19
+ const element = host(this);
20
+ const hasAttribute = element.hasAttribute(name);
21
+ // TODO
22
+ if ((options === null || options === void 0 ? void 0 : options.reflect) && !hasAttribute && !renderd && !ready)
23
+ updateAttribute(element, name, input);
16
24
  if (!renderd)
17
25
  return;
18
26
  if (!(options === null || options === void 0 ? void 0 : options.reflect))
19
27
  return;
20
- const element = host(this);
21
- const name = String(propertyKey);
22
28
  const raw = element.getAttribute(name);
23
29
  const [type] = getMembers(target)[propertyKey];
24
30
  const parsed = parseValue(raw, type);
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  import { appendToMethod } from '../utils/index.js';
3
3
  // TODO: support * key
4
4
  export function Watch(...keys) {
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  export const getMembers = (target) => {
3
3
  var _a;
4
4
  return (_a = target.constructor[CONSTANTS.STATIC_MEMBERS]) !== null && _a !== void 0 ? _a : target[CONSTANTS.STATIC_MEMBERS];
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  export const getStyles = (target) => {
3
3
  var _a;
4
4
  return (_a = target.constructor[CONSTANTS.STATIC_STYLES]) !== null && _a !== void 0 ? _a : target[CONSTANTS.STATIC_STYLES];
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  export const host = (target) => {
3
3
  return target[CONSTANTS.API_HOST]();
4
4
  };
@@ -6,6 +6,7 @@ export * from './get-members.js';
6
6
  export * from './get-styles.js';
7
7
  export * from './host.js';
8
8
  export * from './is-event.js';
9
+ export * from './is-ready.js';
9
10
  export * from './is-server.js';
10
11
  export * from './on-ready.js';
11
12
  export * from './parse-value.js';
@@ -6,6 +6,7 @@ export * from './get-members.js';
6
6
  export * from './get-styles.js';
7
7
  export * from './host.js';
8
8
  export * from './is-event.js';
9
+ export * from './is-ready.js';
9
10
  export * from './is-server.js';
10
11
  export * from './on-ready.js';
11
12
  export * from './parse-value.js';
@@ -0,0 +1,2 @@
1
+ import { PlusElement } from '../../types/index.js';
2
+ export declare const isReady: (target: PlusElement) => boolean;
@@ -0,0 +1,4 @@
1
+ import * as CONSTANTS from '../../constants/index.js';
2
+ export const isReady = (target) => {
3
+ return target[CONSTANTS.API_READY];
4
+ };
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  export function onReady(target, callback) {
3
3
  var _a;
4
4
  var _b;
@@ -1,4 +1,4 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
2
  import { toBoolean } from './to-boolean.js';
3
3
  // TODO: input type & validate date
4
4
  export const parseValue = (value, type) => {
@@ -1,6 +1,8 @@
1
1
  import { html, render as renderer } from 'uhtml';
2
- import * as CONSTANTS from '../../configs/constants.js';
3
- import { call, getStyles, host } from '../utils/index.js';
2
+ import * as CONSTANTS from '../../constants/index.js';
3
+ import { call } from './call.js';
4
+ import { getStyles } from './get-styles.js';
5
+ import { host } from './host.js';
4
6
  export const render = (target) => {
5
7
  const element = host(target);
6
8
  renderer(element.shadowRoot, () => {
@@ -1,8 +1,11 @@
1
- import * as CONSTANTS from '../../configs/constants.js';
2
- import { call, render, task } from '../utils/index.js';
1
+ import * as CONSTANTS from '../../constants/index.js';
2
+ import { call } from '../utils/call';
3
+ import { isReady } from '../utils/is-ready';
4
+ import { render } from '../utils/render';
5
+ import { task } from '../utils/task';
3
6
  const targets = new Map();
4
7
  export const request = (target, state) => {
5
- if (!target[CONSTANTS.API_READY])
8
+ if (!isReady(target))
6
9
  return Promise.resolve(false);
7
10
  let run = targets.get(target);
8
11
  if (run)
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  export const task = (options) => {
11
2
  let states, isPending, updatePromise;
12
3
  const run = (state) => {
@@ -18,10 +9,10 @@ export const task = (options) => {
18
9
  updatePromise = enqueue();
19
10
  return updatePromise;
20
11
  };
21
- const enqueue = () => __awaiter(void 0, void 0, void 0, function* () {
12
+ const enqueue = async () => {
22
13
  isPending = true;
23
14
  try {
24
- yield updatePromise;
15
+ await updatePromise;
25
16
  }
26
17
  catch (error) {
27
18
  Promise.reject(error);
@@ -41,6 +32,6 @@ export const task = (options) => {
41
32
  isPending = false;
42
33
  throw error;
43
34
  }
44
- });
35
+ };
45
36
  return run;
46
37
  };
@@ -1,53 +1,52 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import logUpdate from 'log-update';
11
- const log = (namespace, message) => {
2
+ const log = (namespace, message, persist) => {
12
3
  logUpdate(`${new Date().toLocaleTimeString()} [@htmlplus/element]${namespace ? `[${namespace}]` : ''} ${message}`);
4
+ persist && logUpdate.done();
13
5
  };
14
6
  export default (...plugins) => {
15
7
  let global = {
16
- contexts: {}
8
+ contexts: []
17
9
  };
18
- const start = () => __awaiter(void 0, void 0, void 0, function* () {
19
- log(undefined, 'Starting.');
10
+ const start = async () => {
11
+ log(undefined, 'Starting...', true);
20
12
  for (const plugin of plugins) {
21
- if (!plugin.start)
22
- continue;
23
- global = (yield plugin.start(global)) || global;
13
+ if (plugin.start) {
14
+ global = (await plugin.start(global)) || global;
15
+ }
24
16
  log(plugin.name, 'Started successfully.');
25
17
  }
26
- });
27
- const next = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
18
+ log(undefined, `${plugins.length} Plugins started successfully.`, true);
19
+ };
20
+ const next = async (filePath) => {
28
21
  const key = filePath.split(/[\/|\\]/g).pop();
29
22
  let context = {
30
23
  filePath
31
24
  };
25
+ log(`${key}`, 'Executing...');
32
26
  for (const plugin of plugins) {
33
27
  if (!plugin.next)
34
28
  continue;
35
- context = (yield plugin.next(context, global)) || context;
36
- log(`${key}:${plugin.name}`, 'Executed successfully.');
29
+ context = (await plugin.next(context, global)) || context;
30
+ global.contexts = global.contexts.filter((current) => current.filePath != context.filePath).concat(context);
31
+ if (context.isInvalid)
32
+ break;
37
33
  }
38
- log(key, 'Executed successfully.');
39
- global.contexts[filePath] = context;
34
+ if (context.isInvalid)
35
+ log(key, 'Break executing because file is invalid.');
36
+ else
37
+ log(key, 'Executed successfully.');
40
38
  return context;
41
- });
42
- const finish = () => __awaiter(void 0, void 0, void 0, function* () {
39
+ };
40
+ const finish = async () => {
41
+ log(undefined, 'Finishing...', true);
43
42
  for (const plugin of plugins) {
44
- if (!plugin.finish)
45
- continue;
46
- global = (yield plugin.finish(global)) || global;
43
+ if (plugin.finish) {
44
+ global = (await plugin.finish(global)) || global;
45
+ }
47
46
  log(plugin.name, 'Finished successfully.');
48
47
  }
49
- log(undefined, 'Finished.');
50
- });
48
+ log(undefined, `${plugins.length} Plugins finished successfully.`, true);
49
+ };
51
50
  return {
52
51
  start,
53
52
  next,
@@ -0,0 +1,5 @@
1
+ import { Context, Global } from '../../types/index.js';
2
+ export declare const componentDependencyResolver: () => {
3
+ name: string;
4
+ next: (context: Context, global: Global) => void;
5
+ };
@@ -0,0 +1,40 @@
1
+ import { visitor } from '../utils/index.js';
2
+ export const componentDependencyResolver = () => {
3
+ const name = 'componentDependencyResolver';
4
+ const next = (context, global) => {
5
+ var _a, _b, _c, _d;
6
+ if (!context.dependenciesUnresolved) {
7
+ visitor(context.fileAST, {
8
+ JSXOpeningElement(path) {
9
+ var _a, _b, _c;
10
+ const name = path.node.name.name;
11
+ if (!name.includes('-'))
12
+ return;
13
+ const find = (_a = context.dependenciesUnresolved) === null || _a === void 0 ? void 0 : _a.includes(name);
14
+ if (find)
15
+ return;
16
+ (_b = context.dependenciesUnresolved) !== null && _b !== void 0 ? _b : (context.dependenciesUnresolved = []);
17
+ (_c = context.dependenciesUnresolved) === null || _c === void 0 ? void 0 : _c.push(name);
18
+ }
19
+ });
20
+ }
21
+ for (const current of global.contexts) {
22
+ if (!((_a = current.dependenciesUnresolved) === null || _a === void 0 ? void 0 : _a.length))
23
+ continue;
24
+ const dependencies = global.contexts.filter((context) => { var _a; return (_a = current.dependenciesUnresolved) === null || _a === void 0 ? void 0 : _a.includes(context.componentTag); });
25
+ for (const dependency of dependencies) {
26
+ if ((_b = current.dependencies) === null || _b === void 0 ? void 0 : _b.some((item) => item.componentTag == dependency.componentTag))
27
+ continue;
28
+ (_c = current.dependencies) !== null && _c !== void 0 ? _c : (current.dependencies = []);
29
+ current.dependencies.push(dependency);
30
+ current.dependenciesUnresolved = (_d = current.dependenciesUnresolved) === null || _d === void 0 ? void 0 : _d.filter((current) => current != dependency.componentTag);
31
+ // TODO
32
+ // current.fileAST!.program.body.unshift(t.importDeclaration([], t.stringLiteral(dependency.filePath!)));
33
+ }
34
+ }
35
+ };
36
+ return {
37
+ name,
38
+ next
39
+ };
40
+ };
@@ -1,5 +1,5 @@
1
1
  import { Context } from '../../types/index.js';
2
- export declare const print: () => {
2
+ export declare const customElement: () => {
3
3
  name: string;
4
4
  next: (context: Context) => void;
5
5
  };
@@ -0,0 +1,138 @@
1
+ import t from '@babel/types';
2
+ import * as CONSTANTS from '../../constants/index.js';
3
+ import { print, visitor } from '../utils/index.js';
4
+ export const customElement = () => {
5
+ const name = 'customElement';
6
+ const next = (context) => {
7
+ // attach uhtml importer
8
+ context.fileAST.program.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier('html'), t.identifier('html'))], t.stringLiteral('@htmlplus/element/runtime')));
9
+ // jsx to uhtml syntax
10
+ visitor(context.fileAST, {
11
+ JSXAttribute: {
12
+ exit(path) {
13
+ var _a;
14
+ if (((_a = path.node.value) === null || _a === void 0 ? void 0 : _a.type) == 'JSXExpressionContainer') {
15
+ let node = path.node;
16
+ if (path.node.name.name == 'ref') {
17
+ node = t.jsxAttribute(path.node.name, t.jSXExpressionContainer(t.arrowFunctionExpression([t.identifier('$element')], t.assignmentExpression('=', path.node.value.expression, t.identifier('$element')))));
18
+ }
19
+ path.replaceWith(t.jsxIdentifier(print(node).replace('={', '=${')));
20
+ path.skip();
21
+ return;
22
+ }
23
+ }
24
+ },
25
+ JSXElement: {
26
+ exit(path) {
27
+ if (path.parent.type == 'JSXElement' || path.parent.type == 'JSXFragment') {
28
+ path.replaceWith(t.identifier(print(path.node)));
29
+ return;
30
+ }
31
+ else {
32
+ path.replaceWith(t.identifier('html`' + print(path.node) + '`'));
33
+ return;
34
+ }
35
+ }
36
+ },
37
+ JSXFragment: {
38
+ exit(path) {
39
+ path.replaceWith(t.identifier(['html`', ...path.node.children.map((child) => print(child)), '`'].join('')));
40
+ }
41
+ },
42
+ JSXExpressionContainer: {
43
+ exit(path) {
44
+ if (path.parent.type == 'JSXElement' || path.parent.type == 'JSXFragment') {
45
+ path.replaceWith(t.identifier('$' + print(path.node)));
46
+ return;
47
+ }
48
+ }
49
+ },
50
+ JSXSpreadAttribute: {
51
+ enter(path) {
52
+ // TODO
53
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier('.dataset'), t.jsxExpressionContainer(path.node.argument)));
54
+ }
55
+ }
56
+ });
57
+ // attach members
58
+ context.class.body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_MEMBERS), t.objectExpression([
59
+ ...context.classProperties.map((property) => {
60
+ var _a, _b;
61
+ const type = (_b = (_a = property.typeAnnotation) === null || _a === void 0 ? void 0 : _a.typeAnnotation) === null || _b === void 0 ? void 0 : _b.type;
62
+ const elements = [];
63
+ switch (type) {
64
+ case 'TSBooleanKeyword':
65
+ elements.push(t.stringLiteral(CONSTANTS.TYPE_BOOLEAN));
66
+ break;
67
+ case 'TSStringKeyword':
68
+ elements.push(t.stringLiteral(CONSTANTS.TYPE_STRING));
69
+ break;
70
+ case 'TSNumberKeyword':
71
+ elements.push(t.stringLiteral(CONSTANTS.TYPE_NUMBER));
72
+ break;
73
+ default:
74
+ elements.push(t.nullLiteral());
75
+ break;
76
+ }
77
+ if (property.value)
78
+ elements.push(property.value);
79
+ return t.objectProperty(t.identifier(property.key['name']), t.arrayExpression(elements));
80
+ }),
81
+ ...context.classMethods.map((method) => {
82
+ const elements = [t.stringLiteral(CONSTANTS.TYPE_FUNCTION)];
83
+ return t.objectProperty(t.identifier(method.key['name']), t.arrayExpression(elements));
84
+ })
85
+ ]), undefined, undefined, undefined, true));
86
+ // attach typings
87
+ visitor(context.fileAST, {
88
+ Program(path) {
89
+ path.node.body.push(Object.assign(t.tsModuleDeclaration(t.identifier('global'), t.tsModuleBlock([
90
+ t.tsInterfaceDeclaration(t.identifier(context.componentInterfaceName), null, [], t.tsInterfaceBody([
91
+ ...context.classProperties.map((property) => Object.assign(t.tSPropertySignature(property.key, property.typeAnnotation), {
92
+ optional: property.optional,
93
+ leadingComments: property.leadingComments
94
+ }))
95
+ ])),
96
+ t.variableDeclaration('var', [
97
+ t.variableDeclarator(Object.assign(t.identifier(context.componentInterfaceName), {
98
+ typeAnnotation: t.tSTypeAnnotation(t.tSTypeLiteral([
99
+ t.tSPropertySignature(t.identifier('prototype'), t.tsTypeAnnotation(t.tSTypeReference(t.identifier(context.componentInterfaceName)))),
100
+ t.tSConstructSignatureDeclaration(null, [], t.tSTypeAnnotation(t.tSTypeReference(t.identifier(context.componentInterfaceName))))
101
+ ]))
102
+ }))
103
+ ]),
104
+ t.tsInterfaceDeclaration(t.identifier('HTMLElementTagNameMap'), null, [], t.tsInterfaceBody([
105
+ t.tSPropertySignature(t.stringLiteral(context.componentTag), t.tSTypeAnnotation(t.tSIntersectionType([t.tSTypeReference(t.identifier(context.componentInterfaceName))])))
106
+ ]))
107
+ ])), {
108
+ declare: true,
109
+ global: true
110
+ }));
111
+ path.node.body.push(t.exportNamedDeclaration(t.tsInterfaceDeclaration(
112
+ // TODO
113
+ t.identifier(context.componentClassName + 'JSX'), null, [], t.tsInterfaceBody([
114
+ ...context.classProperties.map((property) => Object.assign(t.tSPropertySignature(property.key, property.typeAnnotation), {
115
+ optional: property.optional,
116
+ leadingComments: property.leadingComments
117
+ })),
118
+ ...context.classEvents.map((event) => {
119
+ var _a, _b;
120
+ return Object.assign(t.tSPropertySignature(event.key, t.tsTypeAnnotation(t.tsFunctionType(undefined, [
121
+ Object.assign({}, t.identifier('event'), {
122
+ typeAnnotation: t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CustomEvent'), (_b = (_a = event.typeAnnotation) === null || _a === void 0 ? void 0 : _a['typeAnnotation']) === null || _b === void 0 ? void 0 : _b.typeParameters))
123
+ })
124
+ ], t.tsTypeAnnotation(t.tsVoidKeyword())))), {
125
+ optional: true,
126
+ leadingComments: event.leadingComments
127
+ });
128
+ })
129
+ ]))));
130
+ }
131
+ });
132
+ context.script = print(context.fileAST);
133
+ };
134
+ return {
135
+ name,
136
+ next
137
+ };
138
+ };
@@ -0,0 +1,12 @@
1
+ import { Global } from '../../../types/index.js';
2
+ export interface CustomElementReactOptions {
3
+ compact?: boolean;
4
+ dist: string;
5
+ eventName?: (eventName: string) => string;
6
+ importerComponent?: (context: any) => string;
7
+ importerComponentType?: (context: any) => string;
8
+ }
9
+ export declare const customElementReact: (options: CustomElementReactOptions) => {
10
+ name: string;
11
+ finish: (global: Global) => void;
12
+ };
@@ -10,17 +10,21 @@ const defaults = {
10
10
  return `YOUR_CORE_PACKAGE_NAME#JSX.${context.componentClassName}`;
11
11
  }
12
12
  };
13
- export const reactProxy = (options) => {
14
- const name = 'react-proxy';
13
+ export const customElementReact = (options) => {
14
+ const name = 'customElementReact';
15
15
  const finish = (global) => {
16
16
  options = Object.assign(Object.assign({}, defaults), options);
17
- global = Object.assign(Object.assign({}, global), { options });
17
+ // TODO
18
+ const globalNew = {
19
+ contexts: global.contexts.reduce((previous, current) => (Object.assign(Object.assign({}, previous), { [current.filePath]: current })), {}),
20
+ options
21
+ };
18
22
  const config = { cwd: __dirname(import.meta.url) };
19
23
  const isEmpty = isDirectoryEmpty(options.dist);
20
24
  const skip = [];
21
25
  const getKey = (component) => component.componentClassName;
22
- for (const key in global.contexts) {
23
- const context = global.contexts[key];
26
+ for (const key in globalNew.contexts) {
27
+ const context = globalNew.contexts[key];
24
28
  const parse = (input) => {
25
29
  const [source, key] = input.split('#');
26
30
  const [root, ...sub] = key.split('.');
@@ -51,7 +55,7 @@ export const reactProxy = (options) => {
51
55
  renderTemplate(patterns, options.dist, config)(state);
52
56
  }
53
57
  if (options.compact) {
54
- global.groups = Object.values(global.contexts)
58
+ globalNew.groups = Object.values(globalNew.contexts)
55
59
  .sort((a, b) => getKey(b).length - getKey(a).length)
56
60
  .map((component, index, components) => ({
57
61
  key: getKey(component),
@@ -93,7 +97,7 @@ export const reactProxy = (options) => {
93
97
  };
94
98
  })
95
99
  .sort((a, b) => (getKey(a.root) < getKey(b.root) ? -1 : 0));
96
- for (const group of global.groups) {
100
+ for (const group of globalNew.groups) {
97
101
  if (group.single)
98
102
  continue;
99
103
  const state = Object.assign({ fileName: group.root.fileName, options }, group);
@@ -107,11 +111,11 @@ export const reactProxy = (options) => {
107
111
  '!templates/src/components/*fileName*.ts.hbs',
108
112
  '!templates/src/components/*fileName*.compact.ts.hbs'
109
113
  ];
110
- renderTemplate(patterns, options.dist, config)(global);
114
+ renderTemplate(patterns, options.dist, config)(globalNew);
111
115
  }
112
116
  if (!isEmpty) {
113
117
  const patterns = ['templates/src/proxy*', 'templates/src/components/index*'];
114
- renderTemplate(patterns, options.dist, config)(global);
118
+ renderTemplate(patterns, options.dist, config)(globalNew);
115
119
  }
116
120
  };
117
121
  return {
@@ -0,0 +1 @@
1
+ export * from './customElementReact.js';
@@ -0,0 +1 @@
1
+ export * from './customElementReact.js';
@@ -1,8 +1,7 @@
1
1
  import * as t from '@babel/types';
2
2
  import { pascalCase, paramCase } from 'change-case';
3
- import fs from 'fs';
4
3
  import path from 'path';
5
- import * as CONSTANTS from '../../configs/constants.js';
4
+ import * as CONSTANTS from '../../constants/index.js';
6
5
  import { hasDecorator, visitor } from '../utils/index.js';
7
6
  export const extract = (options) => {
8
7
  const name = 'extract';
@@ -56,12 +55,6 @@ export const extract = (options) => {
56
55
  // const fileName = "dialogBodyNew"; [OK]
57
56
  // const className = "DialogBody1"; [OK]
58
57
  // const category = "Dialog"; [RAW]
59
- (() => {
60
- const stylePath = path.join(context.directoryPath, `${context.fileName}.scss`);
61
- if (!fs.existsSync(stylePath))
62
- return;
63
- context.stylePath = stylePath;
64
- })();
65
58
  context.classEvents = (context.classMembers || []).filter((member) => hasDecorator(member, CONSTANTS.DECORATOR_EVENT));
66
59
  context.classMethods = (context.classMembers || []).filter((member) => hasDecorator(member, CONSTANTS.DECORATOR_METHOD));
67
60
  context.classProperties = (context.classMembers || []).filter((member) => hasDecorator(member, CONSTANTS.DECORATOR_PROPERTY));
@@ -1,11 +1,7 @@
1
- export * from './react.proxy/index.js';
2
- export * from './attach.js';
3
- export * from './docs.js';
1
+ export * from './customElementReact/index.js';
2
+ export * from './customElement.js';
4
3
  export * from './extract.js';
5
4
  export * from './parse.js';
6
- export * from './print.js';
7
5
  export * from './read.js';
8
- export * from './sass.js';
9
- export * from './uhtml.js';
6
+ export * from './style.js';
10
7
  export * from './validate.js';
11
- export * from './vscode.js';
@@ -1,11 +1,7 @@
1
- export * from './react.proxy/index.js';
2
- export * from './attach.js';
3
- export * from './docs.js';
1
+ export * from './customElementReact/index.js';
2
+ export * from './customElement.js';
4
3
  export * from './extract.js';
5
4
  export * from './parse.js';
6
- export * from './print.js';
7
5
  export * from './read.js';
8
- export * from './sass.js';
9
- export * from './uhtml.js';
6
+ export * from './style.js';
10
7
  export * from './validate.js';
11
- export * from './vscode.js';
@@ -0,0 +1,12 @@
1
+ import { Options } from 'sass';
2
+ import { Context } from '../../types/index.js';
3
+ export declare type StyleOptions = {
4
+ extensions?: Array<'scss' | 'css'>;
5
+ directory?: (context: Context) => string;
6
+ filename?: (context: Context) => string;
7
+ sass?: Options<'sync'>;
8
+ };
9
+ export declare const style: (options: StyleOptions) => {
10
+ name: string;
11
+ next: (context: Context) => void;
12
+ };
@@ -0,0 +1,42 @@
1
+ import t from '@babel/types';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import core from 'sass';
5
+ import * as CONSTANTS from '../../constants/index.js';
6
+ const defaults = {
7
+ extensions: ['scss', 'css'],
8
+ directory(context) {
9
+ return context.directoryPath;
10
+ },
11
+ filename(context) {
12
+ return context.fileName;
13
+ }
14
+ };
15
+ export const style = (options) => {
16
+ const name = 'style';
17
+ options = Object.assign(Object.assign({}, defaults), options);
18
+ const next = (context) => {
19
+ const filename = options.filename(context);
20
+ const directory = options.directory(context);
21
+ for (let extension of options.extensions) {
22
+ const stylePath = path.join(directory, `${filename}.${extension}`);
23
+ if (!fs.existsSync(stylePath))
24
+ continue;
25
+ context.stylePath = stylePath;
26
+ break;
27
+ }
28
+ if (!context.stylePath)
29
+ return;
30
+ const { css, loadedUrls } = core.compile(context.stylePath, Object.assign(Object.assign({}, (options.sass || {})), { style: 'compressed' }));
31
+ context.styleParsed = css.toString();
32
+ // TODO loadedUrls;
33
+ context.styleDependencies = [];
34
+ if (!context.styleParsed)
35
+ return;
36
+ context.class.body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_STYLES), t.stringLiteral(context.styleParsed), undefined, null, undefined, true));
37
+ };
38
+ return {
39
+ name,
40
+ next
41
+ };
42
+ };
@@ -1,6 +1,38 @@
1
+ import * as CONSTANTS from '../../constants/index.js';
2
+ import { hasDecorator, visitor } from '../utils/index.js';
1
3
  export const validate = () => {
2
4
  const name = 'validate';
3
- const next = (context) => { };
5
+ const next = (context) => {
6
+ let hasValidImport;
7
+ visitor(context.fileAST, {
8
+ ImportDeclaration(path) {
9
+ var _a;
10
+ if (((_a = path.node.source) === null || _a === void 0 ? void 0 : _a.value) !== CONSTANTS.PACKAGE_NAME)
11
+ return;
12
+ for (const specifier of path.node.specifiers) {
13
+ if (specifier.imported.name !== CONSTANTS.DECORATOR_ELEMENT)
14
+ continue;
15
+ hasValidImport = true;
16
+ path.stop();
17
+ }
18
+ }
19
+ });
20
+ let hasValidExport;
21
+ visitor(context.fileAST, {
22
+ ExportNamedDeclaration(path) {
23
+ if (hasValidExport) {
24
+ hasValidExport = false;
25
+ return path.stop();
26
+ }
27
+ if (path.node.declaration.type !== 'ClassDeclaration')
28
+ return;
29
+ if (!hasDecorator(path.node.declaration, CONSTANTS.DECORATOR_ELEMENT))
30
+ return;
31
+ hasValidExport = true;
32
+ }
33
+ });
34
+ context.isInvalid = !hasValidImport || !hasValidExport;
35
+ };
4
36
  return {
5
37
  name,
6
38
  next
@@ -1,3 +1,4 @@
1
+ export declare const PACKAGE_NAME = "@htmlplus/element";
1
2
  export declare const API_HOST = "$host$";
2
3
  export declare const API_READY = "$ready$";
3
4
  export declare const API_SETUP = "$setup$";
@@ -1,3 +1,4 @@
1
+ export const PACKAGE_NAME = '@htmlplus/element';
1
2
  // apis
2
3
  export const API_HOST = '$host$';
3
4
  export const API_READY = '$ready$';
@@ -1,5 +1,8 @@
1
1
  import { ClassBody, ClassDeclaration, ClassMethod, ClassProperty, File } from '@babel/types';
2
2
  export interface Context {
3
+ dependencies?: Array<Context>;
4
+ dependenciesUnresolved?: Array<string>;
5
+ isInvalid?: boolean;
3
6
  script?: string;
4
7
  componentClassName?: string;
5
8
  componentInterfaceName?: string;
@@ -0,0 +1,4 @@
1
+ import { Context } from './context.js';
2
+ export interface Global {
3
+ contexts: Array<Context>;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,4 @@
1
1
  export * from './context.js';
2
+ export * from './global.js';
2
3
  export * from './plugin.js';
3
4
  export * from './plus-element.js';
@@ -1,3 +1,4 @@
1
1
  export * from './context.js';
2
+ export * from './global.js';
2
3
  export * from './plugin.js';
3
4
  export * from './plus-element.js';
@@ -1,8 +1,9 @@
1
1
  import { Context } from './context.js';
2
+ import { Global } from './global';
2
3
  export declare type Return<T> = void | T | Promise<T>;
3
4
  export declare type Plugin = {
4
5
  name: string;
5
- start?: (global: any) => Return<any>;
6
- next?: (context: Context, global: any) => Return<Context>;
7
- finish?: (global: any) => Return<any>;
6
+ start?: (global: Global) => Return<Global>;
7
+ next?: (context: Context, global: Global) => Return<Context>;
8
+ finish?: (global: Global) => Return<Global>;
8
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlplus/element",
3
- "version": "0.1.8",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "author": "Masood Abdolian <m.abdolian@gmail.com>",
6
6
  "description": "Compiler of HTMLPlus",
@@ -12,8 +12,8 @@
12
12
  "postbuild": "node scripts/build.post.js",
13
13
  "clean": "rimraf dist",
14
14
  "format": "prettier --write .",
15
- "dev:start": "node src/dev/start.js",
16
- "dev:build": "node src/dev/build.js"
15
+ "dev:start": "node src/dev/scripts/start.js",
16
+ "dev:build": "node src/dev/scripts/build.js"
17
17
  },
18
18
  "exports": {
19
19
  ".": {
@@ -1,11 +0,0 @@
1
- import { Context } from '../../types/index.js';
2
- export interface AttachOptions {
3
- dependencies?: boolean;
4
- members?: boolean;
5
- styles?: boolean;
6
- typings?: boolean;
7
- }
8
- export declare const attach: (options: AttachOptions) => {
9
- name: string;
10
- next: (context: Context) => void;
11
- };
@@ -1,101 +0,0 @@
1
- import t from '@babel/types';
2
- import * as CONSTANTS from '../../configs/constants.js';
3
- import { visitor } from '../utils/index.js';
4
- const defaults = {
5
- dependencies: true,
6
- members: true,
7
- styles: true,
8
- typings: true
9
- };
10
- export const attach = (options) => {
11
- options = Object.assign({}, defaults, options);
12
- const name = 'attach';
13
- const next = (context) => {
14
- // TODO
15
- if (options.dependencies) {
16
- }
17
- if (options.styles && context.styleParsed)
18
- context.class.body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_STYLES), t.stringLiteral(context.styleParsed), undefined, null, undefined, true));
19
- if (options.members) {
20
- context.class.body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_MEMBERS), t.objectExpression([
21
- ...context.classProperties.map((property) => {
22
- var _a, _b;
23
- const type = (_b = (_a = property.typeAnnotation) === null || _a === void 0 ? void 0 : _a.typeAnnotation) === null || _b === void 0 ? void 0 : _b.type;
24
- const elements = [];
25
- switch (type) {
26
- case 'TSBooleanKeyword':
27
- elements.push(t.stringLiteral(CONSTANTS.TYPE_BOOLEAN));
28
- break;
29
- case 'TSStringKeyword':
30
- elements.push(t.stringLiteral(CONSTANTS.TYPE_STRING));
31
- break;
32
- case 'TSNumberKeyword':
33
- elements.push(t.stringLiteral(CONSTANTS.TYPE_NUMBER));
34
- break;
35
- default:
36
- elements.push(t.nullLiteral());
37
- break;
38
- }
39
- if (property.value)
40
- elements.push(property.value);
41
- return t.objectProperty(t.identifier(property.key['name']), t.arrayExpression(elements));
42
- }),
43
- ...context.classMethods.map((method) => {
44
- const elements = [t.stringLiteral(CONSTANTS.TYPE_FUNCTION)];
45
- return t.objectProperty(t.identifier(method.key['name']), t.arrayExpression(elements));
46
- })
47
- ]), undefined, undefined, undefined, true));
48
- }
49
- if (options.typings) {
50
- visitor(context.fileAST, {
51
- Program(path) {
52
- path.node.body.push(Object.assign(t.tsModuleDeclaration(t.identifier('global'), t.tsModuleBlock([
53
- t.tsInterfaceDeclaration(t.identifier(context.componentInterfaceName), null, [], t.tsInterfaceBody([
54
- ...context.classProperties.map((property) => Object.assign(t.tSPropertySignature(property.key, property.typeAnnotation), {
55
- optional: property.optional,
56
- leadingComments: property.leadingComments
57
- }))
58
- ])),
59
- t.variableDeclaration('var', [
60
- t.variableDeclarator(Object.assign(t.identifier(context.componentInterfaceName), {
61
- typeAnnotation: t.tSTypeAnnotation(t.tSTypeLiteral([
62
- t.tSPropertySignature(t.identifier('prototype'), t.tsTypeAnnotation(t.tSTypeReference(t.identifier(context.componentInterfaceName)))),
63
- t.tSConstructSignatureDeclaration(null, [], t.tSTypeAnnotation(t.tSTypeReference(t.identifier(context.componentInterfaceName))))
64
- ]))
65
- }))
66
- ]),
67
- t.tsInterfaceDeclaration(t.identifier('HTMLElementTagNameMap'), null, [], t.tsInterfaceBody([
68
- t.tSPropertySignature(t.stringLiteral(context.componentTag), t.tSTypeAnnotation(t.tSIntersectionType([t.tSTypeReference(t.identifier(context.componentInterfaceName))])))
69
- ]))
70
- ])), {
71
- declare: true,
72
- global: true
73
- }));
74
- path.node.body.push(t.exportNamedDeclaration(t.tsInterfaceDeclaration(
75
- // TODO
76
- t.identifier(context.componentClassName + 'JSX'), null, [], t.tsInterfaceBody([
77
- ...context.classProperties.map((property) => Object.assign(t.tSPropertySignature(property.key, property.typeAnnotation), {
78
- optional: property.optional,
79
- leadingComments: property.leadingComments
80
- })),
81
- ...context.classEvents.map((event) => {
82
- var _a, _b;
83
- return Object.assign(t.tSPropertySignature(event.key, t.tsTypeAnnotation(t.tsFunctionType(undefined, [
84
- Object.assign({}, t.identifier('event'), {
85
- typeAnnotation: t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CustomEvent'), (_b = (_a = event.typeAnnotation) === null || _a === void 0 ? void 0 : _a['typeAnnotation']) === null || _b === void 0 ? void 0 : _b.typeParameters))
86
- })
87
- ], t.tsTypeAnnotation(t.tsVoidKeyword())))), {
88
- optional: true,
89
- leadingComments: event.leadingComments
90
- });
91
- })
92
- ]))));
93
- }
94
- });
95
- }
96
- };
97
- return {
98
- name,
99
- next
100
- };
101
- };
@@ -1,11 +0,0 @@
1
- import { print as core } from '../utils/index.js';
2
- export const print = () => {
3
- const name = 'print';
4
- const next = (context) => {
5
- context.script = core(context.fileAST);
6
- };
7
- return {
8
- name,
9
- next
10
- };
11
- };
@@ -1 +0,0 @@
1
- export * from './react.proxy.js';
@@ -1 +0,0 @@
1
- export * from './react.proxy.js';
@@ -1,11 +0,0 @@
1
- export interface ReactProxyOptions {
2
- compact?: boolean;
3
- dist: string;
4
- eventName?: (eventName: string) => string;
5
- importerComponent?: (context: any) => string;
6
- importerComponentType?: (context: any) => string;
7
- }
8
- export declare const reactProxy: (options: ReactProxyOptions) => {
9
- name: string;
10
- finish: (global: any) => void;
11
- };
@@ -1,6 +0,0 @@
1
- import core from 'sass';
2
- import { Context } from '../../types/index.js';
3
- export declare const sass: (options?: core.Options<"sync"> | undefined) => {
4
- name: string;
5
- next: (context: Context) => void;
6
- };
@@ -1,15 +0,0 @@
1
- import core from 'sass';
2
- export const sass = (options) => {
3
- const name = 'sass';
4
- const next = (context) => {
5
- if (!context.stylePath)
6
- return;
7
- const { css, loadedUrls } = core.compile(context.stylePath, Object.assign(Object.assign({}, (options || {})), { style: 'compressed' }));
8
- context.styleParsed = css.toString();
9
- context.styleDependencies = []; // TODO loadedUrls;
10
- };
11
- return {
12
- name,
13
- next
14
- };
15
- };
@@ -1,5 +0,0 @@
1
- import { Context } from '../../types/index.js';
2
- export declare const uhtml: () => {
3
- name: string;
4
- next: (context: Context) => void;
5
- };
@@ -1,59 +0,0 @@
1
- import t from '@babel/types';
2
- import { print, visitor } from '../utils/index.js';
3
- export const uhtml = () => {
4
- const name = 'uhtml';
5
- const next = (context) => {
6
- context.fileAST.program.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier('html'), t.identifier('html'))], t.stringLiteral('@htmlplus/element/runtime')));
7
- visitor(context.fileAST, {
8
- JSXAttribute: {
9
- exit(path) {
10
- var _a;
11
- if (((_a = path.node.value) === null || _a === void 0 ? void 0 : _a.type) == 'JSXExpressionContainer') {
12
- let node = path.node;
13
- if (path.node.name.name == 'ref') {
14
- node = t.jsxAttribute(path.node.name, t.jSXExpressionContainer(t.arrowFunctionExpression([t.identifier('$element')], t.assignmentExpression('=', path.node.value.expression, t.identifier('$element')))));
15
- }
16
- path.replaceWith(t.jsxIdentifier(print(node).replace('={', '=${')));
17
- path.skip();
18
- return;
19
- }
20
- }
21
- },
22
- JSXElement: {
23
- exit(path) {
24
- if (path.parent.type == 'JSXElement' || path.parent.type == 'JSXFragment') {
25
- path.replaceWith(t.identifier(print(path.node)));
26
- return;
27
- }
28
- else {
29
- path.replaceWith(t.identifier('html`' + print(path.node) + '`'));
30
- return;
31
- }
32
- }
33
- },
34
- JSXFragment: {
35
- exit(path) {
36
- path.replaceWith(t.identifier(['html`', ...path.node.children.map((child) => print(child)), '`'].join('')));
37
- }
38
- },
39
- JSXExpressionContainer: {
40
- exit(path) {
41
- if (path.parent.type == 'JSXElement' || path.parent.type == 'JSXFragment') {
42
- path.replaceWith(t.identifier('$' + print(path.node)));
43
- return;
44
- }
45
- }
46
- },
47
- JSXSpreadAttribute: {
48
- enter(path) {
49
- // TODO
50
- path.replaceWith(t.jsxAttribute(t.jsxIdentifier('.dataset'), t.jsxExpressionContainer(path.node.argument)));
51
- }
52
- }
53
- });
54
- };
55
- return {
56
- name,
57
- next
58
- };
59
- };