@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 +18 -7
- package/dist/{chunk-WGXXYKEU.js → chunk-WOBHMGGC.js} +97 -20
- package/dist/cli.cjs +100 -21
- package/dist/cli.js +5 -2
- package/dist/index.cjs +96 -20
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
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
|
|
78
|
-
| `for (const item
|
|
79
|
-
| `for (const [k, v]
|
|
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
|
|
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@
|
|
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` | `^
|
|
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
|
-
|
|
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
|
|
3099
|
-
|
|
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
|
|
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(${
|
|
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
|
-
${
|
|
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
|
-
|
|
3297
|
-
|
|
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
|
-
|
|
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
|
|
3069
|
-
|
|
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
|
|
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(${
|
|
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
|
-
${
|
|
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
|
-
|
|
3294
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
|
3092
|
-
|
|
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
|
|
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(${
|
|
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
|
-
${
|
|
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
|
-
|
|
3317
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tilua/compiler",
|
|
3
|
-
"version": "
|
|
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": "^
|
|
41
|
+
"@tilua/parser": "^8.1.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^22.20.2",
|