@marko/language-tools 2.5.5 → 2.5.7

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/dist/index.mjs CHANGED
@@ -1614,6 +1614,120 @@ function tryReaddirSync(dir) {
1614
1614
  }
1615
1615
  }
1616
1616
 
1617
+ // src/extractors/script/util/get-runtime-api.ts
1618
+ var RuntimeAPI = {
1619
+ tags: "tags",
1620
+ class: "class"
1621
+ };
1622
+ function getRuntimeAPI(translator, parsed) {
1623
+ return detectAPIFromTranslator(translator) || detectAPIFromFileName(parsed.filename) || detectAPIFromProgram(parsed, parsed.program);
1624
+ }
1625
+ function detectAPIFromTranslator(translator) {
1626
+ switch (translator == null ? void 0 : translator.preferAPI) {
1627
+ case "class":
1628
+ return RuntimeAPI.class;
1629
+ case "tags":
1630
+ return RuntimeAPI.tags;
1631
+ }
1632
+ }
1633
+ function detectAPIFromFileName(filename) {
1634
+ for (let end = filename.length, i = end; --i; ) {
1635
+ switch (filename[i]) {
1636
+ case "/":
1637
+ case "\\":
1638
+ if (filename.startsWith("tags", i + 1)) {
1639
+ return RuntimeAPI.tags;
1640
+ } else if (filename.startsWith("components", i + 1)) {
1641
+ return;
1642
+ }
1643
+ end = i;
1644
+ break;
1645
+ }
1646
+ }
1647
+ }
1648
+ function detectAPIFromProgram(parsed, program) {
1649
+ if (program.comments) {
1650
+ switch (parsed.read(program.comments[0].value).trim()) {
1651
+ case "use tags":
1652
+ return RuntimeAPI.tags;
1653
+ case "use class":
1654
+ return RuntimeAPI.class;
1655
+ }
1656
+ }
1657
+ if (program.static) {
1658
+ for (const stmt of program.static) {
1659
+ switch (stmt.type) {
1660
+ case 26 /* Class */:
1661
+ case 27 /* Style */:
1662
+ return RuntimeAPI.class;
1663
+ }
1664
+ }
1665
+ }
1666
+ return detectAPIFromBody(parsed, program.body);
1667
+ }
1668
+ function detectAPIFromBody(parsed, body) {
1669
+ if (body) {
1670
+ for (const child of body) {
1671
+ const api = detectAPIFromChild(parsed, child);
1672
+ if (api) return api;
1673
+ }
1674
+ }
1675
+ }
1676
+ function detectAPIFromChild(parsed, child) {
1677
+ switch (child.type) {
1678
+ case 23 /* Scriptlet */:
1679
+ return RuntimeAPI.class;
1680
+ case 1 /* Tag */:
1681
+ case 16 /* AttrTag */:
1682
+ return detectAPIFromTag(parsed, child);
1683
+ }
1684
+ }
1685
+ function detectAPIFromTag(parsed, tag) {
1686
+ var _a;
1687
+ switch (tag.nameText) {
1688
+ case "macro":
1689
+ case "include-text":
1690
+ case "include-html":
1691
+ case "init-components":
1692
+ case "await-reorderer":
1693
+ case "while":
1694
+ case "module-code":
1695
+ return RuntimeAPI.class;
1696
+ case "const":
1697
+ case "debug":
1698
+ case "define":
1699
+ case "html-script":
1700
+ case "html-style":
1701
+ case "id":
1702
+ case "let":
1703
+ case "lifecycle":
1704
+ case "log":
1705
+ case "return":
1706
+ return RuntimeAPI.tags;
1707
+ }
1708
+ if (tag.var) {
1709
+ return RuntimeAPI.tags;
1710
+ }
1711
+ if (tag.attrs) {
1712
+ for (const attr of tag.attrs) {
1713
+ if (attr.type !== 15 /* AttrSpread */) {
1714
+ if (((_a = attr.value) == null ? void 0 : _a.type) === 13 /* AttrValue */ && attr.value.bound) {
1715
+ return RuntimeAPI.tags;
1716
+ }
1717
+ if (attr.args) {
1718
+ return RuntimeAPI.class;
1719
+ }
1720
+ if (/^(?:key|no-update(?:-body)?(?:-if)?)$|:(scoped:no-update)$/.test(
1721
+ parsed.read(attr.name)
1722
+ )) {
1723
+ return RuntimeAPI.class;
1724
+ }
1725
+ }
1726
+ }
1727
+ }
1728
+ return detectAPIFromBody(parsed, tag.body);
1729
+ }
1730
+
1617
1731
  // src/extractors/script/util/jsdoc-input-type.ts
