@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.
- package/README.md +22 -16
- package/dist/compiler/babel-plugin.d.ts +4 -0
- package/dist/compiler/babel-plugin.d.ts.map +1 -0
- package/dist/compiler/babel-plugin.js +20 -0
- package/dist/compiler/babel-plugin.js.map +1 -0
- package/dist/compiler/babel-traverse.d.ts +3 -0
- package/dist/compiler/babel-traverse.d.ts.map +1 -0
- package/dist/compiler/babel-traverse.js +7 -0
- package/dist/compiler/babel-traverse.js.map +1 -0
- package/dist/compiler/compiler-utils.d.ts +3 -2
- package/dist/compiler/compiler-utils.d.ts.map +1 -1
- package/dist/compiler/compiler-utils.js +25 -23
- package/dist/compiler/compiler-utils.js.map +1 -1
- package/dist/compiler/config.d.ts +5 -1
- package/dist/compiler/config.d.ts.map +1 -1
- package/dist/compiler/config.js +2 -2
- package/dist/compiler/config.js.map +1 -1
- package/dist/compiler/create-logger.d.ts +3 -0
- package/dist/compiler/create-logger.d.ts.map +1 -0
- package/dist/compiler/create-logger.js +32 -0
- package/dist/compiler/create-logger.js.map +1 -0
- package/dist/compiler/import-discovery.d.ts +43 -4
- package/dist/compiler/import-discovery.d.ts.map +1 -1
- package/dist/compiler/import-discovery.js +306 -160
- package/dist/compiler/import-discovery.js.map +1 -1
- package/dist/compiler/preprocess.d.ts +1 -1
- package/dist/compiler/preprocess.d.ts.map +1 -1
- package/dist/compiler/preprocess.js +5 -4
- package/dist/compiler/preprocess.js.map +1 -1
- package/dist/compiler/transpiler.js +4 -4
- package/dist/compiler/transpiler.js.map +1 -1
- package/dist/compiler/vite-plugin.d.ts +1 -0
- package/dist/compiler/vite-plugin.d.ts.map +1 -1
- package/dist/compiler/vite-plugin.js +11 -15
- package/dist/compiler/vite-plugin.js.map +1 -1
- package/dist/runtime/type-helpers.d.ts +24 -36
- package/dist/runtime/type-helpers.d.ts.map +1 -1
- package/dist/runtime/type-helpers.js +22 -34
- package/dist/runtime/type-helpers.js.map +1 -1
- package/package.json +6 -3
- package/src/compiler/babel-plugin.ts +23 -0
- package/src/compiler/babel-traverse.ts +7 -0
- package/src/compiler/compiler-utils.ts +35 -25
- package/src/compiler/config.ts +7 -2
- package/src/compiler/create-logger.ts +35 -0
- package/src/compiler/import-discovery.ts +381 -202
- package/src/compiler/preprocess.ts +9 -7
- package/src/compiler/transpiler.ts +4 -4
- package/src/compiler/vite-plugin.ts +18 -24
- package/src/runtime/type-helpers.ts +24 -36
- package/dist/compiler/babel-preset.d.ts +0 -6
- package/dist/compiler/babel-preset.d.ts.map +0 -1
- package/dist/compiler/babel-preset.js +0 -27
- package/dist/compiler/babel-preset.js.map +0 -1
- 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 {
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
39
|
-
path.traverse(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 {
|
|
24
|
+
import { deepmerge } from 'deepmerge-ts';
|
|
25
25
|
import type { PluginOption } from 'vite';
|
|
26
26
|
|
|
27
|
-
import {
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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 =
|
|
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
|
|
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 {
|
|
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
|
-
*
|
|
13
|
+
* const MyButtonComponent = toComponent(MyButton);
|
|
14
|
+
*
|
|
15
|
+
* // Usage in JSX - compiler automatically detects this as a custom element
|
|
19
16
|
* const jsx = (
|
|
20
|
-
* <
|
|
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
|
|
24
|
+
export const toComponent = <T extends { new(...args: any): any; tagName: string; }>(
|
|
28
25
|
element: T,
|
|
29
|
-
):
|
|
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
|
|
40
|
+
export type ToComponent<T extends object> = (props: JSX.JSXProps<T>) => string;
|
|
44
41
|
|
|
45
42
|
|
|
46
43
|
/**
|
|
47
|
-
* Creates a dynamic tag
|
|
48
|
-
*
|
|
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
|
-
* //
|
|
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
|
|
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
|
|
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
|
|
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
|
-
* // ❌
|
|
77
|
-
* const
|
|
78
|
-
* return <
|
|
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
|
-
* //
|
|
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
|
|
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
|
|
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
|
-
):
|
|
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
|
-
};
|