@marko/language-tools 2.5.56 → 2.5.58

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
@@ -823,7 +823,10 @@ function sortBySourceThenGenerated(a, b) {
823
823
  }
824
824
 
825
825
  // src/extractors/html/keywords.ts
826
- var builtinTagsRegex = /^(?:a(?:(?:bbr|cronym|ddress|pplet|r(?:ea|ticle)|side|udio))?|b(?:(?:ase(?:font)?|d[io]|gsound|ig|l(?:ink|ockquote)|ody|r|utton))?|c(?:a(?:nvas|ption)|enter|ite|o(?:de|l(?:group)?|mmand|ntent))|d(?:ata(?:list)?|d|e(?:l|tails)|fn|i(?:alog|r|v)|l|t)|e(?:lement|m(?:bed)?)|f(?:i(?:eldset|g(?:caption|ure))|o(?:nt|oter|rm)|rame(?:set)?)|h(?:1|2|3|4|5|6|ead(?:er)?|group|r|tml)|i(?:(?:frame|m(?:age|g)|n(?:put|s)|sindex))?|k(?:bd|eygen)|l(?:abel|egend|i(?:(?:nk|sting))?)|m(?:a(?:in|p|r(?:k|quee)|th)|e(?:nu(?:item)?|t(?:a|er))|ulticol)|n(?:av|extid|o(?:br|embed|frames|script))|o(?:bject|l|pt(?:group|ion)|utput)|p(?:(?:aram|icture|laintext|r(?:e|ogress)))?|q|r(?:bc?|p|tc?|uby)|s(?:(?:amp|cript|e(?:ction|lect)|hadow|lot|mall|ource|pa(?:cer|n)|t(?:r(?:ike|ong)|yle)|u(?:b|mmary|p)|vg))?|t(?:able|body|d|e(?:mplate|xtarea)|foot|h(?:ead)?|i(?:me|tle)|r(?:ack)?|t)|ul?|v(?:ar|ideo)|wbr|xmp)$/;
826
+ var builtinTagsRegex = (
827
+ /* cspell:disable-next-line */
828
+ /^(?:a(?:(?:bbr|cronym|ddress|pplet|r(?:ea|ticle)|side|udio))?|b(?:(?:ase(?:font)?|d[io]|gsound|ig|l(?:ink|ockquote)|ody|r|utton))?|c(?:a(?:nvas|ption)|enter|ite|o(?:de|l(?:group)?|mmand|ntent))|d(?:ata(?:list)?|d|e(?:l|tails)|fn|i(?:alog|r|v)|l|t)|e(?:lement|m(?:bed)?)|f(?:i(?:eldset|g(?:caption|ure))|o(?:nt|oter|rm)|rame(?:set)?)|h(?:1|2|3|4|5|6|ead(?:er)?|group|r|tml)|i(?:(?:frame|m(?:age|g)|n(?:put|s)|sindex))?|k(?:bd|eygen)|l(?:abel|egend|i(?:(?:nk|sting))?)|m(?:a(?:in|p|r(?:k|quee)|th)|e(?:nu(?:item)?|t(?:a|er))|ulticol)|n(?:av|extid|o(?:br|embed|frames|script))|o(?:bject|l|pt(?:group|ion)|utput)|p(?:(?:aram|icture|laintext|r(?:e|ogress)))?|q|r(?:bc?|p|tc?|uby)|s(?:(?:amp|cript|e(?:ction|lect)|hadow|lot|mall|ource|pa(?:cer|n)|t(?:r(?:ike|ong)|yle)|u(?:b|mmary|p)|vg))?|t(?:able|body|d|e(?:mplate|xtarea)|foot|h(?:ead)?|i(?:me|tle)|r(?:ack)?|t)|ul?|v(?:ar|ideo)|wbr|xmp)$/
829
+ );
827
830
  function isHTMLTag(tag) {
828
831
  return builtinTagsRegex.test(tag);
829
832
  }
@@ -1022,31 +1025,16 @@ import { relativeImportPath } from "relative-import-path";
1022
1025
 
1023
1026
  // src/extractors/script/util/attach-scopes.ts
1024
1027
  import { types as t } from "@marko/compiler";
1025
-
1026
- // src/extractors/script/util/is-text-only-script.ts
1027
- function isTextOnlyScript(tag) {
1028
- if (tag.nameText !== "script" || tag.args || tag.attrs || !tag.body) {
1029
- return false;
1030
- }
1031
- for (const child of tag.body) {
1032
- if (child.type !== 17 /* Text */) {
1033
- return false;
1034
- }
1035
- }
1036
- return true;
1037
- }
1038
-
1039
- // src/extractors/script/util/attach-scopes.ts
1040
1028
  var VISITOR_KEYS = t.VISITOR_KEYS;
1041
- var ATTR_UNAMED = "value";
1029
+ var ATTR_UNNAMED = "value";
1042
1030
  var Scopes = /* @__PURE__ */ new WeakMap();
1043
1031
  var BoundAttrValueRange = /* @__PURE__ */ new WeakMap();
