@tilua/compiler 7.0.1 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,7 @@ npx tilua src/main.tilua --out build/main.luau
14
14
 
15
15
  ```
16
16
  tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>]
17
- [--noCheck]
17
+ [--noCheck] [--noLineMap]
18
18
  ```
19
19
 
20
20
  Every module the entry imports is bundled in. Problems are reported as
@@ -74,9 +74,10 @@ JavaScript module the build loads.
74
74
  | `const` / `let` | `local` |
75
75
  | `class C { … }` | one table for the class, one per instance — see below |
76
76
  | `return [a, b]` | `return { a, b }` — several results are an array |
77
- | `for (const item in xs)` | `for _, item in xs do … end` — an array or a table walked for its values |
78
- | `for (const item in step)` | `for item in step do … end` — an iterator function |
79
- | `for (const [k, v] in pairs(t))` | `for item in unpack(pairs(t), 1, 3) do local k, v = item[1], item[2] … end` — an iteration is `[step, state, first]` |
77
+ | `for (const item of xs)` | `for _, item in xs do … end` — an array or a table walked for its values |
78
+ | `for (const item of step)` | `for item in step do … end` — an iterator function |
79
+ | `for (const [k, v] of pairs(t))` | `for item in unpack(pairs(t), 1, 3) do local k, v = item[1], item[2] … end` — an iteration is `[step, state, first]` |
80
+ | `for (const key in t)` | `for key in pairs(t) do … end` — a table's keys, as in TypeScript |
80
81
  | `t ??= v` | `if t == nil then t = v end` — what addresses `t` read once, into locals |
81
82
  | `{ m() { … } }` | `{ m = function(this) … end }` — called with `:` |
82
83
  | `break outer` from a loop inside `outer` | a flag `outer` declares, raised, and a `break`; after each loop on the way out, a check that breaks again — or, at `outer`, does the `break` or `continue` |
@@ -117,7 +118,7 @@ Luau without asking:
117
118
  | `a += b`, `a // b` | `a = a + (b)`, `math.floor(a / (b))` | as written |
118
119
  | `continue` | a `break` out of a one-pass `repeat` | as written |
119
120
  | `c ? a : b`, `a?.b`, `a ?? b` | `and`/`or` where neither arm can be `false`, else a function called on the spot | `if c then a else b` |
120
- | `for (const x in xs)` | `ipairs(xs)` where `xs` is an array by its type; otherwise `tilua_each(xs)`, which walks a table as Luau would — its `__iter` if it has one, `next` if not | `for _, x in xs do` |
121
+ | `for (const x of xs)` | `ipairs(xs)` where `xs` is an array by its type; otherwise `tilua_each(xs)`, which walks a table as Luau would — its `__iter` if it has one, `next` if not | `for _, x in xs do` |
121
122
  | `1_000`, `0b101` | plain numbers | as written |
122
123
  | `@native` and other attributes | dropped | kept |
123
124
  | another file of the bundle | `loadfile` | `require` by path |
@@ -295,6 +296,16 @@ With several files each has its own line map, and a position is read by the
295
296
  map of the file it names — matched by the end of that file's path, since the
296
297
  Lua running it may call it by a full path, a relative one, or an Instance's.
297
298
 
299
+ The map is packed — the files it names once, then three base-64 VLQ numbers a
300
+ line, each counted from the line before — and read out the first time a line
301
+ is looked up, so a program that never fails never unpacks it.
302
+
303
+ For a release nobody will debug, `"lineMap": false` in `tilua.config.json`
304
+ (or `--noLineMap`, or `bundle({ lineMap: false })`) leaves out the map and
305
+ everything that reads it: the entry runs without `xpcall`, a callback handed
306
+ to Roblox is passed through unwrapped, and an error names the bundle's own
307
+ lines, as plain Luau would.
308
+
298
309
  ## Modules
299
310
 
300
311
  Roblox's `require` takes an Instance, so the bundle has its own. Each module
@@ -433,12 +444,12 @@ entry's.
433
444
  <!-- compatibility:start -->
434
445
  ## Compatibility
435
446
 
436
- `@tilua/compiler@7.0.1` works with these tilua packages. *Released with* is the
447
+ `@tilua/compiler@8.1.0` works with these tilua packages. *Released with* is the
437
448
  version it was built and tested against.
438
449
 
439
450
  | Package | Range | Released with | |
440
451
  | --- | --- | --- | --- |
441
- | `@tilua/parser` | `^7.0.0` | 7.0.0 | dependency |
452
+ | `@tilua/parser` | `^8.1.0` | 8.1.0 | dependency |
442
453
  <!-- compatibility:end -->
443
454
 
444
455
  ## Development
