@katabatic/compiler 1.1.0 → 1.1.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@katabatic/compiler",
3
3
  "license": "MIT",
4
- "version": "1.1.0",
4
+ "version": "1.1.2",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
package/src/builders.js CHANGED
@@ -648,72 +648,6 @@ export function $instrument(value) {
648
648
  }
649
649
  }
650
650
 
651
- export function $getBindingProp(object, value, body) {
652
- return {
653
- type: 'CallExpression',
654
- callee: {
655
- type: 'MemberExpression',
656
- object: { type: 'ThisExpression' },
657
- property: {
658
- type: 'MemberExpression',
659
- object: {
660
- type: 'Identifier',
661
- name: '$'
662
- },
663
- property: {
664
- type: 'Identifier',
665
- name: 'getBindingProp'
666
- },
667
- computed: false,
668
- optional: false
669
- },
670
- computed: false,
671
- optional: false
672
- },
673
- arguments: [
674
- object,
675
- { type: 'Literal', value },
676
- {
677
- type: 'ArrowFunctionExpression',
678
- id: null,
679
- expression: false,
680
- generator: false,
681
- async: false,
682
- params: [{ type: 'Identifier', name: 'v' }],
683
- body
684
- }
685
- ],
686
- optional: false
687
- }
688
- }
689
-
690
- export function $setBindingProp(object, value, arg) {
691
- return {
692
- type: 'CallExpression',
693
- callee: {
694
- type: 'MemberExpression',
695
- object: { type: 'ThisExpression' },
696
- property: {
697
- type: 'MemberExpression',
698
- object: {
699
- type: 'Identifier',
700
- name: '$'
701
- },
702
- property: {
703
- type: 'Identifier',
704
- name: 'setBindingProp'
705
- },
706
- computed: false,
707
- optional: false
708
- },
709
- computed: false,
710
- optional: false
711
- },
712
- arguments: [object, { type: 'Literal', value }, arg],
713
- optional: false
714
- }
715
- }
716
-
717
651
  export function createElement(value) {
718
652
  return {
719
653
  type: 'CallExpression',
@@ -36,65 +36,69 @@ function matchSelectors(selectors, template) {
36
36
  if (selectors.length === 0) return false
37
37
 
38
38
  let result = false
39
- walk(template, undefined, {
40
- Element: (node, ctx) => {
41
- ctx.next()
42
39
 
43
- let scopedIdAttribute
44
- let scopedClassAttribute
45
- let scopedElement
40
+ function Visitor(node, ctx) {
41
+ ctx.next()
42
+
43
+ let scopedIdAttribute
44
+ let scopedClassAttribute
45
+ let scopedElement
46
46
 
47
- let classAttribute
47
+ let classAttribute
48
48
 
49
- for (const selector of selectors) {
50
- switch (selector.type) {
51
- case 'TypeSelector':
52
- if (selector.name === node.name) {
53
- classAttribute ??= node.attributes.find((a) => a.name === 'class')
54
- scopedElement = node
55
- scopedClassAttribute = classAttribute
56
- break
57
- }
58
- return
59
- case 'PseudoClassSelector':
49
+ for (const selector of selectors) {
50
+ switch (selector.type) {
51
+ case 'TypeSelector':
52
+ if (selector.name === node.name) {
60
53
  classAttribute ??= node.attributes.find((a) => a.name === 'class')
61
54
  scopedElement = node
62
55
  scopedClassAttribute = classAttribute
63
56
  break
64
- case 'IdSelector':
65
- const idAttribute = node.attributes.find((a) => a.name === 'id')
66
- if (idAttribute?.value[0].data === selector.name) {
67
- scopedIdAttribute = idAttribute
68
- break
69
- }
70
- return
71
- case 'ClassSelector':
72
- classAttribute ??= node.attributes.find((a) => a.name === 'class')
73
- const classes = classAttribute?.value[0].data.split(/\s+/)
74
-
75
- if (classes?.includes(selector.name)) {
76
- scopedClassAttribute = classAttribute
77
- break
78
- }
79
- return
80
- }
81
- }
57
+ }
58
+ return
59
+ case 'PseudoClassSelector':
60
+ classAttribute ??= node.attributes.find((a) => a.name === 'class')
61
+ scopedElement = node
62
+ scopedClassAttribute = classAttribute
63
+ break
64
+ case 'IdSelector':
65
+ const idAttribute = node.attributes.find((a) => a.name === 'id')
66
+ if (idAttribute?.value[0].data === selector.name) {
67
+ scopedIdAttribute = idAttribute
68
+ break
69
+ }
70
+ return
71
+ case 'ClassSelector':
72
+ classAttribute ??= node.attributes.find((a) => a.name === 'class')
73
+ const classes = classAttribute?.value[0].data.split(/\s+/)
82
74
 
83
- if (scopedIdAttribute) {
84
- scopedIdAttribute.metadata ??= {}
85
- scopedIdAttribute.metadata.isScoped = true
86
- }
87
- if (scopedClassAttribute) {
88
- scopedClassAttribute.metadata ??= {}
89
- scopedClassAttribute.metadata.isScoped = true
90
- }
91
- if (scopedElement) {
92
- scopedElement.metadata ??= {}
93
- scopedElement.metadata.isScoped = true
75
+ if (classes?.includes(selector.name)) {
76
+ scopedClassAttribute = classAttribute
77
+ break
78
+ }
79
+ return
94
80
  }
81
+ }
95
82
 
96
- result = true
83
+ if (scopedIdAttribute) {
84
+ scopedIdAttribute.metadata ??= {}
85
+ scopedIdAttribute.metadata.isScoped = true
86
+ }
87
+ if (scopedClassAttribute) {
88
+ scopedClassAttribute.metadata ??= {}
89
+ scopedClassAttribute.metadata.isScoped = true
90
+ }
91
+ if (scopedElement) {
92
+ scopedElement.metadata ??= {}
93
+ scopedElement.metadata.isScoped = true
97
94
  }
95
+
96
+ result = true
97
+ }
98
+
99
+ walk(template, undefined, {
100
+ Element: Visitor,
101
+ CustomElement: Visitor
98
102
  })
99
103
  return result
100
104
  }
@@ -11,7 +11,29 @@ export function matchModule(name, index, template) {
11
11
 
12
12
  result = true
13
13
  }
14
- }
14
+ },
15
+ TypeSelector: (node, ctx) => {
16
+ if (node.name === name) {
17
+ node.metadata ??= {}
18
+ node.metadata.isModule = true
19
+ node.metadata.index = index
20
+
21
+ result = true
22
+ }
23
+ },
24
+ ...CssTree
15
25
  })
16
26
  return result
17
27
  }
28
+
29
+ export const CssTree = {
30
+ StyleSheet: CssTreeNodeFix,
31
+ SelectorList: CssTreeNodeFix,
32
+ Selector: CssTreeNodeFix,
33
+ PseudoClassSelector: CssTreeNodeFix
34
+ }
35
+
36
+ function CssTreeNodeFix(node, ctx) {
37
+ const children = node.children?.map((c) => ctx.visit(c)) ?? null
38
+ return { ...node, children }
39
+ }
@@ -19,6 +19,7 @@ import { CustomElement } from './visitors/CustomElement.js'
19
19
  import { AssignmentExpression } from './visitors/AssignmentExpression.js'
20
20
  import { PropertyDefinition } from './visitors/PropertyDefinition.js'
21
21
  import { PrivateIdentifier } from './visitors/PrivateIdentifier.js'
22
+ import { TypeSelector } from './visitors/TypeSelector.js'
22
23
 
23
24
  const templateVisitors = {
24
25
  Template,
@@ -34,6 +35,7 @@ const templateVisitors = {
34
35
  IfBlock,
35
36
  EachBlock,
36
37
  Selector,
38
+ TypeSelector,
37
39
  ...CssTree
38
40
  }
39
41
 
@@ -52,21 +52,14 @@ export function Attribute(node, ctx) {
52
52
  ])
53
53
  ctx.state.effects.push(stmt)
54
54
  } else if (bindingId) {
55
- const stmt = b.$effect([
56
- b.logical(
57
- '||',
58
- b.$setBindingProp(bindingId, node.name, template.expressions[0]),
59
- b.setAttribute(elementId, b.literal(node.name), template.expressions[0])
60
- )
55
+ const stmt1 = b.$effect([
56
+ b.assignment(b.member(bindingId, node.name), template.expressions[0])
57
+ ])
58
+ const stmt2 = b.$effect([
59
+ b.assignment(template.expressions[0], b.member(bindingId, node.name))
61
60
  ])
62
- ctx.state.effects.push(stmt)
63
61
 
64
- const stmt2 = b.$getBindingProp(
65
- bindingId,
66
- node.name,
67
- b.assignment(template.expressions[0], b.id('v'))
68
- )
69
- ctx.state.changed.push(stmt2)
62
+ ctx.state.effects.push(stmt1, stmt2)
70
63
  } else {
71
64
  const stmt = b.$effect([
72
65
  b.setAttribute(elementId, b.literal(node.name), template.expressions[0])
@@ -18,9 +18,8 @@ export function Program(node, ctx) {
18
18
  stmts1.push(stmt)
19
19
 
20
20
  // style
21
- const css = ctx.state.template.css
22
- const style = css.length >= 0 ? `<style>${ctx.state.template.css.join('')}</style>` : ''
23
- stmt = b.declaration('STYLE', b.literal(style))
21
+ const style = ctx.state.template.style
22
+ stmt = b.declaration('STYLE', b.template(style))
24
23
  stmts1.push(stmt)
25
24
 
26
25
  // $name
@@ -1,11 +1,20 @@
1
1
  import { generate } from 'css-tree'
2
- import { appendText } from '../../utils/template.js'
2
+ import * as b from '../../builders.js'
3
+ import { appendExpression, appendText } from '../../utils/template.js'
3
4
 
4
5
  export function Style(node, ctx) {
5
6
  node = ctx.next() ?? node
6
7
 
7
8
  const css = generate(node.content)
9
+ const style = css.length > 0 ? `<style>${css}</style>` : ''
10
+
11
+ // handle modules
12
+ const tokens = style.split(/(\$Module_\d+)/)
13
+ for (const token of tokens) {
14
+ token.startsWith('$Module_')
15
+ ? appendExpression(ctx.state.style, b.$name(token))
16
+ : appendText(ctx.state.style, token)
17
+ }
8
18
 
9
- ctx.state.css.push(css)
10
19
  appendText(ctx.state.template, '<!-- -->')
11
20
  }
@@ -1,7 +1,7 @@
1
1
  import * as b from '../../builders.js'
2
2
 
3
3
  export function Template(node, ctx) {
4
- const css = []
4
+ const style = { text: [''], expressions: [] }
5
5
  const template = { text: [''], expressions: [] }
6
6
  const init = { elem: [], text: [], binding: [] }
7
7
  const effects = []
@@ -11,7 +11,7 @@ export function Template(node, ctx) {
11
11
 
12
12
  ctx.visit(node.fragment, {
13
13
  ...ctx.state,
14
- css,
14
+ style,
15
15
  template,
16
16
  init,
17
17
  effects,
@@ -40,5 +40,5 @@ export function Template(node, ctx) {
40
40
  const bodyStmt = [...stmts1, ...stmts2, stmt3]
41
41
  const block = b.$block(bodyStmt)
42
42
 
43
- return { type: 'TemplateMod', metadata: node.metadata, css, template, block }
43
+ return { type: 'TemplateMod', metadata: node.metadata, style, template, block }
44
44
  }
@@ -0,0 +1,6 @@
1
+ export function TypeSelector(node) {
2
+ if (node.metadata?.isModule) {
3
+ const name = `$Module_${node.metadata.index + 1}`
4
+ return { ...node, name }
5
+ }
6
+ }