@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.
Files changed (78) hide show
  1. package/README.md +3 -0
  2. package/package.json +32 -0
  3. package/src/analyse/context.js +31 -0
  4. package/src/analyse/index.js +47 -0
  5. package/src/analyse/visitors/AssignmentExpression.js +14 -0
  6. package/src/analyse/visitors/Attribute.js +11 -0
  7. package/src/analyse/visitors/CallExpression.js +36 -0
  8. package/src/analyse/visitors/ClassBody.js +20 -0
  9. package/src/analyse/visitors/ClassDeclaration.js +5 -0
  10. package/src/analyse/visitors/CustomElement.js +10 -0
  11. package/src/analyse/visitors/EachBlock.js +10 -0
  12. package/src/analyse/visitors/Element.js +16 -0
  13. package/src/analyse/visitors/ExpressionTag.js +9 -0
  14. package/src/analyse/visitors/IfBlock.js +16 -0
  15. package/src/analyse/visitors/ImportDeclaration.js +35 -0
  16. package/src/analyse/visitors/MethodDefinition.js +17 -0
  17. package/src/analyse/visitors/Program.js +24 -0
  18. package/src/analyse/visitors/PropertyDefinition.js +12 -0
  19. package/src/analyse/visitors/Selector.js +23 -0
  20. package/src/analyse/visitors/Template.js +14 -0
  21. package/src/builders.js +1663 -0
  22. package/src/checkers.js +120 -0
  23. package/src/css-matcher.js +100 -0
  24. package/src/css-transform.js +21 -0
  25. package/src/css.js +65 -0
  26. package/src/exp-matcher.js +65 -0
  27. package/src/id-matcher.js +17 -0
  28. package/src/index.js +19 -0
  29. package/src/module-matcher.js +17 -0
  30. package/src/parser/attributes.js +66 -0
  31. package/src/parser/each-block.js +73 -0
  32. package/src/parser/element.js +115 -0
  33. package/src/parser/expression.js +44 -0
  34. package/src/parser/if-block.js +71 -0
  35. package/src/parser/index.js +10 -0
  36. package/src/parser/parser.js +259 -0
  37. package/src/parser/root.js +33 -0
  38. package/src/parser/script.js +59 -0
  39. package/src/parser/style.js +57 -0
  40. package/src/parser/template.js +30 -0
  41. package/src/parser/tokentype.js +75 -0
  42. package/src/router/html.js +18 -0
  43. package/src/router/index.js +130 -0
  44. package/src/transform/context.js +74 -0
  45. package/src/transform/index.js +52 -0
  46. package/src/transform/static/index.js +40 -0
  47. package/src/transform/static/visitors/Attribute.js +27 -0
  48. package/src/transform/static/visitors/EachBlock.js +23 -0
  49. package/src/transform/static/visitors/Element.js +17 -0
  50. package/src/transform/static/visitors/ExpressionTag.js +6 -0
  51. package/src/transform/static/visitors/IfBlock.js +28 -0
  52. package/src/transform/static/visitors/Program.js +10 -0
  53. package/src/transform/static/visitors/Script.js +9 -0
  54. package/src/transform/static/visitors/SlotElement.js +8 -0
  55. package/src/transform/static/visitors/Style.js +9 -0
  56. package/src/transform/static/visitors/Template.js +12 -0
  57. package/src/transform/static/visitors/Text.js +5 -0
  58. package/src/transform/visitors/AssignmentExpression.js +7 -0
  59. package/src/transform/visitors/Attribute.js +79 -0
  60. package/src/transform/visitors/CallExpression.js +17 -0
  61. package/src/transform/visitors/ClassBody.js +36 -0
  62. package/src/transform/visitors/CustomElement.js +43 -0
  63. package/src/transform/visitors/EachBlock.js +39 -0
  64. package/src/transform/visitors/Element.js +49 -0
  65. package/src/transform/visitors/ExpressionTag.js +6 -0
  66. package/src/transform/visitors/Fragment.js +42 -0
  67. package/src/transform/visitors/Identifier.js +10 -0
  68. package/src/transform/visitors/IfBlock.js +55 -0
  69. package/src/transform/visitors/ImportDeclaration.js +21 -0
  70. package/src/transform/visitors/MethodDefinition.js +115 -0
  71. package/src/transform/visitors/Program.js +65 -0
  72. package/src/transform/visitors/PropertyDefinition.js +7 -0
  73. package/src/transform/visitors/Selector.js +41 -0
  74. package/src/transform/visitors/Style.js +11 -0
  75. package/src/transform/visitors/Template.js +44 -0
  76. package/src/transform/visitors/Text.js +5 -0
  77. package/src/utils/misc.js +9 -0
  78. package/src/utils/template.js +15 -0
