@arcmantle/lit-jsx 1.0.6 → 1.0.8

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 (55) hide show
  1. package/README.md +22 -16
  2. package/dist/compiler/babel-plugin.d.ts +4 -0
  3. package/dist/compiler/babel-plugin.d.ts.map +1 -0
  4. package/dist/compiler/babel-plugin.js +20 -0
  5. package/dist/compiler/babel-plugin.js.map +1 -0
  6. package/dist/compiler/babel-traverse.d.ts +3 -0
  7. package/dist/compiler/babel-traverse.d.ts.map +1 -0
  8. package/dist/compiler/babel-traverse.js +7 -0
  9. package/dist/compiler/babel-traverse.js.map +1 -0
  10. package/dist/compiler/compiler-utils.d.ts +3 -2
  11. package/dist/compiler/compiler-utils.d.ts.map +1 -1
  12. package/dist/compiler/compiler-utils.js +25 -23
  13. package/dist/compiler/compiler-utils.js.map +1 -1
  14. package/dist/compiler/config.d.ts +5 -1
  15. package/dist/compiler/config.d.ts.map +1 -1
  16. package/dist/compiler/config.js +2 -2
  17. package/dist/compiler/config.js.map +1 -1
  18. package/dist/compiler/create-logger.d.ts +3 -0
  19. package/dist/compiler/create-logger.d.ts.map +1 -0
  20. package/dist/compiler/create-logger.js +32 -0
  21. package/dist/compiler/create-logger.js.map +1 -0
  22. package/dist/compiler/import-discovery.d.ts +43 -4
  23. package/dist/compiler/import-discovery.d.ts.map +1 -1
  24. package/dist/compiler/import-discovery.js +306 -160
  25. package/dist/compiler/import-discovery.js.map +1 -1
  26. package/dist/compiler/preprocess.d.ts +1 -1
  27. package/dist/compiler/preprocess.d.ts.map +1 -1
  28. package/dist/compiler/preprocess.js +5 -4
  29. package/dist/compiler/preprocess.js.map +1 -1
  30. package/dist/compiler/transpiler.js +4 -4
  31. package/dist/compiler/transpiler.js.map +1 -1
  32. package/dist/compiler/vite-plugin.d.ts +1 -0
  33. package/dist/compiler/vite-plugin.d.ts.map +1 -1
  34. package/dist/compiler/vite-plugin.js +11 -15
  35. package/dist/compiler/vite-plugin.js.map +1 -1
  36. package/dist/runtime/type-helpers.d.ts +24 -36
  37. package/dist/runtime/type-helpers.d.ts.map +1 -1
  38. package/dist/runtime/type-helpers.js +22 -34
  39. package/dist/runtime/type-helpers.js.map +1 -1
  40. package/package.json +6 -3
  41. package/src/compiler/babel-plugin.ts +23 -0
  42. package/src/compiler/babel-traverse.ts +7 -0
  43. package/src/compiler/compiler-utils.ts +35 -25
  44. package/src/compiler/config.ts +7 -2
  45. package/src/compiler/create-logger.ts +35 -0
  46. package/src/compiler/import-discovery.ts +381 -202
  47. package/src/compiler/preprocess.ts +9 -7
  48. package/src/compiler/transpiler.ts +4 -4
  49. package/src/compiler/vite-plugin.ts +18 -24
  50. package/src/runtime/type-helpers.ts +24 -36
  51. package/dist/compiler/babel-preset.d.ts +0 -6
  52. package/dist/compiler/babel-preset.d.ts.map +0 -1
  53. package/dist/compiler/babel-preset.js +0 -27
  54. package/dist/compiler/babel-preset.js.map +0 -1
  55. package/src/compiler/babel-preset.ts +0 -34
@@ -1,14 +1,16 @@
1
1
  import type { PluginPass } from '@babel/core';
