@chilts/weave 0.6.0 → 0.7.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/CHANGELOG.md +178 -0
- package/ReadMe.md +53 -2
- package/dist/cli/index.d.ts +16 -0
- package/dist/cli/index.js +96 -11
- package/dist/codegen/index.d.ts +17 -3
- package/dist/codegen/index.js +194 -48
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/lexer/index.js +220 -91
- package/dist/runtime/index.d.ts +6 -0
- package/dist/runtime/index.js +11 -1
- package/package.json +7 -3
package/dist/codegen/index.js
CHANGED
|
@@ -14,6 +14,29 @@ export class CodegenError extends Error {
|
|
|
14
14
|
function capitalize(s) {
|
|
15
15
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
16
16
|
}
|
|
17
|
+
// Appends a compiler-supplied argument (`attrs`, `blocks`, ...) to a
|
|
18
|
+
// captured argument or parameter list. A multi-line list may already end in
|
|
19
|
+
// a trailing comma, and when its ')' sat on a line of its own the extra goes
|
|
20
|
+
// on its own line too, so the output keeps the shape the source was written in.
|
|
21
|
+
// `ownLine` is false for an extra that opens a multi-line literal of its own.
|
|
22
|
+
function appendArg(args, extra, ownLine = true) {
|
|
23
|
+
if (args === '')
|
|
24
|
+
return extra;
|
|
25
|
+
const body = args.trimEnd();
|
|
26
|
+
const tail = args.slice(body.length);
|
|
27
|
+
if (ownLine && tail.includes('\n')) {
|
|
28
|
+
const lastLine = body.slice(body.lastIndexOf('\n') + 1);
|
|
29
|
+
const indent = /^ */.exec(lastLine)[0];
|
|
30
|
+
return `${body}${body.endsWith(',') ? '' : ','}\n${indent}${extra},${tail}`;
|
|
31
|
+
}
|
|
32
|
+
return `${body}${body.endsWith(',') ? ' ' : ', '}${extra}`;
|
|
33
|
+
}
|
|
34
|
+
// Indents the continuation lines of a multi-line captured expression to sit
|
|
35
|
+
// under the output line it starts on. Captured text never holds a string that
|
|
36
|
+
// spans lines, so every newline is safe to indent after.
|
|
37
|
+
function reindent(text, prefix) {
|
|
38
|
+
return prefix === '' ? text : text.replace(/\n(?!\n|$)/g, `\n${prefix}`);
|
|
39
|
+
}
|
|
17
40
|
function camelToKebab(name) {
|
|
18
41
|
return name.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
|
19
42
|
}
|
|
@@ -110,9 +133,10 @@ class CodeGenerator {
|
|
|
110
133
|
case 'MixinDefinition':
|
|
111
134
|
return this.genMixinDefinition(node, indent);
|
|
112
135
|
case 'MixinCall':
|
|
113
|
-
return this.genMixinCall(node);
|
|
136
|
+
return this.genMixinCall(node, indent);
|
|
114
137
|
case 'Include':
|
|
115
|
-
|
|
138
|
+
// Hoisted: generate() emits the import once it knows the names.
|
|
139
|
+
return null;
|
|
116
140
|
case 'Block':
|
|
117
141
|
return this.genBlock(node, indent);
|
|
118
142
|
case 'Extends':
|
|
@@ -157,20 +181,22 @@ class CodeGenerator {
|
|
|
157
181
|
: variable;
|
|
158
182
|
const bi = this.formatted ? this.ind(indent + 1) : ' ';
|
|
159
183
|
const pi = this.formatted ? this.ind(indent) : '';
|
|
160
|
-
const
|
|
184
|
+
const head = reindent(`${iterable}.map(${param} =>`, this.formatted ? this.ind(indent) : '');
|
|
185
|
+
const code = `${head}\n${bi}${bodyChunk.code}\n${pi})`;
|
|
161
186
|
const mappings = [
|
|
162
187
|
mapping(node.loc),
|
|
163
|
-
...offsetMappings(bodyChunk.mappings, 1),
|
|
188
|
+
...offsetMappings(bodyChunk.mappings, 1 + lineCount(head)),
|
|
164
189
|
];
|
|
165
190
|
return { code, mappings };
|
|
166
191
|
}
|
|
167
192
|
parseForParams(params, loc) {
|
|
168
|
-
|
|
169
|
-
|
|
193
|
+
// A multi-line header may put `of` at the start or end of a line.
|
|
194
|
+
const of = /\s+of\s+/.exec(params);
|
|
195
|
+
if (of === null) {
|
|
170
196
|
throw new CodegenError(`Invalid for params: only "for...of" is supported, got "${params}"`, loc.line, loc.col);
|
|
171
197
|
}
|
|
172
|
-
const binding = params.slice(0,
|
|
173
|
-
const iterable = params.slice(
|
|
198
|
+
const binding = params.slice(0, of.index).trim();
|
|
199
|
+
const iterable = params.slice(of.index + of[0].length).trim();
|
|
174
200
|
const variable = binding.replace(/^(const|let)\s+/, '');
|
|
175
201
|
return { variable, iterable };
|
|
176
202
|
}
|
|
@@ -272,13 +298,16 @@ class CodeGenerator {
|
|
|
272
298
|
return `{ ${parts.join(', ')} }`;
|
|
273
299
|
}
|
|
274
300
|
mergeClassValue(prefix, value) {
|
|
275
|
-
|
|
276
|
-
|
|
301
|
+
// String and template literals are always strings, so merge them now.
|
|
302
|
+
// Anything else may be undefined/null/false at render time, which must
|
|
303
|
+
// add nothing rather than stringify into the class list.
|
|
304
|
+
if (value === '""' || value === "''" || value === '``') {
|
|
305
|
+
return `"${prefix}"`;
|
|
277
306
|
}
|
|
278
|
-
if (value.startsWith('"')) {
|
|
279
|
-
return
|
|
307
|
+
if (value.startsWith('`') || value.startsWith('"') || value.startsWith("'")) {
|
|
308
|
+
return `${value[0]}${prefix} ${value.slice(1)}`;
|
|
280
309
|
}
|
|
281
|
-
return
|
|
310
|
+
return `mergeClass("${prefix}", ${value})`;
|
|
282
311
|
}
|
|
283
312
|
attrKey(name) {
|
|
284
313
|
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))
|
|
@@ -330,19 +359,19 @@ class CodeGenerator {
|
|
|
330
359
|
// A mid-layer template both fills its parent's slots and exposes its
|
|
331
360
|
// own (nested `block` nodes), so it needs a `blocks` parameter too.
|
|
332
361
|
const params = templateHasBlocks(node)
|
|
333
|
-
?
|
|
362
|
+
? appendArg(node.params, `blocks: ${capitalize(node.name)}Blocks = {}`)
|
|
334
363
|
: node.params;
|
|
335
364
|
const code = `export function ${node.name}(${params}) {\n${i1}return ${extendsChunk.code}\n}`;
|
|
336
365
|
const mappings = [
|
|
337
366
|
mapping(node.loc),
|
|
338
|
-
...offsetMappings(extendsChunk.mappings, 1),
|
|
367
|
+
...offsetMappings(extendsChunk.mappings, 1 + lineCount(params)),
|
|
339
368
|
];
|
|
340
369
|
return { code, mappings };
|
|
341
370
|
}
|
|
342
371
|
// Check if body tree contains BlockNodes (layout template)
|
|
343
372
|
const hasBlocks = templateHasBlocks(node);
|
|
344
373
|
const params = hasBlocks
|
|
345
|
-
?
|
|
374
|
+
? appendArg(node.params, `blocks: ${capitalize(node.name)}Blocks = {}`)
|
|
346
375
|
: node.params;
|
|
347
376
|
const bodyChunks = node.body
|
|
348
377
|
.map(child => this.genNode(child, indent + 2))
|
|
@@ -371,16 +400,14 @@ class CodeGenerator {
|
|
|
371
400
|
const code = `export function ${node.name}(${params}) {\n${commentPrefix}${i1}return ${bodyChunk.code}\n}`;
|
|
372
401
|
const mappings = [
|
|
373
402
|
mapping(node.loc),
|
|
374
|
-
...offsetMappings(bodyChunk.mappings, 1 + commentLines), // body starts after fn sig + comments
|
|
403
|
+
...offsetMappings(bodyChunk.mappings, 1 + lineCount(params) + commentLines), // body starts after fn sig + comments
|
|
375
404
|
];
|
|
376
405
|
return { code, mappings };
|
|
377
406
|
}
|
|
378
407
|
// --- Mixin generation ---
|
|
379
408
|
genMixinDefinition(node, indent) {
|
|
380
409
|
const i1 = this.ind(indent + 1);
|
|
381
|
-
const params = node.params
|
|
382
|
-
? `${node.params}, attrs: Attrs = {}`
|
|
383
|
-
: 'attrs: Attrs = {}';
|
|
410
|
+
const params = appendArg(node.params, 'attrs: Attrs = {}');
|
|
384
411
|
const bodyChunks = node.body
|
|
385
412
|
.map(child => this.genNode(child, indent + 1))
|
|
386
413
|
.filter((e) => e !== null);
|
|
@@ -388,19 +415,16 @@ class CodeGenerator {
|
|
|
388
415
|
const code = `export function ${node.name}(${params}) {\n${i1}return ${bodyChunk.code}\n}`;
|
|
389
416
|
const mappings = [
|
|
390
417
|
mapping(node.loc),
|
|
391
|
-
...offsetMappings(bodyChunk.mappings, 1),
|
|
418
|
+
...offsetMappings(bodyChunk.mappings, 1 + lineCount(params)),
|
|
392
419
|
];
|
|
393
420
|
return { code, mappings };
|
|
394
421
|
}
|
|
395
|
-
genMixinCall(node) {
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
argParts.push(this.genCallAttrs(node.attrs));
|
|
402
|
-
}
|
|
403
|
-
return chunk(`${node.name}(${argParts.join(', ')})`, node.loc);
|
|
422
|
+
genMixinCall(node, indent = 0) {
|
|
423
|
+
const args = node.attrs.length > 0
|
|
424
|
+
? appendArg(node.args, this.genCallAttrs(node.attrs))
|
|
425
|
+
: node.args;
|
|
426
|
+
const prefix = this.formatted ? this.ind(indent) : '';
|
|
427
|
+
return chunk(reindent(`${node.name}(${args})`, prefix), node.loc);
|
|
404
428
|
}
|
|
405
429
|
genCallAttrs(attrs) {
|
|
406
430
|
const parts = [];
|
|
@@ -446,17 +470,17 @@ class CodeGenerator {
|
|
|
446
470
|
blockChunks.push({ code: blockCode, mappings: blockMappings });
|
|
447
471
|
}
|
|
448
472
|
const joinedBlocks = joinChunks(blockChunks, ',\n');
|
|
449
|
-
const
|
|
473
|
+
const args = reindent(node.args, pi);
|
|
474
|
+
const head = `${node.target}(${appendArg(args, '{', false)}`;
|
|
475
|
+
const code = `${head}\n${joinedBlocks.code}\n${pi}})`;
|
|
450
476
|
const mappings = [
|
|
451
477
|
mapping(node.loc),
|
|
452
|
-
...offsetMappings(joinedBlocks.mappings, 1),
|
|
478
|
+
...offsetMappings(joinedBlocks.mappings, 1 + lineCount(head)),
|
|
453
479
|
];
|
|
454
480
|
return { code, mappings };
|
|
455
481
|
}
|
|
456
|
-
genInclude(node) {
|
|
457
|
-
|
|
458
|
-
const name = segments[segments.length - 1];
|
|
459
|
-
return chunk(`import { ${name} } from '${node.path}.js'`, node.loc);
|
|
482
|
+
genInclude(node, names) {
|
|
483
|
+
return chunk(`import { ${names.join(', ')} } from '${node.path}.js'`, node.loc);
|
|
460
484
|
}
|
|
461
485
|
// --- Simple generators ---
|
|
462
486
|
genBufferedCode(node) {
|
|
@@ -470,12 +494,21 @@ class CodeGenerator {
|
|
|
470
494
|
function countEffective(nodes) {
|
|
471
495
|
return nodes.filter(n => n.type !== 'Comment' && n.type !== 'PassthroughComment').length;
|
|
472
496
|
}
|
|
497
|
+
/** True when shorthand classes merge with a `class=` value that is not a string literal. */
|
|
498
|
+
function needsRuntimeClassMerge(node) {
|
|
499
|
+
const explicitClass = node.attrs.find(a => a.name === 'class' && !a.spread);
|
|
500
|
+
if (!explicitClass || explicitClass.value === null)
|
|
501
|
+
return false;
|
|
502
|
+
return !/^["'`]/.test(explicitClass.value);
|
|
503
|
+
}
|
|
473
504
|
function scanUsedHelpers(node) {
|
|
474
505
|
const helpers = new Set();
|
|
475
506
|
function walk(n) {
|
|
476
507
|
switch (n.type) {
|
|
477
508
|
case 'Element':
|
|
478
509
|
helpers.add('h');
|
|
510
|
+
if (n.classes.length > 0 && needsRuntimeClassMerge(n))
|
|
511
|
+
helpers.add('mergeClass');
|
|
479
512
|
if (n.rawBlock)
|
|
480
513
|
helpers.add('raw');
|
|
481
514
|
for (const c of n.children)
|
|
@@ -570,6 +603,121 @@ function scanUsedHelpers(node) {
|
|
|
570
603
|
walk(node);
|
|
571
604
|
return helpers;
|
|
572
605
|
}
|
|
606
|
+
// --- Include resolution ---
|
|
607
|
+
/** Names of the mixins a document defines at top level. */
|
|
608
|
+
export function definedMixins(doc) {
|
|
609
|
+
return doc.children.flatMap(c => (c.type === 'MixinDefinition' ? [c.name] : []));
|
|
610
|
+
}
|
|
611
|
+
/** Every mixin call in the document, first call of each name, in source order. */
|
|
612
|
+
function collectMixinCalls(doc) {
|
|
613
|
+
const calls = new Map();
|
|
614
|
+
function walkAll(nodes) {
|
|
615
|
+
for (const n of nodes)
|
|
616
|
+
walk(n);
|
|
617
|
+
}
|
|
618
|
+
function walk(n) {
|
|
619
|
+
switch (n.type) {
|
|
620
|
+
case 'MixinCall':
|
|
621
|
+
if (!calls.has(n.name))
|
|
622
|
+
calls.set(n.name, n);
|
|
623
|
+
walkAll(n.block);
|
|
624
|
+
break;
|
|
625
|
+
case 'Element':
|
|
626
|
+
walkAll(n.children);
|
|
627
|
+
break;
|
|
628
|
+
case 'Conditional':
|
|
629
|
+
walkAll(n.consequent);
|
|
630
|
+
for (const alt of n.alternates)
|
|
631
|
+
walkAll(alt.body);
|
|
632
|
+
if (n.fallback)
|
|
633
|
+
walkAll(n.fallback);
|
|
634
|
+
break;
|
|
635
|
+
case 'Iteration':
|
|
636
|
+
case 'Template':
|
|
637
|
+
case 'MixinDefinition':
|
|
638
|
+
walkAll(n.body);
|
|
639
|
+
break;
|
|
640
|
+
case 'Block':
|
|
641
|
+
walkAll(n.children);
|
|
642
|
+
break;
|
|
643
|
+
case 'Extends':
|
|
644
|
+
for (const block of n.blocks)
|
|
645
|
+
walkAll(block.children);
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
walkAll(doc.children);
|
|
650
|
+
return calls;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Value bindings a pass-through `import` statement introduces. A loose read,
|
|
654
|
+
* not a TS parse: it only needs to spot a mixin imported by hand.
|
|
655
|
+
*/
|
|
656
|
+
function importedBindings(statement) {
|
|
657
|
+
if (/^import\s+type\b/.test(statement))
|
|
658
|
+
return [];
|
|
659
|
+
const clause = /^import\s+([\s\S]*?)\s+from\b/.exec(statement)?.[1];
|
|
660
|
+
if (!clause)
|
|
661
|
+
return [];
|
|
662
|
+
const names = [];
|
|
663
|
+
const defaultName = /^([A-Za-z_$][\w$]*)/.exec(clause)?.[1];
|
|
664
|
+
if (defaultName)
|
|
665
|
+
names.push(defaultName);
|
|
666
|
+
const namespace = /\*\s*as\s+([A-Za-z_$][\w$]*)/.exec(clause)?.[1];
|
|
667
|
+
if (namespace)
|
|
668
|
+
names.push(namespace);
|
|
669
|
+
const named = /\{([^}]*)\}/.exec(clause)?.[1];
|
|
670
|
+
if (named) {
|
|
671
|
+
for (const spec of named.split(',')) {
|
|
672
|
+
const s = spec.trim();
|
|
673
|
+
if (s === '' || /^type\s/.test(s))
|
|
674
|
+
continue;
|
|
675
|
+
names.push(s.split(/\s+as\s+/).pop().trim());
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return names;
|
|
679
|
+
}
|
|
680
|
+
/** Which called mixins each include must import, in first-call order. */
|
|
681
|
+
function resolveIncludes(doc, resolveInclude) {
|
|
682
|
+
const includes = doc.children.filter((c) => c.type === 'Include');
|
|
683
|
+
const picks = new Map(includes.map(inc => [inc, []]));
|
|
684
|
+
if (includes.length === 0)
|
|
685
|
+
return picks;
|
|
686
|
+
const provided = new Set(definedMixins(doc));
|
|
687
|
+
for (const child of doc.children) {
|
|
688
|
+
if (child.type === 'Import') {
|
|
689
|
+
for (const name of importedBindings(child.statement))
|
|
690
|
+
provided.add(name);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
const needed = [...collectMixinCalls(doc).values()].filter(call => !provided.has(call.name));
|
|
694
|
+
if (!resolveInclude) {
|
|
695
|
+
if (includes.length > 1 && needed.length > 0) {
|
|
696
|
+
const inc = includes[1];
|
|
697
|
+
throw new CodegenError(`Cannot tell which include defines mixin "${needed[0].name}" without an include resolver`, inc.loc.line, inc.loc.col);
|
|
698
|
+
}
|
|
699
|
+
picks.set(includes[0], needed.map(call => call.name));
|
|
700
|
+
return picks;
|
|
701
|
+
}
|
|
702
|
+
const available = new Map();
|
|
703
|
+
for (const inc of includes) {
|
|
704
|
+
try {
|
|
705
|
+
available.set(inc, new Set(resolveInclude(inc.path)));
|
|
706
|
+
}
|
|
707
|
+
catch (err) {
|
|
708
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
709
|
+
throw new CodegenError(`Cannot include ${inc.path}: ${msg}`, inc.loc.line, inc.loc.col);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
for (const call of needed) {
|
|
713
|
+
const inc = includes.find(i => available.get(i).has(call.name));
|
|
714
|
+
if (!inc) {
|
|
715
|
+
throw new CodegenError(`Mixin "${call.name}" is not defined in this file or any include`, call.loc.line, call.loc.col);
|
|
716
|
+
}
|
|
717
|
+
picks.get(inc).push(call.name);
|
|
718
|
+
}
|
|
719
|
+
return picks;
|
|
720
|
+
}
|
|
573
721
|
// --- Public API ---
|
|
574
722
|
/** Generate a TypeScript expression from a single AST node. */
|
|
575
723
|
export function generateExpr(node) {
|
|
@@ -580,14 +728,14 @@ export function generateExpr(node) {
|
|
|
580
728
|
return result.code;
|
|
581
729
|
}
|
|
582
730
|
/** Generate TypeScript source from a DocumentNode. */
|
|
583
|
-
export function generate(doc) {
|
|
731
|
+
export function generate(doc, options = {}) {
|
|
584
732
|
const gen = new CodeGenerator(true);
|
|
585
733
|
const parts = [];
|
|
586
734
|
// Scan for used runtime helpers
|
|
587
735
|
const helpers = scanUsedHelpers(doc);
|
|
588
736
|
// Emit runtime import (canonical order)
|
|
589
737
|
if (helpers.size > 0) {
|
|
590
|
-
const order = ['h', 'doctype', 'Fragment', 'raw'];
|
|
738
|
+
const order = ['h', 'doctype', 'Fragment', 'raw', 'mergeClass'];
|
|
591
739
|
const used = order.filter(h => helpers.has(h));
|
|
592
740
|
parts.push(chunk(`import { ${used.join(', ')} } from "@chilts/weave"`));
|
|
593
741
|
}
|
|
@@ -616,13 +764,11 @@ export function generate(doc) {
|
|
|
616
764
|
parts.push(chunk(statement, child.loc));
|
|
617
765
|
}
|
|
618
766
|
}
|
|
619
|
-
// Emit include imports
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
parts.push(result);
|
|
625
|
-
}
|
|
767
|
+
// Emit include imports: only the mixins this file calls, so an include
|
|
768
|
+
// that provides nothing used emits nothing.
|
|
769
|
+
for (const [include, names] of resolveIncludes(doc, options.resolveInclude)) {
|
|
770
|
+
if (names.length > 0)
|
|
771
|
+
parts.push(gen.genInclude(include, names));
|
|
626
772
|
}
|
|
627
773
|
// Emit extends imports (auto-import layout function)
|
|
628
774
|
for (const child of doc.children) {
|
|
@@ -647,16 +793,16 @@ export function generate(doc) {
|
|
|
647
793
|
return { code: final.code + '\n', mappings: final.mappings };
|
|
648
794
|
}
|
|
649
795
|
/** Full pipeline: source string → TypeScript source. */
|
|
650
|
-
export function compile(source) {
|
|
796
|
+
export function compile(source, options = {}) {
|
|
651
797
|
const tokens = lex(source);
|
|
652
798
|
const doc = parse(tokens);
|
|
653
|
-
return generate(doc).code;
|
|
799
|
+
return generate(doc, options).code;
|
|
654
800
|
}
|
|
655
801
|
/** Full pipeline with source map generation. */
|
|
656
802
|
export function compileWithSourceMap(source, opts) {
|
|
657
803
|
const tokens = lex(source);
|
|
658
804
|
const doc = parse(tokens);
|
|
659
|
-
const result = generate(doc);
|
|
805
|
+
const result = generate(doc, opts);
|
|
660
806
|
const sourceMap = buildSourceMap(result.mappings, opts.file, opts.sourceFile);
|
|
661
807
|
return { code: result.code, sourceMap };
|
|
662
808
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { h, doctype, Fragment, raw, escape, SafeHtml } from './runtime/index.js';
|
|
1
|
+
export { h, doctype, Fragment, raw, mergeClass, escape, SafeHtml } from './runtime/index.js';
|
|
2
2
|
export type { Attrs } from './runtime/index.js';
|
|
3
|
-
export { compile, compileWithSourceMap, generate, generateExpr, CodegenError } from './codegen/index.js';
|
|
4
|
-
export type { GenerateResult, CodeChunk, Mapping, SourceMap } from './codegen/index.js';
|
|
3
|
+
export { compile, compileWithSourceMap, generate, generateExpr, definedMixins, CodegenError } from './codegen/index.js';
|
|
4
|
+
export type { GenerateResult, GenerateOptions, IncludeResolver, CodeChunk, Mapping, SourceMap } from './codegen/index.js';
|
|
5
5
|
export { lex, LexerError } from './lexer/index.js';
|
|
6
6
|
export type { Token, TokenType } from './lexer/index.js';
|
|
7
7
|
export { parse, ParserError } from './parser/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Runtime
|
|
2
|
-
export { h, doctype, Fragment, raw, escape, SafeHtml } from './runtime/index.js';
|
|
2
|
+
export { h, doctype, Fragment, raw, mergeClass, escape, SafeHtml } from './runtime/index.js';
|
|
3
3
|
// Compiler
|
|
4
|
-
export { compile, compileWithSourceMap, generate, generateExpr, CodegenError } from './codegen/index.js';
|
|
4
|
+
export { compile, compileWithSourceMap, generate, generateExpr, definedMixins, CodegenError } from './codegen/index.js';
|
|
5
5
|
export { lex, LexerError } from './lexer/index.js';
|
|
6
6
|
export { parse, ParserError } from './parser/index.js';
|
|
7
7
|
//# sourceMappingURL=index.js.map
|