@marko/language-tools 2.5.33 → 2.5.34

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;
@@ -2594,42 +2612,41 @@ scope: ${scopeExpr}
2594
2612
  this.#copyWithMutationsReplaced(value.params);
2595
2613
  this.#copyWithMutationsReplaced(value.body);
2596
2614
  break;
2597
- case 13 /* AttrValue */:
2615
+ case 13 /* AttrValue */: {
2616
+ const boundRange = value.bound && getBoundAttrRange(value);
2598
2617
  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(`
2618
+ if (boundRange) {
2619
+ if (!boundRange.member) {
2620
+ const valueLiteral = this.#read(boundRange.value);
2621
+ this.#extractor.copy(boundRange.value).copy(boundRange.types).write(`
2604
2622
  )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write(
2605
2623
  `Change"(_${valueLiteral}) {
2606
2624
  ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}`
2607
- ).copy(value.value).write(`= _${valueLiteral};
2625
+ ).copy(boundRange.value).write(`= _${valueLiteral};
2608
2626
  }`);
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)");
2627
+ } else if (boundRange.member.computed) {
2628
+ this.#extractor.copy(boundRange.value).copy({
2629
+ start: boundRange.value.end,
2630
+ end: boundRange.value.end + 1
2631
+ }).copy(boundRange.member).copy({
2632
+ start: boundRange.member.end,
2633
+ end: boundRange.member.end + 1
2634
+ }).copy(boundRange.types).write(`
2635
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`])");
2624
2636
  } 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`);
2637
+ const memberRange = {
2638
+ start: boundRange.value.start,
2639
+ end: boundRange.member.end
2640
+ };
2641
+ this.#extractor.copy(memberRange).copy(boundRange.types).write(`
2642
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberRange).write("Change)");
2627
2643
  }
2628
2644
  } else {
2629
2645
  this.#copyWithMutationsReplaced(value.value);
2630
2646
  this.#extractor.write("\n)");
2631
2647
  }
2632
2648
  break;
2649
+ }
2633
2650
  }
2634
2651
  } else if (attr.args) {
2635
2652
  this.#extractor.write('"').copy(name).write('": ');
@@ -3324,9 +3341,9 @@ function getForTagType(parsed, tag) {
3324
3341
  case "in":
3325
3342
  return 2 /* in */;
3326
3343
  case "to":
3327
- case "from":
3328
- case "step":
3329
3344
  return 3 /* to */;
3345
+ case "until":
3346
+ return 4 /* until */;
3330
3347
  }
3331
3348
  }
3332
3349
  }
@@ -3340,6 +3357,8 @@ function getForTagRuntime(parsed, tag) {
3340
3357
  return "forInTag";
3341
3358
  case 3 /* to */:
3342
3359
  return "forToTag";
3360
+ case 4 /* until */:
3361
+ return "forUntilTag";
3343
3362
  default:
3344
3363
  return "forTag";
3345
3364
  }
@@ -3352,6 +3371,8 @@ function getForAttrTagRuntime(parsed, tag) {
3352
3371
  return "forInAttrTag";
3353
3372
  case 3 /* to */:
3354
3373
  return "forToAttrTag";
3374
+ case 4 /* until */:
3375
+ return "forUntilAttrTag";
3355
3376
  default:
3356
3377
  return "forAttrTag";
3357
3378
  }
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;
@@ -2557,42 +2575,41 @@ scope: ${scopeExpr}
2557
2575
  this.#copyWithMutationsReplaced(value.params);
2558
2576
  this.#copyWithMutationsReplaced(value.body);
2559
2577
  break;
2560
- case 13 /* AttrValue */:
2578
+ case 13 /* AttrValue */: {
2579
+ const boundRange = value.bound && getBoundAttrRange(value);
2561
2580
  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(`
2581
+ if (boundRange) {
2582
+ if (!boundRange.member) {
2583
+ const valueLiteral = this.#read(boundRange.value);
2584
+ this.#extractor.copy(boundRange.value).copy(boundRange.types).write(`
2567
2585
  )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write(
2568
2586
  `Change"(_${valueLiteral}) {
2569
2587
  ${isMutatedVar(tag.parent, valueLiteral) ? `${varLocal("return")}.mutate.` : ""}`
2570
- ).copy(value.value).write(`= _${valueLiteral};
2588
+ ).copy(boundRange.value).write(`= _${valueLiteral};
2571
2589
  }`);
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)");
2590
+ } else if (boundRange.member.computed) {
2591
+ this.#extractor.copy(boundRange.value).copy({
2592
+ start: boundRange.value.end,
2593
+ end: boundRange.value.end + 1
2594
+ }).copy(boundRange.member).copy({
2595
+ start: boundRange.member.end,
2596
+ end: boundRange.member.end + 1
2597
+ }).copy(boundRange.types).write(`
2598
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(boundRange.value).write("[`${\n").copy(boundRange.member).write("\n}Change`])");
2587
2599
  } 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`);
2600
+ const memberRange = {
2601
+ start: boundRange.value.start,
2602
+ end: boundRange.member.end
2603
+ };
2604
+ this.#extractor.copy(memberRange).copy(boundRange.types).write(`
2605
+ )${SEP_COMMA_NEW_LINE}"`).copy(defaultMapPosition).copy(name).write('Change": (\n').copy(memberRange).write("Change)");
2590
2606
  }
2591
2607
  } else {
2592
2608
  this.#copyWithMutationsReplaced(value.value);
2593
2609
  this.#extractor.write("\n)");
2594
2610
  }
2595
2611
  break;
2612
+ }
2596
2613
  }
2597
2614
  } else if (attr.args) {
2598
2615
  this.#extractor.write('"').copy(name).write('": ');
@@ -3287,9 +3304,9 @@ function getForTagType(parsed, tag) {
3287
3304
  case "in":
3288
3305
  return 2 /* in */;
3289
3306
  case "to":
3290
- case "from":
3291
- case "step":
3292
3307
  return 3 /* to */;
3308
+ case "until":
3309
+ return 4 /* until */;
3293
3310
  }
3294
3311
  }
3295
3312
  }
@@ -3303,6 +3320,8 @@ function getForTagRuntime(parsed, tag) {
3303
3320
  return "forInTag";
3304
3321
  case 3 /* to */:
3305
3322
  return "forToTag";
3323
+ case 4 /* until */:
3324
+ return "forUntilTag";
3306
3325
  default:
3307
3326
  return "forTag";
3308
3327
  }
@@ -3315,6 +3334,8 @@ function getForAttrTagRuntime(parsed, tag) {
3315
3334
  return "forInAttrTag";
3316
3335
  case 3 /* to */:
3317
3336
  return "forToAttrTag";
3337
+ case 4 /* until */:
3338
+ return "forUntilAttrTag";
3318
3339
  default:
3319
3340
  return "forAttrTag";
3320
3341
  }
@@ -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.34",
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
  ".": {