@arcmantle/lit-jsx 1.0.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.
- package/README.md +768 -0
- package/dist/compiler/attribute-processor.d.ts +128 -0
- package/dist/compiler/attribute-processor.d.ts.map +1 -0
- package/dist/compiler/attribute-processor.js +380 -0
- package/dist/compiler/attribute-processor.js.map +1 -0
- package/dist/compiler/babel-preset.d.ts +6 -0
- package/dist/compiler/babel-preset.d.ts.map +1 -0
- package/dist/compiler/babel-preset.js +27 -0
- package/dist/compiler/babel-preset.js.map +1 -0
- package/dist/compiler/builder.d.ts +22 -0
- package/dist/compiler/builder.d.ts.map +1 -0
- package/dist/compiler/builder.js +62 -0
- package/dist/compiler/builder.js.map +1 -0
- package/dist/compiler/compiler-utils.d.ts +81 -0
- package/dist/compiler/compiler-utils.d.ts.map +1 -0
- package/dist/compiler/compiler-utils.js +410 -0
- package/dist/compiler/compiler-utils.js.map +1 -0
- package/dist/compiler/config.d.ts +77 -0
- package/dist/compiler/config.d.ts.map +1 -0
- package/dist/compiler/config.js +78 -0
- package/dist/compiler/config.js.map +1 -0
- package/dist/compiler/postprocess.d.ts +5 -0
- package/dist/compiler/postprocess.d.ts.map +1 -0
- package/dist/compiler/postprocess.js +3 -0
- package/dist/compiler/postprocess.js.map +1 -0
- package/dist/compiler/preprocess.d.ts +5 -0
- package/dist/compiler/preprocess.d.ts.map +1 -0
- package/dist/compiler/preprocess.js +28 -0
- package/dist/compiler/preprocess.js.map +1 -0
- package/dist/compiler/transform-jsx.d.ts +5 -0
- package/dist/compiler/transform-jsx.d.ts.map +1 -0
- package/dist/compiler/transform-jsx.js +25 -0
- package/dist/compiler/transform-jsx.js.map +1 -0
- package/dist/compiler/transpiler.d.ts +48 -0
- package/dist/compiler/transpiler.d.ts.map +1 -0
- package/dist/compiler/transpiler.js +463 -0
- package/dist/compiler/transpiler.js.map +1 -0
- package/dist/compiler/vite-plugin.d.ts +38 -0
- package/dist/compiler/vite-plugin.d.ts.map +1 -0
- package/dist/compiler/vite-plugin.js +96 -0
- package/dist/compiler/vite-plugin.js.map +1 -0
- package/dist/runtime/choose-component.d.ts +39 -0
- package/dist/runtime/choose-component.d.ts.map +1 -0
- package/dist/runtime/choose-component.js +40 -0
- package/dist/runtime/choose-component.js.map +1 -0
- package/dist/runtime/compiler-ctors.d.ts +21 -0
- package/dist/runtime/compiler-ctors.d.ts.map +1 -0
- package/dist/runtime/compiler-ctors.js +21 -0
- package/dist/runtime/compiler-ctors.js.map +1 -0
- package/dist/runtime/for-component.d.ts +25 -0
- package/dist/runtime/for-component.d.ts.map +1 -0
- package/dist/runtime/for-component.js +35 -0
- package/dist/runtime/for-component.js.map +1 -0
- package/dist/runtime/literal-map.d.ts +22 -0
- package/dist/runtime/literal-map.d.ts.map +1 -0
- package/dist/runtime/literal-map.js +29 -0
- package/dist/runtime/literal-map.js.map +1 -0
- package/dist/runtime/rest-directive.d.ts +28 -0
- package/dist/runtime/rest-directive.d.ts.map +1 -0
- package/dist/runtime/rest-directive.js +49 -0
- package/dist/runtime/rest-directive.js.map +1 -0
- package/dist/runtime/show-component.d.ts +33 -0
- package/dist/runtime/show-component.d.ts.map +1 -0
- package/dist/runtime/show-component.js +30 -0
- package/dist/runtime/show-component.js.map +1 -0
- package/dist/runtime/tagged-template.d.ts +12 -0
- package/dist/runtime/tagged-template.d.ts.map +1 -0
- package/dist/runtime/tagged-template.js +12 -0
- package/dist/runtime/tagged-template.js.map +1 -0
- package/dist/runtime/type-helpers.d.ts +80 -0
- package/dist/runtime/type-helpers.d.ts.map +1 -0
- package/dist/runtime/type-helpers.js +85 -0
- package/dist/runtime/type-helpers.js.map +1 -0
- package/dist/shared/jsx-types.d.ts +2139 -0
- package/dist/shared/jsx-types.d.ts.map +1 -0
- package/dist/shared/jsx-types.js +2 -0
- package/dist/shared/jsx-types.js.map +1 -0
- package/dist/shared/jsx-utils.d.ts +30 -0
- package/dist/shared/jsx-utils.d.ts.map +1 -0
- package/dist/shared/jsx-utils.js +58 -0
- package/dist/shared/jsx-utils.js.map +1 -0
- package/dist/shared/mathml-tags.d.ts +12 -0
- package/dist/shared/mathml-tags.d.ts.map +1 -0
- package/dist/shared/mathml-tags.js +215 -0
- package/dist/shared/mathml-tags.js.map +1 -0
- package/dist/shared/svg-tags.d.ts +13 -0
- package/dist/shared/svg-tags.d.ts.map +1 -0
- package/dist/shared/svg-tags.js +95 -0
- package/dist/shared/svg-tags.js.map +1 -0
- package/dist/utils.d.ts +30 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +30 -0
- package/dist/utils.js.map +1 -0
- package/package.json +52 -0
- package/src/compiler/attribute-processor.ts +579 -0
- package/src/compiler/babel-preset.ts +34 -0
- package/src/compiler/builder.ts +86 -0
- package/src/compiler/compiler-utils.ts +789 -0
- package/src/compiler/config.ts +77 -0
- package/src/compiler/postprocess.ts +7 -0
- package/src/compiler/preprocess.ts +40 -0
- package/src/compiler/transform-jsx.ts +36 -0
- package/src/compiler/transpiler.ts +644 -0
- package/src/compiler/vite-plugin.ts +114 -0
- package/src/external.d.ts +9 -0
- package/src/runtime/choose-component.ts +53 -0
- package/src/runtime/compiler-ctors.ts +28 -0
- package/src/runtime/for-component.ts +54 -0
- package/src/runtime/literal-map.ts +37 -0
- package/src/runtime/rest-directive.ts +66 -0
- package/src/runtime/show-component.ts +48 -0
- package/src/runtime/tagged-template.ts +11 -0
- package/src/runtime/type-helpers.ts +91 -0
- package/src/shared/jsx-types.ts +2556 -0
- package/src/shared/jsx-utils.ts +85 -0
- package/src/shared/mathml-tags.ts +235 -0
- package/src/shared/svg-tags.ts +103 -0
- package/src/tsconfig.json +4 -0
- package/src/utils.ts +30 -0
package/dist/utils.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Main entrypoint for jsx-lit runtime utilities and components.
|
|
3
|
+
*
|
|
4
|
+
* This module provides all the runtime utilities needed for jsx-lit compiled templates,
|
|
5
|
+
* including helper components for conditional rendering, iteration, and template composition.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { Choose, For, Show } from "@arcmantle/lit-jsx";
|
|
10
|
+
*
|
|
11
|
+
* function MyComponent() {
|
|
12
|
+
* return (
|
|
13
|
+
* <div>
|
|
14
|
+
* <Show when={condition}>
|
|
15
|
+
* <p>Conditionally rendered content</p>
|
|
16
|
+
* </Show>
|
|
17
|
+
* </div>
|
|
18
|
+
* );
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export * from './runtime/choose-component.js';
|
|
23
|
+
export * from './runtime/compiler-ctors.js';
|
|
24
|
+
export * from './runtime/for-component.js';
|
|
25
|
+
export * from './runtime/literal-map.js';
|
|
26
|
+
export * from './runtime/rest-directive.js';
|
|
27
|
+
export * from './runtime/show-component.js';
|
|
28
|
+
export * from './runtime/tagged-template.js';
|
|
29
|
+
export * from './runtime/type-helpers.js';
|
|
30
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arcmantle/lit-jsx",
|
|
3
|
+
"description": "A JSX runtime and compiler that transforms JSX into Lit templates.",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"contributors": [
|
|
6
|
+
"Kristoffer Roen-Lie"
|
|
7
|
+
],
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/arcmantle/lit-jsx.git"
|
|
11
|
+
},
|
|
12
|
+
"version": "1.0.0",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./dist/react-jsx/jsx-runtime.js",
|
|
19
|
+
"types": "./dist/shared/jsx-types.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./dist/utils.js",
|
|
22
|
+
"./jsx-runtime": "./dist/shared/jsx-types.d.ts",
|
|
23
|
+
"./jsx-dev-runtime": "./dist/shared/jsx-types.d.ts",
|
|
24
|
+
"./vite": "./dist/compiler/vite-plugin.js"
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@babel/core": "^7.20.12",
|
|
29
|
+
"@babel/plugin-syntax-jsx": "^7.18.6",
|
|
30
|
+
"@babel/traverse": "^7.27.4",
|
|
31
|
+
"@babel/types": "^7.27.6",
|
|
32
|
+
"@types/babel__core": "^7.20.5",
|
|
33
|
+
"@types/babel__traverse": "^7.20.7",
|
|
34
|
+
"csstype": "^3.1.3",
|
|
35
|
+
"merge-anything": "^6.0.6",
|
|
36
|
+
"validate-html-nesting": "^1.2.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@arcmantle/tsconfig": "^1.0.0",
|
|
40
|
+
"@types/node": "^24.0.10",
|
|
41
|
+
"lit-html": "^3.3.0",
|
|
42
|
+
"rimraf": "^6.0.1",
|
|
43
|
+
"typescript": "^5.8.3",
|
|
44
|
+
"vite": "^7.0.0",
|
|
45
|
+
"vitest": "^3.2.4"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"dev": "vite build --watch --mode=development",
|
|
49
|
+
"test": "pnpm vitest run",
|
|
50
|
+
"build": "rimraf dist && tsc --project ./src/tsconfig.json"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import type { NodePath } from '@babel/traverse';
|
|
2
|
+
import * as t from '@babel/types';
|
|
3
|
+
import { PartType } from 'lit-html/directive.js';
|
|
4
|
+
|
|
5
|
+
import type { EnsureImport, Values } from './compiler-utils.js';
|
|
6
|
+
import {
|
|
7
|
+
ATTR_BIND_OBJ_NAME,
|
|
8
|
+
ATTR_NAMES,
|
|
9
|
+
ATTR_VALUES,
|
|
10
|
+
ERROR_MESSAGES,
|
|
11
|
+
VARIABLES,
|
|
12
|
+
} from './config.js';
|
|
13
|
+
import type { CompiledContext, TemplateContext } from './transpiler.js';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
interface CallBindingAttribute extends t.JSXAttribute {
|
|
17
|
+
value: t.JSXExpressionContainer & {
|
|
18
|
+
expression: t.CallExpression & {
|
|
19
|
+
callee: t.MemberExpression & {
|
|
20
|
+
object: t.Identifier;
|
|
21
|
+
property: t.Identifier;
|
|
22
|
+
};
|
|
23
|
+
arguments: [ t.Expression ];
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ArrowFunctionAttribute extends t.JSXAttribute {
|
|
29
|
+
value: t.JSXExpressionContainer & {
|
|
30
|
+
expression: t.ArrowFunctionExpression & {
|
|
31
|
+
params: [ t.Identifier & { name: Values<typeof ATTR_VALUES>; } ];
|
|
32
|
+
body: t.Expression;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface JSXAttributeWithExpression extends t.JSXAttribute {
|
|
38
|
+
value: t.JSXExpressionContainer & {
|
|
39
|
+
expression: t.Expression;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface JSXAttributeWithoutExpression extends t.JSXAttribute {
|
|
44
|
+
value: Exclude<t.JSXAttribute['value'], t.JSXExpressionContainer>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface JSXAttributeBoolean extends t.JSXAttribute {
|
|
48
|
+
value: null | undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface ValueBinding {
|
|
52
|
+
type: 'prop' | 'bool';
|
|
53
|
+
name: string;
|
|
54
|
+
expression: t.Expression;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export class AttributeValidators {
|
|
59
|
+
|
|
60
|
+
static isCallBinding(attr: t.JSXAttribute): attr is CallBindingAttribute {
|
|
61
|
+
if (!this.isExpression(attr))
|
|
62
|
+
return false;
|
|
63
|
+
|
|
64
|
+
const expression = attr.value.expression;
|
|
65
|
+
|
|
66
|
+
if (!t.isCallExpression(expression))
|
|
67
|
+
return false;
|
|
68
|
+
|
|
69
|
+
const callee = expression.callee;
|
|
70
|
+
if (!t.isMemberExpression(callee))
|
|
71
|
+
return false;
|
|
72
|
+
|
|
73
|
+
if (!t.isIdentifier(callee.object) || !t.isIdentifier(callee.property))
|
|
74
|
+
return false;
|
|
75
|
+
|
|
76
|
+
const objectNameMatches = callee.object.name === ATTR_BIND_OBJ_NAME;
|
|
77
|
+
if (!objectNameMatches)
|
|
78
|
+
return false;
|
|
79
|
+
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static isArrowBinding(attr: t.JSXAttribute): attr is ArrowFunctionAttribute {
|
|
84
|
+
if (!this.isExpression(attr))
|
|
85
|
+
return false;
|
|
86
|
+
|
|
87
|
+
const expression = attr.value.expression;
|
|
88
|
+
|
|
89
|
+
if (!t.isArrowFunctionExpression(expression))
|
|
90
|
+
return false;
|
|
91
|
+
|
|
92
|
+
// If the arrow function has no parameters, we can skip it.
|
|
93
|
+
if (expression.params.length === 0)
|
|
94
|
+
return false;
|
|
95
|
+
|
|
96
|
+
// If the arrow function has more than one parameter, we can skip it.
|
|
97
|
+
if (expression.params.length > 1)
|
|
98
|
+
return false;
|
|
99
|
+
|
|
100
|
+
// If the param is not an identifier, we can skip it.
|
|
101
|
+
const param = expression.params[0];
|
|
102
|
+
if (!t.isIdentifier(param))
|
|
103
|
+
return false;
|
|
104
|
+
|
|
105
|
+
// If the body of the arrow function is not an expression, we can skip it.
|
|
106
|
+
if (!t.isExpression(expression.body))
|
|
107
|
+
return false;
|
|
108
|
+
|
|
109
|
+
// We check if it is a valid bind parameter.
|
|
110
|
+
return param.name === ATTR_VALUES.PROP
|
|
111
|
+
|| param.name === ATTR_VALUES.BOOL;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static isDirective(attr: t.JSXAttribute): attr is JSXAttributeWithExpression {
|
|
115
|
+
return this.isExpression(attr) && attr.name.name.toString() === ATTR_NAMES.DIRECTIVE;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static isRef(attr: t.JSXAttribute): attr is JSXAttributeWithExpression {
|
|
119
|
+
return this.isExpression(attr) && attr.name.name.toString() === ATTR_NAMES.REF;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static isClassListBinding(attr: t.JSXAttribute): attr is JSXAttributeWithExpression {
|
|
123
|
+
return this.isExpression(attr) && attr.name.name.toString() === ATTR_NAMES.CLASS_LIST;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static isStyleListBinding(attr: t.JSXAttribute): attr is JSXAttributeWithExpression {
|
|
127
|
+
return this.isExpression(attr) && attr.name.name.toString() === ATTR_NAMES.STYLE_LIST;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static isEvent(attr: t.JSXAttribute): attr is JSXAttributeWithExpression {
|
|
131
|
+
return attr.name.name.toString().startsWith(ATTR_NAMES.EVENT_PREFIX);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static isExpression(attr: t.JSXAttribute): attr is JSXAttributeWithExpression {
|
|
135
|
+
return t.isJSXExpressionContainer(attr.value)
|
|
136
|
+
&& t.isExpression(attr.value.expression);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
static isNonExpression(attribute: t.JSXAttribute): attribute is JSXAttributeWithoutExpression {
|
|
140
|
+
return !!attribute.value && !t.isJSXExpressionContainer(attribute.value);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
static isSpread(attr: t.JSXAttribute | t.JSXSpreadAttribute): attr is t.JSXSpreadAttribute {
|
|
144
|
+
return t.isJSXSpreadAttribute(attr);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static isBoolean(attr: t.JSXAttribute): attr is JSXAttributeBoolean {
|
|
148
|
+
return !attr.value;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
export interface ProcessorContext {
|
|
155
|
+
builder: unknown;
|
|
156
|
+
program: t.Program;
|
|
157
|
+
path: NodePath<t.JSXElement | t.JSXFragment>;
|
|
158
|
+
tagName: string;
|
|
159
|
+
isInitialElement: boolean;
|
|
160
|
+
importsUsed: Set<keyof Omit<typeof EnsureImport, 'prototype'>>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
abstract class AttributeProcessor<TContext extends ProcessorContext> {
|
|
165
|
+
|
|
166
|
+
abstract callBinding(attr: CallBindingAttribute, context: TContext): void;
|
|
167
|
+
abstract arrowBinding(attr: ArrowFunctionAttribute, context: TContext): void;
|
|
168
|
+
abstract directive(attr: JSXAttributeWithExpression, context: TContext): void;
|
|
169
|
+
abstract ref(attr: JSXAttributeWithExpression, context: TContext): void;
|
|
170
|
+
abstract classList(attr: JSXAttributeWithExpression, context: TContext): void;
|
|
171
|
+
abstract styleList(attr: JSXAttributeWithExpression, context: TContext): void;
|
|
172
|
+
abstract event(attr: JSXAttributeWithExpression, context: TContext): void;
|
|
173
|
+
abstract expression(attr: JSXAttributeWithExpression, context: TContext): void;
|
|
174
|
+
abstract nonExpression(attr: JSXAttributeWithoutExpression, context: TContext): void;
|
|
175
|
+
abstract spread(attr: t.JSXSpreadAttribute, context: TContext): void;
|
|
176
|
+
abstract boolean(attr: JSXAttributeBoolean, context: TContext): void;
|
|
177
|
+
|
|
178
|
+
processAttribute(attr: t.JSXAttribute | t.JSXSpreadAttribute, context: TContext): void {
|
|
179
|
+
if (AttributeValidators.isSpread(attr))
|
|
180
|
+
this.spread(attr, context);
|
|
181
|
+
else if (AttributeValidators.isNonExpression(attr))
|
|
182
|
+
this.nonExpression(attr, context);
|
|
183
|
+
else if (AttributeValidators.isBoolean(attr))
|
|
184
|
+
this.boolean(attr, context);
|
|
185
|
+
|
|
186
|
+
// Expression attributes are checked based on their type.
|
|
187
|
+
// Order is based on a guess as to which expression is more common.
|
|
188
|
+
else if (AttributeValidators.isEvent(attr))
|
|
189
|
+
this.event(attr, context);
|
|
190
|
+
else if (AttributeValidators.isArrowBinding(attr))
|
|
191
|
+
this.arrowBinding(attr, context);
|
|
192
|
+
else if (AttributeValidators.isCallBinding(attr))
|
|
193
|
+
this.callBinding(attr, context);
|
|
194
|
+
else if (AttributeValidators.isClassListBinding(attr))
|
|
195
|
+
this.classList(attr, context);
|
|
196
|
+
else if (AttributeValidators.isStyleListBinding(attr))
|
|
197
|
+
this.styleList(attr, context);
|
|
198
|
+
else if (AttributeValidators.isRef(attr))
|
|
199
|
+
this.ref(attr, context);
|
|
200
|
+
else if (AttributeValidators.isDirective(attr))
|
|
201
|
+
this.directive(attr, context);
|
|
202
|
+
|
|
203
|
+
// Generic expression attributes are checked last
|
|
204
|
+
// because this condition will be true for all expression attributes.
|
|
205
|
+
// and we want the more specific cases to be checked first.
|
|
206
|
+
else if (AttributeValidators.isExpression(attr))
|
|
207
|
+
this.expression(attr, context);
|
|
208
|
+
else
|
|
209
|
+
throw new Error(ERROR_MESSAGES.UNKNOWN_JSX_ATTRIBUTE_TYPE);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
protected createValueBinding(
|
|
213
|
+
attr: CallBindingAttribute | ArrowFunctionAttribute,
|
|
214
|
+
context: TContext,
|
|
215
|
+
): ValueBinding {
|
|
216
|
+
const expression = attr.value.expression;
|
|
217
|
+
|
|
218
|
+
let isProp: boolean = false;
|
|
219
|
+
let isBool: boolean = false;
|
|
220
|
+
let expressionBody: t.Expression;
|
|
221
|
+
|
|
222
|
+
if (t.isCallExpression(expression)) {
|
|
223
|
+
isProp = expression.callee.property.name === ATTR_VALUES.PROP;
|
|
224
|
+
isBool = expression.callee.property.name === ATTR_VALUES.BOOL;
|
|
225
|
+
expressionBody = expression.arguments[0];
|
|
226
|
+
}
|
|
227
|
+
else if (t.isArrowFunctionExpression(expression)) {
|
|
228
|
+
const param = expression.params[0];
|
|
229
|
+
isProp = param.name === ATTR_VALUES.PROP;
|
|
230
|
+
isBool = param.name === ATTR_VALUES.BOOL;
|
|
231
|
+
expressionBody = expression.body;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
throw new Error(ERROR_MESSAGES.INVALID_DIRECTIVE_VALUE);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (isProp) {
|
|
238
|
+
return {
|
|
239
|
+
type: 'prop',
|
|
240
|
+
name: attr.name.name.toString(),
|
|
241
|
+
expression: expressionBody,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
else if (isBool) {
|
|
245
|
+
return {
|
|
246
|
+
type: 'bool',
|
|
247
|
+
name: attr.name.name.toString(),
|
|
248
|
+
expression: expressionBody,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
throw new Error(ERROR_MESSAGES.INVALID_DIRECTIVE_VALUE);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
protected createDirective(attr: JSXAttributeWithExpression, context: TContext): t.Expression[] {
|
|
257
|
+
// Replace the spread attribute with its argument, minus the compiler func.
|
|
258
|
+
const expression = attr.value.expression;
|
|
259
|
+
|
|
260
|
+
// If the expression is a call, we can add it directly.
|
|
261
|
+
if (t.isCallExpression(expression))
|
|
262
|
+
return [ expression ];
|
|
263
|
+
// If the expression is an array, we can add each item.
|
|
264
|
+
else if (t.isArrayExpression(expression))
|
|
265
|
+
return expression.elements.filter(item => t.isExpression(item));
|
|
266
|
+
else
|
|
267
|
+
throw new Error(ERROR_MESSAGES.INVALID_DIRECTIVE_VALUE);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
protected createRef(attr: JSXAttributeWithExpression, context: TContext): t.CallExpression {
|
|
271
|
+
context.importsUsed.add('createRef');
|
|
272
|
+
|
|
273
|
+
// add a ref call around the expression.
|
|
274
|
+
const expression = t.callExpression(
|
|
275
|
+
t.identifier(VARIABLES.REF),
|
|
276
|
+
[ attr.value.expression ],
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
return expression;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
protected createClassList(attr: JSXAttributeWithExpression, context: TContext): t.CallExpression {
|
|
283
|
+
context.importsUsed.add('classMap');
|
|
284
|
+
|
|
285
|
+
// add a classMap call around the expression.
|
|
286
|
+
const expression = t.callExpression(
|
|
287
|
+
t.identifier(VARIABLES.CLASS_MAP),
|
|
288
|
+
[ attr.value.expression ],
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
return expression;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
protected createStyleList(attr: JSXAttributeWithExpression, context: TContext): t.CallExpression {
|
|
295
|
+
context.importsUsed.add('styleMap');
|
|
296
|
+
|
|
297
|
+
// add a styleMap call around the expression.
|
|
298
|
+
const expression = t.callExpression(
|
|
299
|
+
t.identifier(VARIABLES.STYLE_MAP),
|
|
300
|
+
[ attr.value.expression ],
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
return expression;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
protected createEvent(attr: JSXAttributeWithExpression, context: TContext): [ string, t.Expression ] {
|
|
307
|
+
return [ attr.name.name.toString().slice(3), attr.value.expression ];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
protected createExpression(attr: JSXAttributeWithExpression, context: TContext): [string, t.Expression] {
|
|
311
|
+
return [ attr.name.name.toString(), attr.value.expression ];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
protected createNonExpression(attr: JSXAttributeWithoutExpression, context: TContext): [string, string] {
|
|
315
|
+
// If the value is a string, we can use it directly
|
|
316
|
+
// Here we always bind the value as a string.
|
|
317
|
+
// In the future, we might want to also support numbers.
|
|
318
|
+
if (!t.isStringLiteral(attr.value))
|
|
319
|
+
throw new Error(ERROR_MESSAGES.ONLY_STRING_LITERALS);
|
|
320
|
+
|
|
321
|
+
return [ attr.name.name.toString(), attr.value.value ];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
protected createSpread(attr: t.JSXSpreadAttribute, context: TContext): t.CallExpression {
|
|
325
|
+
context.importsUsed.add('rest');
|
|
326
|
+
|
|
327
|
+
// If it's a spread attribute, we wrap it in our custom `rest` directive.
|
|
328
|
+
// This will allow us to handle the spread attribute correctly.
|
|
329
|
+
// We also need to ensure that the `rest` directive is imported.
|
|
330
|
+
return t.callExpression(
|
|
331
|
+
t.identifier(VARIABLES.REST),
|
|
332
|
+
[ attr.argument ],
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
protected createBoolean(attr: JSXAttributeBoolean, context: TContext): string {
|
|
337
|
+
// If the value is null or undefined, we can bind the attribute name directly.
|
|
338
|
+
// This will result in a attribute without a value, e.g. `<div disabled>`.
|
|
339
|
+
return attr.name.name.toString();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export class TemplateAttributeProcessor extends AttributeProcessor<TemplateContext> {
|
|
345
|
+
|
|
346
|
+
callBinding(attr: CallBindingAttribute, context: TemplateContext): void {
|
|
347
|
+
this.valueBinding(attr, context);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
arrowBinding(attr: ArrowFunctionAttribute, context: TemplateContext): void {
|
|
351
|
+
this.valueBinding(attr, context);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
directive(attr: JSXAttributeWithExpression, context: TemplateContext): void {
|
|
355
|
+
for (const expression of this.createDirective(attr, context)) {
|
|
356
|
+
context.builder.addText(' ');
|
|
357
|
+
context.builder.addExpression(expression);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
ref(attr: JSXAttributeWithExpression, context: TemplateContext): void {
|
|
362
|
+
const expression = this.createRef(attr, context);
|
|
363
|
+
|
|
364
|
+
// add a space to keep correct spacing in the template.
|
|
365
|
+
context.builder.addText(' ');
|
|
366
|
+
context.builder.addExpression(expression);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
classList(attr: JSXAttributeWithExpression, context: TemplateContext): void {
|
|
370
|
+
const expression = this.createClassList(attr, context);
|
|
371
|
+
|
|
372
|
+
context.builder.addText(' class=');
|
|
373
|
+
context.builder.addExpression(expression);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
styleList(attr: JSXAttributeWithExpression, context: TemplateContext): void {
|
|
377
|
+
const expression = this.createStyleList(attr, context);
|
|
378
|
+
|
|
379
|
+
context.builder.addText(' ' + 'style=');
|
|
380
|
+
context.builder.addExpression(expression);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
event(attr: JSXAttributeWithExpression, context: TemplateContext): void {
|
|
384
|
+
const [ name, expression ] = this.createEvent(attr, context);
|
|
385
|
+
|
|
386
|
+
context.builder.addText(' @' + name + '=');
|
|
387
|
+
context.builder.addExpression(expression);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
expression(attr: JSXAttributeWithExpression, context: TemplateContext): void {
|
|
391
|
+
const [ name, expression ] = this.createExpression(attr, context);
|
|
392
|
+
|
|
393
|
+
context.builder.addText(' ' + name + '=');
|
|
394
|
+
context.builder.addExpression(expression);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
nonExpression(attr: JSXAttributeWithoutExpression, context: TemplateContext): void {
|
|
398
|
+
const [ name, value ] = this.createNonExpression(attr, context);
|
|
399
|
+
|
|
400
|
+
context.builder.addText(' ' + name + '="' + value + '"');
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
spread(attribute: t.JSXSpreadAttribute, context: TemplateContext): void {
|
|
404
|
+
const expression = this.createSpread(attribute, context);
|
|
405
|
+
|
|
406
|
+
context.builder.addText(' ');
|
|
407
|
+
context.builder.addExpression(expression);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
boolean(attribute: JSXAttributeBoolean, context: TemplateContext): void {
|
|
411
|
+
const name = this.createBoolean(attribute, context);
|
|
412
|
+
|
|
413
|
+
context.builder.addText(' ' + name);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
protected valueBinding(
|
|
417
|
+
attr: CallBindingAttribute | ArrowFunctionAttribute,
|
|
418
|
+
context: TemplateContext,
|
|
419
|
+
): void {
|
|
420
|
+
const { type, name, expression } = this.createValueBinding(attr, context);
|
|
421
|
+
|
|
422
|
+
if (type === 'prop')
|
|
423
|
+
context.builder.addText(' .');
|
|
424
|
+
else if (type === 'bool')
|
|
425
|
+
context.builder.addText(' ?');
|
|
426
|
+
|
|
427
|
+
context.builder.addText(name + '=');
|
|
428
|
+
context.builder.addExpression(expression);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export class CompiledAttributeProcessor extends AttributeProcessor<CompiledContext> {
|
|
434
|
+
|
|
435
|
+
callBinding(attr: CallBindingAttribute, context: CompiledContext): void {
|
|
436
|
+
this.valueBinding(attr, context);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
arrowBinding(attr: ArrowFunctionAttribute, context: CompiledContext): void {
|
|
440
|
+
this.valueBinding(attr, context);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
directive(attr: JSXAttributeWithExpression, context: CompiledContext): void {
|
|
444
|
+
for (const expression of this.createDirective(attr, context)) {
|
|
445
|
+
context.builder.addPart(CreateCompiledPart.element(context.currentIndex));
|
|
446
|
+
context.builder.addValue(expression);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
ref(attr: JSXAttributeWithExpression, context: CompiledContext): void {
|
|
451
|
+
const expression = this.createRef(attr, context);
|
|
452
|
+
|
|
453
|
+
context.builder.addPart(CreateCompiledPart.element(context.currentIndex));
|
|
454
|
+
context.builder.addValue(expression);
|
|
455
|
+
context.importsUsed.add('createRef');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
classList(attr: JSXAttributeWithExpression, context: CompiledContext): void {
|
|
459
|
+
const expression = this.createClassList(attr, context);
|
|
460
|
+
|
|
461
|
+
context.builder.addPart(CreateCompiledPart.attribute(context.currentIndex, 'class'));
|
|
462
|
+
context.builder.addValue(expression);
|
|
463
|
+
context.importsUsed.add('attributePart');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
styleList(attr: JSXAttributeWithExpression, context: CompiledContext): void {
|
|
467
|
+
const expression = this.createStyleList(attr, context);
|
|
468
|
+
|
|
469
|
+
context.builder.addPart(CreateCompiledPart.attribute(context.currentIndex, 'style'));
|
|
470
|
+
context.builder.addValue(expression);
|
|
471
|
+
context.importsUsed.add('attributePart');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
event(attr: JSXAttributeWithExpression, context: CompiledContext): void {
|
|
475
|
+
const [ name, expression ] = this.createEvent(attr, context);
|
|
476
|
+
|
|
477
|
+
context.builder.addPart(CreateCompiledPart.event(context.currentIndex, name));
|
|
478
|
+
context.builder.addValue(expression);
|
|
479
|
+
context.importsUsed.add('eventPart');
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
expression(attr: JSXAttributeWithExpression, context: CompiledContext): void {
|
|
483
|
+
const [ name, expression ] = this.createExpression(attr, context);
|
|
484
|
+
|
|
485
|
+
context.builder.addPart(CreateCompiledPart.attribute(context.currentIndex, name));
|
|
486
|
+
context.builder.addValue(expression);
|
|
487
|
+
context.importsUsed.add('attributePart');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
nonExpression(attr: JSXAttributeWithoutExpression, context: CompiledContext): void {
|
|
491
|
+
const [ name, value ] = this.createNonExpression(attr, context);
|
|
492
|
+
|
|
493
|
+
context.builder.addText(' ' + name + '="' + value + '"');
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
spread(attr: t.JSXSpreadAttribute, context: CompiledContext): void {
|
|
497
|
+
const expression = this.createSpread(attr, context);
|
|
498
|
+
|
|
499
|
+
context.builder.addPart(CreateCompiledPart.element(context.currentIndex));
|
|
500
|
+
context.builder.addValue(expression);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
boolean(attr: JSXAttributeBoolean, context: CompiledContext): void {
|
|
504
|
+
const name = this.createBoolean(attr, context);
|
|
505
|
+
|
|
506
|
+
context.builder.addText(' ' + name);
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
protected valueBinding(
|
|
510
|
+
attr: CallBindingAttribute | ArrowFunctionAttribute,
|
|
511
|
+
context: CompiledContext,
|
|
512
|
+
): void {
|
|
513
|
+
const { type, name, expression } = this.createValueBinding(attr, context);
|
|
514
|
+
|
|
515
|
+
if (type === 'prop') {
|
|
516
|
+
context.builder.addPart(CreateCompiledPart.property(context.currentIndex, name));
|
|
517
|
+
context.builder.addValue(expression);
|
|
518
|
+
context.importsUsed.add('propertyPart');
|
|
519
|
+
}
|
|
520
|
+
else if (type === 'bool') {
|
|
521
|
+
context.builder.addPart(CreateCompiledPart.boolean(context.currentIndex, name));
|
|
522
|
+
context.builder.addValue(expression);
|
|
523
|
+
context.importsUsed.add('booleanPart');
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
export class CreateCompiledPart {
|
|
531
|
+
|
|
532
|
+
protected static createBasePart(type: PartType, index: number): t.ObjectProperty[] {
|
|
533
|
+
return [
|
|
534
|
+
t.objectProperty(t.stringLiteral('type'), t.numericLiteral(type)),
|
|
535
|
+
t.objectProperty(t.stringLiteral('index'), t.numericLiteral(index)),
|
|
536
|
+
];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
protected static createAttributePart(
|
|
540
|
+
index: number,
|
|
541
|
+
name: string,
|
|
542
|
+
ctor: string,
|
|
543
|
+
): t.ObjectExpression {
|
|
544
|
+
return t.objectExpression([
|
|
545
|
+
...this.createBasePart(PartType.ATTRIBUTE, index),
|
|
546
|
+
t.objectProperty(t.stringLiteral('name'), t.stringLiteral(name)),
|
|
547
|
+
t.objectProperty(t.stringLiteral('strings'), t.arrayExpression([
|
|
548
|
+
t.stringLiteral(''),
|
|
549
|
+
t.stringLiteral(''),
|
|
550
|
+
])),
|
|
551
|
+
t.objectProperty(t.stringLiteral('ctor'), t.identifier(ctor)),
|
|
552
|
+
]);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
static child(index: number): t.ObjectExpression {
|
|
556
|
+
return t.objectExpression(this.createBasePart(PartType.CHILD, index));
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
static element(index: number): t.ObjectExpression {
|
|
560
|
+
return t.objectExpression(this.createBasePart(PartType.ELEMENT, index));
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
static attribute(index: number, name: string): t.ObjectExpression {
|
|
564
|
+
return this.createAttributePart(index, name, VARIABLES.ATTRIBUTE_PART);
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
static property(index: number, name: string): t.ObjectExpression {
|
|
568
|
+
return this.createAttributePart(index, name, VARIABLES.PROPERTY_PART);
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
static boolean(index: number, name: string): t.ObjectExpression {
|
|
572
|
+
return this.createAttributePart(index, name, VARIABLES.BOOLEAN_PART);
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
static event(index: number, name: string): t.ObjectExpression {
|
|
576
|
+
return this.createAttributePart(index, name, VARIABLES.EVENT_PART);
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
};
|