@@ -0,0 +1,44 @@
1
+ import { parseExpressionAt } from 'acorn'
2
+ import { Parser } from './parser.js'
3
+ import { TokenTypes } from './tokentype.js'
4
+
5
+ /**
6
+ *
7
+ * @param {Parser} p
8
+ * @returns
9
+ */
10
+ export function parseExpressionTag(p) {
11
+ p.expectToken([TokenTypes.braceL])
12
+ p.skipWhitespaces()
13
+ const expression = parseExpression(p)
14
+ p.skipWhitespaces()
15
+ p.expectToken([TokenTypes.braceR])
16
+
17
+ return { type: 'ExpressionTag', expression }
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param {Parser} p
23
+ * @returns
24
+ */
25
+ export function parseAttributeExpressionTag(p) {
26
+ p.expectToken([TokenTypes.quoteBraceL, TokenTypes.doubleQuoteBraceL])
27
+ p.skipWhitespaces()
28
+ const expression = parseExpression(p)
29
+ p.skipWhitespaces()
30
+ p.expectToken([TokenTypes.braceRQuote, TokenTypes.braceRDoubleQuote])
31
+
32
+ return { type: 'ExpressionTag', expression }
33
+ }
34
+
35
+ /**
36
+ *
37
+ * @param {Parser} p
38
+ * @returns
39
+ */
40
+ function parseExpression(p) {
41
+ const node = parseExpressionAt(p.input, p.pos, { ecmaVersion: 'latest' })
42
+ p.pos = node.end
43
+ return node
44
+ }
@@ -0,0 +1,71 @@
1
+ import { parseExpressionAt } from 'acorn'
2
+ import { parseFragment } from './element.js'
3
+ import { Parser } from './parser.js'
4
+ import { TokenTypes } from './tokentype.js'
5
+
6
+ /**
7
+ *
8
+ * @param {Parser} p
9
+ * @returns
10
+ */
11
+ export function parseIfBlock(p, elseif = false) {
12
+ const start = p.pos
13
+ p.expectToken([TokenTypes.braceLHash, TokenTypes.braceLColumn])
14
+ p.expectToken([TokenTypes.name])
15
+ const name = p.value
16
+
17
+ if (elseif) {
18
+ p.skipWhitespaces()
19
+ p.expectToken([TokenTypes.name])
20
+ }
21
+
22
+ const test = parseExpression(p)
23
+ p.expectToken([TokenTypes.braceR])
24
+ const consequent = parseFragment(p)
25
+
26
+ const punctToken = p.peakToken([TokenTypes.braceLColumn])
27
+ const nameToken1 = p.peakToken([TokenTypes.name], punctToken)
28
+ const whitespaceToken = p.peakWhitespaces(nameToken1)
29
+ const nameToken2 = p.peakToken([TokenTypes.name], whitespaceToken)
30
+
31
+ let alternate
32
+ if (nameToken1?.value === 'else' && nameToken2?.value === 'if') {
33
+ alternate = fragment([parseIfBlock(p, true)])
34
+ } else if (nameToken1?.value === 'else') {
35
+ p.expectToken([TokenTypes.braceLColumn])
36
+ p.expectToken([TokenTypes.name])
37
+ p.skipWhitespaces()
38
+ p.expectToken([TokenTypes.braceR])
39
+
40
+ alternate = parseFragment(p)
41
+ } else if (punctToken) {
42
+ throw new Error(`unknown block ${nameToken1?.value}`)
43
+ }
44
+
45
+ if (!elseif) {
46
+ p.expectToken([TokenTypes.braceLSlash])
47
+ p.expectToken([TokenTypes.name])
48
+ const blockNameClose = p.value
49
+ p.skipWhitespaces()
50
+ p.expectToken([TokenTypes.braceR])
51
+
52
+ if (name !== blockNameClose) throw new Error('wrong closing tag')
53
+ }
54
+
55
+ return { type: 'IfBlock', elseif, test, consequent, alternate, start, end: p.pos }
56
+ }
57
+
58
+ /**
59
+ *
60
+ * @param {Parser} p
61
+ * @returns
62
+ */
63
+ function parseExpression(p) {
64
+ const node = parseExpressionAt(p.input, p.pos, { ecmaVersion: 'latest' })
65
+ p.pos = node.end
66
+ return node
67
+ }
68
+
69
+ function fragment(nodes) {
70
+ return { type: 'Fragment', nodes }
71
+ }
@@ -0,0 +1,10 @@
1
+ import { Parser } from './parser.js'
2
+
3
+ /**
4
+ *
5
+ * @param {string} input
6
+ * @returns
7
+ */
8
+ export function parse(input) {
9
+ return new Parser(input).parse()
10
+ }
@@ -0,0 +1,259 @@
1
+ import { parseRoot } from './root.js'
2
+
3
+ /** @typedef {import('./tokentype.js').TokenType} TokenType */
4
+
5
+ /**
6
+ * @typedef {Object} Token
7
+ * @property {TokenType} type
8
+ * @property {number} start
9
+ * @property {number} end
10
+ * @property {string} [value]
11
+ */
12
+
13
+ /**
14
+ * * @member {string} input
15
+ */
16
+ export class Parser {
17
+ constructor(input) {
18
+ this.input = input
19
+
20
+ this.start = 0
21
+ this.end = 0
22
+ this.pos = 0
23
+ this.type = undefined
24
+ this.value = undefined
25
+ }
26
+
27
+ parse() {
28
+ return parseRoot(this)
29
+ }
30
+
31
+ /**
32
+ *
33
+ * @param {Array<TokenType>} types
34
+ * @param {Token} [after]
35
+ * @returns {Token}
36
+ */
37
+ peakToken(types, after) {
38
+ for (const type of types) {
39
+ let token
40
+
41
+ if (type.charCodes) {
42
+ token = this.peakCharToken(type, after)
43
+ } else {
44
+ token = this.peakStringToken(type, after)
45
+ }
46
+
47
+ if (token) return token
48
+ }
49
+ return null
50
+ }
51
+
52
+ /**
53
+ *
54
+ * @param {Array<TokenType>} types
55
+ */
56
+ expectToken(types) {
57
+ for (const type of types) {
58
+ if (type.charCodes) {
59
+ if (this.readCharToken(type)) return
60
+ } else {
61
+ if (this.readStringToken(type)) return
62
+ }
63
+ }
64
+ throw new Error(`unexpected token ${this.input[this.pos]} at position ${this.pos}`)
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @param {Array<TokenType>} types
70
+ * @returns boolean
71
+ */
72
+ readToken(types) {
73
+ for (const type of types) {
74
+ if (type.charCodes) {
75
+ if (this.readCharToken(type)) return true
76
+ } else {
77
+ if (this.readStringToken(type)) return true
78
+ }
79
+ }
80
+ return false
81
+ }
82
+
83
+ /**
84
+ *
85
+ * @param {TokenType} type
86
+ * @returns {boolean}
87
+ */
88
+ readStringToken(type) {
89
+ const start = this.pos
90
+ while (this.pos < this.input.length) {
91
+ if (!type.test(this.input.charCodeAt(this.pos))) break
92
+ this.pos++
93
+ }
94
+
95
+ if (this.pos !== start) {
96
+ this.type = type
97
+ this.start = start
98
+ this.end = this.pos
99
+ this.value = this.input.substring(this.start, this.end)
100
+ return true
101
+ }
102
+ return false
103
+ }
104
+
105
+ /**
106
+ *
107
+ * @param {TokenType} type
108
+ * @param {Token} after
109
+ * @returns {Token}
110
+ */
111
+ peakStringToken(type, after) {
112
+ if (after === null) return null
113
+
114
+ const start = after?.end ?? this.pos
115
+ let pos = start
116
+ while (pos < this.input.length) {
117
+ if (!type.test(this.input.charCodeAt(pos))) break
118
+ pos++
119
+ }
120
+
121
+ if (pos !== start) {
122
+ return {
123
+ type,
124
+ start,
125
+ end: pos,
126
+ value: this.input.substring(start, pos)
127
+ }
128
+ }
129
+ return null
130
+ }
131
+
132
+ /**
133
+ *
134
+ * @param {TokenType} type
135
+ * @returns {boolean}
136
+ */
137
+ readCharToken(type) {
138
+ if (this.isCharToken(type)) {
139
+ this.type = type
140
+ this.start = this.pos
141
+ this.pos += type.charCodes.length
142
+ this.end = this.pos
143
+ return true
144
+ }
145
+ return false
146
+ }
147
+
148
+ /**
149
+ *
150
+ * @param {TokenType} type
151
+ * @param {Token} [after]
152
+ * @returns {Token}
153
+ */
154
+ peakCharToken(type, after) {
155
+ if (after === null) return null
156
+
157
+ const pos = after?.end ?? this.pos
158
+ if (this.isCharToken(type, pos)) {
159
+ return {
160
+ type,
161
+ start: pos,
162
+ end: pos + type.charCodes.length
163
+ }
164
+ }
165
+ return null
166
+ }
167
+
168
+ /**
169
+ *
170
+ * @param {TokenType} type
171
+ * @param {number} [pos]
172
+ * @returns {boolean}
173
+ */
174
+ isCharToken(type, pos) {
175
+ assert(!!type.charCodes)
176
+
177
+ pos ??= this.pos
178
+ return (
179
+ this.input.charCodeAt(pos) === type.charCodes[0] &&
180
+ (type.charCodes[1] ? this.input.charCodeAt(pos + 1) === type.charCodes[1] : true) &&
181
+ (type.charCodes[2] ? this.input.charCodeAt(pos + 2) === type.charCodes[2] : true)
182
+ )
183
+ }
184
+
185
+ token() {
186
+ return {
187
+ type: this.type,
188
+ start: this.start,
189
+ end: this.end,
190
+ value: this.value
191
+ }
192
+ }
193
+
194
+ peakWhitespaces(after) {
195
+ if (after === null) return null
196
+
197
+ let pos = after?.end ?? this.pos
198
+ const start = pos
199
+
200
+ while (this.pos < this.input.length) {
201
+ const code = this.input.charCodeAt(pos)
202
+ if (code === 10 || code === 32) {
203
+ pos++
204
+ continue
205
+ }
206
+ break
207
+ }
208
+
209
+ if (pos !== start) {
210
+ return {
211
+ type: { label: 'whitespace' },
212
+ start,
213
+ end: pos
214
+ }
215
+ }
216
+ return null
217
+ }
218
+
219
+ skipWhitespaces() {
220
+ while (this.pos < this.input.length) {
221
+ const code = this.input.charCodeAt(this.pos)
222
+ if (code === 10 || code === 32) {
223
+ this.pos++
224
+ continue
225
+ }
226
+ break
227
+ }
228
+ }
229
+
230
+ raiseUnexpectedToken() {
231
+ throw new Error(`unexpected token ${this.input[this.pos]} at position ${this.pos}`)
232
+ }
233
+
234
+ isEOF() {
235
+ return this.pos === this.input.length
236
+ }
237
+ }
238
+
239
+ /**
240
+ *
241
+ * @param {number} code
242
+ * @returns {boolean}
243
+ */
244
+ function isIdentifierChar(code) {
245
+ if (code < 48) return false
246
+ if (code < 58) return true
247
+ if (code < 65) return false
248
+ if (code < 91) return true
249
+ if (code < 123) return true
250
+ return false
251
+ }
252
+
253
+ /**
254
+ *
255
+ * @param {boolean} test
256
+ */
257
+ function assert(test) {
258
+ if (!test) throw new Error('assert error')
259
+ }
@@ -0,0 +1,33 @@
1
+ import { Parser } from './parser.js'
2
+ import { parseScript } from './script.js'
3
+ import { parseTemplate } from './template.js'
4
+ import { TokenTypes } from './tokentype.js'
5
+
6
+ /**
7
+ * @param {Parser} p
8
+ * @returns
9
+ */
10
+ export function parseRoot(p) {
11
+ let script
12
+ let template
13
+
14
+ p.skipWhitespaces()
15
+ while (!p.isEOF()) {
16
+ const lteToken = p.peakToken([TokenTypes.lte])
17
+ const nameToken = p.peakToken([TokenTypes.name], lteToken)
18
+
19
+ switch (nameToken?.value) {
20
+ case 'script':
21
+ script = parseScript(p)
22
+ break
23
+ case 'template':
24
+ template = parseTemplate(p)
25
+ break
26
+ default:
27
+ throw new Error('unexpected html tag at position ' + p.pos)
28
+ }
29
+ p.skipWhitespaces()
30
+ }
31
+
32
+ return { type: 'Root', script, template }
33
+ }
@@ -0,0 +1,59 @@
1
+ import { parse as parseJS } from 'acorn'
2
+ import { TokenTypes } from './tokentype.js'
3
+ import { Parser } from './parser.js'
4
+ import { parseAttributes } from './attributes.js'
5
+ /** @import {Program} from 'acorn' */
6
+
7
+ /**
8
+ *
9
+ * @param {Parser} p
10
+ * @returns
11
+ */
12
+ export function parseScript(p) {
13
+ const start = p.pos
14
+ p.expectToken([TokenTypes.lte])
15
+ p.expectToken([TokenTypes.name])
16
+ const name = p.value
17
+ parseAttributes(p)
18
+ p.expectToken([TokenTypes.gte])
19
+
20
+ const content = parseProgram(p)
21
+
22
+ p.expectToken([TokenTypes.lteSlash])
23
+ p.expectToken([TokenTypes.name])
24
+ const tagNameClose = p.value
25
+ p.skipWhitespaces()
26
+ p.expectToken([TokenTypes.gte])
27
+
28
+ if (name !== tagNameClose) throw new Error('wrong closing tag')
29
+
30
+ return { type: 'Script', content, start, end: p.pos }
31
+ }
32
+
33
+ /**
34
+ *
35
+ * @param {Parser} p
36
+ * @returns {Program}
37
+ */
38
+ function parseProgram(p) {
39
+ const start = p.pos
40
+ skipCode(p)
41
+ return parseJS(p.input.slice(start, p.pos), { ecmaVersion: 'latest', sourceType: 'module' })
42
+ }
43
+
44
+ /**
45
+ *
46
+ * @param {Parser} p
47
+ */
48
+ function skipCode(p) {
49
+ while (p.pos < p.input.length) {
50
+ if (
51
+ p.input.charCodeAt(p.pos) === 60 &&
52
+ p.input.charCodeAt(p.pos + 1) === 47 &&
53
+ p.input.substring(p.pos + 2, p.pos + 8) === 'script'
54
+ ) {
55
+ break
56
+ }
57
+ p.pos++
58
+ }
59
+ }
@@ -0,0 +1,57 @@
1
+ import { parse } from 'css-tree'
2
+ import { TokenTypes } from './tokentype.js'
3
+ import { Parser } from './parser.js'
4
+
5
+ /**
6
+ *
7
+ * @param {Parser} p
8
+ * @returns
9
+ */
10
+ export function parseStyle(p) {
11
+ const start = p.pos
12
+ p.expectToken([TokenTypes.lte])
13
+ p.expectToken([TokenTypes.name])
14
+ const name = p.value
15
+
16
+ p.skipWhitespaces()
17
+ p.expectToken([TokenTypes.gte])
18
+
19
+ const content = parseCSS(p)
20
+
21
+ p.expectToken([TokenTypes.lteSlash])
22
+ p.expectToken([TokenTypes.name])
23
+ const tagNameClose = p.value
24
+ p.skipWhitespaces()
25
+ p.expectToken([TokenTypes.gte])
26
+
27
+ if (name !== tagNameClose) throw new Error('wrong closing tag')
28
+
29
+ return { type: 'Style', content, start, end: p.pos }
30
+ }
31
+
32
+ /**
33
+ *
34
+ * @param {Parser} p
35
+ */
36
+ function parseCSS(p) {
37
+ const start = p.pos
38
+ skipCSS(p)
39
+ return parse(p.input.slice(start, p.pos))
40
+ }
41
+
42
+ /**
43
+ *
44
+ * @param {Parser} p
45
+ */
46
+ function skipCSS(p) {
47
+ while (p.pos < p.input.length) {
48
+ if (
49
+ p.input.charCodeAt(p.pos) === 60 &&
50
+ p.input.charCodeAt(p.pos + 1) === 47 &&
51
+ p.input.substring(p.pos + 2, p.pos + 7) === 'style'
52
+ ) {
53
+ break
54
+ }
55
+ p.pos++
56
+ }
57
+ }
@@ -0,0 +1,30 @@
1
+ import { parseAttributes } from './attributes.js'
2
+ import { parseFragment } from './element.js'
3
+ import { Parser } from './parser.js'
4
+ import { TokenTypes } from './tokentype.js'
5
+
6
+ /**
7
+ *
8
+ * @param {Parser} p
9
+ */
10
+ export function parseTemplate(p) {
11
+ const start = p.pos
12
+
13
+ p.expectToken([TokenTypes.lte])
14
+ p.expectToken([TokenTypes.name])
15
+ const name = p.value
16
+ const attributes = parseAttributes(p)
17
+ p.expectToken([TokenTypes.gte])
18
+
19
+ const fragment = parseFragment(p, true, true)
20
+
21
+ p.expectToken([TokenTypes.lteSlash])
22
+ p.expectToken([TokenTypes.name])
23
+ const tagNameClose = p.value
24
+ p.skipWhitespaces()
25
+ p.expectToken([TokenTypes.gte])
26
+
27
+ if (name !== tagNameClose) throw new Error('wrong closing tag')
28
+
29
+ return { type: 'Template', attributes, fragment, start, end: p.pos }
30
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @typedef {Object} TokenType
3
+ * @property {string} label
4
+ * @property {Array<number>} [charCodes]
5
+ * @property {(char: number) => boolean} [test]
6
+ */
7
+
8
+ /**
9
+ *
10
+ * @param {string} label
11
+ * @param {Array<number>} charCodes
12
+ * @returns {TokenType}
13
+ */
14
+ function charTT(label, charCodes) {
15
+ return { label, charCodes }
16
+ }
17
+
18
+ /**
19
+ *
20
+ * @param {string} label
21
+ * @param {(char: number) => boolean} test
22
+ * @returns {TokenType}
23
+ */
24
+ function stringTT(label, test) {
25
+ return { label, test }
26
+ }
27
+
28
+ export const TokenTypes = {
29
+ name: stringTT('name', name),
30
+ text: stringTT('text', text),
31
+
32
+ // html punctuation
33
+ lte: charTT('<', [60]),
34
+ gte: charTT('>', [62]),
35
+ slashGte: charTT('/>', [47, 62]),
36
+ lteSlash: charTT('</', [60, 47]),
37
+ eq: charTT('=', [61]),
38
+ quote: charTT('\'', [39]),
39
+ doubleQuote: charTT('"', [34]),
40
+
41
+ // block punctuation
42
+ quoteBraceL: charTT('\'{', [39, 123]),
43
+ doubleQuoteBraceL: charTT('"{', [34, 123]),
44
+ braceRQuote: charTT('}\'', [125, 39]),
45
+ braceRDoubleQuote: charTT('}"', [125, 34]),
46
+ braceL: charTT('{', [123]),
47
+ braceR: charTT('}', [125]),
48
+ braceLHash: charTT('{#', [123, 35]),
49
+ braceLColumn: charTT('{:', [123, 58]),
50
+ braceLSlash: charTT('{/', [123, 47]),
51
+ parenthesesL: charTT('(', [40]),
52
+ parenthesesR: charTT(')', [41]),
53
+ }
54
+
55
+ function name(code) {
56
+ if (code === 45) return true
57
+ if (code < 48) return false
58
+ if (code < 58) return true
59
+ if (code < 65) return false
60
+ if (code < 91) return true
61
+ if (code < 123) return true
62
+ return false
63
+ }
64
+
65
+ function text(code) {
66
+ if (code === 10) return true
67
+ if (code === 32) return true
68
+ if (code === 47) return true
69
+ if (code < 48) return false
70
+ if (code < 58) return true
71
+ if (code < 65) return false
72
+ if (code < 91) return true
73
+ if (code < 123) return true
74
+ return false
75
+ }
@@ -0,0 +1,18 @@
1
+ export function compileHtmlIndex(source, context) {
2
+ const template = '`' + source.replace('%katabatic.body%', '${slot.body}') + '`'
3
+
4
+ return {
5
+ ...context,
6
+ ...printIndex({ template })
7
+ }
8
+ }
9
+
10
+ function printIndex({ template }) {
11
+ return {
12
+ code: `
13
+ export function renderIndex(slot) {
14
+ return ${template}
15
+ }
16
+ `
17
+ }
18
+ }