@katabatic/compiler 1.0.0 → 1.1.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@katabatic/compiler",
3
3
  "license": "MIT",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
package/src/builders.js CHANGED
@@ -179,7 +179,7 @@ export function thisExp() {
179
179
  return { type: 'ThisExpression' }
180
180
  }
181
181
 
182
- export function exportDec(declaration) {
182
+ export function exp(declaration) {
183
183
  return { type: 'ExportNamedDeclaration', declaration }
184
184
  }
185
185
 
@@ -192,6 +192,10 @@ export function program(body = []) {
192
192
  }
193
193
 
194
194
  export function func(id, body = []) {
195
+ if (typeof id === 'string') {
196
+ id = { type: 'Identifier', name: id }
197
+ }
198
+
195
199
  return {
196
200
  type: 'FunctionDeclaration',
197
201
  id,
@@ -532,28 +536,6 @@ export function $name(object) {
532
536
  }
533
537
  }
534
538
 
535
- export function $nameDecl(value) {
536
- return {
537
- type: 'ExportNamedDeclaration',
538
- declaration: {
539
- type: 'VariableDeclaration',
540
- declarations: [
541
- {
542
- type: 'VariableDeclarator',
543
- id: {
544
- type: 'Identifier',
545
- name: '$name'
546
- },
547
- init: { type: 'Literal', value }
548
- }
549
- ],
550
- kind: 'const'
551
- },
552
- specifiers: [],
553
- source: null
554
- }
555
- }
556
-
557
539
  export function $set(object, nodeId, attribute, value) {
558
540
  return {
559
541
  type: 'CallExpression',
@@ -933,54 +915,6 @@ export function appendChild(object, node) {
933
915
  }
934
916
  }
935
917
 
936
- export function queueMicrotask(body) {
937
- return {
938
- type: 'ExpressionStatement',
939
- expression: {
940
- type: 'CallExpression',
941
- callee: { type: 'Identifier', name: 'queueMicrotask' },
942
- arguments: [
943
- {
944
- type: 'ArrowFunctionExpression',
945
- id: null,
946
- expression: false,
947
- generator: false,
948
- async: false,
949
- params: [],
950
- body: {
951
- type: 'BlockStatement',
952
- body
953
- }
954
- }
955
- ],
956
- optional: false
957
- }
958
- }
959
- }
960
-
961
- export function connectedMoveCallback() {
962
- return {
963
- type: 'ExpressionStatement',
964
- expression: {
965
- type: 'CallExpression',
966
- callee: {
967
- type: 'MemberExpression',
968
- object: {
969
- type: 'ThisExpression'
970
- },
971
- property: {
972
- type: 'Identifier',
973
- name: 'connectedMoveCallback'
974
- },
975
- computed: false,
976
- optional: false
977
- },
978
- arguments: [],
979
- optional: true
980
- }
981
- }
982
- }
983
-
984
918
  export function $dispose() {
985
919
  return {
986
920
  type: 'CallExpression',
@@ -1010,7 +944,7 @@ export function $dispose() {
1010
944
  }
1011
945
  }
1012
946
 
1013
- export function $lifecycle(value) {
947
+ export function $lifecycle(value, body) {
1014
948
  return {
1015
949
  type: 'CallExpression',
1016
950
  callee: {
@@ -1034,7 +968,21 @@ export function $lifecycle(value) {
1034
968
  computed: false,
1035
969
  optional: false
1036
970
  },
1037
- arguments: [{ type: 'Literal', value }],
971
+ arguments: [
972
+ { type: 'Literal', value },
973
+ {
974
+ type: 'ArrowFunctionExpression',
975
+ id: null,
976
+ expression: false,
977
+ generator: false,
978
+ async: false,
979
+ params: [],
980
+ body: {
981
+ type: 'BlockStatement',
982
+ body
983
+ }
984
+ }
985
+ ],
1038
986
  optional: false
1039
987
  }
1040
988
  }
package/src/checkers.js CHANGED
@@ -6,6 +6,30 @@ export function thisMember(node) {
6
6
  return node.type === 'MemberExpression' && node.object.type === 'ThisExpression'
7
7
  }
8
8
 
9
+ export function thisAssignment(node) {
10
+ if (node.type === 'ExpressionStatement') {
11
+ node = node.expression
12
+ }
13
+
14
+ return (
15
+ node.type === 'AssignmentExpression' &&
16
+ node.left.type === 'MemberExpression' &&
17
+ node.left.object.type === 'ThisExpression'
18
+ )
19
+ }
20
+
21
+ export function expression(node) {
22
+ return node.type === 'ExpressionStatement'
23
+ }
24
+
25
+ export function superCall(node) {
26
+ if (node.type === 'ExpressionStatement') {
27
+ node = node.expression
28
+ }
29
+
30
+ return node.type === 'CallExpression' && node.callee.type === 'Super'
31
+ }
32
+
9
33
  export function privateId(node) {
10
34
  return node.type === 'PrivateIdentifier'
11
35
  }
@@ -117,4 +141,4 @@ export function shadowRootModeAttribute(node) {
117
141
 
118
142
  export function ifBlock(node) {
119
143
  return node.type === 'IfBlock'
120
- }
144
+ }
package/src/hot.js ADDED
@@ -0,0 +1,37 @@
1
+ import { walk } from 'zimmerframe'
2
+ import * as b from './builders.js'
3
+ import * as is from './checkers.js'
4
+
5
+ export function $hot(program) {
6
+ const stmts1 = []
7
+ const stmts2 = []
8
+
9
+ walk(program, undefined, {
10
+ PropertyDefinition: (node) => {
11
+ if (!node.static) {
12
+ const stmt = b.assignment(b.thisMember(node.key), node.value, '??=')
13
+ stmts1.push(stmt)
14
+ }
15
+ },
16
+ MethodDefinition: (node) => {
17
+ if (node.key.name === 'constructor') {
18
+ for (let _node of node.value.body.body) {
19
+ if (is.superCall(_node)) {
20
+ continue
21
+ }
22
+
23
+ if (is.thisAssignment(_node)) {
24
+ _node = is.expression(_node) ? _node.expression : _node
25
+
26
+ const stmt = { ..._node, operator: '??=' }
27
+ stmts2.push(stmt)
28
+ continue
29
+ }
30
+ stmts2.push(_node)
31
+ }
32
+ }
33
+ }
34
+ })
35
+
36
+ return b.exp(b.func('$hot', [...stmts1, ...stmts2]))
37
+ }
@@ -28,8 +28,6 @@ export function pathStmt(ctx, nodes) {
28
28
  subPath.push(...(Array.isArray(nodes) ? nodes : [nodes]))
29
29
  }
30
30
 
31
- console.log(subPath)
32
-
33
31
  let stmt = b.member('template', 'content')
34
32
  let fragment
35
33
  for (const node of subPath) {
@@ -18,6 +18,7 @@ import { EachBlock } from './visitors/EachBlock.js'
18
18
  import { CustomElement } from './visitors/CustomElement.js'
19
19
  import { AssignmentExpression } from './visitors/AssignmentExpression.js'
20
20
  import { PropertyDefinition } from './visitors/PropertyDefinition.js'
21
+ import { PrivateIdentifier } from './visitors/PrivateIdentifier.js'
21
22
 
22
23
  const templateVisitors = {
23
24
  Template,
@@ -43,7 +44,8 @@ const scriptVisitors = {
43
44
  ImportDeclaration,
44
45
  CallExpression,
45
46
  AssignmentExpression,
46
- PropertyDefinition
47
+ PropertyDefinition,
48
+ PrivateIdentifier
47
49
  }
48
50
 
49
51
  export function transform(ast, analysis, context) {
@@ -3,7 +3,7 @@ import * as b from '../../../builders.js'
3
3
  export function Program(node, ctx) {
4
4
  node = ctx.next() ?? node
5
5
 
6
- const stmt = b.exportDec(
6
+ const stmt = b.exp(
7
7
  b.render([...ctx.state.template.blocks, b.returnStmt(ctx.state.template.template)])
8
8
  )
9
9
  return { ...node, body: [...node.body, stmt] }
@@ -1,6 +1,8 @@
1
1
  import * as b from '../../builders.js'
2
2
 
3
- export function AssignmentExpression(node) {
3
+ export function AssignmentExpression(node, ctx) {
4
+ node = ctx.next() ?? node
5
+
4
6
  if (node.metadata?.isProperty && !node.metadata?.isPrivate) {
5
7
  return { ...node, right: b.$$init(node.left.property.name, node.right) }
6
8
  }
@@ -2,7 +2,7 @@ import * as b from '../../builders.js'
2
2
  import { transformQuerySelector } from '../../css-transform.js'
3
3
 
4
4
  export function CallExpression(node, ctx) {
5
- ctx.next()
5
+ node = ctx.next() ?? node
6
6
 
7
7
  if (node.metadata?.isGetElementById && node.metadata?.isScoped) {
8
8
  const id = node.arguments[0].value
@@ -30,7 +30,7 @@ export function ClassBody(node, ctx) {
30
30
  stmts2.push(stmt)
31
31
  }
32
32
 
33
- if (stmts2.length >= 0) {
33
+ if (stmts1.length >= 0 || stmts2.length >= 0) {
34
34
  return { ...node, body: [...stmts1, ...node.body, ...stmts2] }
35
35
  }
36
36
  }
@@ -14,7 +14,6 @@ export function Element(node, ctx) {
14
14
  function getElementId() {
15
15
  if (!elementId) {
16
16
  elementId = nextElementId(ctx)
17
- console.log('ELEM')
18
17
  const stmt = b.declaration(elementId, pathStmt(ctx))
19
18
  ctx.state.init.elem.push(stmt)
20
19
  }
@@ -11,7 +11,7 @@ export function Fragment(node, ctx) {
11
11
  case 'Text':
12
12
  case 'ExpressionTag':
13
13
  textNode = child
14
- ctx.visit(child, { template, analysis: ctx.state.analysis })
14
+ ctx.visit(child, { ...ctx.state, template })
15
15
  break
16
16
  default:
17
17
  finalize()
@@ -1,10 +1,13 @@
1
1
  import * as b from '../../builders.js'
2
2
 
3
- export function Identifier(node) {
3
+ export function Identifier(node, ctx) {
4
4
  if (node.metadata?.isBlockVar) {
5
5
  return b.call(node)
6
6
  }
7
7
  if (node.metadata?.isProperty || node.metadata?.isMethod) {
8
+ if (ctx.state.context.hot) {
9
+ return b.thisMember(node.metadata?.isPrivate ? b.id(`___${node.name}`) : node)
10
+ }
8
11
  return b.thisMember(b.id(node, node.metadata?.isPrivate))
9
12
  }
10
13
  }
@@ -35,17 +35,13 @@ export function MethodDefinition(node, ctx) {
35
35
  const stmts1 = []
36
36
  const stmts2 = []
37
37
  if (shadowRootMode) {
38
- stmts1.push(b.assignment(b.shadow(), b.attachShadow(shadowRootMode)))
38
+ stmts1.push(b.assignment(b.shadow(), b.attachShadow(shadowRootMode), '??='))
39
39
  }
40
40
  if (node.value.body.body.length > 0) {
41
41
  stmts2.push(b.$boundary(node.value.body.body))
42
42
  }
43
-
44
- const stmt = b.ifStmt(b.$lifecycle('connected'), [
45
- ...stmts1,
46
- ctx.state.template.block,
47
- ...stmts2
48
- ])
43
+
44
+ const stmt = b.$lifecycle('connected', [...stmts1, ctx.state.template.block, ...stmts2])
49
45
 
50
46
  return {
51
47
  ...node,
@@ -60,14 +56,7 @@ export function MethodDefinition(node, ctx) {
60
56
  }
61
57
 
62
58
  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
- ])
59
+ const stmt = b.$lifecycle('disconnected', [b.$dispose(), ...node.value.body.body])
71
60
 
72
61
  return {
73
62
  ...node,
@@ -75,7 +64,7 @@ export function MethodDefinition(node, ctx) {
75
64
  ...node.value,
76
65
  body: {
77
66
  ...node.value.body,
78
- body: [stmt1, stmt2]
67
+ body: [stmt]
79
68
  }
80
69
  }
81
70
  }
@@ -0,0 +1,7 @@
1
+ import * as b from '../../builders.js'
2
+
3
+ export function PrivateIdentifier(node, ctx) {
4
+ if (ctx.state.context.hot) {
5
+ return b.id(`___${node.name}`)
6
+ }
7
+ }
@@ -1,4 +1,5 @@
1
1
  import * as b from '../../builders.js'
2
+ import { $hot } from '../../hot.js'
2
3
 
3
4
  export function Program(node, ctx) {
4
5
  node = ctx.next() ?? node
@@ -23,7 +24,22 @@ export function Program(node, ctx) {
23
24
  stmts1.push(stmt)
24
25
 
25
26
  // $name
26
- stmt = b.$nameDecl(node.metadata?.customElement.name ?? ctx.state.context.customElementName)
27
+ stmt = b.exp(
28
+ b.declaration(
29
+ '$name',
30
+ b.literal(node.metadata?.customElement.name ?? ctx.state.context.customElementName)
31
+ )
32
+ )
33
+ stmts1.push(stmt)
34
+
35
+ // $class
36
+ stmt = b.exp(b.declaration('$class', b.id(node.metadata?.customElement.className)))
37
+ stmts2.push(stmt)
38
+
39
+ // $shadowRootMode
40
+ stmt = b.exp(
41
+ b.declaration('$shadowRootMode', b.literal(ctx.state.template.metadata?.shadowRootMode))
42
+ )
27
43
  stmts1.push(stmt)
28
44
 
29
45
  // $set
@@ -44,6 +60,11 @@ export function Program(node, ctx) {
44
60
  }
45
61
  stmts1.push(stmt)
46
62
 
63
+ //$hot
64
+ if (ctx.state.context.hot) {
65
+ stmts1.push($hot(node))
66
+ }
67
+
47
68
  // defineCustomElement
48
69
  if (!node.metadata?.hasDefineCustomElement) {
49
70
  stmt = b.defineCustomElement(
@@ -1,6 +1,8 @@
1
1
  import * as b from '../../builders.js'
2
2
 
3
- export function PropertyDefinition(node) {
3
+ export function PropertyDefinition(node, ctx) {
4
+ node = ctx.next() ?? node
5
+
4
6
  if (!node.static && !node.metadata?.isPrivate) {
5
7
  return { ...node, value: b.$$init(node.key.name, node.value ?? b.undefined()) }
6
8
  }