@marko/language-tools 2.5.33 → 2.5.35

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.
@@ -1,4 +1,4 @@
1
- import { type Node, Parsed, Repeatable, Repeated } from "../../../parser";
1
+ import { type Node, Parsed, type Range, Repeatable, Repeated } from "../../../parser";
2
2
  import type { ScriptParser } from "./script-parser";
3
3
  export interface Options {
4
4
  parsed: Parsed;
@@ -58,5 +58,11 @@ export declare function getHoistSources(body: Node.ParentNode["body"]): Repeatab
58
58
  export declare function getMutatedVars(node: Node.ParentNode): Set<VarBinding> | undefined;
59
59
  export declare function isMutatedVar(node: Node.ParentNode, name: string): boolean;
60
60
  export declare function hasHoists(node: Node.ParentTag): boolean;
61
- export declare function getBoundAttrMemberExpressionStartOffset(value: Node.AttrValue): number | undefined;
61
+ export declare function getBoundAttrRange(value: Node.AttrValue): {
62
+ value: Range;
63
+ types: undefined | Range;
64
+ member: undefined | (Range & {
65
+ computed: boolean;
66
+ });
67
+ } | undefined;
62
68
  export {};
package/dist/index.js CHANGED
@@ -1079,7 +1079,7 @@ function isTextOnlyScript(tag) {
1079
1079
  // src/extractors/script/util/attach-scopes.ts
1080
1080
  var ATTR_UNAMED = "value";
1081
1081
  var Scopes = /* @__PURE__ */ new WeakMap();
1082
- var BoundAttrMemberExpressionStartOffsets = /* @__PURE__ */ new WeakMap();
1082
+ var BoundAttrValueRange = /* @__PURE__ */ new WeakMap();
1083
1083
  function crawlProgramScope(parsed, scriptParser) {
1084
1084
  var _a;
1085
1085
  const { program, read } = parsed;
@@ -1240,37 +1240,55 @@ ${read({
1240
1240
  case 10 /* AttrNamed */: {
1241
1241
  switch ((_a2 = attr.value) == null ? void 0 : _a2.type) {
1242
1242
  case 13 /* AttrValue */: {
1243
- const parsedValue = scriptParser.expressionAt(
1243
+ let parsedValue = scriptParser.expressionAt(
1244
1244
  attr.value.value.start,
1245
1245
  read(attr.value.value)
1246
1246
  );
1247
1247
  if (parsedValue) {
1248
- switch (parsedValue.type) {
1249
- case "Identifier":
1250
- if (attr.value.bound) {
1251
- const binding = resolveWritableVar(
1252
- parentScope,
1253
- parsedValue.name
1254
- );
1255
- if (binding) {
1256
- binding.mutated = true;
1257
- (parentScope.mutatedBindings ||= /* @__PURE__ */ new Set()).add(
1258
- binding
1259
- );
1260
- }
1261
- }
1262
- break;
1263
- case "MemberExpression":
1264
- if (attr.value.bound) {
1265
- BoundAttrMemberExpressionStartOffsets.set(
1266
- attr.value,
1267
- parsedValue.property.start - 1
1248
+ if (!attr.value.bound) {
1249
+ checkForMutations(parentScope, parsedValue);
1250
+ } else {
1251
+ let types;
1252
+ if (parsedValue.type === "TSAsExpression" || parsedValue.type === "TSSatisfiesExpression") {
1253
+ types = {
1254
+ start: parsedValue.expression.end + 1,
1255
+ end: parsedValue.end
1256
+ };
1257
+ parsedValue = parsedValue.expression;
1258
+ }
1259
+ if (parsedValue.type === "Identifier") {
1260
+ const binding = resolveWritableVar(
1261
+ parentScope,
1262
+ parsedValue.name
1263
+ );
1264
+ if (binding) {
1265
+ binding.mutated = true;
1266
+ (parentScope.mutatedBindings ||= /* @__PURE__ */ new Set()).add(
1267
+ binding
1268
1268
  );
1269
1269
  }
1270
- break;
1271
- default:
1272
- checkForMutations(parentScope, parsedValue);
1273
- break;
1270
+ BoundAttrValueRange.set(attr.value, {
1271
+ types,
1272
+ value: {
1273
+ start: parsedValue.start,
1274
+ end: parsedValue.end
1275
+ },
1276
+ member: void 0
1277
+ });
1278
+ } else if (parsedValue.type === "MemberExpression") {
1279
+ BoundAttrValueRange.set(attr.value, {
1280
+ types,
1281
+ value: {
1282
+ start: parsedValue.start,
1283
+ end: parsedValue.property.start - 1
1284
+ },
1285
+ member: {
1286
+ start: parsedValue.property.start,
1287
+ end: parsedValue.property.end,
1288
+ computed: parsedValue.computed
1289
+ }
1290
+ });
1291
+ }
1274
1292
  }
1275
1293
  }
1276
1294
  break;
@@ -1355,8 +1373,8 @@ function isMutatedVar(node, name) {
1355
1373
  function hasHoists(node) {
1356
1374
  return node.body ? Scopes.get(node.body).hoists : false;
1357
1375
  }
1358
- function getBoundAttrMemberExpressionStartOffset(value) {
1359
- return BoundAttrMemberExpressionStartOffsets.get(value);
1376
+ function getBoundAttrRange(value) {
1377
+ return BoundAttrValueRange.get(value);
1360
1378
  }
1361
1379
  function resolveWritableVar(scope, name) {
1362
1380
  var _a;
@@ -2083,7 +2101,7 @@ var ScriptExtractor = class {
2083
2101
  );
2084
2102
  } else {
2085
2103
  this.#extractor.write(
2086
- `/** @typedef {${isExternalComponentFile ? "Component['input']" : "Record<string, unknown>"}} Input */
2104
+ `/** @typedef {Record<string, unknown>} Input */
2087
2105
  `
2088
2106
  );
2089
2107
  }
@@ -2095,13 +2113,14 @@ var ScriptExtractor = class {
2095
2113
  `import type Component from "${stripExt(
2096
2114
  (0, import_relative_import_path.relativeImportPath)(this.#filename, componentFileName)
2097
2115
  )}";
2116
+ export { type Component }
2098
2117
  `
2099
2118
  );
2100
2119
  } else {
2101
2120
  this.#extractor.write(
2102
2121
  `/** @typedef {import("${stripExt(
2103
2122
  (0, import_relative_import_path.relativeImportPath)(this.#filename, componentFileName)
2104
- )}") extends infer Component ? Component extends { default: infer Component } ? Component : Component : never} Component */
2123
+ )}") extends infer Component ? Component extends { default: infer Component } ? Component : Component : Marko.Component<Input${typeArgsStr}>} Component */
2105
2124
  `
2106
2125
  );
2107
2126
  }
@@ -2594,42 +2613,41 @@ scope: ${scopeExpr}
2594
2613
  this.#copyWithMutationsReplaced(value.params);
2595
2614
  this.#copyWithMutationsReplaced(value.body);
2596
2615
  break;
2597
- case 13 /* AttrValue */:
2616
+ case 13 /* AttrValue */: {
2617
+ const boundRange = value.bound && getBoundAttrRange(value);
2598
2618
  this.#extractor.write('"').copy(defaultMapPosition).copy(name).write('": (\n');
2599
- if (value.bound) {
2600
- const memberExpressionStart = getBoundAttrMemberExpressionStartOffset(value);
2601
- if (memberExpressionStart === void 0) {
2602
- const valueLiteral = this.#read(value.value);
2603
- this.#extractor.copy(value.value).write(`
2619
+ if (boundRange) {
2620
+ if (!boundRange.member) {
2621
+ const valueLiteral = this.#read(boundRange.value);
2622
+ this.#extractor.copy(boundRange.value).copy(boundRange.types).write(`
2604
2623
  )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write(
2605
2624
  `Change"(_${valueLiteral}) {
2606
2625
  ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}`
2607
- ).copy(value.value).write(`= _${valueLiteral};
2626
+ ).copy(boundRange.value).write(`= _${valueLiteral};
2608
2627
  }`);
2609
- } else if (this.#code[memberExpressionStart] === "[") {
2610
- const memberObjectRange = {
2611
- start: value.value.start,
2612
- end: memberExpressionStart + 1
2613
- };
2614
- const memberPropertyRange = {
2615
- start: memberObjectRange.end,
2616
- end: value.value.end - 1
2617
- };
2618
- const memberPropertyCloseRange = {
2619
- start: memberPropertyRange.end,
2620
- end: value.value.end
2621
- };
2622
- this.#extractor.copy(memberObjectRange).copy(memberPropertyRange).copy(memberPropertyCloseRange).write(`
2623
- )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberObjectRange).write("\n`${\n").copy(memberPropertyRange).write("\n}Change`\n").copy(memberPropertyCloseRange).write("\n)");
2628
+ } else if (boundRange.member.computed) {
2629
+ this.#extractor.copy(boundRange.value).copy({
2630
+ start: boundRange.value.end,
2631
+ end: boundRange.value.end + 1
2632
+ }).copy(boundRange.member).copy({
2633
+ start: boundRange.member.end,
2634
+ end: boundRange.member.end + 1
2635
+ }).copy(boundRange.types).write(`
2636
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`])");
2624
2637
  } else {
2625
- this.#extractor.copy(value.value).write(`
2626
- )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change"').write(": ").copy(value.value).write(`Change`);
2638
+ const memberRange = {
2639
+ start: boundRange.value.start,
2640
+ end: boundRange.member.end
2641
+ };
2642
+ this.#extractor.copy(memberRange).copy(boundRange.types).write(`
2643
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberRange).write("Change)");
2627
2644
  }
2628
2645
  } else {
2629
2646
  this.#copyWithMutationsReplaced(value.value);
2630
2647
  this.#extractor.write("\n)");
2631
2648
  }
2632
2649
  break;
2650
+ }
2633
2651
  }
2634
2652
  } else if (attr.args) {
2635
2653
  this.#extractor.write('"').copy(name).write('": ');
@@ -3324,9 +3342,9 @@ function getForTagType(parsed, tag) {
3324
3342
  case "in":
3325
3343
  return 2 /* in */;
3326
3344
  case "to":
3327
- case "from":
3328
- case "step":
3329
3345
  return 3 /* to */;
3346
+ case "until":
3347
+ return 4 /* until */;
3330
3348
  }
3331
3349
  }
3332
3350
  }
@@ -3340,6 +3358,8 @@ function getForTagRuntime(parsed, tag) {
3340
3358
  return "forInTag";
3341
3359
  case 3 /* to */:
3342
3360
  return "forToTag";
3361
+ case 4 /* until */:
3362
+ return "forUntilTag";
3343
3363
  default:
3344
3364
  return "forTag";
3345
3365
  }
@@ -3352,6 +3372,8 @@ function getForAttrTagRuntime(parsed, tag) {
3352
3372
  return "forInAttrTag";
3353
3373
  case 3 /* to */:
3354
3374
  return "forToAttrTag";
3375
+ case 4 /* until */:
3376
+ return "forUntilAttrTag";
3355
3377
  default:
3356
3378
  return "forAttrTag";
3357
3379
  }
@@ -3894,7 +3916,12 @@ var marko_default = {
3894
3916
  return ts.isTypeAliasDeclaration(statement) && statement.name.escapedText === "Input" && ts.isTypeLiteralNode(statement.type) && !statement.typeParameters && statement.type.members.length === 0 || ts.isInterfaceDeclaration(statement) && statement.name.escapedText === "Input" && !statement.heritageClauses && !statement.typeParameters && statement.members.length === 0;
3895
3917
  }
3896
3918
  function isExportComponentType(statement) {
3897
- return ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.length === 1 && ts.isIdentifier(statement.exportClause.elements[0].name) && statement.exportClause.elements[0].name.escapedText === "Component";
3919
+ if (ts.isExportDeclaration(statement)) {
3920
+ return statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.length === 1 && ts.isIdentifier(statement.exportClause.elements[0].name) && statement.exportClause.elements[0].name.escapedText === "Component";
3921
+ } else if (ts.isTypeAliasDeclaration(statement)) {
3922
+ return statement.name.text === "Component";
3923
+ }
3924
+ return false;
3898
3925
  }
3899
3926
  function isVariableStatementForName(statement, name) {
3900
3927
  if (ts.isVariableStatement(statement)) {
package/dist/index.mjs CHANGED
@@ -1039,7 +1039,7 @@ function isTextOnlyScript(tag) {
1039
1039
  // src/extractors/script/util/attach-scopes.ts
1040
1040
  var ATTR_UNAMED = "value";
1041
1041
  var Scopes = /* @__PURE__ */ new WeakMap();
1042
- var BoundAttrMemberExpressionStartOffsets = /* @__PURE__ */ new WeakMap();
1042
+ var BoundAttrValueRange = /* @__PURE__ */ new WeakMap();
1043
1043
  function crawlProgramScope(parsed, scriptParser) {
1044
1044
  var _a;
1045
1045
  const { program, read } = parsed;
@@ -1200,37 +1200,55 @@ ${read({
1200
1200
  case 10 /* AttrNamed */: {
1201
1201
  switch ((_a2 = attr.value) == null ? void 0 : _a2.type) {
1202
1202
  case 13 /* AttrValue */: {
1203
- const parsedValue = scriptParser.expressionAt(
1203
+ let parsedValue = scriptParser.expressionAt(
1204
1204
  attr.value.value.start,
1205
1205
  read(attr.value.value)
1206
1206
  );
1207
1207
  if (parsedValue) {
1208
- switch (parsedValue.type) {
1209
- case "Identifier":
1210
- if (attr.value.bound) {
1211
- const binding = resolveWritableVar(
1212
- parentScope,
1213
- parsedValue.name
1214
- );
1215
- if (binding) {
1216
- binding.mutated = true;
1217
- (parentScope.mutatedBindings ||= /* @__PURE__ */ new Set()).add(
1218
- binding
1219
- );
1220
- }
1221
- }
1222
- break;
1223
- case "MemberExpression":
1224
- if (attr.value.bound) {
1225
- BoundAttrMemberExpressionStartOffsets.set(
1226
- attr.value,
1227
- parsedValue.property.start - 1
1208
+ if (!attr.value.bound) {
1209
+ checkForMutations(parentScope, parsedValue);
1210
+ } else {
1211
+ let types;
1212
+ if (parsedValue.type === "TSAsExpression" || parsedValue.type === "TSSatisfiesExpression") {
1213
+ types = {
1214
+ start: parsedValue.expression.end + 1,
1215
+ end: parsedValue.end
1216
+ };
1217
+ parsedValue = parsedValue.expression;
1218
+ }
1219
+ if (parsedValue.type === "Identifier") {
1220
+ const binding = resolveWritableVar(
1221
+ parentScope,
1222
+ parsedValue.name
1223
+ );
1224
+ if (binding) {
1225
+ binding.mutated = true;
1226
+ (parentScope.mutatedBindings ||= /* @__PURE__ */ new Set()).add(
1227
+ binding
1228
1228
  );
1229
1229
  }
1230
- break;
1231
- default:
1232
- checkForMutations(parentScope, parsedValue);
1233
- break;
1230
+ BoundAttrValueRange.set(attr.value, {
1231
+ types,
1232
+ value: {
1233
+ start: parsedValue.start,
1234
+ end: parsedValue.end
1235
+ },
1236
+ member: void 0
1237
+ });
1238
+ } else if (parsedValue.type === "MemberExpression") {
1239
+ BoundAttrValueRange.set(attr.value, {
1240
+ types,
1241
+ value: {
1242
+ start: parsedValue.start,
1243
+ end: parsedValue.property.start - 1
1244
+ },
1245
+ member: {
1246
+ start: parsedValue.property.start,
1247
+ end: parsedValue.property.end,
1248
+ computed: parsedValue.computed
1249
+ }
1250
+ });
1251
+ }
1234
1252
  }
1235
1253
  }
1236
1254
  break;
@@ -1315,8 +1333,8 @@ function isMutatedVar(node, name) {
1315
1333
  function hasHoists(node) {
1316
1334
  return node.body ? Scopes.get(node.body).hoists : false;
1317
1335
  }
1318
- function getBoundAttrMemberExpressionStartOffset(value) {
1319
- return BoundAttrMemberExpressionStartOffsets.get(value);
1336
+ function getBoundAttrRange(value) {
1337
+ return BoundAttrValueRange.get(value);
1320
1338
  }
1321
1339
  function resolveWritableVar(scope, name) {
1322
1340
  var _a;
@@ -2046,7 +2064,7 @@ var ScriptExtractor = class {
2046
2064
  );
2047
2065
  } else {
2048
2066
  this.#extractor.write(
2049
- `/** @typedef {${isExternalComponentFile ? "Component['input']" : "Record<string, unknown>"}} Input */
2067
+ `/** @typedef {Record<string, unknown>} Input */
2050
2068
  `
2051
2069
  );
2052
2070
  }
@@ -2058,13 +2076,14 @@ var ScriptExtractor = class {
2058
2076
  `import type Component from "${stripExt(
2059
2077
  relativeImportPath(this.#filename, componentFileName)
2060
2078
  )}";
2079
+ export { type Component }
2061
2080
  `
2062
2081
  );
2063
2082
  } else {
2064
2083
  this.#extractor.write(
2065
2084
  `/** @typedef {import("${stripExt(
2066
2085
  relativeImportPath(this.#filename, componentFileName)
2067
- )}") extends infer Component ? Component extends { default: infer Component } ? Component : Component : never} Component */
2086
+ )}") extends infer Component ? Component extends { default: infer Component } ? Component : Component : Marko.Component<Input${typeArgsStr}>} Component */
2068
2087
  `
2069
2088
  );
2070
2089
  }
@@ -2557,42 +2576,41 @@ scope: ${scopeExpr}
2557
2576
  this.#copyWithMutationsReplaced(value.params);
2558
2577
  this.#copyWithMutationsReplaced(value.body);
2559
2578
  break;
2560
- case 13 /* AttrValue */:
2579
+ case 13 /* AttrValue */: {
2580
+ const boundRange = value.bound && getBoundAttrRange(value);
2561
2581
  this.#extractor.write('"').copy(defaultMapPosition).copy(name).write('": (\n');
2562
- if (value.bound) {
2563
- const memberExpressionStart = getBoundAttrMemberExpressionStartOffset(value);
2564
- if (memberExpressionStart === void 0) {
2565
- const valueLiteral = this.#read(value.value);
2566
- this.#extractor.copy(value.value).write(`
2582
+ if (boundRange) {
2583
+ if (!boundRange.member) {
2584
+ const valueLiteral = this.#read(boundRange.value);
2585
+ this.#extractor.copy(boundRange.value).copy(boundRange.types).write(`
2567
2586
  )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write(
2568
2587
  `Change"(_${valueLiteral}) {
2569
2588
  ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}`
2570
- ).copy(value.value).write(`= _${valueLiteral};
2589
+ ).copy(boundRange.value).write(`= _${valueLiteral};
2571
2590
  }`);
2572
- } else if (this.#code[memberExpressionStart] === "[") {
2573
- const memberObjectRange = {
2574
- start: value.value.start,
2575
- end: memberExpressionStart + 1
2576
- };
2577
- const memberPropertyRange = {
2578
- start: memberObjectRange.end,
2579
- end: value.value.end - 1
2580
- };
2581
- const memberPropertyCloseRange = {
2582
- start: memberPropertyRange.end,
2583
- end: value.value.end
2584
- };
2585
- this.#extractor.copy(memberObjectRange).copy(memberPropertyRange).copy(memberPropertyCloseRange).write(`
2586
- )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberObjectRange).write("\n`${\n").copy(memberPropertyRange).write("\n}Change`\n").copy(memberPropertyCloseRange).write("\n)");
2591
+ } else if (boundRange.member.computed) {
2592
+ this.#extractor.copy(boundRange.value).copy({
2593
+ start: boundRange.value.end,
2594
+ end: boundRange.value.end + 1
2595
+ }).copy(boundRange.member).copy({
2596
+ start: boundRange.member.end,
2597
+ end: boundRange.member.end + 1
2598
+ }).copy(boundRange.types).write(`
2599
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`])");
2587
2600
  } else {
2588
- this.#extractor.copy(value.value).write(`
2589
- )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change"').write(": ").copy(value.value).write(`Change`);
2601
+ const memberRange = {
2602
+ start: boundRange.value.start,
2603
+ end: boundRange.member.end
2604
+ };
2605
+ this.#extractor.copy(memberRange).copy(boundRange.types).write(`
2606
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberRange).write("Change)");
2590
2607
  }
2591
2608
  } else {
2592
2609
  this.#copyWithMutationsReplaced(value.value);
2593
2610
  this.#extractor.write("\n)");
2594
2611
  }
2595
2612
  break;
2613
+ }
2596
2614
  }
2597
2615
  } else if (attr.args) {
2598
2616
  this.#extractor.write('"').copy(name).write('": ');
@@ -3287,9 +3305,9 @@ function getForTagType(parsed, tag) {
3287
3305
  case "in":
3288
3306
  return 2 /* in */;
3289
3307
  case "to":
3290
- case "from":
3291
- case "step":
3292
3308
  return 3 /* to */;
3309
+ case "until":
3310
+ return 4 /* until */;
3293
3311
  }
3294
3312
  }
3295
3313
  }
@@ -3303,6 +3321,8 @@ function getForTagRuntime(parsed, tag) {
3303
3321
  return "forInTag";
3304
3322
  case 3 /* to */:
3305
3323
  return "forToTag";
3324
+ case 4 /* until */:
3325
+ return "forUntilTag";
3306
3326
  default:
3307
3327
  return "forTag";
3308
3328
  }
@@ -3315,6 +3335,8 @@ function getForAttrTagRuntime(parsed, tag) {
3315
3335
  return "forInAttrTag";
3316
3336
  case 3 /* to */:
3317
3337
  return "forToAttrTag";
3338
+ case 4 /* until */:
3339
+ return "forUntilAttrTag";
3318
3340
  default:
3319
3341
  return "forAttrTag";
3320
3342
  }
@@ -3857,7 +3879,12 @@ var marko_default = {
3857
3879
  return ts.isTypeAliasDeclaration(statement) && statement.name.escapedText === "Input" && ts.isTypeLiteralNode(statement.type) && !statement.typeParameters && statement.type.members.length === 0 || ts.isInterfaceDeclaration(statement) && statement.name.escapedText === "Input" && !statement.heritageClauses && !statement.typeParameters && statement.members.length === 0;
3858
3880
  }
3859
3881
  function isExportComponentType(statement) {
3860
- return ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.length === 1 && ts.isIdentifier(statement.exportClause.elements[0].name) && statement.exportClause.elements[0].name.escapedText === "Component";
3882
+ if (ts.isExportDeclaration(statement)) {
3883
+ return statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.length === 1 && ts.isIdentifier(statement.exportClause.elements[0].name) && statement.exportClause.elements[0].name.escapedText === "Component";
3884
+ } else if (ts.isTypeAliasDeclaration(statement)) {
3885
+ return statement.name.text === "Component";
3886
+ }
3887
+ return false;
3861
3888
  }
3862
3889
  function isVariableStatementForName(statement, name) {
3863
3890
  if (ts.isVariableStatement(statement)) {
@@ -224,6 +224,21 @@ declare global {
224
224
  content: BodyContent,
225
225
  ): ReturnAndScope<BodyContentScope<BodyContent>, void>;
226
226
 
227
+ export function forUntilTag<
228
+ From extends void | number,
229
+ Until extends number,
230
+ Step extends void | number,
231
+ BodyContent extends Marko.Body<[index: number], void>,
232
+ >(
233
+ input: {
234
+ from?: From;
235
+ until: Until;
236
+ step?: Step;
237
+ by?: (index: number) => string;
238
+ },
239
+ content: BodyContent,
240
+ ): ReturnAndScope<BodyContentScope<BodyContent>, void>;
241
+
227
242
  export function forTag<BodyContent extends AnyMarkoBody>(
228
243
  input: (
229
244
  | {
@@ -231,6 +246,11 @@ declare global {
231
246
  to: number;
232
247
  step?: number;
233
248
  }
249
+ | {
250
+ from?: number;
251
+ until: number;
252
+ step?: number;
253
+ }
234
254
  | {
235
255
  in: object | false | void | null;
236
256
  }
@@ -301,6 +321,32 @@ declare global {
301
321
  : never;
302
322
  };
303
323
 
324
+ export function forUntilAttrTag<
325
+ From extends void | number,
326
+ Until extends number,
327
+ Step extends void | number,
328
+ const Return,
329
+ >(
330
+ input: {
331
+ from?: From;
332
+ until: Until;
333
+ step?: Step;
334
+ },
335
+ content: (index: number) => Return,
336
+ ): {
337
+ [Key in keyof Return]: Return[Key] extends
338
+ | readonly (infer Item)[]
339
+ | (infer Item extends Record<PropertyKey, any>)
340
+ ? number extends From | Until | Step
341
+ ? undefined | Marko.AttrTag<Item>
342
+ : Step extends 0
343
+ ? never
344
+ : [Until] extends [From extends void ? 0 : From]
345
+ ? undefined
346
+ : Marko.AttrTag<Item>
347
+ : never;
348
+ };
349
+
304
350
  export function forAttrTag<const Return>(
305
351
  input:
306
352
  | {
@@ -313,6 +359,11 @@ declare global {
313
359
  from?: number;
314
360
  to: number;
315
361
  step?: number;
362
+ }
363
+ | {
364
+ from?: number;
365
+ until: number;
366
+ step?: number;
316
367
  },
317
368
  content: (...args: unknown[]) => Return,
318
369
  ): {
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "@marko/language-tools",
3
3
  "description": "Marko Language Tools",
4
- "version": "2.5.33",
4
+ "version": "2.5.35",
5
5
  "bugs": "https://github.com/marko-js/language-server/issues/new?template=Bug_report.md",
6
6
  "peerDependencies": {
7
7
  "@marko/compiler": "^5.28.4"
8
8
  },
9
9
  "dependencies": {
10
- "@babel/parser": "^7.28.3",
10
+ "@babel/parser": "^7.28.4",
11
11
  "@luxass/strip-json-comments": "^1.4.0",
12
12
  "htmljs-parser": "^5.7.4",
13
13
  "relative-import-path": "^1.0.0"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@babel/code-frame": "^7.27.1",
17
- "@marko/compiler": "^5.39.33",
17
+ "@marko/compiler": "^5.39.35",
18
18
  "@types/babel__code-frame": "^7.0.6",
19
19
  "@typescript/vfs": "^1.6.1",
20
- "marko": "^5.37.47",
20
+ "marko": "^5.37.55",
21
21
  "mitata": "^1.0.34",
22
- "tsx": "^4.20.4"
22
+ "tsx": "^4.20.5"
23
23
  },
24
24
  "exports": {
25
25
  ".": {