2
- import type { VisitNodeFunction } from '@babel/traverse';
3
- import { isJSXElement, isJSXIdentifier, type Program } from '@babel/types';
2
+ import type { NodePath, VisitNodeFunction } from '@babel/traverse';
3
+ import type { JSXElement, Program } from '@babel/types';
4
+ import { isJSXElement, isJSXIdentifier } from '@babel/types';
4
5
  import { isValidHTMLNesting } from 'validate-html-nesting';
5
6
 
6
7
  import { isComponent } from './compiler-utils.js';
7
8
 
8
9
 
9
- // From https://github.com/MananTank/babel-plugin-validate-jsx-nesting/blob/main/src/index.js
10
- const JSXValidator = {
11
- JSXElement(path: any) {
10
+ const preprocessVisitors = {
11
+ // From https://github.com/MananTank/babel-plugin-validate-jsx-nesting/blob/main/src/index.js
12
+ // Validates JSX nesting based on HTML5 rules.
13
+ JSXElement(path: NodePath<JSXElement>) {
12
14
  const elName = path.node.openingElement.name;
13
15
  const parent = path.parent;
14
16
 
@@ -35,6 +37,6 @@ const JSXValidator = {
35
37
  };
36
38
 
37
39
 
38
- export const preprocess: VisitNodeFunction<PluginPass, Program> = (path, state): void => {
39
- path.traverse(JSXValidator);
40
+ export const preprocess: VisitNodeFunction<PluginPass, Program> = (path): void => {
41
+ path.traverse(preprocessVisitors);
40
42
  };
@@ -92,7 +92,7 @@ export class TemplateTranspiler extends JSXTranspiler<TemplateContext> {
92
92
 
93
93
  context.tagName = getJSXElementName(context.path.node);
94
94
 
95
- if (isJSXCustomElementComponent(context.tagName)) {
95
+ if (isJSXCustomElementComponent(context.path)) {
96
96
  this.openingTag(context);
97
97
  this.attributes(context);
98
98
  this.children(context);
@@ -101,7 +101,7 @@ export class TemplateTranspiler extends JSXTranspiler<TemplateContext> {
101
101
  return;
102
102
  }
103
103
 
104
- if (isJSXFunctionElementComponent(context.tagName)) {
104
+ if (isJSXFunctionElementComponent(context.path)) {
105
105
  // Process attributes and children into a props object
106
106
  if (!context.isInitialElement)
107
107
  return this.functionalComponent(context);
@@ -118,7 +118,7 @@ export class TemplateTranspiler extends JSXTranspiler<TemplateContext> {
118
118
  }
119
119
 
120
120
  override openingTag(context: TemplateContext): void {
121
- if (isJSXCustomElementComponent(context.tagName)) {
121
+ if (isJSXCustomElementComponent(context.path)) {
122
122
  const literalIdentifier = Ensure.componentLiteral(
123
123
  context.tagName,
124
124
  COMPONENT_LITERAL_PREFIX + context.tagName,
@@ -414,7 +414,7 @@ export class CompiledTranspiler extends JSXTranspiler<CompiledContext> {
414
414
 
415
415
  context.tagName = getJSXElementName(context.path.node);
416
416
 
417
- if (isJSXFunctionElementComponent(context.tagName)) {
417
+ if (isJSXFunctionElementComponent(context.path)) {
418
418
  // Process attributes and children into a props object
419
419
  if (!context.isInitialElement)
420
420
  return this.functionalComponent(context);
@@ -21,13 +21,12 @@
21
21
  */
22
22
 
23
23
  import * as babel from '@babel/core';
24
- import { mergeAndConcat } from 'merge-anything';
24
+ import { deepmerge } from 'deepmerge-ts';
25
25
  import type { PluginOption } from 'vite';
26
26
 
27
- import { litJsxBabelPreset } from './babel-preset.js';
28
-
29
-
30
- type BabelPlugins = NonNullable<NonNullable<babel.TransformOptions['parserOpts']>['plugins']>;
27
+ import { litJsxBabelPlugin } from './babel-plugin.js';
28
+ import { babelPlugins, debugMode } from './config.js';
29
+ import { ImportDiscovery } from './import-discovery.js';
31
30
 
32
31
 
33
32
  /**
@@ -41,6 +40,7 @@ type BabelPlugins = NonNullable<NonNullable<babel.TransformOptions['parserOpts']
41
40
  * @returns Vite plugin configuration
42
41
  */
43
42
  export const litJsx = (options: {
43
+ debug?: boolean; // Enable debug mode for additional logging
44
44
  /** Options for the Babel transform */
45
45
  babel?:
46
46
  | babel.TransformOptions
@@ -48,6 +48,8 @@ export const litJsx = (options: {
48
48
  } = {}): PluginOption => {
49
49
  let projectRoot: string;
50
50
 
51
+ debugMode.value = !!options.debug;
52
+
51
53
  return {
52
54
  name: 'lit-jsx-preserve',
53
55
  config: {
@@ -63,10 +65,6 @@ export const litJsx = (options: {
63
65
  },
64
66
  order: 'pre',
65
67
  async handler(source, id) {
66
- const plugins: BabelPlugins = [ 'jsx', 'decorators', 'decoratorAutoAccessors' ];
67
- if (id.endsWith('.tsx'))
68
- plugins.push('typescript');
69
-
70
68
  // Default value for babel user options
71
69
  let babelUserOptions: babel.TransformOptions = {};
72
70
 
@@ -86,29 +84,25 @@ export const litJsx = (options: {
86
84
  root: projectRoot,
87
85
  filename: id,
88
86
  sourceFileName: id,
89
- presets: [
90
- [
91
- litJsxBabelPreset,
92
- /* merged into the metadata obj through state.opts */
93
- {},
94
- ],
95
- ],
96
- plugins: [],
97
- ast: false,
98
- sourceMaps: true,
99
- configFile: false,
100
- babelrc: false,
101
- parserOpts: {
102
- plugins,
87
+ plugins: [ litJsxBabelPlugin() ],
88
+ ast: false,
89
+ sourceMaps: true,
90
+ configFile: false,
91
+ babelrc: false,
92
+ parserOpts: {
93
+ plugins: babelPlugins,
103
94
  },
104
95
  };
105
96
 
106
- const opts = mergeAndConcat(babelUserOptions, babelOptions);
97
+ const opts = deepmerge(babelUserOptions, babelOptions);
107
98
  const result = await babel.transformAsync(source, opts);
108
99
 
109
100
  if (result?.code)
110
101
  return { code: result.code, map: result.map };
111
102
  },
112
103
  },
104
+ hotUpdate(options) {
105
+ ImportDiscovery.clearCacheForFileAndDependents(options.file);
106
+ },
113
107
  };
114
108
  };
@@ -1,32 +1,29 @@
1
1
  /**
2
- * Creates a variable which can be used using the Component syntax in JSX.
2
+ * Creates a component that can be used directly in JSX syntax.
3
3
  * Also registers the custom element if it hasn't been registered yet.
4
4
  *
5
5
  * @example
6
6
  * ```tsx
7
- * import { toJSX } from 'jsx-lit';
7
+ * import { toComponent } from 'jsx-lit';
8
8
  *
9
9
  * export class MyButton extends LitElement {
10
10
  * static tagName = 'my-button';
11
- * static tag = toJSX(MyButton);
12
- *
13
- * render() {
14
- * return html`<button><slot></slot></button>`;
15
- * }
16
11
  * }
17
12
  *
18
- * // Usage in JSX
13
+ * const MyButtonComponent = toComponent(MyButton);
14
+ *
15
+ * // Usage in JSX - compiler automatically detects this as a custom element
19
16
  * const jsx = (
20
- * <MyButton.tag
17
+ * <MyButtonComponent
21
18
  * class="my-button"
22
19
  * on-click={() => { console.log('Clicked!'); }}
23
20
  * />
24
21
  * );
25
22
  * ```
26
23
  */
27
- export const toJSX = <T extends { new(...args: any): any; tagName: string; }>(
24
+ export const toComponent = <T extends { new(...args: any): any; tagName: string; }>(
28
25
  element: T,
29
- ): ToJSX<InstanceType<T>> => {
26
+ ): ToComponent<InstanceType<T>> => {
30
27
  if (!element.tagName)
31
28
  throw new Error('Element must have a static tagName property');
32
29
 
@@ -40,57 +37,48 @@ export const toJSX = <T extends { new(...args: any): any; tagName: string; }>(
40
37
  return element.tagName as any;
41
38
  };
42
39
 
43
- export type ToJSX<T extends object> = (props: JSX.JSXProps<T>) => string;
40
+ export type ToComponent<T extends object> = (props: JSX.JSXProps<T>) => string;
44
41
 
45
42
 
46
43
  /**
47
- * Creates a dynamic tag name object that can be used with jsx-lit's Component syntax.
48
- * This function is required for dynamic tag names to compile to static literals.
49
- *
50
- * **IMPORTANT**: Dynamic tag names must use the `.tag` property pattern to be properly
51
- * compiled to lit-html static templates. Without this pattern, jsx-lit cannot detect
52
- * and transform the dynamic tag name into efficient static template literals.
44
+ * Creates a dynamic tag that can be used directly in JSX syntax.
45
+ * The compiler automatically detects when this helper is used and compiles
46
+ * it to efficient static lit-html templates.
53
47
  *
54
48
  * @example
55
49
  * ```tsx
56
50
  * import { toTag } from 'jsx-lit';
57
51
  *
58
- * // Correct usage - creates { tag: 'div' } object
52
+ * // Creates a dynamic tag that the compiler will recognize
59
53
  * const DynamicDiv = toTag('div');
60
54
  * const DynamicCustomElement = toTag('my-custom-element');
61
55
  *
62
- * // Usage in JSX with .tag property (required for compilation)
56
+ * // Usage in JSX - compiler automatically handles the transformation
63
57
  * function renderConditional({ useDiv }) {
64
58
  * const Tag = toTag(useDiv ? 'div' : 'span');
65
- * return <Tag.tag class="dynamic">Content</Tag.tag>;
59
+ * return <Tag class="dynamic">Content</Tag>;
66
60
  * }
67
61
  *
68
- * // Compiles to efficient static templates:
62
+ * // Compiles to efficient static templates automatically:
69
63
  * // const Tag = toTag(useDiv ? 'div' : 'span');
70
- * // const __$Tag = __$literalMap.get(Tag.tag);
64
+ * // const __$Tag = __$literalMap.get(Tag);
71
65
  * // htmlStatic`<${__$Tag} class="dynamic">Content</${__$Tag}>`
72
66
  * ```
73
67
  *
74
68
  * @example
75
69
  * ```tsx
76
- * // ❌ Incorrect usage - won't compile to static templates
77
- * const badTag = 'div';
78
- * return <badTag>Content</badTag>; // This won't work with jsx-lit
70
+ * // ❌ Without toTag helper - won't compile to static templates
71
+ * const BadTag = 'div';
72
+ * return <BadTag>Content</BadTag>; // This won't work with jsx-lit
79
73
  *
80
- * // Incorrect usage - missing .tag property
81
- * const BadTag = toTag('div');
82
- * return <BadTag>Content</BadTag>; // Won't compile correctly
83
- *
84
- * // ✅ Correct usage - with .tag property
74
+ * // With toTag helper - compiler automatically optimizes
85
75
  * const GoodTag = toTag('div');
86
- * return <GoodTag.tag>Content</GoodTag.tag>; // Compiles to static templates
76
+ * return <GoodTag>Content</GoodTag>; // Compiles to static templates
87
77
  * ```
88
78
  *
89
79
  * @param tag - The HTML tag name (standard HTML elements or custom element names)
90
- * @returns An object with a `tag` property containing the tag name, designed for use with jsx-lit's Component syntax
80
+ * @returns A tag identifier that the compiler recognizes for optimization
91
81
  */
92
82
  export const toTag = <T extends keyof HTMLElementTagNameMap | (string & {})>(
93
83
  tag: T,
94
- ): { tag: T; } => {
95
- return { tag } as any;
96
- };
84
+ ): T => tag;
@@ -1,6 +0,0 @@
1
- import type { PluginObj, PluginOptions } from '@babel/core';
2
- /** Compiles jsx to a combination of standard and compiled lit-html */
3
- export declare const litJsxBabelPreset: (context: any, options?: {}) => {
4
- plugins: [PluginObj, PluginOptions][];
5
- };
6
- //# sourceMappingURL=babel-preset.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"babel-preset.d.ts","sourceRoot":"","sources":["../../src/compiler/babel-preset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ5D,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,GAC7B,SAAS,GAAG,EACZ,YAAY,KACV;IAAE,OAAO,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,EAAE,CAAC;CAqB1C,CAAC"}
@@ -1,27 +0,0 @@
1
- import SyntaxJSX from '@babel/plugin-syntax-jsx';
2
- import { postprocess } from './postprocess.js';
3
- import { preprocess } from './preprocess.js';
4
- import { transformJSXElement } from './transform-jsx.js';
5
- /** Compiles jsx to a combination of standard and compiled lit-html */
6
- export const litJsxBabelPreset = (context, options = {}) => {
7
- return {
8
- plugins: [
9
- [
10
- {
11
- name: 'lit-jsx-transform',
12
- inherits: SyntaxJSX.default,
13
- visitor: {
14
- JSXElement: transformJSXElement,
15
- JSXFragment: transformJSXElement,
16
- Program: {
17
- enter: preprocess,
18
- exit: postprocess,
19
- },
20
- },
21
- },
22
- Object.assign({}, options),
23
- ],
24
- ],
25
- };
26
- };
27
- //# sourceMappingURL=babel-preset.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"babel-preset.js","sourceRoot":"","sources":["../../src/compiler/babel-preset.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,0BAA0B,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,OAAY,EACZ,OAAO,GAAG,EAAE,EACiC,EAAE;IAC/C,OAAO;QACN,OAAO,EAAE;YACR;gBACC;oBACC,IAAI,EAAM,mBAAmB;oBAC7B,QAAQ,EAAE,SAAS,CAAC,OAAO;oBAC3B,OAAO,EAAG;wBACT,UAAU,EAAG,mBAAmB;wBAChC,WAAW,EAAE,mBAAmB;wBAChC,OAAO,EAAM;4BACZ,KAAK,EAAE,UAAU;4BACjB,IAAI,EAAG,WAAW;yBAClB;qBACD;iBACD;gBACD,MAAM,CAAC,MAAM,CAAC,EACb,EAAE,OAAO,CAAC;aACX;SACD;KACD,CAAC;AACH,CAAC,CAAC"}
@@ -1,34 +0,0 @@
1
- import type { PluginObj, PluginOptions } from '@babel/core';
2
- import SyntaxJSX from '@babel/plugin-syntax-jsx';
3
-
4
- import { postprocess } from './postprocess.js';
5
- import { preprocess } from './preprocess.js';
6
- import { transformJSXElement } from './transform-jsx.js';
7
-
8
-
9
- /** Compiles jsx to a combination of standard and compiled lit-html */
10
- export const litJsxBabelPreset = (
11
- context: any,
12
- options = {},
13
- ): { plugins: [PluginObj, PluginOptions][]; } => {
14
- return {
15
- plugins: [
16
- [
17
- {
18
- name: 'lit-jsx-transform',
19
- inherits: SyntaxJSX.default,
20
- visitor: {
21
- JSXElement: transformJSXElement,
22
- JSXFragment: transformJSXElement,
23
- Program: {
24
- enter: preprocess,
25
- exit: postprocess,
26
- },
27
- },
28
- },
29
- Object.assign({
30
- }, options),
31
- ],
32
- ],
33
- };
34
- };