@tilua/compiler 8.0.0 → 9.0.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 +118 -13
- package/dist/{chunk-TOP7NC3Z.js → chunk-VUIF62OE.js} +483 -67
- package/dist/cli.cjs +651 -105
- package/dist/cli.js +159 -24
- package/dist/index.cjs +491 -73
- package/dist/index.d.cts +59 -9
- package/dist/index.d.ts +59 -9
- package/dist/index.js +14 -5
- package/package.json +3 -3
|
@@ -384,6 +384,10 @@ var SharedRuntime = class {
|
|
|
384
384
|
return { declare, define };
|
|
385
385
|
}
|
|
386
386
|
};
|
|
387
|
+
function moduleArguments(context, name) {
|
|
388
|
+
const loader2 = context.loader?.(name);
|
|
389
|
+
return loader2 ? [string(name), loader2] : [string(name)];
|
|
390
|
+
}
|
|
387
391
|
function lower(program2, scopes, options = {}) {
|
|
388
392
|
const result2 = new Lowerer(program2, scopes, options).run();
|
|
389
393
|
dropUnreachable(result2.statements);
|
|
@@ -700,6 +704,7 @@ var Lowerer = class {
|
|
|
700
704
|
const plugin3 = lowerings[i].plugin;
|
|
701
705
|
if (!plugin3.methodCall) continue;
|
|
702
706
|
const answer = plugin3.methodCall({
|
|
707
|
+
options: lowerings[i].options ?? {},
|
|
703
708
|
method,
|
|
704
709
|
receiver,
|
|
705
710
|
receiverGlobal,
|
|
@@ -731,6 +736,7 @@ var Lowerer = class {
|
|
|
731
736
|
const plugin3 = lowerings[i].plugin;
|
|
732
737
|
if (!plugin3.globalCall) continue;
|
|
733
738
|
const answer = plugin3.globalCall({
|
|
739
|
+
options: lowerings[i].options ?? {},
|
|
734
740
|
name,
|
|
735
741
|
at: this.callSite(node.callee),
|
|
736
742
|
get arguments() {
|
|
@@ -750,6 +756,7 @@ var Lowerer = class {
|
|
|
750
756
|
if (name === void 0) return void 0;
|
|
751
757
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
752
758
|
const answer = lowerings[i].plugin.globalValue?.({
|
|
759
|
+
options: lowerings[i].options ?? {},
|
|
753
760
|
name,
|
|
754
761
|
at: this.callSite(node),
|
|
755
762
|
use: (runtime2) => this.loweringRuntime(i, runtime2)
|
|
@@ -1003,12 +1010,12 @@ end`).body.statements, out);
|
|
|
1003
1010
|
local2 = this.names.fresh(moduleName(key));
|
|
1004
1011
|
moduleLocals.set(key, local2);
|
|
1005
1012
|
locals.push(local2);
|
|
1006
|
-
requires.push(assign([identifier(local2)], [call(context.require,
|
|
1013
|
+
requires.push(assign([identifier(local2)], [call(context.require, moduleArguments(context, key))]));
|
|
1007
1014
|
}
|
|
1008
1015
|
return local2;
|
|
1009
1016
|
};
|
|
1010
1017
|
const load = (key) => {
|
|
1011
|
-
if (!moduleLocals.has(key)) requires.push(callStatement(call(context.require,
|
|
1018
|
+
if (!moduleLocals.has(key)) requires.push(callStatement(call(context.require, moduleArguments(context, key))));
|
|
1012
1019
|
};
|
|
1013
1020
|
const exportBinding = (node, exported) => {
|
|
1014
1021
|
const binding = node && this.bindingByDeclaration.get(node);
|
|
@@ -1117,20 +1124,22 @@ end`).body.statements, out);
|
|
|
1117
1124
|
continue;
|
|
1118
1125
|
}
|
|
1119
1126
|
if (declaration.type === "ClassDeclaration") {
|
|
1120
|
-
body.push(...this.classDeclaration(declaration, "assign"));
|
|
1127
|
+
body.push(...this.classDeclaration(declaration, "assign").map((s) => this.from(s, declaration)));
|
|
1121
1128
|
continue;
|
|
1122
1129
|
}
|
|
1123
1130
|
switch (declaration.type) {
|
|
1131
|
+
// Stamped with where they were written, as any statement is:
|
|
1132
|
+
// an error in a top-level `const` names its line.
|
|
1124
1133
|
case "VariableDeclaration":
|
|
1125
|
-
body.push(...this.variableDeclaration(declaration, "assign"));
|
|
1134
|
+
body.push(...this.variableDeclaration(declaration, "assign").map((s) => this.from(s, declaration)));
|
|
1126
1135
|
break;
|
|
1127
1136
|
case "ExportDefaultStatement": {
|
|
1128
1137
|
const exported = declaration.declaration;
|
|
1129
1138
|
if (exported.type === "ClassDeclaration") {
|
|
1130
|
-
body.push(...this.classDeclaration(exported, "assign"));
|
|
1131
|
-
body.push(assign([member(exportsTable(), "default")], [this.reference(exported.name)]));
|
|
1139
|
+
body.push(...this.classDeclaration(exported, "assign").map((s) => this.from(s, exported)));
|
|
1140
|
+
body.push(this.from(assign([member(exportsTable(), "default")], [this.reference(exported.name)]), declaration));
|
|
1132
1141
|
} else {
|
|
1133
|
-
body.push(assign([member(exportsTable(), "default")], [this.expression(exported)]));
|
|
1142
|
+
body.push(this.from(assign([member(exportsTable(), "default")], [this.expression(exported)]), declaration));
|
|
1134
1143
|
}
|
|
1135
1144
|
break;
|
|
1136
1145
|
}
|
|
@@ -1168,7 +1177,7 @@ end`).body.statements, out);
|
|
|
1168
1177
|
this.report(source, `Cannot find module '${source.value}'`);
|
|
1169
1178
|
return nil();
|
|
1170
1179
|
}
|
|
1171
|
-
return call(context.import ?? context.require,
|
|
1180
|
+
return call(context.import ?? context.require, moduleArguments(context, key));
|
|
1172
1181
|
}
|
|
1173
1182
|
isRewritten(node) {
|
|
1174
1183
|
const binding = this.bindingByDeclaration.get(node);
|
|
@@ -1367,9 +1376,9 @@ end`).body.statements, out);
|
|
|
1367
1376
|
return this.assignment(node);
|
|
1368
1377
|
case "CompoundAssignmentStatement": {
|
|
1369
1378
|
if (node.operator === "??=") return this.nullishAssignment(node);
|
|
1370
|
-
const
|
|
1371
|
-
if (
|
|
1372
|
-
const operator =
|
|
1379
|
+
const join2 = node.operator === "+=" ? this.options.types?.joins.get(node) : void 0;
|
|
1380
|
+
if (join2 === "dynamic") return this.dynamicAddition(node);
|
|
1381
|
+
const operator = join2 === "concat" ? "..=" : node.operator;
|
|
1373
1382
|
if (!this.syntax.has("compoundAssignment")) return this.compoundAssignment51(node, operator);
|
|
1374
1383
|
return [{
|
|
1375
1384
|
type: "CompoundAssignmentStatement",
|
|
@@ -2055,9 +2064,9 @@ end
|
|
|
2055
2064
|
return call(this.helper("instanceof"), [this.keptToOne(left), this.keptToOne(right)]);
|
|
2056
2065
|
}
|
|
2057
2066
|
if (node.operator === "+") {
|
|
2058
|
-
const
|
|
2059
|
-
if (
|
|
2060
|
-
if (
|
|
2067
|
+
const join2 = this.options.types?.joins.get(node);
|
|
2068
|
+
if (join2 === "concat") return binary("..", left, right);
|
|
2069
|
+
if (join2 === "dynamic") return call(this.helper("add"), [this.keptToOne(left), this.keptToOne(right)]);
|
|
2061
2070
|
}
|
|
2062
2071
|
if (!this.syntax.has("floorDivision") && node.operator === "//") return this.floorDivide(left, right);
|
|
2063
2072
|
return binary(node.operator, left, right);
|
|
@@ -2774,7 +2783,7 @@ async function loadLowerings(modules) {
|
|
|
2774
2783
|
});
|
|
2775
2784
|
continue;
|
|
2776
2785
|
}
|
|
2777
|
-
lowerings.push({ plugin: plugin3, from: module.from, library: module.library });
|
|
2786
|
+
lowerings.push({ plugin: plugin3, from: module.from, library: module.library, options: module.options });
|
|
2778
2787
|
} catch (error) {
|
|
2779
2788
|
problems.push({
|
|
2780
2789
|
file: module.file,
|
|
@@ -2786,8 +2795,8 @@ async function loadLowerings(modules) {
|
|
|
2786
2795
|
}
|
|
2787
2796
|
|
|
2788
2797
|
// src/bundle.ts
|
|
2789
|
-
import { readFileSync as readFileSync3, statSync } from "fs";
|
|
2790
|
-
import { basename, dirname, extname, posix, relative, resolve as resolve2 } from "path";
|
|
2798
|
+
import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
|
|
2799
|
+
import { basename, dirname, extname, isAbsolute, join, posix, relative, resolve as resolve2 } from "path";
|
|
2791
2800
|
import {
|
|
2792
2801
|
parse,
|
|
2793
2802
|
analyzeScopes,
|
|
@@ -2804,7 +2813,7 @@ import {
|
|
|
2804
2813
|
LexError,
|
|
2805
2814
|
luauString as luauString4
|
|
2806
2815
|
} from "@tilua/parser";
|
|
2807
|
-
import { parse as parseLuau2, parseExpressionFromSource as parseExpressionFromSource2, print } from "luau-parser";
|
|
2816
|
+
import { parse as parseLuau2, parseExpressionFromSource as parseExpressionFromSource2, print as print2 } from "luau-parser";
|
|
2808
2817
|
|
|
2809
2818
|
// src/treeshake.ts
|
|
2810
2819
|
function walk(node, visit, parent) {
|
|
@@ -3072,23 +3081,29 @@ function ownExport(f, name) {
|
|
|
3072
3081
|
// src/linemap.ts
|
|
3073
3082
|
import { luauString as luauString3 } from "@tilua/parser";
|
|
3074
3083
|
function statementsOf(node) {
|
|
3075
|
-
|
|
3076
|
-
|
|
3084
|
+
return statementTree(node).statements;
|
|
3085
|
+
}
|
|
3086
|
+
function statementTree(node) {
|
|
3087
|
+
const statements = [];
|
|
3088
|
+
const parents = [];
|
|
3089
|
+
const visit = (value, parent) => {
|
|
3077
3090
|
if (!value || typeof value !== "object") return;
|
|
3078
|
-
if (Array.isArray(value)) return void value.forEach(visit);
|
|
3091
|
+
if (Array.isArray(value)) return void value.forEach((item) => visit(item, parent));
|
|
3079
3092
|
const record = value;
|
|
3093
|
+
let inside = parent;
|
|
3080
3094
|
if (typeof record.type === "string" && record.type.endsWith("Statement")) {
|
|
3081
|
-
|
|
3095
|
+
inside = statements.push(value) - 1;
|
|
3096
|
+
parents.push(parent);
|
|
3082
3097
|
}
|
|
3083
3098
|
for (const [key, child] of Object.entries(record)) {
|
|
3084
|
-
if (key !== "line" && key !== "column") visit(child);
|
|
3099
|
+
if (key !== "line" && key !== "column") visit(child, inside);
|
|
3085
3100
|
}
|
|
3086
3101
|
};
|
|
3087
|
-
visit(node);
|
|
3088
|
-
return
|
|
3102
|
+
visit(node, -1);
|
|
3103
|
+
return { statements, parents };
|
|
3089
3104
|
}
|
|
3090
3105
|
function buildLineMap(emitted, printed, origins) {
|
|
3091
|
-
const before =
|
|
3106
|
+
const { statements: before, parents } = statementTree(emitted);
|
|
3092
3107
|
const after = statementsOf(printed);
|
|
3093
3108
|
if (before.length !== after.length) return /* @__PURE__ */ new Map();
|
|
3094
3109
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3099,26 +3114,102 @@ function buildLineMap(emitted, printed, origins) {
|
|
|
3099
3114
|
const line = after[i].line.start;
|
|
3100
3115
|
if (!map.has(line)) map.set(line, origin);
|
|
3101
3116
|
}
|
|
3117
|
+
const holds = /* @__PURE__ */ new Set();
|
|
3118
|
+
for (let i = 0; i < before.length; i++) {
|
|
3119
|
+
if (!origins.has(before[i])) continue;
|
|
3120
|
+
for (let up = parents[i]; up >= 0 && !holds.has(up); up = parents[up]) holds.add(up);
|
|
3121
|
+
}
|
|
3122
|
+
for (let i = 0; i < before.length; i++) {
|
|
3123
|
+
const origin = origins.get(before[i]);
|
|
3124
|
+
if (!origin || holds.has(i)) continue;
|
|
3125
|
+
for (let line = after[i].line.start + 1; line <= after[i].line.end; line++) {
|
|
3126
|
+
if (!map.has(line)) map.set(line, origin);
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3102
3129
|
return map;
|
|
3103
3130
|
}
|
|
3104
|
-
|
|
3131
|
+
var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
3132
|
+
function vlq(n) {
|
|
3133
|
+
let value = n < 0 ? -n * 2 + 1 : n * 2;
|
|
3134
|
+
let out = "";
|
|
3135
|
+
do {
|
|
3136
|
+
const digit = value % 32;
|
|
3137
|
+
value = Math.floor(value / 32);
|
|
3138
|
+
out += VLQ_DIGITS[value > 0 ? digit + 32 : digit];
|
|
3139
|
+
} while (value > 0);
|
|
3140
|
+
return out;
|
|
3141
|
+
}
|
|
3142
|
+
function lineMapSource(map, unpack) {
|
|
3105
3143
|
const entries = [...map.entries()].sort((a, b) => a[0] - b[0]);
|
|
3106
|
-
const
|
|
3107
|
-
|
|
3144
|
+
const files = [];
|
|
3145
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
3146
|
+
let data = "";
|
|
3147
|
+
let line = 0, file = 0, source = 0;
|
|
3148
|
+
for (const [at, origin] of entries) {
|
|
3149
|
+
const name = origin.file.replace(/\\/g, "/");
|
|
3150
|
+
if (!indexes.has(name)) indexes.set(name, files.push(name));
|
|
3151
|
+
const index2 = indexes.get(name);
|
|
3152
|
+
data += vlq(at - line) + vlq(index2 - file) + vlq(origin.line - source);
|
|
3153
|
+
line = at;
|
|
3154
|
+
file = index2;
|
|
3155
|
+
source = origin.line;
|
|
3156
|
+
}
|
|
3157
|
+
return `${unpack}({${files.map(luauString3).join(",")}},${luauString3(data)})`;
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
// src/output.ts
|
|
3161
|
+
import { print, PrintError } from "luau-parser";
|
|
3162
|
+
var WRITTEN = /* @__PURE__ */ new Set([
|
|
3163
|
+
"compoundAssignment",
|
|
3164
|
+
"continue",
|
|
3165
|
+
"ifExpression",
|
|
3166
|
+
"floorDivision",
|
|
3167
|
+
"attributes",
|
|
3168
|
+
"numberLiterals"
|
|
3169
|
+
]);
|
|
3170
|
+
function printOptions(syntax, format = {}) {
|
|
3171
|
+
return {
|
|
3172
|
+
syntax: [...syntax].some((s) => WRITTEN.has(s)) ? "luau" : "lua51",
|
|
3173
|
+
compact: format.minify ?? false,
|
|
3174
|
+
...format.indent !== void 0 && { indent: format.indent }
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
function printOutput(node, options) {
|
|
3178
|
+
try {
|
|
3179
|
+
return { code: print(node, options) };
|
|
3180
|
+
} catch (error) {
|
|
3181
|
+
if (!(error instanceof PrintError)) throw error;
|
|
3182
|
+
return {
|
|
3183
|
+
problem: `The output cannot be written as Lua 5.1: ${error.message.replace(/ \(\d+:\d+\)$/, "")}. Nothing in 'types' says the project's Lua has it \u2014 "luau" does, and "roblox" brings "luau"`
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3108
3186
|
}
|
|
3109
3187
|
|
|
3110
3188
|
// src/bundle.ts
|
|
3189
|
+
var WRITTEN_BY_TILUA = "-- Written by tilua";
|
|
3111
3190
|
async function bundle(options) {
|
|
3112
|
-
const entry = resolve2(options.entry);
|
|
3113
3191
|
const diagnostics = [];
|
|
3192
|
+
const from = options.entry !== void 0 ? resolve2(options.entry) : resolve2(options.root ?? process.cwd(), "tilua.config.json");
|
|
3114
3193
|
const inline = options.config !== void 0 && typeof options.config !== "string";
|
|
3115
|
-
const { config, problems } = resolveConfig(options.config,
|
|
3194
|
+
const { config, problems } = resolveConfig(options.config, from, options.root ?? (inline ? dirname(from) : process.cwd()));
|
|
3116
3195
|
for (const p of problems) diagnostics.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3117
|
-
const root = resolve2(options.root ?? config?.directory ?? dirname(
|
|
3196
|
+
const root = resolve2(options.root ?? config?.directory ?? dirname(from));
|
|
3118
3197
|
const nameOf = (file) => relative(root, file).replace(/\\/g, "/").replace(/\.tilua$/, "");
|
|
3198
|
+
const mode = options.output ?? config?.output ?? "single";
|
|
3199
|
+
const perFile = mode === "files";
|
|
3200
|
+
const rootDir = resolve2(config?.rootDir ?? root);
|
|
3201
|
+
const entry = options.entry !== void 0 ? resolve2(options.entry) : void 0;
|
|
3202
|
+
const anchor = entry ?? config?.path ?? from;
|
|
3203
|
+
const stop = (message, file = anchor) => ({
|
|
3204
|
+
files: [],
|
|
3205
|
+
modules: [],
|
|
3206
|
+
diagnostics: [...diagnostics, { file, message, line: 1, column: 1, category: "config" }]
|
|
3207
|
+
});
|
|
3208
|
+
if (!perFile && entry === void 0) return stop('No entry to build: only "output": "files" builds without one');
|
|
3119
3209
|
const sources = /* @__PURE__ */ new Map();
|
|
3120
3210
|
const directives = /* @__PURE__ */ new Map();
|
|
3121
|
-
const queue = [entry];
|
|
3211
|
+
const queue = perFile ? tiluaFiles(rootDir) : [entry];
|
|
3212
|
+
if (perFile && !queue.length) return stop(`No .tilua file under ${relative(process.cwd(), rootDir) || "."}`);
|
|
3122
3213
|
while (queue.length) {
|
|
3123
3214
|
const file = queue.shift();
|
|
3124
3215
|
if (sources.has(file)) continue;
|
|
@@ -3136,6 +3227,22 @@ async function bundle(options) {
|
|
|
3136
3227
|
if (target && !target.endsWith(".d.tilua")) queue.push(target);
|
|
3137
3228
|
}
|
|
3138
3229
|
}
|
|
3230
|
+
if (perFile) {
|
|
3231
|
+
const outside = [...sources.keys()].filter((file) => isOutside(rootDir, file));
|
|
3232
|
+
if (outside.length) {
|
|
3233
|
+
return {
|
|
3234
|
+
files: [],
|
|
3235
|
+
modules: [],
|
|
3236
|
+
diagnostics: [...diagnostics, ...outside.map((file) => ({
|
|
3237
|
+
file,
|
|
3238
|
+
message: `This file is imported, but it is outside rootDir (${relative(root, rootDir) || "."}), where every file of "files" output has to be`,
|
|
3239
|
+
line: 1,
|
|
3240
|
+
column: 1,
|
|
3241
|
+
category: "module"
|
|
3242
|
+
}))]
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3139
3246
|
const analysis = analyzeModules([...sources.values()], config);
|
|
3140
3247
|
const { lowerings, problems: loweringProblems } = await loadLowerings(analysis.lowerings);
|
|
3141
3248
|
for (const p of loweringProblems) {
|
|
@@ -3146,18 +3253,56 @@ async function bundle(options) {
|
|
|
3146
3253
|
const G = names.fresh("G");
|
|
3147
3254
|
const requireExpression = member(identifier(G), "require");
|
|
3148
3255
|
const importExpression = member(identifier(G), "import");
|
|
3149
|
-
const mode = options.output ?? config?.output ?? "single";
|
|
3150
3256
|
const byPath = syntaxOf(lowerings).has("requireByPath");
|
|
3257
|
+
if (perFile && !byPath) {
|
|
3258
|
+
return stop(`"output": "files" needs a Lua that requires a file by its path, which Lua 5.1 does not \u2014 add "luau" to 'types' ("roblox" loads it)`, config?.path ?? anchor);
|
|
3259
|
+
}
|
|
3260
|
+
const outputPath = (file) => relative(rootDir, file).replace(/\\/g, "/").replace(/\.tilua$/, ".luau");
|
|
3261
|
+
const fileOfModule = new Map([...sources.values()].map((s) => [s.name, s.file]));
|
|
3262
|
+
const outDir = resolve2(options.outDir ?? config?.outDir ?? rootDir);
|
|
3263
|
+
const written = (file) => join(outDir, outputPath(file));
|
|
3264
|
+
let host;
|
|
3265
|
+
let runtimeFile = join(outDir, "_tilua.luau");
|
|
3266
|
+
if (perFile) {
|
|
3267
|
+
const outputs = [...sources.keys()].map(written);
|
|
3268
|
+
const taken = new Set(outputs.map(pathKey));
|
|
3269
|
+
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = join(outDir, `_tilua${n}.luau`);
|
|
3270
|
+
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3271
|
+
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3272
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3273
|
+
}
|
|
3274
|
+
for (const problem of host?.problems ?? []) {
|
|
3275
|
+
diagnostics.push({
|
|
3276
|
+
file: problem.file ?? config?.path ?? anchor,
|
|
3277
|
+
message: problem.message,
|
|
3278
|
+
line: 1,
|
|
3279
|
+
column: 1,
|
|
3280
|
+
category: "config",
|
|
3281
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3282
|
+
});
|
|
3283
|
+
}
|
|
3284
|
+
if (host?.runtime !== void 0) {
|
|
3285
|
+
if (isOutside(outDir, resolve2(host.runtime))) return stop(`The runtime has to go inside outDir, not at ${host.runtime}`);
|
|
3286
|
+
if (taken.has(pathKey(host.runtime))) return stop(`The runtime cannot go at ${host.runtime}: a module's file is there`);
|
|
3287
|
+
runtimeFile = resolve2(host.runtime);
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
const placeOf = (file) => host?.place?.(file) ?? placeInFolder(relative(outDir, file));
|
|
3291
|
+
const requireFrom = (from2, to) => pathBetween(placeOf(from2), placeOf(to), host?.root);
|
|
3292
|
+
const isScript = (file) => host?.script?.(file) ?? false;
|
|
3151
3293
|
const modules = /* @__PURE__ */ new Map();
|
|
3152
3294
|
const origins = /* @__PURE__ */ new WeakMap();
|
|
3153
3295
|
const shared = new SharedRuntime(names);
|
|
3154
3296
|
const shaking = options.treeShaking ?? config?.treeShaking ?? false;
|
|
3297
|
+
const format = { indent: options.indent ?? config?.indent, minify: options.minify ?? config?.minify ?? false };
|
|
3298
|
+
const printing = printOptions(syntaxOf(lowerings), format);
|
|
3299
|
+
const mapping = !format.minify && (options.lineMap ?? config?.lineMap ?? true);
|
|
3155
3300
|
const resolveIn = (file) => (specifier) => {
|
|
3156
3301
|
const found = resolveModulePath(file, specifier, config);
|
|
3157
3302
|
return found !== void 0 && sources.has(found) ? found : void 0;
|
|
3158
3303
|
};
|
|
3159
|
-
const shaken = shaking ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry) : void 0;
|
|
3160
|
-
const pending = [entry];
|
|
3304
|
+
const shaken = shaking && entry !== void 0 && !perFile ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry) : void 0;
|
|
3305
|
+
const pending = perFile ? [...sources.keys()] : [entry];
|
|
3161
3306
|
while (pending.length) {
|
|
3162
3307
|
const file = pending.shift();
|
|
3163
3308
|
if (modules.has(file)) continue;
|
|
@@ -3190,9 +3335,16 @@ async function bundle(options) {
|
|
|
3190
3335
|
import: importExpression,
|
|
3191
3336
|
// One file has one line map. Several have one each, and a
|
|
3192
3337
|
// module reads the one of the file it is in.
|
|
3193
|
-
lines: mode === "single" ? `${G}.lines` : `${G}.maps[${luauString4(source.name)}]`,
|
|
3194
|
-
fail: `${G}.fail
|
|
3338
|
+
lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${luauString4(source.name)}]`,
|
|
3339
|
+
fail: mapping ? `${G}.fail` : void 0,
|
|
3195
3340
|
arrays: `${G}.arrays`,
|
|
3341
|
+
// The file a module is in, required from this one by its
|
|
3342
|
+
// path, written out.
|
|
3343
|
+
loader: !perFile ? void 0 : (name) => {
|
|
3344
|
+
const target = fileOfModule.get(name);
|
|
3345
|
+
if (target === void 0) return void 0;
|
|
3346
|
+
return parseExpressionFromSource2(`function() return require(${luauString4(requireFrom(written(file), written(target)))}) end`);
|
|
3347
|
+
},
|
|
3196
3348
|
resolve: (specifier, dynamic) => {
|
|
3197
3349
|
const found = resolveModulePath(file, specifier, config);
|
|
3198
3350
|
if (!found || found.endsWith(".d.tilua") || !sources.has(found)) return void 0;
|
|
@@ -3244,6 +3396,102 @@ async function bundle(options) {
|
|
|
3244
3396
|
return { files: [], modules: moduleNames, diagnostics };
|
|
3245
3397
|
}
|
|
3246
3398
|
if (shaking) shared.shake(lowered.flatMap((m) => m.statements));
|
|
3399
|
+
const unwritable = (problem) => ({
|
|
3400
|
+
files: [],
|
|
3401
|
+
modules: moduleNames,
|
|
3402
|
+
diagnostics: [...diagnostics, { file: anchor, message: problem, line: 1, column: 1, category: "config" }]
|
|
3403
|
+
});
|
|
3404
|
+
const write = (node) => {
|
|
3405
|
+
const printed2 = printOutput(node, printing);
|
|
3406
|
+
return "problem" in printed2 ? printed2 : printed2.code;
|
|
3407
|
+
};
|
|
3408
|
+
if (perFile) {
|
|
3409
|
+
const imported = [];
|
|
3410
|
+
for (const [file, source] of sources) {
|
|
3411
|
+
for (const { specifier, line, column } of importSites(source.program)) {
|
|
3412
|
+
const target = resolveIn(file)(specifier);
|
|
3413
|
+
if (target === void 0 || !isScript(written(target))) continue;
|
|
3414
|
+
imported.push({
|
|
3415
|
+
file,
|
|
3416
|
+
line,
|
|
3417
|
+
column,
|
|
3418
|
+
category: "module",
|
|
3419
|
+
message: `'${specifier}' is a script the game runs, which nothing can import: move what it shares into a module of its own`
|
|
3420
|
+
});
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
if (imported.length) return { files: [], modules: moduleNames, diagnostics: [...diagnostics, ...imported] };
|
|
3424
|
+
const runtimePath = relative(outDir, runtimeFile).replace(/\\/g, "/");
|
|
3425
|
+
const files2 = [];
|
|
3426
|
+
for (const [file, module] of modules) {
|
|
3427
|
+
const path = outputPath(file);
|
|
3428
|
+
const at = written(file);
|
|
3429
|
+
const script = isScript(at);
|
|
3430
|
+
const prelude = host?.prelude?.(at);
|
|
3431
|
+
const body = [
|
|
3432
|
+
...prelude !== void 0 ? parseLuau2(prelude).body.statements : [],
|
|
3433
|
+
...parseLuau2(`local ${G} = require(${luauString4(requireFrom(at, runtimeFile))})`).body.statements
|
|
3434
|
+
];
|
|
3435
|
+
for (let i = 0; i < module.shared.length; i += 100) {
|
|
3436
|
+
const some = module.shared.slice(i, i + 100);
|
|
3437
|
+
body.push(local(some, some.map((name) => member(member(identifier(G), "shared"), name))));
|
|
3438
|
+
}
|
|
3439
|
+
if (module.usesScriptArgs) body.push(...parseLuau2(`local scriptArgs = ${G}.scriptArgs`).body.statements);
|
|
3440
|
+
body.push(assign(
|
|
3441
|
+
[index(member(identifier(G), "modules"), string(module.name))],
|
|
3442
|
+
[moduleTable(module)]
|
|
3443
|
+
));
|
|
3444
|
+
const value = `${G}.${mapping ? "run" : "require"}(${luauString4(module.name)})`;
|
|
3445
|
+
const returned2 = module.info.exports && !script ? entryReturn(lowerings, module.name, value, () => analysis.exportsOf(file)) : { statements: [], value };
|
|
3446
|
+
if ("problem" in returned2) return stop(returned2.problem.message, file);
|
|
3447
|
+
const ending = parseLuau2(`${returned2.statements.join("\n")}
|
|
3448
|
+
return ${returned2.value}`).body.statements;
|
|
3449
|
+
const chunk = program(body);
|
|
3450
|
+
if (mapping) {
|
|
3451
|
+
const text = write(chunk);
|
|
3452
|
+
if (typeof text !== "string") return unwritable(text.problem);
|
|
3453
|
+
const lines = buildLineMap(chunk, parseLuau2(text), origins);
|
|
3454
|
+
const named = host?.place?.(at) ? `${placeOf(at).join("/")}.luau` : path;
|
|
3455
|
+
body.push(...mapRegistration(G, { path: named, modules: [module] }, lineMapSource(lines, `${G}.lineMap`)));
|
|
3456
|
+
}
|
|
3457
|
+
body.push(...ending);
|
|
3458
|
+
const code = write(chunk);
|
|
3459
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3460
|
+
const from2 = relative(dirname(at), file).replace(/\\/g, "/");
|
|
3461
|
+
files2.push({ path, code: `${code}
|
|
3462
|
+
${WRITTEN_BY_TILUA} from ${from2}: edit that file, not this one.
|
|
3463
|
+
`, modules: [module.name] });
|
|
3464
|
+
}
|
|
3465
|
+
const runtimeProgram = parseLuau2(runtime(G, {
|
|
3466
|
+
several: true,
|
|
3467
|
+
perFile: true,
|
|
3468
|
+
byPath,
|
|
3469
|
+
files: /* @__PURE__ */ new Map(),
|
|
3470
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3471
|
+
mapping
|
|
3472
|
+
}));
|
|
3473
|
+
const helpers2 = shared.chunk(new Set(lowered.flatMap((m) => m.shared)));
|
|
3474
|
+
const helperNames = helpers2.declare.flatMap((statement) => statement.type === "LocalStatement" ? statement.names.map((n) => n.name) : []);
|
|
3475
|
+
runtimeProgram.body.statements.unshift(...helpers2.declare);
|
|
3476
|
+
runtimeProgram.body.statements.push(...helpers2.define);
|
|
3477
|
+
if (helperNames.length) {
|
|
3478
|
+
runtimeProgram.body.statements.push(assign(
|
|
3479
|
+
[member(identifier(G), "shared")],
|
|
3480
|
+
[table(helperNames.map((name) => field(name, identifier(name))))]
|
|
3481
|
+
));
|
|
3482
|
+
}
|
|
3483
|
+
if (lowered.some((m) => m.usesScriptArgs)) {
|
|
3484
|
+
runtimeProgram.body.statements.push(...parseLuau2(`${G}.scriptArgs = {}
|
|
3485
|
+
${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
3486
|
+
}
|
|
3487
|
+
runtimeProgram.body.statements.push(returns([identifier(G)]));
|
|
3488
|
+
const runtimeCode = write(runtimeProgram);
|
|
3489
|
+
if (typeof runtimeCode !== "string") return unwritable(runtimeCode.problem);
|
|
3490
|
+
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3491
|
+
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3492
|
+
`, modules: [] });
|
|
3493
|
+
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3494
|
+
}
|
|
3247
3495
|
const several = mode !== "single";
|
|
3248
3496
|
const layout = layoutOf(mode, modules.get(entry), lowered, options.outFile);
|
|
3249
3497
|
const usesScriptArgs = lowered.some((m) => m.usesScriptArgs);
|
|
@@ -3255,7 +3503,8 @@ async function bundle(options) {
|
|
|
3255
3503
|
several,
|
|
3256
3504
|
byPath,
|
|
3257
3505
|
files: elsewhere,
|
|
3258
|
-
imports: lowered.some((m) => m.dynamicImports.size > 0)
|
|
3506
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3507
|
+
mapping
|
|
3259
3508
|
}));
|
|
3260
3509
|
const assignment = program2.body.statements[1];
|
|
3261
3510
|
if (usesScriptArgs) {
|
|
@@ -3272,27 +3521,38 @@ async function bundle(options) {
|
|
|
3272
3521
|
program2.body.statements.unshift(...helpers.declare);
|
|
3273
3522
|
const ok = names.fresh("ok");
|
|
3274
3523
|
const result2 = names.fresh("result");
|
|
3275
|
-
const
|
|
3524
|
+
const entryName = luauString4(sources.get(entry).name);
|
|
3525
|
+
const returnsExports = modules.get(entry).info.exports;
|
|
3526
|
+
const returned = returnsExports ? entryReturn(lowerings, sources.get(entry).name, mapping ? result2 : `${G}.require(${entryName})`, () => analysis.exportsOf(entry)) : void 0;
|
|
3527
|
+
if (returned && "problem" in returned) return stop(returned.problem.message);
|
|
3528
|
+
const declarations = returned?.statements.join("\n") ?? "";
|
|
3529
|
+
const entryStatements = parseLuau2(!mapping ? `${declarations}
|
|
3530
|
+
${returned ? `return ${returned.value}` : `${G}.require(${entryName})`}` : `
|
|
3276
3531
|
local ${ok}, ${result2} = xpcall(function()
|
|
3277
|
-
return ${G}.require(${
|
|
3532
|
+
return ${G}.require(${entryName})
|
|
3278
3533
|
end, ${G}.fail)
|
|
3279
3534
|
if not ${ok} then
|
|
3280
3535
|
error(${result2}, 0)
|
|
3281
3536
|
end
|
|
3282
|
-
${
|
|
3537
|
+
${declarations}
|
|
3538
|
+
${returned ? `return ${returned.value}` : ""}
|
|
3283
3539
|
`).body.statements;
|
|
3284
3540
|
program2.body.statements.push(...entryStatements);
|
|
3285
|
-
|
|
3286
|
-
if (
|
|
3541
|
+
let printed = write(program2);
|
|
3542
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3543
|
+
const map = mapping ? buildLineMap(program2, parseLuau2(printed), origins) : /* @__PURE__ */ new Map();
|
|
3544
|
+
if (mapping && (map.size || several)) {
|
|
3287
3545
|
const mapStatements = [assign(
|
|
3288
3546
|
[member(identifier(G), "lines")],
|
|
3289
|
-
[parseExpressionFromSource2(lineMapSource(map))]
|
|
3547
|
+
[parseExpressionFromSource2(lineMapSource(map, `${G}.lineMap`))]
|
|
3290
3548
|
)];
|
|
3291
3549
|
if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
|
|
3292
3550
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
|
|
3293
3551
|
}
|
|
3294
3552
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...helpers.define);
|
|
3295
|
-
|
|
3553
|
+
printed = write(program2);
|
|
3554
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3555
|
+
const files = [{ path: layout[0].path, code: printed + "\n", modules: layout[0].modules.map((m) => m.name) }];
|
|
3296
3556
|
for (const file of layout.slice(1)) {
|
|
3297
3557
|
const fileHelpers = shared.chunk(new Set(file.modules.flatMap((m) => m.shared)));
|
|
3298
3558
|
const body = [...fileHelpers.declare];
|
|
@@ -3304,12 +3564,35 @@ ${modules.get(entry).info.exports ? `return ${result2}` : ""}
|
|
|
3304
3564
|
));
|
|
3305
3565
|
}
|
|
3306
3566
|
const chunk = program([returns([functionExpression(functionBody([G], body))])]);
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3567
|
+
if (mapping) {
|
|
3568
|
+
const lines = buildLineMap(chunk, parseLuau2(print2(chunk, printing)), origins);
|
|
3569
|
+
body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
|
|
3570
|
+
}
|
|
3571
|
+
body.push(...fileHelpers.define);
|
|
3572
|
+
const code = write(chunk);
|
|
3573
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3574
|
+
files.push({ path: file.path, code: code + "\n", modules: file.modules.map((m) => m.name) });
|
|
3310
3575
|
}
|
|
3311
3576
|
return { code: files[0].code, files, modules: moduleNames, diagnostics };
|
|
3312
3577
|
}
|
|
3578
|
+
function entryReturn(lowerings, module, value, exports) {
|
|
3579
|
+
const syntax = [...syntaxOf(lowerings)];
|
|
3580
|
+
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
3581
|
+
const { plugin: plugin3, from, options } = lowerings[i];
|
|
3582
|
+
if (!plugin3.entryExports) continue;
|
|
3583
|
+
const answer = plugin3.entryExports({ options: options ?? {}, module, value, exports: exports(), syntax });
|
|
3584
|
+
if (!answer) continue;
|
|
3585
|
+
const statements = [...answer.statements ?? []];
|
|
3586
|
+
try {
|
|
3587
|
+
parseLuau2(`${statements.join("\n")}
|
|
3588
|
+
return ${answer.value}`);
|
|
3589
|
+
} catch (error) {
|
|
3590
|
+
return { problem: { message: `'${from}' answered entryExports with Luau that does not parse: ${error.message}` } };
|
|
3591
|
+
}
|
|
3592
|
+
return { statements, value: answer.value };
|
|
3593
|
+
}
|
|
3594
|
+
return { statements: [], value };
|
|
3595
|
+
}
|
|
3313
3596
|
function moduleTable(module) {
|
|
3314
3597
|
const { names: exported, links, stars } = module.info;
|
|
3315
3598
|
const fields = [];
|
|
@@ -3329,10 +3612,6 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3329
3612
|
const entryStem = outFile !== void 0 ? basename(outFile, extname(outFile)) : posix.basename(entry.name);
|
|
3330
3613
|
const others = modules.filter((m) => m !== entry);
|
|
3331
3614
|
if (mode === "single") return [{ path: `${entryStem}${extension}`, modules: [entry, ...others] }];
|
|
3332
|
-
if (mode === "modules") {
|
|
3333
|
-
const pathOf = (m) => `${m.name.split("/").map((part) => part === ".." ? "__" : part).join("/")}${extension}`;
|
|
3334
|
-
return [entry, ...others].map((m) => ({ path: pathOf(m), modules: [m] }));
|
|
3335
|
-
}
|
|
3336
3615
|
const byName = new Map(modules.map((m) => [m.name, m]));
|
|
3337
3616
|
const reach = (root) => {
|
|
3338
3617
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3368,11 +3647,70 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3368
3647
|
return files;
|
|
3369
3648
|
}
|
|
3370
3649
|
function loadPath(entryPath, file, byPath) {
|
|
3371
|
-
|
|
3372
|
-
|
|
3650
|
+
return byPath ? requirePath(entryPath, file) : posix.relative(posix.dirname(entryPath), file);
|
|
3651
|
+
}
|
|
3652
|
+
function placeInFolder(path) {
|
|
3653
|
+
const parts = path.replace(/\\/g, "/").replace(/\.luau?$/, "").split("/").filter((part) => part !== "");
|
|
3654
|
+
if (parts.at(-1) === "init") parts.pop();
|
|
3655
|
+
return parts;
|
|
3656
|
+
}
|
|
3657
|
+
function pathBetween(from, to, root) {
|
|
3658
|
+
if (root !== void 0 && from[0] !== to[0]) return `${root}/${to.join("/")}`;
|
|
3659
|
+
if (to.length > from.length && from.every((part, i) => to[i] === part)) return `@self/${to.slice(from.length).join("/")}`;
|
|
3660
|
+
const base = from.slice(0, -1);
|
|
3661
|
+
let shared = 0;
|
|
3662
|
+
while (shared < base.length && shared < to.length - 1 && base[shared] === to[shared]) shared++;
|
|
3663
|
+
const up = base.length - shared;
|
|
3664
|
+
return `${up === 0 ? "./" : "../".repeat(up)}${to.slice(shared).join("/")}`;
|
|
3665
|
+
}
|
|
3666
|
+
function importSites(program2) {
|
|
3667
|
+
const sites = [];
|
|
3668
|
+
for (const statement of program2.body.statements) {
|
|
3669
|
+
if (statement.type === "ImportStatement" || statement.type === "ExportAllStatement" || statement.type === "ExportNamedStatement" && statement.source) {
|
|
3670
|
+
const source = statement.source;
|
|
3671
|
+
sites.push({ specifier: source.value, line: source.line.start, column: source.column.start });
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
for (const node of importExpressions(program2)) {
|
|
3675
|
+
if (node.source.type === "StringLiteral") sites.push({ specifier: node.source.value, line: node.source.line.start, column: node.source.column.start });
|
|
3676
|
+
}
|
|
3677
|
+
return sites;
|
|
3678
|
+
}
|
|
3679
|
+
function pathKey(path) {
|
|
3680
|
+
const full = resolve2(path);
|
|
3681
|
+
return process.platform === "win32" ? full.toLowerCase() : full;
|
|
3682
|
+
}
|
|
3683
|
+
function requirePath(from, to) {
|
|
3684
|
+
const path = posix.relative(posix.dirname(from), to);
|
|
3373
3685
|
const bare = path.slice(0, path.length - posix.extname(path).length);
|
|
3374
3686
|
return bare.startsWith("../") ? bare : `./${bare}`;
|
|
3375
3687
|
}
|
|
3688
|
+
function tiluaFiles(folder) {
|
|
3689
|
+
const found = [];
|
|
3690
|
+
const walk2 = (at) => {
|
|
3691
|
+
let entries;
|
|
3692
|
+
try {
|
|
3693
|
+
entries = readdirSync(at, { withFileTypes: true });
|
|
3694
|
+
} catch {
|
|
3695
|
+
return;
|
|
3696
|
+
}
|
|
3697
|
+
for (const item of entries) {
|
|
3698
|
+
if (item.name.startsWith(".")) continue;
|
|
3699
|
+
const path = join(at, item.name);
|
|
3700
|
+
if (item.isDirectory()) {
|
|
3701
|
+
if (item.name !== "node_modules") walk2(path);
|
|
3702
|
+
} else if (item.name.endsWith(".tilua") && !item.name.endsWith(".d.tilua")) {
|
|
3703
|
+
found.push(path);
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
};
|
|
3707
|
+
walk2(folder);
|
|
3708
|
+
return found.sort();
|
|
3709
|
+
}
|
|
3710
|
+
function isOutside(folder, file) {
|
|
3711
|
+
const path = relative(folder, file);
|
|
3712
|
+
return path === "" || path.startsWith("..") || isAbsolute(path);
|
|
3713
|
+
}
|
|
3376
3714
|
function mapRegistration(G, file, map) {
|
|
3377
3715
|
const extension = posix.extname(file.path);
|
|
3378
3716
|
const parts = file.path.slice(0, file.path.length - extension.length).split(/[/.]/).filter((part) => part !== "");
|
|
@@ -3403,7 +3741,8 @@ function loader(G, byPath) {
|
|
|
3403
3741
|
require(file)(${G})`;
|
|
3404
3742
|
}
|
|
3405
3743
|
function runtime(G, options) {
|
|
3406
|
-
const { several } = options;
|
|
3744
|
+
const { several, mapping } = options;
|
|
3745
|
+
const perFile = options.perFile ?? false;
|
|
3407
3746
|
const files = [...options.files].map(([name, file]) => `[${luauString4(name)}] = ${luauString4(file)}`).join(", ");
|
|
3408
3747
|
return `
|
|
3409
3748
|
local ${G}
|
|
@@ -3411,7 +3750,7 @@ ${G} = {
|
|
|
3411
3750
|
modules = {},
|
|
3412
3751
|
-- Every array the program made, so \`typeof\` can tell one from an object.
|
|
3413
3752
|
-- The keys are held weakly: being written down keeps no array alive.
|
|
3414
|
-
arrays = setmetatable({}, { __mode = "k" })
|
|
3753
|
+
arrays = setmetatable({}, { __mode = "k" }),${mapping ? `
|
|
3415
3754
|
-- Filled in just before the entry runs: bundle line -> { file, line }.
|
|
3416
3755
|
lines = nil,
|
|
3417
3756
|
-- What an error nothing caught says, in the project's files: the bundle's
|
|
@@ -3579,32 +3918,96 @@ ${several ? `
|
|
|
3579
3918
|
end
|
|
3580
3919
|
return mapped .. "\\n" .. table.concat(frames, "\\n")
|
|
3581
3920
|
end,
|
|
3582
|
-
|
|
3921
|
+
-- A line map as it is written: the files it names, and base-64 VLQ
|
|
3922
|
+
-- numbers, three to a line \u2014 how far down the bundle, which file, how far
|
|
3923
|
+
-- down that file, each counted from the line before. It is read out the
|
|
3924
|
+
-- first time a line is looked up, which is when something went wrong.
|
|
3925
|
+
lineMap = function(files, data)
|
|
3926
|
+
local map = {}
|
|
3927
|
+
return setmetatable(map, { __index = function(_, key)
|
|
3928
|
+
setmetatable(map, nil)
|
|
3929
|
+
local digits = {}
|
|
3930
|
+
for i = 1, 64 do
|
|
3931
|
+
digits[("${VLQ_DIGITS}"):byte(i)] = i - 1
|
|
3932
|
+
end
|
|
3933
|
+
local at = 1
|
|
3934
|
+
local function read()
|
|
3935
|
+
local value, scale = 0, 1
|
|
3936
|
+
repeat
|
|
3937
|
+
local digit = digits[data:byte(at)]
|
|
3938
|
+
at = at + 1
|
|
3939
|
+
value = value + digit % 32 * scale
|
|
3940
|
+
scale = scale * 32
|
|
3941
|
+
until digit < 32
|
|
3942
|
+
if value % 2 == 1 then
|
|
3943
|
+
return -math.floor(value / 2)
|
|
3944
|
+
end
|
|
3945
|
+
return math.floor(value / 2)
|
|
3946
|
+
end
|
|
3947
|
+
local line, file, source = 0, 0, 0
|
|
3948
|
+
while at <= #data do
|
|
3949
|
+
line = line + read()
|
|
3950
|
+
file = file + read()
|
|
3951
|
+
source = source + read()
|
|
3952
|
+
map[line] = { files[file], source }
|
|
3953
|
+
end
|
|
3954
|
+
return map[key]
|
|
3955
|
+
end })
|
|
3956
|
+
end,` : ""}
|
|
3957
|
+
records = {},${several && !perFile ? `
|
|
3583
3958
|
-- The file each module outside this one is in, as \`load\` is handed it.
|
|
3584
3959
|
files = { ${files} },
|
|
3585
|
-
loaded = {}
|
|
3960
|
+
loaded = {},` : ""}${several && mapping ? `
|
|
3586
3961
|
-- Every file's line map: by the module, and by the file's name.
|
|
3587
3962
|
maps = {},
|
|
3588
|
-
sources = {}
|
|
3963
|
+
sources = {},` : ""}${several && !perFile ? `
|
|
3589
3964
|
-- Another of the bundle's files: a function that adds its modules here.
|
|
3590
3965
|
load = function(file)
|
|
3591
3966
|
if ${G}.loaded[file] then
|
|
3592
3967
|
return
|
|
3593
3968
|
end
|
|
3594
3969
|
${G}.loaded[file] = true${loader(G, options.byPath)}
|
|
3970
|
+
end,` : ""}${perFile && mapping ? `
|
|
3971
|
+
-- What a file returns: its module's exports. The first file asked for
|
|
3972
|
+
-- runs under \`xpcall\`, so an error nothing caught is reported in the
|
|
3973
|
+
-- project's files; the files it requires in turn are inside that already.
|
|
3974
|
+
running = false,
|
|
3975
|
+
run = function(name)
|
|
3976
|
+
if ${G}.running then
|
|
3977
|
+
return ${G}.require(name)
|
|
3978
|
+
end
|
|
3979
|
+
${G}.running = true
|
|
3980
|
+
local ok, result = xpcall(${G}.require, ${G}.fail, name)
|
|
3981
|
+
${G}.running = false
|
|
3982
|
+
if not ok then
|
|
3983
|
+
error(result, 0)
|
|
3984
|
+
end
|
|
3985
|
+
return result
|
|
3595
3986
|
end,` : ""}${options.imports ? `
|
|
3596
3987
|
-- \`import("./x")\`: the module's exports, asked for where the code runs
|
|
3597
3988
|
-- rather than before its module does. \`require\` does the rest \u2014 and
|
|
3598
3989
|
-- loads the file the module is in, if it is not this one.
|
|
3599
|
-
import = function(name)
|
|
3600
|
-
return ${G}.require(name)
|
|
3990
|
+
import = function(name${perFile ? ", load" : ""})
|
|
3991
|
+
return ${G}.require(name${perFile ? ", load" : ""})
|
|
3601
3992
|
end,` : ""}
|
|
3602
|
-
require = function(name)
|
|
3993
|
+
require = function(name${perFile ? ", load" : ""})
|
|
3603
3994
|
local record = ${G}.records[name]
|
|
3604
3995
|
if record ~= nil then
|
|
3605
3996
|
return record.exports
|
|
3606
3997
|
end
|
|
3607
|
-
local module = ${G}.modules[name]${
|
|
3998
|
+
local module = ${G}.modules[name]${perFile ? `
|
|
3999
|
+
-- Its file has not run: requiring it adds the module, and runs it.
|
|
4000
|
+
if module == nil and load ~= nil then
|
|
4001
|
+
load()
|
|
4002
|
+
record = ${G}.records[name]
|
|
4003
|
+
if record ~= nil then
|
|
4004
|
+
return record.exports
|
|
4005
|
+
end
|
|
4006
|
+
module = ${G}.modules[name]
|
|
4007
|
+
end
|
|
4008
|
+
if module == nil then
|
|
4009
|
+
error(("Cannot find module '%s': nothing has loaded the file it is in"):format(name), 2)
|
|
4010
|
+
end` : several ? `
|
|
3608
4011
|
if module == nil then
|
|
3609
4012
|
${G}.load(${G}.files[name])
|
|
3610
4013
|
module = ${G}.modules[name]
|
|
@@ -3710,7 +4113,7 @@ var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
|
3710
4113
|
function analyzeModules(modules, config) {
|
|
3711
4114
|
const out = [];
|
|
3712
4115
|
const analyses = /* @__PURE__ */ new Map();
|
|
3713
|
-
const libraries = config ? resolveTypeLibraries(config) : { files: [], lowerings: [], problems: [] };
|
|
4116
|
+
const libraries = config ? resolveTypeLibraries(config) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3714
4117
|
for (const p of libraries.problems) out.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3715
4118
|
const libs = libraries.files.map(parsedLibrary);
|
|
3716
4119
|
const noLib = config?.noLib ?? false;
|
|
@@ -3749,7 +4152,7 @@ function analyzeModules(modules, config) {
|
|
|
3749
4152
|
const at = d.node;
|
|
3750
4153
|
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type", severity: d.severity });
|
|
3751
4154
|
}
|
|
3752
|
-
const result2 = { types, diagnostics: said };
|
|
4155
|
+
const result2 = { types, diagnostics: said, scopes };
|
|
3753
4156
|
if (partials === before) {
|
|
3754
4157
|
analyzed.set(file, result2);
|
|
3755
4158
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
@@ -3806,7 +4209,16 @@ function analyzeModules(modules, config) {
|
|
|
3806
4209
|
analyses.set(module.file, types);
|
|
3807
4210
|
out.push(...diagnostics);
|
|
3808
4211
|
}
|
|
3809
|
-
|
|
4212
|
+
const exportsOf = (file) => {
|
|
4213
|
+
const cached = exportsCache.get(file);
|
|
4214
|
+
if (cached) return cached;
|
|
4215
|
+
const module = byFile.get(file);
|
|
4216
|
+
const { types, scopes } = analyzeModule(file, module.program);
|
|
4217
|
+
const exports = moduleExports(module.program, scopes, types, resolverFor(file));
|
|
4218
|
+
exportsCache.set(file, exports);
|
|
4219
|
+
return exports;
|
|
4220
|
+
};
|
|
4221
|
+
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings], exportsOf };
|
|
3810
4222
|
}
|
|
3811
4223
|
function allStatements(statements) {
|
|
3812
4224
|
const out = [];
|
|
@@ -3828,7 +4240,11 @@ function allStatements(statements) {
|
|
|
3828
4240
|
export {
|
|
3829
4241
|
resolveConfig,
|
|
3830
4242
|
program,
|
|
4243
|
+
syntaxOf,
|
|
3831
4244
|
lower,
|
|
4245
|
+
printOptions,
|
|
4246
|
+
printOutput,
|
|
3832
4247
|
loadLowerings,
|
|
4248
|
+
WRITTEN_BY_TILUA,
|
|
3833
4249
|
bundle
|
|
3834
4250
|
};
|