@@ -1448,8 +1448,15 @@ end`).body.statements, out);
1448
1448
  item = this.names.fresh("item");
1449
1449
  prelude.push(...this.destructure(variable, identifier(item), "declare"));
1450
1450
  }
1451
- const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
1451
+ const form = this.options.types?.loops.get(node) ?? { walks: node.over === "keys" ? "keys" : "values", viaIter: false };
1452
1452
  let source = this.expression(node.iterator);
1453
+ if (form.walks === "keys") {
1454
+ return [genericFor(
1455
+ [item],
1456
+ [call(this.builtin("pairs"), [source])],
1457
+ this.loopBody51(this.block(node.body, prelude)).statements
1458
+ )];
1459
+ }
1453
1460
  if (form.viaIter) source = methodCall(source, "__iter", []);
1454
1461
  const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
1455
1462
  let iterators = form.walks === "iteration" ? [call(this.helper("unpack"), [source, number(1), number(3)])] : [source];
@@ -2792,6 +2799,7 @@ import {
2792
2799
  directivesOf,
2793
2800
  applyDirectives,
2794
2801
  UNUSED_EXPECT_ERROR,
2802
+ UNUSED_EXPECT_WARNING,
2795
2803
  ParseError,
2796
2804
  LexError,
2797
2805
  luauString as luauString4
@@ -3093,10 +3101,33 @@ function buildLineMap(emitted, printed, origins) {
3093
3101
  }
3094
3102
  return map;
3095
3103
  }
3096
- function lineMapSource(map) {
3104
+ var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3105
+ function vlq(n) {
3106
+ let value = n < 0 ? -n * 2 + 1 : n * 2;
3107
+ let out = "";
3108
+ do {
3109
+ const digit = value % 32;
3110
+ value = Math.floor(value / 32);
3111
+ out += VLQ_DIGITS[value > 0 ? digit + 32 : digit];
3112
+ } while (value > 0);
3113
+ return out;
3114
+ }
3115
+ function lineMapSource(map, unpack) {
3097
3116
  const entries = [...map.entries()].sort((a, b) => a[0] - b[0]);
3098
- const quoted = (s) => luauString3(s.replace(/\\/g, "/"));
3099
- return `{${entries.map(([line, o]) => `[${line}]={${quoted(o.file)},${o.line}}`).join(",")}}`;
3117
+ const files = [];
3118
+ const indexes = /* @__PURE__ */ new Map();
3119
+ let data = "";
3120
+ let line = 0, file = 0, source = 0;
3121
+ for (const [at, origin] of entries) {
3122
+ const name = origin.file.replace(/\\/g, "/");
3123
+ if (!indexes.has(name)) indexes.set(name, files.push(name));
3124
+ const index2 = indexes.get(name);
3125
+ data += vlq(at - line) + vlq(index2 - file) + vlq(origin.line - source);
3126
+ line = at;
3127
+ file = index2;
3128
+ source = origin.line;
3129
+ }
3130
+ return `${unpack}({${files.map(luauString3).join(",")}},${luauString3(data)})`;
3100
3131
  }
3101
3132
 
3102
3133
  // src/bundle.ts
@@ -3144,6 +3175,7 @@ async function bundle(options) {
3144
3175
  const origins = /* @__PURE__ */ new WeakMap();
3145
3176
  const shared = new SharedRuntime(names);
3146
3177
  const shaking = options.treeShaking ?? config?.treeShaking ?? false;
3178
+ const mapping = options.lineMap ?? config?.lineMap ?? true;
3147
3179
  const resolveIn = (file) => (specifier) => {
3148
3180
  const found = resolveModulePath(file, specifier, config);
3149
3181
  return found !== void 0 && sources.has(found) ? found : void 0;
@@ -3182,8 +3214,8 @@ async function bundle(options) {
3182
3214
  import: importExpression,
3183
3215
  // One file has one line map. Several have one each, and a
3184
3216
  // module reads the one of the file it is in.
3185
- lines: mode === "single" ? `${G}.lines` : `${G}.maps[${luauString4(source.name)}]`,
3186
- fail: `${G}.fail`,
3217
+ lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${luauString4(source.name)}]`,
3218
+ fail: mapping ? `${G}.fail` : void 0,
3187
3219
  arrays: `${G}.arrays`,
3188
3220
  resolve: (specifier, dynamic) => {
3189
3221
  const found = resolveModulePath(file, specifier, config);
@@ -3213,7 +3245,7 @@ async function bundle(options) {
3213
3245
  }
3214
3246
  for (const [file, fileDirectives] of directives) {
3215
3247
  const semantic = diagnostics.filter((d) => d.file === file && (d.category === "scope" || d.category === "type"));
3216
- const { kept, unusedExpectErrors } = applyDirectives(fileDirectives, semantic, (d) => d.line);
3248
+ const { kept, unusedExpectErrors, unusedExpectWarnings } = applyDirectives(fileDirectives, semantic, (d) => d.line, (d) => d.severity === "warning");
3217
3249
  const suppressed = new Set(semantic.filter((d) => !kept.includes(d)));
3218
3250
  const remaining = diagnostics.filter((d) => !suppressed.has(d));
3219
3251
  diagnostics.length = 0;
@@ -3222,6 +3254,9 @@ async function bundle(options) {
3222
3254
  for (const d of unusedExpectErrors) {
3223
3255
  diagnostics.push({ file, message: UNUSED_EXPECT_ERROR, line: d.line, column: d.column, category: "type" });
3224
3256
  }
3257
+ for (const d of unusedExpectWarnings) {
3258
+ diagnostics.push({ file, message: UNUSED_EXPECT_WARNING, line: d.line, column: d.column, category: "type", severity: "warning" });
3259
+ }
3225
3260
  }
3226
3261
  const moduleProblems = new Set(diagnostics.filter((d) => d.category === "module").map((d) => `${d.file}:${d.line}:${d.column}:${d.message}`));
3227
3262
  const reported = diagnostics.filter((d) => d.category !== "type" || !moduleProblems.has(`${d.file}:${d.line}:${d.column}:${d.message}`));
@@ -3244,7 +3279,8 @@ async function bundle(options) {
3244
3279
  several,
3245
3280
  byPath,
3246
3281
  files: elsewhere,
3247
- imports: lowered.some((m) => m.dynamicImports.size > 0)
3282
+ imports: lowered.some((m) => m.dynamicImports.size > 0),
3283
+ mapping
3248
3284
  }));
3249
3285
  const assignment = program2.body.statements[1];
