@katabatic/compiler 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 +3 -0
- package/package.json +32 -0
- package/src/analyse/context.js +31 -0
- package/src/analyse/index.js +47 -0
- package/src/analyse/visitors/AssignmentExpression.js +14 -0
- package/src/analyse/visitors/Attribute.js +11 -0
- package/src/analyse/visitors/CallExpression.js +36 -0
- package/src/analyse/visitors/ClassBody.js +20 -0
- package/src/analyse/visitors/ClassDeclaration.js +5 -0
- package/src/analyse/visitors/CustomElement.js +10 -0
- package/src/analyse/visitors/EachBlock.js +10 -0
- package/src/analyse/visitors/Element.js +16 -0
- package/src/analyse/visitors/ExpressionTag.js +9 -0
- package/src/analyse/visitors/IfBlock.js +16 -0
- package/src/analyse/visitors/ImportDeclaration.js +35 -0
- package/src/analyse/visitors/MethodDefinition.js +17 -0
- package/src/analyse/visitors/Program.js +24 -0
- package/src/analyse/visitors/PropertyDefinition.js +12 -0
- package/src/analyse/visitors/Selector.js +23 -0
- package/src/analyse/visitors/Template.js +14 -0
- package/src/builders.js +1663 -0
- package/src/checkers.js +120 -0
- package/src/css-matcher.js +100 -0
- package/src/css-transform.js +21 -0
- package/src/css.js +65 -0
- package/src/exp-matcher.js +65 -0
- package/src/id-matcher.js +17 -0
- package/src/index.js +19 -0
- package/src/module-matcher.js +17 -0
- package/src/parser/attributes.js +66 -0
- package/src/parser/each-block.js +73 -0
- package/src/parser/element.js +115 -0
- package/src/parser/expression.js +44 -0
- package/src/parser/if-block.js +71 -0
- package/src/parser/index.js +10 -0
- package/src/parser/parser.js +259 -0
- package/src/parser/root.js +33 -0
- package/src/parser/script.js +59 -0
- package/src/parser/style.js +57 -0
- package/src/parser/template.js +30 -0
- package/src/parser/tokentype.js +75 -0
- package/src/router/html.js +18 -0
- package/src/router/index.js +130 -0
- package/src/transform/context.js +74 -0
- package/src/transform/index.js +52 -0
- package/src/transform/static/index.js +40 -0
- package/src/transform/static/visitors/Attribute.js +27 -0
- package/src/transform/static/visitors/EachBlock.js +23 -0
- package/src/transform/static/visitors/Element.js +17 -0
- package/src/transform/static/visitors/ExpressionTag.js +6 -0
- package/src/transform/static/visitors/IfBlock.js +28 -0
- package/src/transform/static/visitors/Program.js +10 -0
- package/src/transform/static/visitors/Script.js +9 -0
- package/src/transform/static/visitors/SlotElement.js +8 -0
- package/src/transform/static/visitors/Style.js +9 -0
- package/src/transform/static/visitors/Template.js +12 -0
- package/src/transform/static/visitors/Text.js +5 -0
- package/src/transform/visitors/AssignmentExpression.js +7 -0
- package/src/transform/visitors/Attribute.js +79 -0
- package/src/transform/visitors/CallExpression.js +17 -0
- package/src/transform/visitors/ClassBody.js +36 -0
- package/src/transform/visitors/CustomElement.js +43 -0
- package/src/transform/visitors/EachBlock.js +39 -0
- package/src/transform/visitors/Element.js +49 -0
- package/src/transform/visitors/ExpressionTag.js +6 -0
- package/src/transform/visitors/Fragment.js +42 -0
- package/src/transform/visitors/Identifier.js +10 -0
- package/src/transform/visitors/IfBlock.js +55 -0
- package/src/transform/visitors/ImportDeclaration.js +21 -0
- package/src/transform/visitors/MethodDefinition.js +115 -0
- package/src/transform/visitors/Program.js +65 -0
- package/src/transform/visitors/PropertyDefinition.js +7 -0
- package/src/transform/visitors/Selector.js +41 -0
- package/src/transform/visitors/Style.js +11 -0
- package/src/transform/visitors/Template.js +44 -0
- package/src/transform/visitors/Text.js +5 -0
- package/src/utils/misc.js +9 -0
- package/src/utils/template.js +15 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
import { appendText } from '../../utils/template.js'
|
|
3
|
+
import { nextElementId, pathStmt } from '../context.js'
|
|
4
|
+
|
|
5
|
+
export function EachBlock(node, ctx) {
|
|
6
|
+
const template = { text: [''], expressions: [] }
|
|
7
|
+
const init = { elem: [], text: [], binding: [] }
|
|
8
|
+
const effects = []
|
|
9
|
+
const animates = []
|
|
10
|
+
const handlers = []
|
|
11
|
+
const blocks = []
|
|
12
|
+
|
|
13
|
+
ctx.visit(node.body, { ...ctx.state, template, init, effects, animates, handlers, blocks })
|
|
14
|
+
|
|
15
|
+
const stmts1 = [
|
|
16
|
+
b.declaration('template', b.createElement('template')),
|
|
17
|
+
b.assignment(b.innerHTML('template'), b.template(template))
|
|
18
|
+
]
|
|
19
|
+
const stmts2 = [
|
|
20
|
+
...init.elem,
|
|
21
|
+
...init.text,
|
|
22
|
+
...init.binding,
|
|
23
|
+
...effects,
|
|
24
|
+
...animates,
|
|
25
|
+
...handlers,
|
|
26
|
+
...blocks
|
|
27
|
+
]
|
|
28
|
+
const stmt3 = b.insertBefore('anchor', b.member('template', 'content'))
|
|
29
|
+
|
|
30
|
+
const anchorId = nextElementId(ctx)
|
|
31
|
+
const bodyStmt = [...stmts1, ...stmts2, stmt3]
|
|
32
|
+
const expressionStmt = ctx.visit(node.expression)
|
|
33
|
+
const anchorStmt = b.declaration(anchorId, pathStmt(ctx, node))
|
|
34
|
+
const blockStmt = b.eachBlock(anchorId, expressionStmt, node.context, node.key, bodyStmt)
|
|
35
|
+
|
|
36
|
+
ctx.state.init.elem.push(anchorStmt)
|
|
37
|
+
ctx.state.blocks.push(blockStmt)
|
|
38
|
+
appendText(ctx.state.template, '<!-- -->')
|
|
39
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
import { appendText } from '../../utils/template.js'
|
|
3
|
+
import { nextBindingId, nextElementId, pathStmt } from '../context.js'
|
|
4
|
+
|
|
5
|
+
export function Element(node, ctx) {
|
|
6
|
+
let attributes = node.attributes
|
|
7
|
+
if (node.metadata?.isScoped && !node.metadata?.hasClass) {
|
|
8
|
+
attributes = [...attributes, b.attribute('class', '', { isScoped: true })]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const changed = []
|
|
12
|
+
|
|
13
|
+
let elementId
|
|
14
|
+
function getElementId() {
|
|
15
|
+
if (!elementId) {
|
|
16
|
+
elementId = nextElementId(ctx)
|
|
17
|
+
console.log('ELEM')
|
|
18
|
+
const stmt = b.declaration(elementId, pathStmt(ctx))
|
|
19
|
+
ctx.state.init.elem.push(stmt)
|
|
20
|
+
}
|
|
21
|
+
return elementId
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let bindingId
|
|
25
|
+
function getBindingId() {
|
|
26
|
+
if (!bindingId && node.metadata?.hasBinding) {
|
|
27
|
+
bindingId = nextBindingId(ctx)
|
|
28
|
+
const stmt = b.declaration(bindingId, {
|
|
29
|
+
...node.metadata?.bindExpression,
|
|
30
|
+
arguments: [getElementId(), ...node.metadata?.bindExpression.arguments]
|
|
31
|
+
})
|
|
32
|
+
ctx.state.init.binding.push(stmt)
|
|
33
|
+
}
|
|
34
|
+
return bindingId
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
appendText(ctx.state.template, `<${node.name}`)
|
|
38
|
+
for (const attribute of attributes) {
|
|
39
|
+
ctx.visit(attribute, { ...ctx.state, getElementId, getBindingId, changed })
|
|
40
|
+
}
|
|
41
|
+
appendText(ctx.state.template, '>')
|
|
42
|
+
ctx.visit(node.fragment, { ...ctx.state, getElementId })
|
|
43
|
+
appendText(ctx.state.template, `</${node.name}>`)
|
|
44
|
+
|
|
45
|
+
if (changed.length > 0) {
|
|
46
|
+
const stmt = b.addEventListener(bindingId, 'changed', changed)
|
|
47
|
+
ctx.state.handlers.push(stmt)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
import { appendText, hasExpression, isEmpty } from '../../utils/template.js'
|
|
3
|
+
import { nextTextId, pathStmt } from '../context.js'
|
|
4
|
+
|
|
5
|
+
export function Fragment(node, ctx) {
|
|
6
|
+
let template = { text: [''], expressions: [] }
|
|
7
|
+
let textNode
|
|
8
|
+
|
|
9
|
+
for (const child of node.nodes) {
|
|
10
|
+
switch (child.type) {
|
|
11
|
+
case 'Text':
|
|
12
|
+
case 'ExpressionTag':
|
|
13
|
+
textNode = child
|
|
14
|
+
ctx.visit(child, { template, analysis: ctx.state.analysis })
|
|
15
|
+
break
|
|
16
|
+
default:
|
|
17
|
+
finalize()
|
|
18
|
+
ctx.visit(child)
|
|
19
|
+
break
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
finalize()
|
|
23
|
+
|
|
24
|
+
function finalize() {
|
|
25
|
+
if (hasExpression(template)) {
|
|
26
|
+
const textId = nextTextId(ctx)
|
|
27
|
+
const textStmt = b.declaration(textId, pathStmt(ctx, [node, textNode]))
|
|
28
|
+
ctx.state.init.text.push(textStmt)
|
|
29
|
+
|
|
30
|
+
const effectStmt = b.$effect([
|
|
31
|
+
b.assignment(b.textContent(textId), b.template(template))
|
|
32
|
+
])
|
|
33
|
+
ctx.state.effects.push(effectStmt)
|
|
34
|
+
|
|
35
|
+
appendText(ctx.state.template, ' ')
|
|
36
|
+
template = { text: [''], expressions: [] }
|
|
37
|
+
} else if (!isEmpty(template)) {
|
|
38
|
+
appendText(ctx.state.template, template.text.join(''))
|
|
39
|
+
template = { text: [''], expressions: [] }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
|
|
3
|
+
export function Identifier(node) {
|
|
4
|
+
if (node.metadata?.isBlockVar) {
|
|
5
|
+
return b.call(node)
|
|
6
|
+
}
|
|
7
|
+
if (node.metadata?.isProperty || node.metadata?.isMethod) {
|
|
8
|
+
return b.thisMember(b.id(node, node.metadata?.isPrivate))
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
import { appendText } from '../../utils/template.js'
|
|
3
|
+
import { nextElementId, pathStmt } from '../context.js'
|
|
4
|
+
|
|
5
|
+
export function IfBlock(node, ctx) {
|
|
6
|
+
function branchStmt(node, hasElseif = false) {
|
|
7
|
+
if (node) {
|
|
8
|
+
const template = { text: [''], expressions: [] }
|
|
9
|
+
const init = { elem: [], text: [], binding: [] }
|
|
10
|
+
const effects = []
|
|
11
|
+
const animates = []
|
|
12
|
+
const handlers = []
|
|
13
|
+
const blocks = []
|
|
14
|
+
|
|
15
|
+
ctx.visit(node, { ...ctx.state, template, init, effects, animates, handlers, blocks })
|
|
16
|
+
|
|
17
|
+
if (!hasElseif) {
|
|
18
|
+
const stmts1 = [
|
|
19
|
+
b.declaration('template', b.createElement('template')),
|
|
20
|
+
b.assignment(b.innerHTML('template'), b.template(template))
|
|
21
|
+
]
|
|
22
|
+
const stmts2 = [
|
|
23
|
+
...init.elem,
|
|
24
|
+
...init.text,
|
|
25
|
+
...init.binding,
|
|
26
|
+
...effects,
|
|
27
|
+
...animates,
|
|
28
|
+
...handlers,
|
|
29
|
+
...blocks
|
|
30
|
+
]
|
|
31
|
+
const stmt3 = b.insertBefore('anchor', b.member('template', 'content'))
|
|
32
|
+
|
|
33
|
+
return [...stmts1, ...stmts2, stmt3]
|
|
34
|
+
}
|
|
35
|
+
return blocks
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const testStmt = ctx.visit(node.test)
|
|
40
|
+
const consequentStmt = branchStmt(node.consequent)
|
|
41
|
+
const alternateStmt = branchStmt(node.alternate, node.metadata?.hasElseif)
|
|
42
|
+
|
|
43
|
+
if (!node.elseif) {
|
|
44
|
+
const anchorId = nextElementId(ctx)
|
|
45
|
+
const anchorStmt = b.declaration(anchorId, pathStmt(ctx, node))
|
|
46
|
+
const blockStmt = b.ifBlock(anchorId, testStmt, consequentStmt, alternateStmt)
|
|
47
|
+
|
|
48
|
+
ctx.state.init.elem.push(anchorStmt)
|
|
49
|
+
ctx.state.blocks.push(blockStmt)
|
|
50
|
+
appendText(ctx.state.template, '<!-- -->')
|
|
51
|
+
} else {
|
|
52
|
+
const blockStmt = b.ifBlock(b.id('anchor'), testStmt, consequentStmt, alternateStmt)
|
|
53
|
+
ctx.state.blocks.push(blockStmt)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
|
|
3
|
+
export function ImportDeclaration(node, ctx) {
|
|
4
|
+
if (node.metadata?.isModule) {
|
|
5
|
+
const moduleId = `$Module_${node.metadata.index + 1}`
|
|
6
|
+
const raw = undefined
|
|
7
|
+
|
|
8
|
+
let value
|
|
9
|
+
if (ctx.state.context.rewriteRelativeImportExtensions) {
|
|
10
|
+
value = `${node.metadata.dirname}/${node.metadata.filename}.js`
|
|
11
|
+
} else {
|
|
12
|
+
value = `${node.metadata.dirname}/${node.metadata.filename}.${node.metadata.extension}`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
...node,
|
|
17
|
+
specifiers: [...node.specifiers, b.importNamespaceSpecifier(moduleId)],
|
|
18
|
+
source: { ...node.source, value, raw }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
import { getProgram } from '../context.js'
|
|
3
|
+
|
|
4
|
+
export function MethodDefinition(node, ctx) {
|
|
5
|
+
node = ctx.next() ?? node
|
|
6
|
+
|
|
7
|
+
if (node.key.name === 'constructor') {
|
|
8
|
+
const program = getProgram(ctx)
|
|
9
|
+
const { properties, setters } = program.metadata?.customElement
|
|
10
|
+
|
|
11
|
+
const stmt1 = b.assignment(b.$(), b.$$())
|
|
12
|
+
const stmts2 = []
|
|
13
|
+
for (const setter of setters) {
|
|
14
|
+
stmts2.push(b.$$init(setter))
|
|
15
|
+
}
|
|
16
|
+
for (const property of properties) {
|
|
17
|
+
stmts2.push(b.$instrument(property))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
...node,
|
|
22
|
+
value: {
|
|
23
|
+
...node.value,
|
|
24
|
+
body: {
|
|
25
|
+
...node.value.body,
|
|
26
|
+
body: [...node.value.body.body, stmt1, ...stmts2]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (node.key.name === 'connectedCallback') {
|
|
33
|
+
const shadowRootMode = ctx.state.template.metadata?.shadowRootMode
|
|
34
|
+
|
|
35
|
+
const stmts1 = []
|
|
36
|
+
const stmts2 = []
|
|
37
|
+
if (shadowRootMode) {
|
|
38
|
+
stmts1.push(b.assignment(b.shadow(), b.attachShadow(shadowRootMode)))
|
|
39
|
+
}
|
|
40
|
+
if (node.value.body.body.length > 0) {
|
|
41
|
+
stmts2.push(b.$boundary(node.value.body.body))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const stmt = b.ifStmt(b.$lifecycle('connected'), [
|
|
45
|
+
...stmts1,
|
|
46
|
+
ctx.state.template.block,
|
|
47
|
+
...stmts2
|
|
48
|
+
])
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
...node,
|
|
52
|
+
value: {
|
|
53
|
+
...node.value,
|
|
54
|
+
body: {
|
|
55
|
+
...node.value.body,
|
|
56
|
+
body: [stmt]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (node.key.name === 'disconnectedCallback') {
|
|
63
|
+
const stmt1 = b.$lifecycle('disconnected')
|
|
64
|
+
const stmt2 = b.queueMicrotask([
|
|
65
|
+
b.ifStmt(
|
|
66
|
+
b.$lifecycle('microtask'),
|
|
67
|
+
[b.$dispose(), ...node.value.body.body],
|
|
68
|
+
[b.connectedMoveCallback()]
|
|
69
|
+
)
|
|
70
|
+
])
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
...node,
|
|
74
|
+
value: {
|
|
75
|
+
...node.value,
|
|
76
|
+
body: {
|
|
77
|
+
...node.value.body,
|
|
78
|
+
body: [stmt1, stmt2]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (node.key.name === 'getAttribute') {
|
|
85
|
+
const stmt1 = b.$trackAttribute(node.value.params)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
...node,
|
|
89
|
+
value: {
|
|
90
|
+
...node.value,
|
|
91
|
+
params: stmt1.arguments,
|
|
92
|
+
body: {
|
|
93
|
+
...node.value.body,
|
|
94
|
+
body: [stmt1, ...node.value.body.body]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (node.key.name === 'attributeChangedCallback') {
|
|
101
|
+
const stmt1 = b.$attributeChanged(node.value.params)
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
...node,
|
|
105
|
+
value: {
|
|
106
|
+
...node.value,
|
|
107
|
+
params: stmt1.arguments,
|
|
108
|
+
body: {
|
|
109
|
+
...node.value.body,
|
|
110
|
+
body: [stmt1, ...node.value.body.body]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
|
|
3
|
+
export function Program(node, ctx) {
|
|
4
|
+
node = ctx.next() ?? node
|
|
5
|
+
|
|
6
|
+
let stmt
|
|
7
|
+
const stmts1 = []
|
|
8
|
+
const stmts2 = []
|
|
9
|
+
|
|
10
|
+
// import
|
|
11
|
+
stmt = b.importSpecifier('$$', '@katabatic/runtime')
|
|
12
|
+
stmts1.push(stmt)
|
|
13
|
+
|
|
14
|
+
// html template
|
|
15
|
+
const template = ctx.state.template.template
|
|
16
|
+
stmt = b.declaration('TEMPLATE', b.template(template))
|
|
17
|
+
stmts1.push(stmt)
|
|
18
|
+
|
|
19
|
+
// style
|
|
20
|
+
const css = ctx.state.template.css
|
|
21
|
+
const style = css.length >= 0 ? `<style>${ctx.state.template.css.join('')}</style>` : ''
|
|
22
|
+
stmt = b.declaration('STYLE', b.literal(style))
|
|
23
|
+
stmts1.push(stmt)
|
|
24
|
+
|
|
25
|
+
// $name
|
|
26
|
+
stmt = b.$nameDecl(node.metadata?.customElement.name ?? ctx.state.context.customElementName)
|
|
27
|
+
stmts1.push(stmt)
|
|
28
|
+
|
|
29
|
+
// $set
|
|
30
|
+
const properties = [
|
|
31
|
+
...node.metadata?.customElement.properties,
|
|
32
|
+
...node.metadata?.customElement.setters
|
|
33
|
+
]
|
|
34
|
+
if (properties.length > 0) {
|
|
35
|
+
stmt = b.$setDecl([
|
|
36
|
+
b.ifStmt(
|
|
37
|
+
b.includes(b.array(properties), 'attribute'),
|
|
38
|
+
[b.setProperty('node', 'attribute', 'value')],
|
|
39
|
+
[b.setAttribute('node', 'attribute', 'value')]
|
|
40
|
+
)
|
|
41
|
+
])
|
|
42
|
+
} else {
|
|
43
|
+
stmt = b.$setDecl([b.setAttribute('node', 'attribute', 'value')])
|
|
44
|
+
}
|
|
45
|
+
stmts1.push(stmt)
|
|
46
|
+
|
|
47
|
+
// defineCustomElement
|
|
48
|
+
if (!node.metadata?.hasDefineCustomElement) {
|
|
49
|
+
stmt = b.defineCustomElement(
|
|
50
|
+
ctx.state.context.customElementName,
|
|
51
|
+
node.metadata?.customElement.className
|
|
52
|
+
)
|
|
53
|
+
stmts2.push(stmt)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...node,
|
|
58
|
+
body: [
|
|
59
|
+
...node.body.filter((n) => n.type === 'ImportDeclaration'),
|
|
60
|
+
...stmts1,
|
|
61
|
+
...node.body.filter((n) => n.type !== 'ImportDeclaration'),
|
|
62
|
+
...stmts2
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
|
|
3
|
+
export function Selector(node, ctx) {
|
|
4
|
+
node = CssTreeNodeFix(node, ctx)
|
|
5
|
+
|
|
6
|
+
const children = []
|
|
7
|
+
let unscoped = []
|
|
8
|
+
for (const child of node.children) {
|
|
9
|
+
switch (child.type) {
|
|
10
|
+
case 'Combinator':
|
|
11
|
+
scope()
|
|
12
|
+
children.push(child)
|
|
13
|
+
break
|
|
14
|
+
default:
|
|
15
|
+
unscoped.push(child)
|
|
16
|
+
break
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
scope()
|
|
20
|
+
|
|
21
|
+
function scope() {
|
|
22
|
+
if (unscoped.length > 0) {
|
|
23
|
+
unscoped.push(b.classSelector(`ktb-${ctx.state.context.hash}`))
|
|
24
|
+
children.push(...unscoped)
|
|
25
|
+
unscoped = []
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return { type: 'Selector', children }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const CssTree = {
|
|
33
|
+
StyleSheet: CssTreeNodeFix,
|
|
34
|
+
SelectorList: CssTreeNodeFix,
|
|
35
|
+
PseudoClassSelector: CssTreeNodeFix
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function CssTreeNodeFix(node, ctx) {
|
|
39
|
+
const children = node.children?.map((c) => ctx.visit(c)) ?? null
|
|
40
|
+
return { ...node, children }
|
|
41
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { generate } from 'css-tree'
|
|
2
|
+
import { appendText } from '../../utils/template.js'
|
|
3
|
+
|
|
4
|
+
export function Style(node, ctx) {
|
|
5
|
+
node = ctx.next() ?? node
|
|
6
|
+
|
|
7
|
+
const css = generate(node.content)
|
|
8
|
+
|
|
9
|
+
ctx.state.css.push(css)
|
|
10
|
+
appendText(ctx.state.template, '<!-- -->')
|
|
11
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as b from '../../builders.js'
|
|
2
|
+
|
|
3
|
+
export function Template(node, ctx) {
|
|
4
|
+
const css = []
|
|
5
|
+
const template = { text: [''], expressions: [] }
|
|
6
|
+
const init = { elem: [], text: [], binding: [] }
|
|
7
|
+
const effects = []
|
|
8
|
+
const animates = []
|
|
9
|
+
const handlers = []
|
|
10
|
+
const blocks = []
|
|
11
|
+
|
|
12
|
+
ctx.visit(node.fragment, {
|
|
13
|
+
...ctx.state,
|
|
14
|
+
css,
|
|
15
|
+
template,
|
|
16
|
+
init,
|
|
17
|
+
effects,
|
|
18
|
+
animates,
|
|
19
|
+
handlers,
|
|
20
|
+
blocks
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const rootId = node.metadata?.shadowRootMode ? b.shadow() : b.thisExp()
|
|
24
|
+
|
|
25
|
+
const stmts1 = [
|
|
26
|
+
b.declaration('template', b.createElement('template')),
|
|
27
|
+
b.assignment(b.innerHTML('template'), b.binary('+', b.id('TEMPLATE'), b.id('STYLE')))
|
|
28
|
+
]
|
|
29
|
+
const stmts2 = [
|
|
30
|
+
...init.elem,
|
|
31
|
+
...init.text,
|
|
32
|
+
...init.binding,
|
|
33
|
+
...effects,
|
|
34
|
+
...animates,
|
|
35
|
+
...handlers,
|
|
36
|
+
...blocks
|
|
37
|
+
]
|
|
38
|
+
const stmt3 = b.replaceChildren(rootId, b.member('template', 'content'))
|
|
39
|
+
|
|
40
|
+
const bodyStmt = [...stmts1, ...stmts2, stmt3]
|
|
41
|
+
const block = b.$block(bodyStmt)
|
|
42
|
+
|
|
43
|
+
return { type: 'TemplateMod', metadata: node.metadata, css, template, block }
|
|
44
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function appendText(template, value) {
|
|
2
|
+
template.text[template.text.length - 1] += value
|
|
3
|
+
}
|
|
4
|
+
export function appendExpression(template, value) {
|
|
5
|
+
template.expressions.push(value)
|
|
6
|
+
template.text.push('')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function hasExpression(template) {
|
|
10
|
+
return template.expressions.length > 0
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isEmpty(template) {
|
|
14
|
+
return template.expressions.length == 0 && template.text.length == 1 && template.text[0] === ''
|
|
15
|
+
}
|