1618
1732
  var MaybeInputTypedefReg = /@typedef\b[\s\S]*\bInput\b/;
1619
1733
  function getJSDocInputType(comment, ts) {
@@ -1793,7 +1907,7 @@ var REG_TAG_IMPORT = /(?<=(['"]))<([^'">]+)>(?=\1)/;
1793
1907
  var REG_INPUT_TYPE = /\s*(interface|type)\s+Input\b/y;
1794
1908
  var REG_OBJECT_PROPERTY = /^[_$a-z][_$a-z0-9]*$/i;
1795
1909
  var REG_COMMENT_PRAGMA = /\/\/(?:\s*@ts-|\/\s*<)/y;
1796
- var REG_TAG_NAME_IDENTIFIER = /^[A-Z][a-zA-Z_$]+$/;
1910
+ var REG_TAG_NAME_IDENTIFIER = /^[A-Z][a-zA-Z0-9_$]+$/;
1797
1911
  var IF_TAG_ALTERNATES = /* @__PURE__ */ new WeakMap();
1798
1912
  var WROTE_COMMENT = /* @__PURE__ */ new WeakSet();
1799
1913
  var START_OF_FILE = { start: 0, end: 0 };
@@ -1813,11 +1927,14 @@ var ScriptExtractor = class {
1813
1927
  #scriptParser;
1814
1928
  #read;
1815
1929
  #lookup;
1930
+ #tagIds = /* @__PURE__ */ new Map();
1816
1931
  #renderIds = /* @__PURE__ */ new Map();
1817
1932
  #scriptLang;
1818
1933
  #ts;
1819
1934
  #runtimeTypes;
1935
+ #api;
1820
1936
  #mutationOffsets;
1937
+ #tagId = 1;
1821
1938
  #renderId = 1;
1822
1939
  constructor(opts) {
1823
1940
  const { parsed, lookup, scriptLang } = opts;
@@ -1831,6 +1948,7 @@ var ScriptExtractor = class {
1831
1948
  this.#extractor = new Extractor(parsed);
1832
1949
  this.#scriptParser = new ScriptParser(parsed);
1833
1950
  this.#read = parsed.read.bind(parsed);
1951
+ this.#api = getRuntimeAPI(opts.translator, parsed);
1834
1952
  this.#mutationOffsets = crawlProgramScope(this.#parsed, this.#scriptParser);
1835
1953
  this.#writeProgram(parsed.program);
1836
1954
  }
@@ -1989,8 +2107,8 @@ function ${templateName}() {
1989
2107
  ${varShared("noop")}({ input, component, state, out, $global, $signal });
1990
2108
  `);
1991
2109
  const body = this.#processBody(program);
1992
- if (body == null ? void 0 : body.renderBody) {
1993
- this.#writeChildren(program, body.renderBody);
2110
+ if (body == null ? void 0 : body.content) {
2111
+ this.#writeChildren(program, body.content);
1994
2112
  }
1995
2113
  const hoists = getHoists(program);
1996
2114
  if (hoists) {
@@ -2021,6 +2139,7 @@ function ${templateName}() {
2021
2139
  "ReturnWithScope"
2022
2140
  )}<${internalInput}, ${didReturn ? `typeof ${templateName + typeArgsStr} extends () => infer Return ? Return : never` : "void"}>)`;
2023
2141
  const templateOverrideClass = `${templateBaseClass}<{${this.#runtimeTypes ? getRuntimeOverrides(this.#runtimeTypes, typeParamsStr, typeArgsStr) : ""}
2142
+ ${this.#api ? `api: "${this.#api}",` : ""}
2024
2143
  _${typeParamsStr ? `<${internalApply} = 1>(): ${internalApply} extends 0
2025
2144
  ? ${typeParamsStr}() => <${internalInputWithExtends}>${renderAndReturn}
2026
2145
  : () => <${internalInputWithExtends}, ${typeParamsStr.slice(
@@ -2127,9 +2246,9 @@ constructor(_?: Return) {}
2127
2246
  this.#getRangeWithoutTrailingComma((_a = child.args) == null ? void 0 : _a.value) || this.#getAttrValue(child, ATTR_UNAMED2) || "undefined"
2128
2247
  ).write(") {\n");
2129
2248
  const ifBody = this.#processBody(child);
2130
- if (ifBody == null ? void 0 : ifBody.renderBody) {
2249
+ if (ifBody == null ? void 0 : ifBody.content) {
2131
2250
  const localBindings = getHoistSources(child);
2132
- this.#writeChildren(child, ifBody.renderBody, true);
2251
+ this.#writeChildren(child, ifBody.content, true);
2133
2252
  if (localBindings) {
2134
2253
  this.#extractor.write("return {\nscope:");
2135
2254
  this.#writeObjectKeys(localBindings);
@@ -2149,9 +2268,9 @@ constructor(_?: Return) {}
2149
2268
  this.#extractor.write("\n} else if (undefined) {\n");
2150
2269
  }
2151
2270
  const alternateBody = this.#processBody(node);
2152
- if (alternateBody == null ? void 0 : alternateBody.renderBody) {
2271
+ if (alternateBody == null ? void 0 : alternateBody.content) {
2153
2272
  const localBindings = getHoistSources(node);
2154
- this.#writeChildren(node, alternateBody.renderBody, true);
2273
+ this.#writeChildren(node, alternateBody.content, true);
2155
2274
  if (localBindings) {
2156
2275
  this.#extractor.write("return {\nscope:");
2157
2276
  this.#writeObjectKeys(localBindings);
@@ -2192,12 +2311,12 @@ constructor(_?: Return) {}
2192
2311
  }
2193
2312
  this.#extractor.write("\n) => {\n");
2194
2313
  const body = this.#processBody(child);
2195
- if (body == null ? void 0 : body.renderBody) {
2196
- this.#writeChildren(child, body.renderBody);
2314
+ if (body == null ? void 0 : body.content) {
2315
+ this.#writeChildren(child, body.content);
2197
2316
  }
2198
2317
  this.#writeReturn(
2199
2318
  void 0,
2200
- (body == null ? void 0 : body.renderBody) ? getHoistSources(child) : void 0
2319
+ (body == null ? void 0 : body.content) ? getHoistSources(child) : void 0
2201
2320
  );
2202
2321
  if (renderId) {
2203
2322
  this.#extractor.write("\n}));\n");
@@ -2212,8 +2331,8 @@ constructor(_?: Return) {}
2212
2331
  this.#getRangeWithoutTrailingComma((_b = child.args) == null ? void 0 : _b.value) || "undefined"
2213
2332
  ).write("\n) {\n");
2214
2333
  const body = this.#processBody(child);
2215
- if (body == null ? void 0 : body.renderBody) {
2216
- this.#writeChildren(child, body.renderBody);
2334
+ if (body == null ? void 0 : body.content) {
2335
+ this.#writeChildren(child, body.content);
2217
2336
  }
2218
2337
  this.#extractor.write("\n}\n");
2219
2338
  break;
@@ -2273,51 +2392,53 @@ constructor(_?: Return) {}
2273
2392
  #writeTag(tag) {
2274
2393
  const tagName = tag.nameText;
2275
2394
  const renderId = this.#getRenderId(tag);
2276
- let nestedTagType;
2395
+ const def = tagName ? this.#lookup.getTag(tagName) : void 0;
2277
2396
  if (renderId) {
2278
2397
  this.#extractor.write(
2279
- `${varShared("assertRendered")}(${varShared(
2280
- "rendered"
2281
- )}, ${renderId}, `
2398
+ `${varShared("assertRendered")}(${varShared("rendered")},${renderId},`
2282
2399
  );
2283
2400
  }
2284
- if (tagName) {
2285
- const def = this.#lookup.getTag(tagName);
2286
- if (def) {
2287
- const importPath = resolveTagImport(this.#filename, def);
2288
- const isMarkoFile = importPath == null ? void 0 : importPath.endsWith(".marko");
2289
- if (isMarkoFile) {
2290
- nestedTagType = `import("${importPath}").Input`;
2291
- }
2292
- const renderer = (importPath == null ? void 0 : importPath.endsWith(".marko")) ? `renderTemplate(import("${importPath}"))` : def.html ? `renderNativeTag("${def.name}")` : "missingTag";
2293
- if (!def.html && REG_TAG_NAME_IDENTIFIER.test(tagName)) {
2401
+ if (def == null ? void 0 : def.html) {
2402
+ this.#extractor.write(`${varShared("renderNativeTag")}("`).copy(tag.name).write('")');
2403
+ } else {
2404
+ const importPath = def && resolveTagImport(this.#filename, def);
2405
+ if (def && !importPath) {
2406
+ this.#extractor.write(varShared("missingTag"));
2407
+ } else {
2408
+ const tagId = this.#ensureTagId(tag);
2409
+ let isDynamic = true;
2410
+ this.#extractor.write(
2411
+ `(${varShared("assertTag")}(${varShared("tags")},${tagId},(
2412
+ `
2413
+ );
2414
+ if (tagName && REG_TAG_NAME_IDENTIFIER.test(tagName)) {
2415
+ if (importPath) {
2416
+ this.#extractor.write(
2417
+ `${varShared("fallbackTemplate")}(${tagName},import("${importPath}"))`
2418
+ );
2419
+ } else {
2420
+ this.#extractor.copy(tag.name);
2421
+ }
2422
+ } else if (importPath) {
2423
+ isDynamic = !importPath.endsWith(".marko");
2294
2424
  this.#extractor.write(
2295
- `${varShared("renderPreferLocal")}(
2296
- // @ts-expect-error We expect the compiler to error because we are checking if the tag is defined.
2297
- (${varShared("error")}, `
2298
- ).copy(tag.name).write(`),
2299
- ${varShared(renderer)})`);
2425
+ `${varShared("resolveTemplate")}(import("${importPath}"))`
2426
+ );
2300
2427
  } else {
2301
- this.#extractor.write(varShared(renderer));
2428
+ this.#writeDynamicTagName(tag);
2302
2429
  }
2303
- } else if (REG_TAG_NAME_IDENTIFIER.test(tagName)) {
2304
- nestedTagType = `Marko.Input<typeof ${this.#read(tag.name)}>`;
2305
- this.#extractor.write(`${varShared("renderDynamicTag")}(
2306
- `).copy(tag.name).write("\n)");
2307
- } else {
2308
- this.#extractor.write(`${varShared("missingTag")}`);
2430
+ this.#extractor.write(
2431
+ `
2432
+ )),${varShared(isDynamic ? "renderDynamicTag" : "renderTemplate")}(${varShared("tags")}[${tagId}]))`
2433
+ );
2309
2434
  }
2310
- } else {
2311
- this.#extractor.write(`${varShared("renderDynamicTag")}(`);
2312
- this.#writeDynamicTagName(tag);
2313
- this.#extractor.write(")");
2314
2435
  }
2315
2436
  if (tag.typeArgs) {
2316
2437
  this.#extractor.write(`<0>()`).copy(tag.typeArgs).write("()(");
2317
2438
  } else {
2318
2439
  this.#extractor.write("()()(");
2319
2440
  }
2320
- this.#writeTagInputObject(tag, nestedTagType);
2441
+ this.#writeTagInputObject(tag);
2321
2442
  if (renderId) {
2322
2443
  this.#extractor.write(`)`);
2323
2444
  }
@@ -2501,7 +2622,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}
2501
2622
  );
2502
2623
  return hasAttrs;
2503
2624
  }
2504
- #writeAttrTags({ staticAttrTags, dynamicAttrTagParents }, inMerge, nestedTagType) {
2625
+ #writeAttrTags({ staticAttrTags, dynamicAttrTagParents }, inMerge) {
2505
2626
  let wasMerge = false;
2506
2627
  if (dynamicAttrTagParents) {
2507
2628
  if (staticAttrTags) {
@@ -2517,7 +2638,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}
2517
2638
  }
2518
2639
  }
2519
2640
  if (staticAttrTags) {
2520
- this.#writeStaticAttrTags(staticAttrTags, inMerge, nestedTagType);
2641
+ this.#writeStaticAttrTags(staticAttrTags, inMerge);
2521
2642
  if (dynamicAttrTagParents)
2522
2643
  this.#extractor.write(`}${SEP_COMMA_NEW_LINE}`);
2523
2644
  }
@@ -2526,7 +2647,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}
2526
2647
  if (wasMerge) this.#extractor.write(`)${SEP_COMMA_NEW_LINE}`);
2527
2648
  }
2528
2649
  }
2529
- #writeStaticAttrTags(staticAttrTags, wasMerge, nestedTagType) {
2650
+ #writeStaticAttrTags(staticAttrTags, wasMerge) {
2530
2651
  if (!wasMerge) this.#extractor.write("...{");
2531
2652
  this.#extractor.write(
2532
2653
  `[${varShared("never")}](){
@@ -2547,36 +2668,40 @@ const attrTags = ${varShared(
2547
2668
  this.#extractor.write(SEP_COMMA_NEW_LINE);
2548
2669
  for (const nameText in staticAttrTags) {
2549
2670
  const attrTag = staticAttrTags[nameText];
2550
- const attrTagDef = this.#lookup.getTag(nameText);
2551
2671
  const isRepeated = attrTag.length > 1;
2552
2672
  const [firstAttrTag] = attrTag;
2553
- const name = (attrTagDef == null ? void 0 : attrTagDef.targetProperty) || nameText.slice(nameText.lastIndexOf(":") + 1);
2673
+ const name = this.#getAttrTagName(firstAttrTag);
2554
2674
  this.#extractor.write(`["${name}"`);
2555
2675
  this.#writeTagNameComment(firstAttrTag);
2556
2676
  this.#extractor.write("]: ");
2557
2677
  if (isRepeated) {
2558
- this.#extractor.write(`${varShared("repeatedAttrTag")}(
2559
- ...
2560
- `);
2561
- if (nestedTagType && this.#scriptLang === "js" /* js */) {
2678
+ const tagId = this.#tagIds.get(firstAttrTag.owner);
2679
+ if (tagId) {
2680
+ let accessor = `["${name}"]`;
2681
+ let curTag = firstAttrTag.parent;
2682
+ while (curTag) {
2683
+ if (curTag.type === 16 /* AttrTag */) {
2684
+ accessor = `["${this.#getAttrTagName(curTag)}"]${accessor}`;
2685
+ } else if (!isControlFlowTag(curTag)) {
2686
+ break;
2687
+ }
2688
+ curTag = curTag.parent;
2689
+ }
2562
2690
  this.#extractor.write(
2563
- `/** @satisfies {${nestedTagType}["${name}"][]} */
2691
+ `${varShared("attrTags")}(${varShared("input")}(${varShared("tags")}[${tagId}])${accessor})([
2564
2692
  `
2565
2693
  );
2566
- }
2567
- this.#extractor.write(`([
2694
+ } else {
2695
+ this.#extractor.write(`${varShared("attrTags")}()([
2568
2696
  `);
2697
+ }
2569
2698
  }
2570
2699
  for (const childNode of attrTag) {
2571
2700
  this.#writeTagInputObject(childNode);
2572
2701
  this.#extractor.write(SEP_COMMA_NEW_LINE);
2573
2702
  }
2574
2703
  if (isRepeated) {
2575
- this.#extractor.write("])");
2576
- if (nestedTagType && this.#scriptLang === "ts" /* ts */) {
2577
- this.#extractor.write(` satisfies ${nestedTagType}["${name}"][]`);
2578
- }
2579
- this.#extractor.write(`)${SEP_COMMA_NEW_LINE}`);
2704
+ this.#extractor.write(`])${SEP_COMMA_NEW_LINE}`);
2580
2705
  }
2581
2706
  }
2582
2707
  }
@@ -2639,7 +2764,7 @@ const attrTags = ${varShared(
2639
2764
  this.#extractor.write(SEP_COMMA_NEW_LINE);
2640
2765
  }
2641
2766
  }
2642
- #writeTagInputObject(tag, nestedTagType) {
2767
+ #writeTagInputObject(tag) {
2643
2768
  if (!tag.params) this.#writeComments(tag);
2644
2769
  let hasInput = false;
2645
2770
  this.#extractor.write("{\n");
@@ -2657,7 +2782,7 @@ const attrTags = ${varShared(
2657
2782
  hasInput = true;
2658
2783
  }
2659
2784
  const isScript = isTextOnlyScript(tag);
2660
- let hasRenderBody = false;
2785
+ let hasBodyContent = false;
2661
2786
  let body;
2662
2787
  if (isScript) {
2663
2788
  this.#extractor.write("async value(){");
@@ -2670,14 +2795,35 @@ const attrTags = ${varShared(
2670
2795
  body = this.#processBody(tag);
2671
2796
  if (body) {
2672
2797
  hasInput = true;
2673
- this.#writeAttrTags(body, false, nestedTagType);
2674
- hasRenderBody = body.renderBody !== void 0;
2798
+ this.#writeAttrTags(body, false);
2799
+ hasBodyContent = body.content !== void 0;
2675
2800
  } else if (tag.close) {
2676
- hasRenderBody = true;
2801
+ hasBodyContent = true;
2677
2802
  }
2678
2803
  }
2679
- if (tag.params || hasRenderBody) {
2680
- this.#extractor.write('["renderBody"');
2804
+ if (tag.params || hasBodyContent) {
2805
+ this.#extractor.write("[");
2806
+ switch (this.#api) {
2807
+ case RuntimeAPI.tags:
2808
+ this.#extractor.write('"content"');
2809
+ break;
2810
+ case RuntimeAPI.class:
2811
+ this.#extractor.write('"renderBody"');
2812
+ break;
2813
+ default: {
2814
+ const tagId = this.#tagIds.get(
2815
+ tag.type === 16 /* AttrTag */ ? tag.owner : tag
2816
+ );
2817
+ if (tagId) {
2818
+ this.#extractor.write(
2819
+ `${varShared("contentFor")}(${varShared("tags")}[${tagId}])`
2820
+ );
2821
+ } else {
2822
+ this.#extractor.write(varShared("content"));
2823
+ }
2824
+ break;
2825
+ }
2826
+ }
2681
2827
  this.#writeTagNameComment(tag);
2682
2828
  this.#extractor.write("]: ");
2683
2829
  if (tag.params) {
@@ -2691,8 +2837,8 @@ const attrTags = ${varShared(
2691
2837
  `);
2692
2838
  }
2693
2839
  let didReturn = false;
2694
- if (body == null ? void 0 : body.renderBody) {
2695
- didReturn = this.#writeChildren(tag, body.renderBody);
2840
+ if (body == null ? void 0 : body.content) {
2841
+ didReturn = this.#writeChildren(tag, body.content);
2696
2842
  }
2697
2843
  if (!tag.params) {
2698
2844
  this.#extractor.write(`return () => {
@@ -2781,7 +2927,7 @@ const attrTags = ${varShared(
2781
2927
  const { body } = parent;
2782
2928
  if (!body) return;
2783
2929
  const last = body.length - 1;
2784
- let renderBody;
2930
+ let content;
2785
2931
  let staticAttrTags;
2786
2932
  let dynamicAttrTagParents;
2787
2933
  let i = 0;
@@ -2870,48 +3016,48 @@ const attrTags = ${varShared(
2870
3016
  } else {
2871
3017
  dynamicAttrTagParents = [child];
2872
3018
  }
2873
- } else if (renderBody) {
2874
- renderBody.push(child);
3019
+ } else if (content) {
3020
+ content.push(child);
2875
3021
  } else {
2876
- renderBody = [child];
3022
+ content = [child];
2877
3023
  }
2878
3024
  break;
2879
3025
  }
2880
3026
  case 17 /* Text */: {
2881
3027
  if (!this.#isEmptyText(child)) {
2882
- if (renderBody) {
2883
- renderBody.push(child);
3028
+ if (content) {
3029
+ content.push(child);
2884
3030
  } else {
2885
- renderBody = [child];
3031
+ content = [child];
2886
3032
  }
2887
3033
  }
2888
3034
  break;
2889
3035
  }
2890
3036
  default:
2891
- if (renderBody) {
2892
- renderBody.push(child);
3037
+ if (content) {
3038
+ content.push(child);
2893
3039
  } else {
2894
- renderBody = [child];
3040
+ content = [child];
2895
3041
  }
2896
3042
  break;
2897
3043
  }
2898
3044
  }
2899
- if (renderBody || staticAttrTags || dynamicAttrTagParents) {
2900
- return { renderBody, staticAttrTags, dynamicAttrTagParents };
3045
+ if (content || staticAttrTags || dynamicAttrTagParents) {
3046
+ return { content, staticAttrTags, dynamicAttrTagParents };
2901
3047
  }
2902
3048
  }
2903
3049
  #writeDynamicAttrTagBody(tag) {
2904
3050
  const body = this.#processBody(tag);
2905
3051
  if (body) {
2906
- if (body.renderBody) {
3052
+ if (body.content) {
2907
3053
  this.#extractor.write("(() => {\n");
2908
- this.#writeChildren(tag, body.renderBody);
3054
+ this.#writeChildren(tag, body.content);
2909
3055
  this.#extractor.write("return ");
2910
3056
  }
2911
3057
  this.#extractor.write("{\n");
2912
3058
  this.#writeAttrTags(body, true);
2913
3059
  this.#extractor.write("}");
2914
- if (body.renderBody) {
3060
+ if (body.content) {
2915
3061
  this.#extractor.write(";\n})()");
2916
3062
  }
2917
3063
  } else {
@@ -3014,6 +3160,14 @@ const attrTags = ${varShared(
3014
3160
  }
3015
3161
  return renderId;
3016
3162
  }
3163
+ #ensureTagId(tag) {
3164
+ let tagId = this.#tagIds.get(tag);
3165
+ if (!tagId) {
3166
+ tagId = this.#tagId++;
3167
+ this.#tagIds.set(tag, tagId);
3168
+ }
3169
+ return tagId;
3170
+ }
3017
3171
  #getNamedAttrModifierIndex(attr) {
3018
3172
  const start = attr.name.start + 1;
3019
3173
  const end = attr.name.end - 1;
@@ -3022,6 +3176,11 @@ const attrTags = ${varShared(
3022
3176
  }
3023
3177
  return false;
3024
3178
  }
3179
+ #getAttrTagName(tag) {
3180
+ var _a;
3181
+ const { nameText } = tag;
3182
+ return ((_a = this.#lookup.getTag(nameText)) == null ? void 0 : _a.targetProperty) || nameText.slice(nameText.lastIndexOf(":") + 1);
3183
+ }
3025
3184
  #testAtIndex(reg, index) {
3026
3185
  reg.lastIndex = index;
3027
3186
  return reg.test(this.#code);
@@ -3511,6 +3670,7 @@ var marko_default = {
3511
3670
  return extractScript({
3512
3671
  ts,
3513
3672
  parsed,
3673
+ translator: getConfig(dir).translator,
3514
3674
  lookup: getTagLookup(dir),
3515
3675
  scriptLang: getScriptLang(
3516
3676
  fileName,
@@ -3660,6 +3820,7 @@ export {
3660
3820
  getLines,
3661
3821
  getLocation,
3662
3822
  getPosition,
3823
+ isControlFlowTag,
3663
3824
  isDefinitionFile,
3664
3825
  parse
3665
3826
  };
package/dist/parser.d.ts CHANGED
@@ -80,7 +80,7 @@ export declare namespace Node {
80
80
  interface AttrTag extends Range, Commentable {
81
81
  type: NodeType.AttrTag;
82
82
  parent: ParentTag;
83
- owner: ParentTag | undefined;
83
+ owner: Tag | undefined;
84
84
  concise: boolean;
85
85
  selfClosed: boolean;
86
86
  hasAttrTags: boolean;
@@ -225,3 +225,9 @@ export declare function parse(code: string, filename?: string): {
225
225
  program: Node.Program;
226
226
  code: string;
227
227
  };
228
+ /**
229
+ * Used to check if a node should be ignored as the parent of an attribute tag.
230
+ * When control flow is the parent of an attribute tag, we add the attribute tag to
231
+ * the closest non control flow ancestor attrs instead.
232
+ */
233
+ export declare function isControlFlowTag(node: Node.Tag): node is Node.ControlFlowTag;
@@ -7,6 +7,7 @@ export interface Meta {
7
7
  config: Omit<Compiler.Config, "cache" | "translator"> & {
8
8
  cache: Map<any, any>;
9
9
  translator: {
10
+ preferAPI?: string;
10
11
  runtimeTypes?: string;
11
12
  [x: string]: unknown;
12
13
  };
@@ -25,6 +26,7 @@ export declare function getCache(dir?: string): Map<any, any>;
25
26
  export declare function getConfig(dir?: string): Omit<Compiler.Config, "cache" | "translator"> & {
26
27
  cache: Map<any, any>;
27
28
  translator: {
29
+ preferAPI?: string;
28
30
  runtimeTypes?: string;
29
31
  [x: string]: unknown;
30
32
  };