3250
3286
  if (usesScriptArgs) {
@@ -3261,21 +3297,23 @@ async function bundle(options) {
3261
3297
  program2.body.statements.unshift(...helpers.declare);
3262
3298
  const ok = names.fresh("ok");
3263
3299
  const result2 = names.fresh("result");
3264
- const entryStatements = parseLuau2(`
3300
+ const entryName = luauString4(sources.get(entry).name);
3301
+ const returnsExports = modules.get(entry).info.exports;
3302
+ const entryStatements = parseLuau2(!mapping ? `${returnsExports ? "return " : ""}${G}.require(${entryName})` : `
3265
3303
  local ${ok}, ${result2} = xpcall(function()
3266
- return ${G}.require(${luauString4(sources.get(entry).name)})
3304
+ return ${G}.require(${entryName})
3267
3305
  end, ${G}.fail)
3268
3306
  if not ${ok} then
3269
3307
  error(${result2}, 0)
3270
3308
  end
3271
- ${modules.get(entry).info.exports ? `return ${result2}` : ""}
3309
+ ${returnsExports ? `return ${result2}` : ""}
3272
3310
  `).body.statements;
3273
3311
  program2.body.statements.push(...entryStatements);
3274
- const map = buildLineMap(program2, parseLuau2(print(program2)), origins);
3275
- if (map.size || several) {
3312
+ const map = mapping ? buildLineMap(program2, parseLuau2(print(program2)), origins) : /* @__PURE__ */ new Map();
3313
+ if (mapping && (map.size || several)) {
3276
3314
  const mapStatements = [assign(
3277
3315
  [member(identifier(G), "lines")],
3278
- [parseExpressionFromSource2(lineMapSource(map))]
3316
+ [parseExpressionFromSource2(lineMapSource(map, `${G}.lineMap`))]
3279
3317
  )];
3280
3318
  if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
3281
3319
  program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
@@ -3293,8 +3331,11 @@ ${modules.get(entry).info.exports ? `return ${result2}` : ""}
3293
3331
  ));
3294
3332
  }
3295
3333
  const chunk = program([returns([functionExpression(functionBody([G], body))])]);
3296
- const lines = buildLineMap(chunk, parseLuau2(print(chunk)), origins);
3297
- body.push(...mapRegistration(G, file, lineMapSource(lines)), ...fileHelpers.define);
3334
+ if (mapping) {
3335
+ const lines = buildLineMap(chunk, parseLuau2(print(chunk)), origins);
3336
+ body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
3337
+ }
3338
+ body.push(...fileHelpers.define);
3298
3339
  files.push({ path: file.path, code: print(chunk) + "\n", modules: file.modules.map((m) => m.name) });
3299
3340
  }
3300
3341
  return { code: files[0].code, files, modules: moduleNames, diagnostics };
@@ -3392,7 +3433,7 @@ function loader(G, byPath) {
3392
3433
  require(file)(${G})`;
3393
3434
  }
3394
3435
  function runtime(G, options) {
3395
- const { several } = options;
3436
+ const { several, mapping } = options;
3396
3437
  const files = [...options.files].map(([name, file]) => `[${luauString4(name)}] = ${luauString4(file)}`).join(", ");
3397
3438
  return `
3398
3439
  local ${G}
@@ -3400,7 +3441,7 @@ ${G} = {
3400
3441
  modules = {},
3401
3442
  -- Every array the program made, so \`typeof\` can tell one from an object.
3402
3443
  -- The keys are held weakly: being written down keeps no array alive.
3403
- arrays = setmetatable({}, { __mode = "k" }),
3444
+ arrays = setmetatable({}, { __mode = "k" }),${mapping ? `
3404
3445
  -- Filled in just before the entry runs: bundle line -> { file, line }.
3405
3446
  lines = nil,
3406
3447
  -- What an error nothing caught says, in the project's files: the bundle's
@@ -3568,13 +3609,49 @@ ${several ? `
3568
3609
  end
3569
3610
  return mapped .. "\\n" .. table.concat(frames, "\\n")
3570
3611
  end,
3612
+ -- A line map as it is written: the files it names, and base-64 VLQ
3613
+ -- numbers, three to a line \u2014 how far down the bundle, which file, how far
3614
+ -- down that file, each counted from the line before. It is read out the
3615
+ -- first time a line is looked up, which is when something went wrong.
3616
+ lineMap = function(files, data)
3617
+ local map = {}
3618
+ return setmetatable(map, { __index = function(_, key)
3619
+ setmetatable(map, nil)
3620
+ local digits = {}
3621
+ for i = 1, 64 do
3622
+ digits[("${VLQ_DIGITS}"):byte(i)] = i - 1
3623
+ end
3624
+ local at = 1
3625
+ local function read()
3626
+ local value, scale = 0, 1
3627
+ repeat
3628
+ local digit = digits[data:byte(at)]
3629
+ at = at + 1
3630
+ value = value + digit % 32 * scale
3631
+ scale = scale * 32
3632
+ until digit < 32
3633
+ if value % 2 == 1 then
3634
+ return -math.floor(value / 2)
3635
+ end
3636
+ return math.floor(value / 2)
3637
+ end
3638
+ local line, file, source = 0, 0, 0
3639
+ while at <= #data do
3640
+ line = line + read()
3641
+ file = file + read()
3642
+ source = source + read()
3643
+ map[line] = { files[file], source }
3644
+ end
3645
+ return map[key]
3646
+ end })
3647
+ end,` : ""}
3571
3648
  records = {},${several ? `
3572
3649
  -- The file each module outside this one is in, as \`load\` is handed it.
3573
3650
  files = { ${files} },
3574
- loaded = {},
3651
+ loaded = {},${mapping ? `
3575
3652
  -- Every file's line map: by the module, and by the file's name.
3576
3653
  maps = {},
3577
- sources = {},
3654
+ sources = {},` : ""}
3578
3655
  -- Another of the bundle's files: a function that adds its modules here.
3579
3656
  load = function(file)
3580
3657
  if ${G}.loaded[file] then
package/dist/cli.cjs CHANGED
@@ -1465,8 +1465,15 @@ end`).body.statements, out2);
1465
1465
  item = this.names.fresh("item");
1466
1466
  prelude.push(...this.destructure(variable, identifier(item), "declare"));
1467
1467
  }
1468
- const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
1468
+ const form = this.options.types?.loops.get(node) ?? { walks: node.over === "keys" ? "keys" : "values", viaIter: false };
1469
1469
  let source = this.expression(node.iterator);
1470
+ if (form.walks === "keys") {
1471
+ return [genericFor(
1472
+ [item],
1473
+ [call(this.builtin("pairs"), [source])],
1474
+ this.loopBody51(this.block(node.body, prelude)).statements
1475
+ )];
1476
+ }
1470
1477
  if (form.viaIter) source = methodCall(source, "__iter", []);
1471
1478
  const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
1472
1479
  let iterators = form.walks === "iteration" ? [call(this.helper("unpack"), [source, number(1), number(3)])] : [source];
@@ -3063,10 +3070,33 @@ function buildLineMap(emitted, printed, origins) {
3063
3070
  }
3064
3071
  return map;
3065
3072
  }