1044
- function crawlProgramScope(parsed, scriptParser) {
1032
+ function crawlProgramScope(parsed, ast) {
1045
1033
  var _a;
1046
- const { program, read } = parsed;
1034
+ const { program } = parsed;
1047
1035
  const mutations = [];
1048
1036
  const potentialHoists = [];
1049
- const nodesToCheckForMutations = /* @__PURE__ */ new Map();
1037
+ const potentialMutations = /* @__PURE__ */ new Map();
1050
1038
  const programScope = {
1051
1039
  parent: void 0,
1052
1040
  hoists: false,
@@ -1094,10 +1082,13 @@ function crawlProgramScope(parsed, scriptParser) {
1094
1082
  }
1095
1083
  }
1096
1084
  }
1097
- for (const [scope, nodes] of nodesToCheckForMutations) {
1085
+ for (const [scope, nodes] of potentialMutations) {
1086
+ const shadows = /* @__PURE__ */ new Set();
1087
+ const blockMutations = [];
1098
1088
  for (const node of nodes) {
1099
- trackMutationsInClosures(node, scope, mutations);
1089
+ trackMutations(node, scope, mutations, shadows, blockMutations);
1100
1090
  }
1091
+ flushMutations(scope, mutations, shadows, blockMutations);
1101
1092
  }
1102
1093
  if (mutations.length) {
1103
1094
  return mutations.sort(byStart);
@@ -1110,18 +1101,14 @@ function crawlProgramScope(parsed, scriptParser) {
1110
1101
  case 16 /* AttrTag */: {
1111
1102
  if (child.var) {
1112
1103
  parentScope.bindings ??= {};
1113
- const parsedFn = scriptParser.expressionAt(
1114
- child.var.value.start - 1,
1115
- `(${read(child.var.value)})=>0`
1116
- );
1117
- if (parsedFn) {
1118
- const lVal = parsedFn.params[0];
1119
- checkForMutations(parentScope, lVal);
1104
+ const tagVar = ast.tagVar(child.var);
1105
+ if (tagVar) {
1106
+ checkForMutations(parentScope, tagVar);
1120
1107
  for (const id of getVarIdentifiers(
1121
1108
  parsed,
1122
- lVal,
1109
+ tagVar,
1123
1110
  "",
1124
- ATTR_UNAMED
1111
+ ATTR_UNNAMED
1125
1112
  )) {
1126
1113
  const { name, objectPath, sourceName } = id;
1127
1114
  const binding = parentScope.bindings[name] = {
@@ -1146,12 +1133,9 @@ function crawlProgramScope(parsed, scriptParser) {
1146
1133
  };
1147
1134
  if (child.params) {
1148
1135
  bodyScope.bindings ??= {};
1149
- const parsedFn = scriptParser.expressionAt(
1150
- child.params.start,
1151
- `(${read(child.params.value)})=>{}`
1152
- );
1153
- if (parsedFn) {
1154
- for (const param of parsedFn.params) {
1136
+ const parsedParams = ast.tagParams(child.params);
1137
+ if (parsedParams) {
1138
+ for (const param of parsedParams) {
1155
1139
  checkForMutations(bodyScope, param);
1156
1140
  for (const name of getIdentifiers(param)) {
1157
1141
  bodyScope.bindings[name] = {
@@ -1165,19 +1149,16 @@ function crawlProgramScope(parsed, scriptParser) {
1165
1149
  }
1166
1150
  }
1167
1151
  }
1168
- if (isTextOnlyScript(child)) {
1169
- checkForMutations(
1170
- parentScope,
1171
- scriptParser.expressionAt(
1172
- child.body[0].start - "async ()=>{\n".length,
1173
- `async ()=>{
1174
- ${read({
1175
- start: child.body[0].start,
1176
- end: child.body[child.body.length - 1].end
1177
- })}
1178
- }`
1179
- )
1180
- );
1152
+ const scriptBody = ast.scriptBody(child);
1153
+ if (scriptBody) {
1154
+ const nodes = potentialMutations.get(parentScope);
1155
+ if (nodes) {
1156
+ nodes.push(...scriptBody);
1157
+ } else {
1158
+ potentialMutations.set(parentScope, [
1159
+ ...scriptBody
1160
+ ]);
1161
+ }
1181
1162
  } else {
1182
1163
  visit(child.body, bodyScope);
1183
1164
  }
@@ -1187,22 +1168,13 @@ ${read({
1187
1168
  for (const attr of child.attrs) {
1188
1169
  switch (attr.type) {
1189
1170
  case 15 /* AttrSpread */: {
1190
- checkForMutations(
1191
- parentScope,
1192
- scriptParser.expressionAt(
1193
- attr.value.start,
1194
- read(attr.value)
1195
- )
1196
- );
1171
+ checkForMutations(parentScope, ast.attrSpread(attr));
1197
1172
  break;
1198
1173
  }
1199
1174
  case 10 /* AttrNamed */: {
1200
1175
  switch ((_a2 = attr.value) == null ? void 0 : _a2.type) {
1201
1176
  case 13 /* AttrValue */: {
1202
- let parsedValue = scriptParser.expressionAt(
1203
- attr.value.value.start,
1204
- read(attr.value.value)
1205
- );
1177
+ let parsedValue = ast.attrValue(attr.value);
1206
1178
  if (parsedValue) {
1207
1179
  if (!attr.value.bound) {
1208
1180
  checkForMutations(parentScope, parsedValue);
@@ -1252,13 +1224,7 @@ ${read({
1252
1224
  case 14 /* AttrMethod */: {
1253
1225
  checkForMutations(
1254
1226
  parentScope,
1255
- scriptParser.expressionAt(
1256
- attr.value.params.start - 2,
1257
- `{_${read({
1258
- start: attr.value.params.start,
1259
- end: attr.value.body.end
1260
- })}}`
1261
- )
1227
+ ast.attrMethod(attr.value)
1262
1228
  );
1263
1229
  break;
1264
1230
  }
@@ -1275,12 +1241,24 @@ ${read({
1275
1241
  }
1276
1242
  function checkForMutations(scope, node) {
1277
1243
  if (node) {
1278
- const nodes = nodesToCheckForMutations.get(scope);
1279
- if (nodes) {
1280
- nodes.push(node);
1281
- } else {
1282
- nodesToCheckForMutations.set(scope, [node]);
1283
- }
1244
+ traverse(node, (child) => {
1245
+ switch (child.type) {
1246
+ case "FunctionDeclaration":
1247
+ case "FunctionExpression":
1248
+ case "ObjectMethod":
1249
+ case "ArrowFunctionExpression":
1250
+ case "ClassMethod":
1251
+ case "ClassPrivateMethod": {
1252
+ const nodes = potentialMutations.get(scope);
1253
+ if (nodes) {
1254
+ nodes.push(child);
1255
+ } else {
1256
+ potentialMutations.set(scope, [child]);
1257
+ }
1258
+ return true;
1259
+ }
1260
+ }
1261
+ });
1284
1262
  }
1285
1263
  }
1286
1264
  }
@@ -1459,32 +1437,13 @@ function* getVarIdentifiers(parsed, lVal, objectPath, sourceName) {
1459
1437
  break;
1460
1438
  }
1461
1439
  }
1462
- function trackMutationsInClosures(root, scope, mutations) {
1463
- traverse(root, (node) => {
1464
- switch (node.type) {
1465
- // Since the root will always be an expression it's impossible
1466
- // to hit a "FunctionDeclaration" without first going through
1467
- // a a different function context. So we don't need to track it.
1468
- // case "FunctionDeclaration":
1469
- case "FunctionExpression":
1470
- case "ObjectMethod":
1471
- case "ArrowFunctionExpression":
1472
- case "ClassMethod":
1473
- case "ClassPrivateMethod":
1474
- trackMutations(node, scope, mutations, node, /* @__PURE__ */ new Set(), []);
1475
- return true;
1476
- }
1477
- });
1478
- }
1479
- function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows, parentBlockMutations) {
1440
+ function trackMutations(node, scope, mutations, parentBlockShadows, parentBlockMutations) {
1480
1441
  if (!node) return;
1481
- let block = parentBlock;
1482
1442
  let blockShadows = parentBlockShadows;
1483
1443
  let blockMutations = parentBlockMutations;
1484
1444
  switch (node.type) {
1485
1445
  case "BlockStatement":
1486
- if (block !== node) {
1487
- block = node;
1446
+ if (blockMutations === parentBlockMutations) {
1488
1447
  blockShadows = new Set(blockShadows);
1489
1448
  blockMutations = [];
1490
1449
  }
@@ -1492,12 +1451,10 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1492
1451
  case "ForStatement":
1493
1452
  case "ForInStatement":
1494
1453
  case "ForOfStatement":
1495
- block = node.body;
1496
1454
  blockShadows = new Set(blockShadows);
1497
1455
  blockMutations = [];
1498
1456
  break;
1499
1457
  case "ArrowFunctionExpression":
1500
- block = node.body;
1501
1458
  blockShadows = new Set(blockShadows);
1502
1459
  blockMutations = [];
1503
1460
  for (const param of node.params) {
@@ -1507,7 +1464,6 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1507
1464
  case "ObjectMethod":
1508
1465
  case "ClassMethod":
1509
1466
  case "ClassPrivateMethod":
1510
- block = node.body;
1511
1467
  blockShadows = new Set(blockShadows);
1512
1468
  blockMutations = [];
1513
1469
  for (const param of node.params) {
@@ -1515,7 +1471,6 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1515
1471
  }
1516
1472
  break;
1517
1473
  case "FunctionExpression":
1518
- block = node.body;
1519
1474
  blockShadows = new Set(blockShadows);
1520
1475
  blockMutations = [];
1521
1476
  if (node.id) {
@@ -1527,7 +1482,6 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1527
1482
  break;
1528
1483
  case "FunctionDeclaration":
1529
1484
  trackShadows(node.id, scope, parentBlockShadows);
1530
- block = node.body;
1531
1485
  blockShadows = new Set(blockShadows);
1532
1486
  blockMutations = [];
1533
1487
  for (const param of node.params) {
@@ -1535,7 +1489,6 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1535
1489
  }
1536
1490
  break;
1537
1491
  case "ClassExpression":
1538
- block = node.body;
1539
1492
  blockShadows = new Set(blockShadows);
1540
1493
  blockMutations = [];
1541
1494
  if (node.id) {
@@ -1546,12 +1499,10 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1546
1499
  if (node.id) {
1547
1500
  trackShadows(node.id, scope, parentBlockShadows);
1548
1501
  }
1549
- block = node.body;
1550
1502
  blockShadows = new Set(blockShadows);
1551
1503
  blockMutations = [];
1552
1504
  break;
1553
1505
  case "CatchClause":
1554
- block = node.body;
1555
1506
  blockShadows = new Set(blockShadows);
1556
1507
  blockMutations = [];
1557
1508
  if (node.param) {
@@ -1578,34 +1529,23 @@ function trackMutations(node, scope, mutations, parentBlock, parentBlockShadows,
1578
1529
  const child = node[key];
1579
1530
  if (Array.isArray(child)) {
1580
1531
  for (const item of child) {
1581
- trackMutations(
1582
- item,
1583
- scope,
1584
- mutations,
1585
- block,
1586
- blockShadows,
1587
- blockMutations
1588
- );
1532
+ trackMutations(item, scope, mutations, blockShadows, blockMutations);
1589
1533
  }
1590
1534
  } else {
1591
- trackMutations(
1592
- child,
1593
- scope,
1594
- mutations,
1595
- block,
1596
- blockShadows,
1597
- blockMutations
1598
- );
1535
+ trackMutations(child, scope, mutations, blockShadows, blockMutations);
1599
1536
  }
1600
1537
  }
1601
- if (block !== parentBlock && blockMutations.length) {
1602
- for (const { name, start } of blockMutations) {
1603
- if (start == null || blockShadows.has(name)) continue;
1604
- const binding = resolveWritableVar(scope, name);
1605
- if (binding) {
1606
- binding.mutated = true;
1607
- mutations.push({ start, binding });
1608
- }
1538
+ if (blockMutations !== parentBlockMutations && blockMutations.length) {
1539
+ flushMutations(scope, mutations, blockShadows, blockMutations);
1540
+ }
1541
+ }
1542
+ function flushMutations(scope, mutations, blockShadows, blockMutations) {
1543
+ for (const { name, start } of blockMutations) {
1544
+ if (start == null || blockShadows.has(name)) continue;
1545
+ const binding = resolveWritableVar(scope, name);
1546
+ if (binding) {
1547
+ binding.mutated = true;
1548
+ mutations.push({ start, binding });
1609
1549
  }
1610
1550
  }
1611
1551
  }
@@ -1792,6 +1732,19 @@ function detectAPIFromTag(parsed, tag) {
1792
1732
  return detectAPIFromBody(parsed, tag.body);
1793
1733
  }
1794
1734
 
1735
+ // src/extractors/script/util/is-text-only-script.ts
1736
+ function isTextOnlyScript(tag) {
1737
+ if (tag.nameText !== "script" || tag.args || tag.attrs || !tag.body) {
1738
+ return false;
1739
+ }
1740
+ for (const child of tag.body) {
1741
+ if (child.type !== 17 /* Text */) {
1742
+ return false;
1743
+ }
1744
+ }
1745
+ return true;
1746
+ }
1747
+
1795
1748
  // src/extractors/script/util/jsdoc-input-type.ts
1796
1749
  var MaybeInputTypedefReg = /@typedef\b[\s\S]*\bInput\b/;
1797
1750
  function getJSDocInputType(comment, ts) {
@@ -1909,13 +1862,137 @@ import {
1909
1862
  var plugins = ["exportDefaultFrom", "importAssertions", "typescript"];
1910
1863
  var ScriptParser = class {
1911
1864
  #parsed;
1865
+ #cache = /* @__PURE__ */ new Map();
1912
1866
  constructor(parsed) {
1913
1867
  this.#parsed = parsed;
1914
1868
  }
1915
- statementAt(startIndex, src) {
1916
- const pos = this.#parsed.positionAt(startIndex);
1869
+ tagName(name) {
1870
+ return this.#templateExpressions(name);
1871
+ }
1872
+ tagShorthandId(shorthandId) {
1873
+ return this.#templateExpressions(shorthandId);
1874
+ }
1875
+ tagShorthandClassName(node) {
1876
+ return this.#templateExpressions(node);
1877
+ }
1878
+ tagVar(node) {
1879
+ const start = node.value.start - 1;
1880
+ const expr = this.#cache.get(start) ?? this.#expressionAt(start, `(${this.#parsed.read(node.value)})=>0`);
1881
+ if (expr) {
1882
+ return expr.params[0];
1883
+ }
1884
+ }
1885
+ tagParams(node) {
1886
+ const start = node.start;
1887
+ const expr = this.#cache.get(start) ?? this.#expressionAt(start, `(${this.#parsed.read(node.value)})=>0`);
1888
+ if (expr) {
1889
+ return expr.params;
1890
+ }
1891
+ }
1892
+ tagTypeParams(node) {
1893
+ const start = node.value.start - 1;
1894
+ const expr = this.#cache.get(start) ?? this.#expressionAt(start, `<${this.#parsed.read(node.value)}>()=>0`);
1895
+ if (expr) {
1896
+ return expr.typeParameters;
1897
+ }
1898
+ }
1899
+ tagArgs(node) {
1900
+ const start = node.value.start - 2;
1901
+ const expr = this.#cache.get(start) ?? this.#expressionAt(start, `_(${this.#parsed.read(node.value)})`);
1902
+ if (expr) {
1903
+ return expr.arguments;
1904
+ }
1905
+ }
1906
+ tagTypeArgs(node) {
1907
+ const start = node.value.start - 2;
1908
+ const expr = this.#cache.get(start) ?? this.#expressionAt(start, `_<${this.#parsed.read(node.value)}>()`);
1909
+ if (expr) {
1910
+ return expr.typeParameters;
1911
+ }
1912
+ }
1913
+ attrValue(node) {
1914
+ const start = node.value.start;
1915
+ return (this.#cache.get(start) ?? this.#expressionAt(start, this.#parsed.read(node.value))) || void 0;
1916
+ }
1917
+ attrSpread(node) {
1918
+ const start = node.value.start;
1919
+ return (this.#cache.get(start) ?? this.#expressionAt(start, this.#parsed.read(node.value))) || void 0;
1920
+ }
1921
+ attrMethod(node) {
1922
+ const start = node.params.start - 2;
1923
+ const expr = this.#cache.get(start) ?? this.#expressionAt(
1924
+ start,
1925
+ `{_${this.#parsed.read({ start: node.params.start, end: node.body.end })}}`
1926
+ );
1927
+ if (expr) {
1928
+ return expr.properties[0];
1929
+ }
1930
+ }
1931
+ attrArgs(node) {
1932
+ const start = node.value.start;
1933
+ return (this.#cache.get(start) ?? this.#expressionAt(start, this.#parsed.read(node.value))) || void 0;
1934
+ }
1935
+ placeholder(node) {
1936
+ const start = node.value.start;
1937
+ return (this.#cache.get(start) ?? this.#expressionAt(start, this.#parsed.read(node.value))) || void 0;
1938
+ }
1939
+ scriptBody(node) {
1940
+ if (!isTextOnlyScript(node)) return;
1941
+ const start = node.body[0].start;
1942
+ const statements = this.#cache.get(start) ?? this.#statementsAt(
1943
+ start,
1944
+ this.#parsed.read({ start, end: node.body[node.body.length - 1].end })
1945
+ );
1946
+ if (statements) {
1947
+ return statements;
1948
+ }
1949
+ }
1950
+ scriptlet(node) {
1951
+ const start = node.value.start;
1952
+ const statements = this.#cache.get(start) ?? this.#statementsAt(start, this.#parsed.read(node.value));
1953
+ if (statements) {
1954
+ return statements;
1955
+ }
1956
+ }
1957
+ import(node) {
1958
+ const statements = this.#cache.get(node.start) ?? this.#statementsAt(node.start, this.#parsed.read(node));
1959
+ if (statements) {
1960
+ return statements[0];
1961
+ }
1962
+ }
1963
+ export(node) {
1964
+ const statements = this.#cache.get(node.start) ?? this.#statementsAt(node.start, this.#parsed.read(node));
1965
+ if (statements) {
1966
+ return statements[0];
1967
+ }
1968
+ }
1969
+ class(node) {
1970
+ const expr = this.#cache.get(node.start) ?? this.#expressionAt(node.start, this.#parsed.read(node));
1971
+ return expr || void 0;
1972
+ }
1973
+ static(node) {
1974
+ const start = node.start + "static ".length;
1975
+ const statements = this.#cache.get(start) ?? this.#statementsAt(start, this.#parsed.read({ start, end: node.end }));
1976
+ if (statements) {
1977
+ return statements;
1978
+ }
1979
+ }
1980
+ #templateExpressions(template) {
1981
+ const { expressions } = template;
1982
+ if (!expressions.length) return;
1983
+ const result = [];
1984
+ for (const expr of expressions) {
1985
+ const start = expr.value.start;
1986
+ const parsed = this.#cache.get(start) ?? this.#expressionAt(start, this.#parsed.read(expr.value));
1987
+ if (!parsed) return;
1988
+ result.push(parsed);
1989
+ }
1990
+ if (result.length) return result;
1991
+ }
1992
+ #statementsAt(startIndex, src) {
1917
1993
  try {
1918
- return parseStatement(src, {
1994
+ const pos = this.#parsed.positionAt(startIndex);
1995
+ const result = parseStatement(src, {
1919
1996
  plugins,
1920
1997
  startIndex,
1921
1998
  startLine: pos.line + 1,
@@ -1929,14 +2006,18 @@ var ScriptParser = class {
1929
2006
  allowReturnOutsideFunction: true,
1930
2007
  sourceFilename: this.#parsed.filename
1931
2008
  }).program.body;
2009
+ if (result.length) {
2010
+ this.#cache.set(startIndex, result);
2011
+ return result;
2012
+ }
1932
2013
  } catch {
1933
- return [];
1934
2014
  }
2015
+ this.#cache.set(startIndex, false);
1935
2016
  }
1936
- expressionAt(startIndex, src) {
1937
- const pos = this.#parsed.positionAt(startIndex);
2017
+ #expressionAt(startIndex, src) {
1938
2018
  try {
1939
- return parseExpression(src, {
2019
+ const pos = this.#parsed.positionAt(startIndex);
2020
+ const result = parseExpression(src, {
1940
2021
  plugins,
1941
2022
  startIndex,
1942
2023
  startLine: pos.line + 1,
@@ -1950,8 +2031,10 @@ var ScriptParser = class {
1950
2031
  allowReturnOutsideFunction: true,
1951
2032
  sourceFilename: this.#parsed.filename
1952
2033
  });
2034
+ this.#cache.set(startIndex, result);
2035
+ return result;
1953
2036
  } catch {
1954
- return;
2037
+ this.#cache.set(startIndex, false);
1955
2038
  }
1956
2039
  }
1957
2040
  };
@@ -1963,7 +2046,7 @@ var SEP_COMMA_SPACE = ", ";
1963
2046
  var SEP_COMMA_NEW_LINE = ",\n";
1964
2047
  var VAR_LOCAL_PREFIX = "__marko_internal_";
1965
2048
  var VAR_SHARED_PREFIX = `Marko._.`;
1966
- var ATTR_UNAMED2 = "value";
2049
+ var ATTR_UNNAMED2 = "value";
1967
2050
  var REG_EXT = /(?<=[/\\][^/\\]+)\.[^.]+$/;
1968
2051
  var REG_BLOCK = /\s*{/y;
1969
2052
  var REG_NEW_LINE = /^|(\r?\n)/g;
@@ -1994,7 +2077,7 @@ var ScriptExtractor = class {
1994
2077
  #interop;
1995
2078
  #parsed;
1996
2079
  #extractor;
1997
- #scriptParser;
2080
+ #ast;
1998
2081
  #read;
1999
2082
  #lookup;
2000
2083
  #scriptLang;
@@ -2020,9 +2103,9 @@ var ScriptExtractor = class {
2020
2103
  this.#ts = opts.ts;
2021
2104
  this.#runtimeTypes = opts.runtimeTypesCode;
2022
2105
  this.#extractor = new Extractor(parsed);
2023
- this.#scriptParser = new ScriptParser(parsed);
2106
+ this.#ast = new ScriptParser(parsed);
2024
2107
  this.#read = parsed.read.bind(parsed);
2025
- this.#mutations = crawlProgramScope(this.#parsed, this.#scriptParser);
2108
+ this.#mutations = crawlProgramScope(this.#parsed, this.#ast);
2026
2109
  this.#writeProgram(parsed.program);
2027
2110
  }
2028
2111
  end() {
@@ -2322,8 +2405,10 @@ function ${templateName}() {
2322
2405
  this.#extractor.write(`return new (class MarkoReturn<Return = void> {
2323
2406
  `);
2324
2407
  if (scopeExpr) {
2325
- this.#extractor.write(`[${varShared("scope")}] = ${scopeExpr};
2326
- `);
2408
+ this.#extractor.write(
2409
+ `readonly [${varShared("scope")}] = ${scopeExpr};
2410
+ `
2411
+ );
2327
2412
  }
2328
2413
  this.#extractor.write(`declare return: Return;
2329
2414
  constructor(_?: Return) {}
@@ -2367,7 +2452,7 @@ constructor(_?: Return) {}
2367
2452
  }
2368
2453
  this.#writeComments(child);
2369
2454
  this.#extractor.write("if (").copy(
2370
- this.#getRangeWithoutTrailingComma((_a = child.args) == null ? void 0 : _a.value) || this.#getAttrValue(child, ATTR_UNAMED2) || "undefined"
2455
+ this.#getRangeWithoutTrailingComma((_a = child.args) == null ? void 0 : _a.value) || this.#getAttrValue(child, ATTR_UNNAMED2) || "undefined"
2371
2456
  ).write(") {\n");
2372
2457
  const ifBody = this.#processBody(child);
2373
2458
  if (ifBody == null ? void 0 : ifBody.content) {
@@ -2645,11 +2730,11 @@ scope: ${scopeExpr}
2645
2730
  case 10 /* AttrNamed */: {
2646
2731
  const isDefault = isEmptyRange2(attr.name);
2647
2732
  const value = attr.value;
2648
- const modifierIndex = !isDefault && (!value || value.type === 13 /* AttrValue */) && this.#getNamedAttrModifierIndex(attr);
2733
+ const modifier = !value || value.type === 13 /* AttrValue */ ? this.#getNamedAttrModifier(attr) : void 0;
2649
2734
  const defaultMapPosition = isDefault ? attr.name : void 0;
2650
- let name = isDefault ? ATTR_UNAMED2 : attr.name;
2651
- if (modifierIndex !== false) {
2652
- name = { start: attr.name.start, end: modifierIndex };
2735
+ let name = isDefault ? ATTR_UNNAMED2 : attr.name;
2736
+ if (modifier) {
2737
+ name = { start: attr.name.start, end: modifier.start - 1 };
2653
2738
  }
2654
2739
  if (value) {
2655
2740
  switch (value.type) {
@@ -2668,9 +2753,10 @@ scope: ${scopeExpr}
2668
2753
  )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write(
2669
2754
  `Change"(
2670
2755
  // @ts-ignore
2671
- _${valueLiteral}) {
2756
+ _${valueLiteral}
2757
+ ) {
2672
2758
  ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`) : ""}`
2673
- ).copy(boundRange.value).write(`= _${valueLiteral};
2759
+ ).copy(boundRange.value).write("= ").copy(modifier).write(`(_${valueLiteral});
2674
2760
  }`);
2675
2761
  } else if (boundRange.member.computed) {
2676
2762
  this.#extractor.copy(boundRange.value).copy({
@@ -2680,14 +2766,26 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2680
2766
  start: boundRange.member.end,
2681
2767
  end: boundRange.member.end + 1
2682
2768
  }).copy(boundRange.types).write(`
2683
- )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`])");
2769
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n');
2770
+ if (modifier) {
2771
+ this.#extractor.copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`] && ((\n// @ts-ignore\n_\n)=>{\n").copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`](").copy(modifier).write("(_));\n})");
2772
+ } else {
2773
+ this.#extractor.copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`]");
2774
+ }
2775
+ this.#extractor.write(")");
2684
2776
  } else {
2685
2777
  const memberRange = {
2686
2778
  start: boundRange.value.start,
2687
2779
  end: boundRange.member.end
2688
2780
  };
2689
2781
  this.#extractor.copy(memberRange).copy(boundRange.types).write(`
2690
- )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberRange).write("Change)");
2782
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n');
2783
+ if (modifier) {
2784
+ this.#extractor.copy(memberRange).write("Change && ((\n// @ts-ignore\n_\n)=>{\n").copy(memberRange).write("Change(").copy(modifier).write("(_));\n})");
2785
+ } else {
2786
+ this.#extractor.copy(memberRange).write("Change");
2787
+ }
2788
+ this.#extractor.write(")");
2691
2789
  }
2692
2790
  } else {
2693
2791
  this.#copyWithMutationsReplaced(value.value);
@@ -2711,10 +2809,10 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2711
2809
  stringLiteralFirstArgMatch[2]
2712
2810
  );
2713
2811
  if (isValidProperty) {
2714
- const propertNameStart = stringLiteralStart + 1;
2812
+ const propertyNameStart = stringLiteralStart + 1;
2715
2813
  this.#extractor.write("component.").copy({
2716
- start: propertNameStart,
2717
- end: propertNameStart + stringLiteralValue.length
2814
+ start: propertyNameStart,
2815
+ end: propertyNameStart + stringLiteralValue.length
2718
2816
  });
2719
2817
  } else {
2720
2818
  this.#extractor.write(`component[`).copy({
@@ -2736,7 +2834,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2736
2834
  this.#extractor.copy(attr.args);
2737
2835
  }
2738
2836
  } else {
2739
- this.#extractor.write('"').copy(defaultMapPosition).copy(name).write(`": ${modifierIndex === false ? "true" : '""'}`);
2837
+ this.#extractor.write('"').copy(defaultMapPosition).copy(name).write(`": ${modifier ? '""' : "true"}`);
2740
2838
  }
2741
2839
  break;
2742
2840
  }
@@ -2750,7 +2848,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2750
2848
  );
2751
2849
  return hasAttrs;
2752
2850
  }
2753
- #writeAttrTags({ staticAttrTags, dynamicAttrTagParents }) {
2851
+ #writeAttrTags({ staticAttrTags, dynamicAttrTagParents }, constraintExpr) {
2754
2852
  let wasMerge = false;
2755
2853
  if (dynamicAttrTagParents) {
2756
2854
  if (staticAttrTags) {
@@ -2771,7 +2869,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2771
2869
  this.#extractor.write(`}${SEP_COMMA_NEW_LINE}`);
2772
2870
  }
2773
2871
  if (dynamicAttrTagParents) {
2774
- this.#writeDynamicAttrTagParents(dynamicAttrTagParents);
2872
+ this.#writeDynamicAttrTagParents(dynamicAttrTagParents, constraintExpr);
2775
2873
  if (wasMerge) this.#extractor.write(`)${SEP_COMMA_NEW_LINE}`);
2776
2874
  }
2777
2875
  }
@@ -2787,18 +2885,8 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2787
2885
  if (isRepeated) {
2788
2886
  const templateVar = this.#getTemplateVar(firstAttrTag.owner);
2789
2887
  if (templateVar) {
2790
- let accessor = `"${name}"`;
2791
- let curTag = firstAttrTag.parent;
2792
- while (curTag) {
2793
- if (curTag.type === 16 /* AttrTag */) {
2794
- accessor = `"${this.#getAttrTagName(curTag)}",${accessor}`;
2795
- } else if (!isControlFlowTag(curTag)) {
2796
- break;
2797
- }
2798
- curTag = curTag.parent;
2799
- }
2800
2888
  this.#extractor.write(
2801
- `${varShared("attrTagFor")}(${templateVar},${accessor})(`
2889
+ `${varShared("attrTagFor")}(${templateVar},${this.#getAttrTagPath(firstAttrTag)})(`
2802
2890
  );
2803
2891
  } else {
2804
2892
  this.#extractor.write(`${varShared("attrTag")}(`);
@@ -2820,7 +2908,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2820
2908
  }
2821
2909
  }
2822
2910
  }
2823
- #writeDynamicAttrTagParents(dynamicAttrTagParents) {
2911
+ #writeDynamicAttrTagParents(dynamicAttrTagParents, constraintExpr) {
2824
2912
  var _a, _b, _c;
2825
2913
  for (const tag of dynamicAttrTagParents) {
2826
2914
  switch (tag.nameText) {
@@ -2828,7 +2916,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2828
2916
  const alternates = IF_TAG_ALTERNATES.get(tag);
2829
2917
  this.#writeComments(tag);
2830
2918
  this.#extractor.write("((\n").copy(
2831
- this.#getRangeWithoutTrailingComma((_a = tag.args) == null ? void 0 : _a.value) || this.#getAttrValue(tag, ATTR_UNAMED2) || "undefined"
2919
+ this.#getRangeWithoutTrailingComma((_a = tag.args) == null ? void 0 : _a.value) || this.#getAttrValue(tag, ATTR_UNNAMED2) || "undefined"
2832
2920
  ).write("\n) ? ");
2833
2921
  this.#writeDynamicAttrTagBody(tag);
2834
2922
  let needsAlternate = true;
@@ -2862,8 +2950,12 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2862
2950
  this.#extractor.write("\n}, \n");
2863
2951
  this.#writeComments(tag);
2864
2952
  this.#extractor.copy(tag.typeParams).write("(\n").copy((_b = tag.params) == null ? void 0 : _b.value).write("\n) => (");
2865
- this.#writeDynamicAttrTagBody(tag);
2866
- this.#extractor.write("))");
2953
+ this.#writeDynamicAttrTagBody(tag, constraintExpr);
2954
+ this.#extractor.write(")");
2955
+ if (constraintExpr) {
2956
+ this.#extractor.write(`,${constraintExpr}`);
2957
+ }
2958
+ this.#extractor.write(")");
2867
2959
  break;
2868
2960
  }
2869
2961
  case "while": {
@@ -2921,7 +3013,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
2921
3013
  this.#extractor.write(`}${SEP_COMMA_NEW_LINE}`);
2922
3014
  } else if (body) {
2923
3015
  hasInput = true;
2924
- this.#writeAttrTags(body);
3016
+ this.#writeAttrTags(body, this.#getTagInputType(tag));
2925
3017
  hasBodyContent = body.content !== void 0;
2926
3018
  } else if (tag.close) {
2927
3019
  hasBodyContent = true;
@@ -3084,7 +3176,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
3084
3176
  const alternate = {
3085
3177
  condition: this.#getRangeWithoutTrailingComma(
3086
3178
  (_a = nextChild.args) == null ? void 0 : _a.value
3087
- ) || this.#getAttrValue(nextChild, ATTR_UNAMED2),
3179
+ ) || this.#getAttrValue(nextChild, ATTR_UNNAMED2),
3088
3180
  node: nextChild
3089
3181
  };
3090
3182
  hasDynamicAttrTags ||= nextChild.hasAttrTags;
@@ -3157,7 +3249,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
3157
3249
  return { content, staticAttrTags, dynamicAttrTagParents };
3158
3250
  }
3159
3251
  }
3160
- #writeDynamicAttrTagBody(tag) {
3252
+ #writeDynamicAttrTagBody(tag, constraintExpr) {
3161
3253
  const body = this.#processBody(tag);
3162
3254
  if (body) {
3163
3255
  if (body.content) {
@@ -3166,7 +3258,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
3166
3258
  this.#extractor.write("return ");
3167
3259
  }
3168
3260
  this.#extractor.write("{\n");
3169
- this.#writeAttrTags(body);
3261
+ this.#writeAttrTags(body, constraintExpr);
3170
3262
  this.#extractor.write("}");
3171
3263
  if (body.content) {
3172
3264
  this.#endChildren();
@@ -3179,7 +3271,7 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
3179
3271
  #getAttrValue(tag, name) {
3180
3272
  if (tag.attrs) {
3181
3273
  for (const attr of tag.attrs) {
3182
- if (isValueAttribute(attr) && (this.#read(attr.name) || ATTR_UNAMED2) === name) {
3274
+ if (isValueAttribute(attr) && (this.#read(attr.name) || ATTR_UNNAMED2) === name) {
3183
3275
  return attr.value.value;
3184
3276
  }
3185
3277
  }
@@ -3217,9 +3309,9 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
3217
3309
  var _a;
3218
3310
  for (const node of program.static) {
3219
3311
  if (node.type === 25 /* Export */) {
3220
- const start = node.start + "export ".length;
3221
- if (this.#testAtIndex(REG_INPUT_TYPE, start)) {
3222
- const [inputType] = this.#scriptParser.statementAt(start, this.#read({ start, end: node.end }));
3312
+ if (this.#testAtIndex(REG_INPUT_TYPE, node.start + "export ".length)) {
3313
+ const exported = this.#ast.export(node);
3314
+ const inputType = exported == null ? void 0 : exported.declaration;
3223
3315
  return {
3224
3316
  typeParameters: (_a = inputType == null ? void 0 : inputType.typeParameters) == null ? void 0 : _a.params.map((param) => {
3225
3317
  return {
@@ -3314,19 +3406,42 @@ ${isMutatedVar(tag.parent, valueLiteral) ? varLocal(`change__${valueLiteral}.`)
3314
3406
  return `${varShared("readScopes")}({ ${hoistVars.join(SEP_COMMA_SPACE)} })`;
3315
3407
  }
3316
3408
  }
3317
- #getNamedAttrModifierIndex(attr) {
3318
- const start = attr.name.start + 1;
3319
- const end = attr.name.end - 1;
3320
- for (let i = end; i-- > start; ) {
3321
- if (this.#code.charAt(i) === ":") return i;
3409
+ #getNamedAttrModifier(attr) {
3410
+ const start = attr.name.start;
3411
+ const end = attr.name.end;
3412
+ for (let i = end - 1; i-- > start; ) {
3413
+ if (this.#code.charAt(i) === ":") return { start: i + 1, end };
3322
3414
  }
3323
- return false;
3324
3415
  }
3325
3416
  #getAttrTagName(tag) {
3326
3417
  var _a;
3327
3418
  const { nameText } = tag;
3328
3419
  return ((_a = this.#lookup.getTag(nameText)) == null ? void 0 : _a.targetProperty) || nameText.slice(nameText.lastIndexOf(":") + 1);
3329
3420
  }
3421
+ #getAttrTagPath(tag) {
3422
+ let path4 = `"${this.#getAttrTagName(tag)}"`;
3423
+ let curTag = tag.parent;
3424
+ while (curTag) {
3425
+ if (curTag.type === 16 /* AttrTag */) {
3426
+ path4 = `"${this.#getAttrTagName(curTag)}",${path4}`;
3427
+ } else if (!isControlFlowTag(curTag)) {
3428
+ break;
3429
+ }
3430
+ curTag = curTag.parent;
3431
+ }
3432
+ return path4;
3433
+ }
3434
+ #getTagInputType(tag) {
3435
+ if (tag.type === 16 /* AttrTag */) {
3436
+ if (!tag.owner) return;
3437
+ const templateVar2 = this.#getTemplateVar(tag.owner);
3438
+ if (!templateVar2) return;
3439
+ return `${varShared("inputForAttr")}(${templateVar2},${this.#getAttrTagPath(tag)})`;
3440
+ }
3441
+ const templateVar = this.#getTemplateVar(tag);
3442
+ if (!templateVar) return;
3443
+ return `${varShared("input")}(${templateVar})`;
3444
+ }
3330
3445
  #writeAttrTagTree(tree, valueExpression, nested) {
3331
3446
  this.#extractor.write(
3332
3447
  `${varShared(nested ? "nestedAttrTagNames" : "attrTagNames")}(${valueExpression},input=>{
@@ -3916,7 +4031,7 @@ var marko_default = {
3916
4031
  isExportComponentType(statement) || // skips the generated `export { type Component }`.
3917
4032
  isImportComponentType(statement) || // skips the generated `import type Component from "..."`.
3918
4033
  isExportEmptyInputType(statement) || // skips empty exported Input, eg `export type Input = {}` or `export interface Input {}`.
3919
- isExportInputTypeAsComponentInput(statement) || // skips outputing `export type Input = Component["input"]` since it's inferred.
4034
+ isExportInputTypeAsComponentInput(statement) || // skips outputting `export type Input = Component["input"]` since it's inferred.
3920
4035
  defaultExportId && // If the `export default` was an identifier, we also remove the variable that declared the identifier.
3921
4036
  isVariableStatementForName(statement, defaultExportId)) {
3922
4037
  continue;