3066
- function lineMapSource(map) {
3073
+ var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3074
+ function vlq(n) {
3075
+ let value = n < 0 ? -n * 2 + 1 : n * 2;
3076
+ let out2 = "";
3077
+ do {
3078
+ const digit = value % 32;
3079
+ value = Math.floor(value / 32);
3080
+ out2 += VLQ_DIGITS[value > 0 ? digit + 32 : digit];
3081
+ } while (value > 0);
3082
+ return out2;
3083
+ }
3084
+ function lineMapSource(map, unpack) {
3067
3085
  const entries = [...map.entries()].sort((a, b) => a[0] - b[0]);
3068
- const quoted = (s) => (0, import_parser6.luauString)(s.replace(/\\/g, "/"));
3069
- return `{${entries.map(([line, o]) => `[${line}]={${quoted(o.file)},${o.line}}`).join(",")}}`;
3086
+ const files = [];
3087
+ const indexes = /* @__PURE__ */ new Map();
3088
+ let data = "";
3089
+ let line = 0, file = 0, source = 0;
3090
+ for (const [at, origin] of entries) {
3091
+ const name = origin.file.replace(/\\/g, "/");
3092
+ if (!indexes.has(name)) indexes.set(name, files.push(name));
3093
+ const index2 = indexes.get(name);
3094
+ data += vlq(at - line) + vlq(index2 - file) + vlq(origin.line - source);
3095
+ line = at;
3096
+ file = index2;
3097
+ source = origin.line;
3098
+ }
3099
+ return `${unpack}({${files.map(import_parser6.luauString).join(",")}},${(0, import_parser6.luauString)(data)})`;
3070
3100
  }
3071
3101
 
3072
3102
  // src/lowering.ts
@@ -3141,6 +3171,7 @@ async function bundle(options) {
3141
3171
  const origins = /* @__PURE__ */ new WeakMap();
3142
3172
  const shared = new SharedRuntime(names);
3143
3173
  const shaking = options.treeShaking ?? config2?.treeShaking ?? false;
3174
+ const mapping = options.lineMap ?? config2?.lineMap ?? true;
3144
3175
  const resolveIn = (file) => (specifier) => {
3145
3176
  const found = (0, import_parser7.resolveModulePath)(file, specifier, config2);
3146
3177
  return found !== void 0 && sources.has(found) ? found : void 0;
@@ -3179,8 +3210,8 @@ async function bundle(options) {
3179
3210
  import: importExpression,
3180
3211
  // One file has one line map. Several have one each, and a
3181
3212
  // module reads the one of the file it is in.
3182
- lines: mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
3183
- fail: `${G}.fail`,
3213
+ lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
3214
+ fail: mapping ? `${G}.fail` : void 0,
3184
3215
  arrays: `${G}.arrays`,
3185
3216
  resolve: (specifier, dynamic) => {
3186
3217
  const found = (0, import_parser7.resolveModulePath)(file, specifier, config2);
@@ -3210,7 +3241,7 @@ async function bundle(options) {
3210
3241
  }
3211
3242
  for (const [file, fileDirectives] of directives) {
3212
3243
  const semantic = diagnostics.filter((d) => d.file === file && (d.category === "scope" || d.category === "type"));
3213
- const { kept, unusedExpectErrors } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line);
3244
+ const { kept, unusedExpectErrors, unusedExpectWarnings } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line, (d) => d.severity === "warning");
3214
3245
  const suppressed = new Set(semantic.filter((d) => !kept.includes(d)));
3215
3246
  const remaining = diagnostics.filter((d) => !suppressed.has(d));
3216
3247
  diagnostics.length = 0;
@@ -3219,6 +3250,9 @@ async function bundle(options) {
3219
3250
  for (const d of unusedExpectErrors) {
3220
3251
  diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_ERROR, line: d.line, column: d.column, category: "type" });
3221
3252
  }
3253
+ for (const d of unusedExpectWarnings) {
3254
+ diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_WARNING, line: d.line, column: d.column, category: "type", severity: "warning" });
3255
+ }
3222
3256
  }
3223
3257
  const moduleProblems = new Set(diagnostics.filter((d) => d.category === "module").map((d) => `${d.file}:${d.line}:${d.column}:${d.message}`));
3224
3258
  const reported = diagnostics.filter((d) => d.category !== "type" || !moduleProblems.has(`${d.file}:${d.line}:${d.column}:${d.message}`));
@@ -3241,7 +3275,8 @@ async function bundle(options) {
3241
3275
  several,
3242
3276
  byPath,
3243
3277
  files: elsewhere,
3244
- imports: lowered.some((m) => m.dynamicImports.size > 0)
3278
+ imports: lowered.some((m) => m.dynamicImports.size > 0),
3279
+ mapping
3245
3280
  }));
3246
3281
  const assignment = program2.body.statements[1];
3247
3282
  if (usesScriptArgs) {
@@ -3258,21 +3293,23 @@ async function bundle(options) {
3258
3293
  program2.body.statements.unshift(...helpers.declare);
3259
3294
  const ok = names.fresh("ok");
3260
3295
  const result2 = names.fresh("result");
3261
- const entryStatements = (0, import_luau_parser2.parse)(`
3296
+ const entryName = (0, import_parser7.luauString)(sources.get(entry2).name);
3297
+ const returnsExports = modules.get(entry2).info.exports;
3298
+ const entryStatements = (0, import_luau_parser2.parse)(!mapping ? `${returnsExports ? "return " : ""}${G}.require(${entryName})` : `
3262
3299
  local ${ok}, ${result2} = xpcall(function()
3263
- return ${G}.require(${(0, import_parser7.luauString)(sources.get(entry2).name)})
3300
+ return ${G}.require(${entryName})
3264
3301
  end, ${G}.fail)
3265
3302
  if not ${ok} then
3266
3303
  error(${result2}, 0)
3267
3304
  end
3268
- ${modules.get(entry2).info.exports ? `return ${result2}` : ""}
3305
+ ${returnsExports ? `return ${result2}` : ""}
3269
3306
  `).body.statements;
3270
3307
  program2.body.statements.push(...entryStatements);
3271
- const map = buildLineMap(program2, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(program2)), origins);
3272
- if (map.size || several) {
3308
+ const map = mapping ? buildLineMap(program2, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(program2)), origins) : /* @__PURE__ */ new Map();
3309
+ if (mapping && (map.size || several)) {
3273
3310
  const mapStatements = [assign(
3274
3311
  [member(identifier(G), "lines")],
3275
- [(0, import_luau_parser2.parseExpressionFromSource)(lineMapSource(map))]
3312
+ [(0, import_luau_parser2.parseExpressionFromSource)(lineMapSource(map, `${G}.lineMap`))]
3276
3313
  )];
3277
3314
  if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
3278
3315
  program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
@@ -3290,8 +3327,11 @@ ${modules.get(entry2).info.exports ? `return ${result2}` : ""}
3290
3327
  ));
3291
3328
  }
3292
3329
  const chunk = program([returns([functionExpression(functionBody([G], body))])]);
3293
- const lines = buildLineMap(chunk, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(chunk)), origins);
3294
- body.push(...mapRegistration(G, file, lineMapSource(lines)), ...fileHelpers.define);
3330
+ if (mapping) {
3331
+ const lines = buildLineMap(chunk, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(chunk)), origins);
3332
+ body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
3333
+ }
3334
+ body.push(...fileHelpers.define);
3295
3335
  files.push({ path: file.path, code: (0, import_luau_parser2.print)(chunk) + "\n", modules: file.modules.map((m) => m.name) });
3296
3336
  }
3297
3337
  return { code: files[0].code, files, modules: moduleNames, diagnostics };
@@ -3389,7 +3429,7 @@ function loader(G, byPath) {
3389
3429
  require(file)(${G})`;
3390
3430
  }
3391
3431
  function runtime(G, options) {
3392
- const { several } = options;
3432
+ const { several, mapping } = options;
3393
3433
  const files = [...options.files].map(([name, file]) => `[${(0, import_parser7.luauString)(name)}] = ${(0, import_parser7.luauString)(file)}`).join(", ");
3394
3434
  return `
3395
3435
  local ${G}
@@ -3397,7 +3437,7 @@ ${G} = {
3397
3437
  modules = {},
3398
3438
  -- Every array the program made, so \`typeof\` can tell one from an object.
3399
3439
  -- The keys are held weakly: being written down keeps no array alive.
3400
- arrays = setmetatable({}, { __mode = "k" }),
3440
+ arrays = setmetatable({}, { __mode = "k" }),${mapping ? `
3401
3441
  -- Filled in just before the entry runs: bundle line -> { file, line }.
3402
3442
  lines = nil,
3403
3443
  -- What an error nothing caught says, in the project's files: the bundle's
@@ -3565,13 +3605,49 @@ ${several ? `
3565
3605
  end
3566
3606
  return mapped .. "\\n" .. table.concat(frames, "\\n")
3567
3607
  end,
3608
+ -- A line map as it is written: the files it names, and base-64 VLQ
3609
+ -- numbers, three to a line \u2014 how far down the bundle, which file, how far
3610
+ -- down that file, each counted from the line before. It is read out the
3611
+ -- first time a line is looked up, which is when something went wrong.
3612
+ lineMap = function(files, data)
3613
+ local map = {}
3614
+ return setmetatable(map, { __index = function(_, key)
3615
+ setmetatable(map, nil)
3616
+ local digits = {}
3617
+ for i = 1, 64 do
3618
+ digits[("${VLQ_DIGITS}"):byte(i)] = i - 1
3619
+ end
3620
+ local at = 1
3621
+ local function read()
3622
+ local value, scale = 0, 1
3623
+ repeat
3624
+ local digit = digits[data:byte(at)]
3625
+ at = at + 1
3626
+ value = value + digit % 32 * scale
3627
+ scale = scale * 32
3628
+ until digit < 32
3629
+ if value % 2 == 1 then
3630
+ return -math.floor(value / 2)
3631
+ end
3632
+ return math.floor(value / 2)
3633
+ end
3634
+ local line, file, source = 0, 0, 0
3635
+ while at <= #data do
3636
+ line = line + read()
3637
+ file = file + read()
3638
+ source = source + read()
3639
+ map[line] = { files[file], source }
3640
+ end
3641
+ return map[key]
3642
+ end })
3643
+ end,` : ""}
3568
3644
  records = {},${several ? `
3569
3645
  -- The file each module outside this one is in, as \`load\` is handed it.
3570
3646
  files = { ${files} },
3571
- loaded = {},
3647
+ loaded = {},${mapping ? `
3572
3648
  -- Every file's line map: by the module, and by the file's name.
3573
3649
  maps = {},
3574
- sources = {},
3650
+ sources = {},` : ""}
3575
3651
  -- Another of the bundle's files: a function that adds its modules here.
3576
3652
  load = function(file)
3577
3653
  if ${G}.loaded[file] then
@@ -3812,18 +3888,20 @@ function allStatements(statements) {
3812
3888
  }
3813
3889
 
3814
3890
  // src/cli.ts
3815
- var usage = "usage: tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>] [--noCheck]";
3891
+ var usage = "usage: tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>] [--noCheck] [--noLineMap]";
3816
3892
  var args = process.argv.slice(2);
3817
3893
  var entry;
3818
3894
  var out;
3819
3895
  var config;
3820
3896
  var typeCheck = true;
3897
+ var lineMap;
3821
3898
  var output;
3822
3899
  for (let i = 0; i < args.length; i++) {
3823
3900
  const arg = args[i];
3824
3901
  if (arg === "--out") out = args[++i];
3825
3902
  else if (arg === "--config") config = args[++i];
3826
3903
  else if (arg === "--noCheck") typeCheck = false;
3904
+ else if (arg === "--noLineMap") lineMap = false;
3827
3905
  else if (arg === "--target") {
3828
3906
  console.error(`--target is gone: the output runs on Lua 5.1 to 5.4, LuaJIT and Luau, and a library says what more its Lua has \u2014 add "luau" to the config's 'types'`);
3829
3907
  process.exit(2);
@@ -3853,6 +3931,7 @@ async function main(from) {
3853
3931
  config,
3854
3932
  typeCheck,
3855
3933
  output: mode,
3934
+ lineMap,
3856
3935
  outFile: entryFile !== void 0 ? (0, import_node_path3.basename)(entryFile) : void 0
3857
3936
  });
3858
3937
  for (const d of result2.diagnostics) {
package/dist/cli.js CHANGED
@@ -2,23 +2,25 @@
2
2
  import {
3
3
  bundle,
4
4
  resolveConfig
5
- } from "./chunk-WGXXYKEU.js";
5
+ } from "./chunk-WOBHMGGC.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { mkdirSync, writeFileSync } from "fs";
9
9
  import { basename, dirname, join, relative, resolve } from "path";
10
- var usage = "usage: tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>] [--noCheck]";
10
+ var usage = "usage: tilua <entry> [--out <file>] [--output single|chunks|modules] [--config <tilua.config.json>] [--noCheck] [--noLineMap]";
11
11
  var args = process.argv.slice(2);
12
12
  var entry;
13
13
  var out;
14
14
  var config;
15
15
  var typeCheck = true;
16
+ var lineMap;
16
17
  var output;
17
18
  for (let i = 0; i < args.length; i++) {
18
19
  const arg = args[i];
19
20
  if (arg === "--out") out = args[++i];
20
21
  else if (arg === "--config") config = args[++i];
21
22
  else if (arg === "--noCheck") typeCheck = false;
23
+ else if (arg === "--noLineMap") lineMap = false;
22
24
  else if (arg === "--target") {
23
25
  console.error(`--target is gone: the output runs on Lua 5.1 to 5.4, LuaJIT and Luau, and a library says what more its Lua has \u2014 add "luau" to the config's 'types'`);
24
26
  process.exit(2);
@@ -48,6 +50,7 @@ async function main(from) {
48
50
  config,
49
51
  typeCheck,
50
52
  output: mode,
53
+ lineMap,
51
54
  outFile: entryFile !== void 0 ? basename(entryFile) : void 0
52
55
  });
53
56
  for (const d of result.diagnostics) {
package/dist/index.cjs CHANGED
@@ -1488,8 +1488,15 @@ end`).body.statements, out);
1488
1488
  item = this.names.fresh("item");
1489
1489
  prelude.push(...this.destructure(variable, identifier(item), "declare"));
1490
1490
  }
1491
- const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
1491
+ const form = this.options.types?.loops.get(node) ?? { walks: node.over === "keys" ? "keys" : "values", viaIter: false };
1492
1492
  let source = this.expression(node.iterator);
1493
+ if (form.walks === "keys") {
1494
+ return [genericFor(
1495
+ [item],
1496
+ [call(this.builtin("pairs"), [source])],
1497
+ this.loopBody51(this.block(node.body, prelude)).statements
1498
+ )];
1499
+ }
1493
1500
  if (form.viaIter) source = methodCall(source, "__iter", []);
1494
1501
  const variables = form.walks === "values" ? [this.names.fresh("_"), item] : [item];
1495
1502
  let iterators = form.walks === "iteration" ? [call(this.helper("unpack"), [source, number(1), number(3)])] : [source];
@@ -3086,10 +3093,33 @@ function buildLineMap(emitted, printed, origins) {
3086
3093
  }
3087
3094
  return map;
3088
3095
  }
3089
- function lineMapSource(map) {
3096
+ var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3097
+ function vlq(n) {
3098
+ let value = n < 0 ? -n * 2 + 1 : n * 2;
3099
+ let out = "";
3100
+ do {
3101
+ const digit = value % 32;
3102
+ value = Math.floor(value / 32);
3103
+ out += VLQ_DIGITS[value > 0 ? digit + 32 : digit];
3104
+ } while (value > 0);
3105
+ return out;
3106
+ }
3107
+ function lineMapSource(map, unpack) {
3090
3108
  const entries = [...map.entries()].sort((a, b) => a[0] - b[0]);
3091
- const quoted = (s) => (0, import_parser6.luauString)(s.replace(/\\/g, "/"));
3092
- return `{${entries.map(([line, o]) => `[${line}]={${quoted(o.file)},${o.line}}`).join(",")}}`;
3109
+ const files = [];
3110
+ const indexes = /* @__PURE__ */ new Map();
3111
+ let data = "";
3112
+ let line = 0, file = 0, source = 0;
3113
+ for (const [at, origin] of entries) {
3114
+ const name = origin.file.replace(/\\/g, "/");
3115
+ if (!indexes.has(name)) indexes.set(name, files.push(name));
3116
+ const index2 = indexes.get(name);
3117
+ data += vlq(at - line) + vlq(index2 - file) + vlq(origin.line - source);
3118
+ line = at;
3119
+ file = index2;
3120
+ source = origin.line;
3121
+ }
3122
+ return `${unpack}({${files.map(import_parser6.luauString).join(",")}},${(0, import_parser6.luauString)(data)})`;
3093
3123
  }
3094
3124
 
3095
3125
  // src/lowering.ts
@@ -3164,6 +3194,7 @@ async function bundle(options) {
3164
3194
  const origins = /* @__PURE__ */ new WeakMap();
3165
3195
  const shared = new SharedRuntime(names);
3166
3196
  const shaking = options.treeShaking ?? config?.treeShaking ?? false;
3197
+ const mapping = options.lineMap ?? config?.lineMap ?? true;
3167
3198
  const resolveIn = (file) => (specifier) => {
3168
3199
  const found = (0, import_parser7.resolveModulePath)(file, specifier, config);
3169
3200
  return found !== void 0 && sources.has(found) ? found : void 0;
@@ -3202,8 +3233,8 @@ async function bundle(options) {
3202
3233
  import: importExpression,
3203
3234
  // One file has one line map. Several have one each, and a
3204
3235
  // module reads the one of the file it is in.
3205
- lines: mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
3206
- fail: `${G}.fail`,
3236
+ lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
3237
+ fail: mapping ? `${G}.fail` : void 0,
3207
3238
  arrays: `${G}.arrays`,
3208
3239
  resolve: (specifier, dynamic) => {
3209
3240
  const found = (0, import_parser7.resolveModulePath)(file, specifier, config);
@@ -3233,7 +3264,7 @@ async function bundle(options) {
3233
3264
  }
3234
3265
  for (const [file, fileDirectives] of directives) {
3235
3266
  const semantic = diagnostics.filter((d) => d.file === file && (d.category === "scope" || d.category === "type"));
3236
- const { kept, unusedExpectErrors } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line);
3267
+ const { kept, unusedExpectErrors, unusedExpectWarnings } = (0, import_parser7.applyDirectives)(fileDirectives, semantic, (d) => d.line, (d) => d.severity === "warning");
3237
3268
  const suppressed = new Set(semantic.filter((d) => !kept.includes(d)));
3238
3269
  const remaining = diagnostics.filter((d) => !suppressed.has(d));
3239
3270
  diagnostics.length = 0;
@@ -3242,6 +3273,9 @@ async function bundle(options) {
3242
3273
  for (const d of unusedExpectErrors) {
3243
3274
  diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_ERROR, line: d.line, column: d.column, category: "type" });
3244
3275
  }
3276
+ for (const d of unusedExpectWarnings) {
3277
+ diagnostics.push({ file, message: import_parser7.UNUSED_EXPECT_WARNING, line: d.line, column: d.column, category: "type", severity: "warning" });
3278
+ }
3245
3279
  }
3246
3280
  const moduleProblems = new Set(diagnostics.filter((d) => d.category === "module").map((d) => `${d.file}:${d.line}:${d.column}:${d.message}`));
3247
3281
  const reported = diagnostics.filter((d) => d.category !== "type" || !moduleProblems.has(`${d.file}:${d.line}:${d.column}:${d.message}`));
@@ -3264,7 +3298,8 @@ async function bundle(options) {
3264
3298
  several,
3265
3299
  byPath,
3266
3300
  files: elsewhere,
3267
- imports: lowered.some((m) => m.dynamicImports.size > 0)
3301
+ imports: lowered.some((m) => m.dynamicImports.size > 0),
3302
+ mapping
3268
3303
  }));
3269
3304
  const assignment = program2.body.statements[1];
3270
3305
  if (usesScriptArgs) {
@@ -3281,21 +3316,23 @@ async function bundle(options) {
3281
3316
  program2.body.statements.unshift(...helpers.declare);
3282
3317
  const ok = names.fresh("ok");
3283
3318
  const result2 = names.fresh("result");
3284
- const entryStatements = (0, import_luau_parser2.parse)(`
3319
+ const entryName = (0, import_parser7.luauString)(sources.get(entry).name);
3320
+ const returnsExports = modules.get(entry).info.exports;
3321
+ const entryStatements = (0, import_luau_parser2.parse)(!mapping ? `${returnsExports ? "return " : ""}${G}.require(${entryName})` : `
3285
3322
  local ${ok}, ${result2} = xpcall(function()
3286
- return ${G}.require(${(0, import_parser7.luauString)(sources.get(entry).name)})
3323
+ return ${G}.require(${entryName})
3287
3324
  end, ${G}.fail)
3288
3325
  if not ${ok} then
3289
3326
  error(${result2}, 0)
3290
3327
  end
3291
- ${modules.get(entry).info.exports ? `return ${result2}` : ""}
3328
+ ${returnsExports ? `return ${result2}` : ""}
3292
3329
  `).body.statements;
3293
3330
  program2.body.statements.push(...entryStatements);
3294
- const map = buildLineMap(program2, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(program2)), origins);
3295
- if (map.size || several) {
3331
+ const map = mapping ? buildLineMap(program2, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(program2)), origins) : /* @__PURE__ */ new Map();
3332
+ if (mapping && (map.size || several)) {
3296
3333
  const mapStatements = [assign(
3297
3334
  [member(identifier(G), "lines")],
3298
- [(0, import_luau_parser2.parseExpressionFromSource)(lineMapSource(map))]
3335
+ [(0, import_luau_parser2.parseExpressionFromSource)(lineMapSource(map, `${G}.lineMap`))]
3299
3336
  )];
3300
3337
  if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
3301
3338
  program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
@@ -3313,8 +3350,11 @@ ${modules.get(entry).info.exports ? `return ${result2}` : ""}
3313
3350
  ));
3314
3351
  }
3315
3352
  const chunk = program([returns([functionExpression(functionBody([G], body))])]);
3316
- const lines = buildLineMap(chunk, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(chunk)), origins);
3317
- body.push(...mapRegistration(G, file, lineMapSource(lines)), ...fileHelpers.define);
3353
+ if (mapping) {
3354
+ const lines = buildLineMap(chunk, (0, import_luau_parser2.parse)((0, import_luau_parser2.print)(chunk)), origins);
3355
+ body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
3356
+ }
3357
+ body.push(...fileHelpers.define);
3318
3358
  files.push({ path: file.path, code: (0, import_luau_parser2.print)(chunk) + "\n", modules: file.modules.map((m) => m.name) });
3319
3359
  }
3320
3360
  return { code: files[0].code, files, modules: moduleNames, diagnostics };
@@ -3412,7 +3452,7 @@ function loader(G, byPath) {
3412
3452
  require(file)(${G})`;
3413
3453
  }
3414
3454
  function runtime(G, options) {
3415
- const { several } = options;
3455
+ const { several, mapping } = options;
3416
3456
  const files = [...options.files].map(([name, file]) => `[${(0, import_parser7.luauString)(name)}] = ${(0, import_parser7.luauString)(file)}`).join(", ");
3417
3457
  return `
3418
3458
  local ${G}
@@ -3420,7 +3460,7 @@ ${G} = {
3420
3460
  modules = {},
3421
3461
  -- Every array the program made, so \`typeof\` can tell one from an object.
3422
3462
  -- The keys are held weakly: being written down keeps no array alive.
3423
- arrays = setmetatable({}, { __mode = "k" }),
3463
+ arrays = setmetatable({}, { __mode = "k" }),${mapping ? `
3424
3464
  -- Filled in just before the entry runs: bundle line -> { file, line }.
3425
3465
  lines = nil,
3426
3466
  -- What an error nothing caught says, in the project's files: the bundle's
@@ -3588,13 +3628,49 @@ ${several ? `
3588
3628
  end
3589
3629
  return mapped .. "\\n" .. table.concat(frames, "\\n")
3590
3630
  end,
3631
+ -- A line map as it is written: the files it names, and base-64 VLQ
3632
+ -- numbers, three to a line \u2014 how far down the bundle, which file, how far
3633
+ -- down that file, each counted from the line before. It is read out the
3634
+ -- first time a line is looked up, which is when something went wrong.
3635
+ lineMap = function(files, data)
3636
+ local map = {}
3637
+ return setmetatable(map, { __index = function(_, key)
3638
+ setmetatable(map, nil)
3639
+ local digits = {}
3640
+ for i = 1, 64 do
3641
+ digits[("${VLQ_DIGITS}"):byte(i)] = i - 1
3642
+ end
3643
+ local at = 1
3644
+ local function read()
3645
+ local value, scale = 0, 1
3646
+ repeat
3647
+ local digit = digits[data:byte(at)]
3648
+ at = at + 1
3649
+ value = value + digit % 32 * scale
3650
+ scale = scale * 32
3651
+ until digit < 32
3652
+ if value % 2 == 1 then
3653
+ return -math.floor(value / 2)
3654
+ end
3655
+ return math.floor(value / 2)
3656
+ end
3657
+ local line, file, source = 0, 0, 0
3658
+ while at <= #data do
3659
+ line = line + read()
3660
+ file = file + read()
3661
+ source = source + read()
3662
+ map[line] = { files[file], source }
3663
+ end
3664
+ return map[key]
3665
+ end })
3666
+ end,` : ""}
3591
3667
  records = {},${several ? `
3592
3668
  -- The file each module outside this one is in, as \`load\` is handed it.
3593
3669
  files = { ${files} },
3594
- loaded = {},
3670
+ loaded = {},${mapping ? `
3595
3671
  -- Every file's line map: by the module, and by the file's name.
3596
3672
  maps = {},
3597
- sources = {},
3673
+ sources = {},` : ""}
3598
3674
  -- Another of the bundle's files: a function that adds its modules here.
3599
3675
  load = function(file)
3600
3676
  if ${G}.loaded[file] then
package/dist/index.d.cts CHANGED
@@ -22,6 +22,9 @@ interface TiluaConfigJson {
22
22
  noLib?: boolean;
23
23
  /** Leave out of the bundle what the entry never reaches (`treeShake`). */
24
24
  treeShaking?: boolean;
25
+ /** Write the map from the bundle's lines back to the project's, which
26
+ * error reports and `console` read. Default: true. */
27
+ lineMap?: boolean;
25
28
  }
26
29
  /** A config file's path, or the config itself. Relative paths — to a config
27
30
  * file, and inside an inline config — resolve from `cwd`. */
@@ -51,6 +54,10 @@ interface BundleOptions {
51
54
  /** Leave out what the entry never reaches. Overrides the config's
52
55
  * `treeShaking`; off without either. */
53
56
  readonly treeShaking?: boolean;
57
+ /** Write the map from the bundle's lines back to the project's. Overrides
58
+ * the config's `lineMap`; on without either. Without it an error names
59
+ * the bundle's lines, and the entry does not run under `xpcall`. */
60
+ readonly lineMap?: boolean;
54
61
  /** What the entry's file is called: `main.luau`. The other files of
55
62
  * `"chunks"` are named after it (`main_shop.luau`), and every file takes
56
63
  * its extension. Default: the entry's own name, with `.luau`. */
package/dist/index.d.ts CHANGED
@@ -22,6 +22,9 @@ interface TiluaConfigJson {
22
22
  noLib?: boolean;
23
23
  /** Leave out of the bundle what the entry never reaches (`treeShake`). */
24
24
  treeShaking?: boolean;
25
+ /** Write the map from the bundle's lines back to the project's, which
26
+ * error reports and `console` read. Default: true. */
27
+ lineMap?: boolean;
25
28
  }
26
29
  /** A config file's path, or the config itself. Relative paths — to a config
27
30
  * file, and inside an inline config — resolve from `cwd`. */
@@ -51,6 +54,10 @@ interface BundleOptions {
51
54
  /** Leave out what the entry never reaches. Overrides the config's
52
55
  * `treeShaking`; off without either. */
53
56
  readonly treeShaking?: boolean;
57
+ /** Write the map from the bundle's lines back to the project's. Overrides
58
+ * the config's `lineMap`; on without either. Without it an error names
59
+ * the bundle's lines, and the entry does not run under `xpcall`. */
60
+ readonly lineMap?: boolean;
54
61
  /** What the entry's file is called: `main.luau`. The other files of
55
62
  * `"chunks"` are named after it (`main_shop.luau`), and every file takes
56
63
  * its extension. Default: the entry's own name, with `.luau`. */
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  lower,
5
5
  program,
6
6
  resolveConfig
7
- } from "./chunk-WGXXYKEU.js";
7
+ } from "./chunk-WOBHMGGC.js";
8
8
 
9
9
  // src/compile.ts
10
10
  import { readFileSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua/compiler",
3
- "version": "7.0.1",
3
+ "version": "8.1.0",
4
4
  "description": "Compiles tilua to Luau: lowers the @tilua/parser AST to a luau-parser AST and prints it",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -38,7 +38,7 @@
38
38
  "type": "module",
39
39
  "dependencies": {
40
40
  "luau-parser": "^1.0.3",
41
- "@tilua/parser": "^7.0.0"
41
+ "@tilua/parser": "^8.1.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^22.20.2",