@tilua/compiler 8.1.0 → 9.0.1
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 +115 -13
- package/dist/{chunk-WOBHMGGC.js → chunk-3RJVN4KC.js} +447 -59
- package/dist/cli.cjs +733 -98
- package/dist/cli.js +279 -24
- package/dist/index.cjs +453 -66
- package/dist/index.d.cts +52 -9
- package/dist/index.d.ts +52 -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,
|
|
@@ -2796,6 +2805,9 @@ import {
|
|
|
2796
2805
|
resolveModulePath,
|
|
2797
2806
|
resolveTypeLibraries,
|
|
2798
2807
|
importExpressions,
|
|
2808
|
+
sourceMapOf,
|
|
2809
|
+
sourceMapTypes,
|
|
2810
|
+
outputPathOf,
|
|
2799
2811
|
directivesOf,
|
|
2800
2812
|
applyDirectives,
|
|
2801
2813
|
UNUSED_EXPECT_ERROR,
|
|
@@ -2804,7 +2816,7 @@ import {
|
|
|
2804
2816
|
LexError,
|
|
2805
2817
|
luauString as luauString4
|
|
2806
2818
|
} from "@tilua/parser";
|
|
2807
|
-
import { parse as parseLuau2, parseExpressionFromSource as parseExpressionFromSource2, print } from "luau-parser";
|
|
2819
|
+
import { parse as parseLuau2, parseExpressionFromSource as parseExpressionFromSource2, print as print2 } from "luau-parser";
|
|
2808
2820
|
|
|
2809
2821
|
// src/treeshake.ts
|
|
2810
2822
|
function walk(node, visit, parent) {
|
|
@@ -3072,23 +3084,29 @@ function ownExport(f, name) {
|
|
|
3072
3084
|
// src/linemap.ts
|
|
3073
3085
|
import { luauString as luauString3 } from "@tilua/parser";
|
|
3074
3086
|
function statementsOf(node) {
|
|
3075
|
-
|
|
3076
|
-
|
|
3087
|
+
return statementTree(node).statements;
|
|
3088
|
+
}
|
|
3089
|
+
function statementTree(node) {
|
|
3090
|
+
const statements = [];
|
|
3091
|
+
const parents = [];
|
|
3092
|
+
const visit = (value, parent) => {
|
|
3077
3093
|
if (!value || typeof value !== "object") return;
|
|
3078
|
-
if (Array.isArray(value)) return void value.forEach(visit);
|
|
3094
|
+
if (Array.isArray(value)) return void value.forEach((item) => visit(item, parent));
|
|
3079
3095
|
const record = value;
|
|
3096
|
+
let inside = parent;
|
|
3080
3097
|
if (typeof record.type === "string" && record.type.endsWith("Statement")) {
|
|
3081
|
-
|
|
3098
|
+
inside = statements.push(value) - 1;
|
|
3099
|
+
parents.push(parent);
|
|
3082
3100
|
}
|
|
3083
3101
|
for (const [key, child] of Object.entries(record)) {
|
|
3084
|
-
if (key !== "line" && key !== "column") visit(child);
|
|
3102
|
+
if (key !== "line" && key !== "column") visit(child, inside);
|
|
3085
3103
|
}
|
|
3086
3104
|
};
|
|
3087
|
-
visit(node);
|
|
3088
|
-
return
|
|
3105
|
+
visit(node, -1);
|
|
3106
|
+
return { statements, parents };
|
|
3089
3107
|
}
|
|
3090
3108
|
function buildLineMap(emitted, printed, origins) {
|
|
3091
|
-
const before =
|
|
3109
|
+
const { statements: before, parents } = statementTree(emitted);
|
|
3092
3110
|
const after = statementsOf(printed);
|
|
3093
3111
|
if (before.length !== after.length) return /* @__PURE__ */ new Map();
|
|
3094
3112
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3099,6 +3117,18 @@ function buildLineMap(emitted, printed, origins) {
|
|
|
3099
3117
|
const line = after[i].line.start;
|
|
3100
3118
|
if (!map.has(line)) map.set(line, origin);
|
|
3101
3119
|
}
|
|
3120
|
+
const holds = /* @__PURE__ */ new Set();
|
|
3121
|
+
for (let i = 0; i < before.length; i++) {
|
|
3122
|
+
if (!origins.has(before[i])) continue;
|
|
3123
|
+
for (let up = parents[i]; up >= 0 && !holds.has(up); up = parents[up]) holds.add(up);
|
|
3124
|
+
}
|
|
3125
|
+
for (let i = 0; i < before.length; i++) {
|
|
3126
|
+
const origin = origins.get(before[i]);
|
|
3127
|
+
if (!origin || holds.has(i)) continue;
|
|
3128
|
+
for (let line = after[i].line.start + 1; line <= after[i].line.end; line++) {
|
|
3129
|
+
if (!map.has(line)) map.set(line, origin);
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3102
3132
|
return map;
|
|
3103
3133
|
}
|
|
3104
3134
|
var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -3130,18 +3160,59 @@ function lineMapSource(map, unpack) {
|
|
|
3130
3160
|
return `${unpack}({${files.map(luauString3).join(",")}},${luauString3(data)})`;
|
|
3131
3161
|
}
|
|
3132
3162
|
|
|
3163
|
+
// src/output.ts
|
|
3164
|
+
import { print, PrintError } from "luau-parser";
|
|
3165
|
+
var WRITTEN = /* @__PURE__ */ new Set([
|
|
3166
|
+
"compoundAssignment",
|
|
3167
|
+
"continue",
|
|
3168
|
+
"ifExpression",
|
|
3169
|
+
"floorDivision",
|
|
3170
|
+
"attributes",
|
|
3171
|
+
"numberLiterals"
|
|
3172
|
+
]);
|
|
3173
|
+
function printOptions(syntax, format = {}) {
|
|
3174
|
+
return {
|
|
3175
|
+
syntax: [...syntax].some((s) => WRITTEN.has(s)) ? "luau" : "lua51",
|
|
3176
|
+
compact: format.minify ?? false,
|
|
3177
|
+
...format.indent !== void 0 && { indent: format.indent }
|
|
3178
|
+
};
|
|
3179
|
+
}
|
|
3180
|
+
function printOutput(node, options) {
|
|
3181
|
+
try {
|
|
3182
|
+
return { code: print(node, options) };
|
|
3183
|
+
} catch (error) {
|
|
3184
|
+
if (!(error instanceof PrintError)) throw error;
|
|
3185
|
+
return {
|
|
3186
|
+
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"`
|
|
3187
|
+
};
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3133
3191
|
// src/bundle.ts
|
|
3192
|
+
var WRITTEN_BY_TILUA = "-- Written by tilua";
|
|
3134
3193
|
async function bundle(options) {
|
|
3135
|
-
const entry = resolve2(options.entry);
|
|
3136
3194
|
const diagnostics = [];
|
|
3195
|
+
const from = options.entry !== void 0 ? resolve2(options.entry) : resolve2(options.root ?? process.cwd(), "tilua.config.json");
|
|
3137
3196
|
const inline = options.config !== void 0 && typeof options.config !== "string";
|
|
3138
|
-
const { config, problems } = resolveConfig(options.config,
|
|
3197
|
+
const { config, problems } = resolveConfig(options.config, from, options.root ?? (inline ? dirname(from) : process.cwd()));
|
|
3139
3198
|
for (const p of problems) diagnostics.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3140
|
-
const root = resolve2(options.root ?? config?.directory ?? dirname(
|
|
3199
|
+
const root = resolve2(options.root ?? config?.directory ?? dirname(from));
|
|
3141
3200
|
const nameOf = (file) => relative(root, file).replace(/\\/g, "/").replace(/\.tilua$/, "");
|
|
3201
|
+
const mode = options.output ?? config?.output ?? "single";
|
|
3202
|
+
const perFile = mode === "files";
|
|
3203
|
+
const rootDir = resolve2(config?.rootDir ?? root);
|
|
3204
|
+
const entry = options.entry !== void 0 ? resolve2(options.entry) : void 0;
|
|
3205
|
+
const anchor = entry ?? config?.path ?? from;
|
|
3206
|
+
const stop = (message, file = anchor) => ({
|
|
3207
|
+
files: [],
|
|
3208
|
+
modules: [],
|
|
3209
|
+
diagnostics: [...diagnostics, { file, message, line: 1, column: 1, category: "config" }]
|
|
3210
|
+
});
|
|
3211
|
+
if (!perFile && entry === void 0) return stop('No entry to build: only "output": "files" builds without one');
|
|
3142
3212
|
const sources = /* @__PURE__ */ new Map();
|
|
3143
3213
|
const directives = /* @__PURE__ */ new Map();
|
|
3144
|
-
const queue = [entry];
|
|
3214
|
+
const queue = perFile ? tiluaFiles(rootDir) : [entry];
|
|
3215
|
+
if (perFile && !queue.length) return stop(`No .tilua file under ${relative(process.cwd(), rootDir) || "."}`);
|
|
3145
3216
|
while (queue.length) {
|
|
3146
3217
|
const file = queue.shift();
|
|
3147
3218
|
if (sources.has(file)) continue;
|
|
@@ -3159,6 +3230,22 @@ async function bundle(options) {
|
|
|
3159
3230
|
if (target && !target.endsWith(".d.tilua")) queue.push(target);
|
|
3160
3231
|
}
|
|
3161
3232
|
}
|
|
3233
|
+
if (perFile) {
|
|
3234
|
+
const outside = [...sources.keys()].filter((file) => isOutside(rootDir, file));
|
|
3235
|
+
if (outside.length) {
|
|
3236
|
+
return {
|
|
3237
|
+
files: [],
|
|
3238
|
+
modules: [],
|
|
3239
|
+
diagnostics: [...diagnostics, ...outside.map((file) => ({
|
|
3240
|
+
file,
|
|
3241
|
+
message: `This file is imported, but it is outside rootDir (${relative(root, rootDir) || "."}), where every file of "files" output has to be`,
|
|
3242
|
+
line: 1,
|
|
3243
|
+
column: 1,
|
|
3244
|
+
category: "module"
|
|
3245
|
+
}))]
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3162
3249
|
const analysis = analyzeModules([...sources.values()], config);
|
|
3163
3250
|
const { lowerings, problems: loweringProblems } = await loadLowerings(analysis.lowerings);
|
|
3164
3251
|
for (const p of loweringProblems) {
|
|
@@ -3169,19 +3256,56 @@ async function bundle(options) {
|
|
|
3169
3256
|
const G = names.fresh("G");
|
|
3170
3257
|
const requireExpression = member(identifier(G), "require");
|
|
3171
3258
|
const importExpression = member(identifier(G), "import");
|
|
3172
|
-
const mode = options.output ?? config?.output ?? "single";
|
|
3173
3259
|
const byPath = syntaxOf(lowerings).has("requireByPath");
|
|
3260
|
+
if (perFile && !byPath) {
|
|
3261
|
+
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);
|
|
3262
|
+
}
|
|
3263
|
+
const outputPath = (file) => relative(rootDir, file).replace(/\\/g, "/").replace(/\.tilua$/, ".luau");
|
|
3264
|
+
const fileOfModule = new Map([...sources.values()].map((s) => [s.name, s.file]));
|
|
3265
|
+
const outDir = resolve2(options.outDir ?? config?.outDir ?? rootDir);
|
|
3266
|
+
const written = (file) => join(outDir, outputPath(file));
|
|
3267
|
+
let host;
|
|
3268
|
+
let runtimeFile = join(outDir, "_tilua.luau");
|
|
3269
|
+
if (perFile) {
|
|
3270
|
+
const outputs = [...sources.keys()].map(written);
|
|
3271
|
+
const taken = new Set(outputs.map(pathKey));
|
|
3272
|
+
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = join(outDir, `_tilua${n}.luau`);
|
|
3273
|
+
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3274
|
+
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3275
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3276
|
+
}
|
|
3277
|
+
for (const problem of host?.problems ?? []) {
|
|
3278
|
+
diagnostics.push({
|
|
3279
|
+
file: problem.file ?? config?.path ?? anchor,
|
|
3280
|
+
message: problem.message,
|
|
3281
|
+
line: 1,
|
|
3282
|
+
column: 1,
|
|
3283
|
+
category: "config",
|
|
3284
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3285
|
+
});
|
|
3286
|
+
}
|
|
3287
|
+
if (host?.runtime !== void 0) {
|
|
3288
|
+
if (isOutside(outDir, resolve2(host.runtime))) return stop(`The runtime has to go inside outDir, not at ${host.runtime}`);
|
|
3289
|
+
if (taken.has(pathKey(host.runtime))) return stop(`The runtime cannot go at ${host.runtime}: a module's file is there`);
|
|
3290
|
+
runtimeFile = resolve2(host.runtime);
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
const placeOf = (file) => host?.place?.(file) ?? placeInFolder(relative(outDir, file));
|
|
3294
|
+
const requireFrom = (from2, to) => pathBetween(placeOf(from2), placeOf(to), host?.root);
|
|
3295
|
+
const isScript = (file) => host?.script?.(file) ?? false;
|
|
3174
3296
|
const modules = /* @__PURE__ */ new Map();
|
|
3175
3297
|
const origins = /* @__PURE__ */ new WeakMap();
|
|
3176
3298
|
const shared = new SharedRuntime(names);
|
|
3177
3299
|
const shaking = options.treeShaking ?? config?.treeShaking ?? false;
|
|
3178
|
-
const
|
|
3300
|
+
const format = { indent: options.indent ?? config?.indent, minify: options.minify ?? config?.minify ?? false };
|
|
3301
|
+
const printing = printOptions(syntaxOf(lowerings), format);
|
|
3302
|
+
const mapping = !format.minify && (options.lineMap ?? config?.lineMap ?? true);
|
|
3179
3303
|
const resolveIn = (file) => (specifier) => {
|
|
3180
3304
|
const found = resolveModulePath(file, specifier, config);
|
|
3181
3305
|
return found !== void 0 && sources.has(found) ? found : void 0;
|
|
3182
3306
|
};
|
|
3183
|
-
const shaken = shaking ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry) : void 0;
|
|
3184
|
-
const pending = [entry];
|
|
3307
|
+
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;
|
|
3308
|
+
const pending = perFile ? [...sources.keys()] : [entry];
|
|
3185
3309
|
while (pending.length) {
|
|
3186
3310
|
const file = pending.shift();
|
|
3187
3311
|
if (modules.has(file)) continue;
|
|
@@ -3217,6 +3341,13 @@ async function bundle(options) {
|
|
|
3217
3341
|
lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${luauString4(source.name)}]`,
|
|
3218
3342
|
fail: mapping ? `${G}.fail` : void 0,
|
|
3219
3343
|
arrays: `${G}.arrays`,
|
|
3344
|
+
// The file a module is in, required from this one by its
|
|
3345
|
+
// path, written out.
|
|
3346
|
+
loader: !perFile ? void 0 : (name) => {
|
|
3347
|
+
const target = fileOfModule.get(name);
|
|
3348
|
+
if (target === void 0) return void 0;
|
|
3349
|
+
return parseExpressionFromSource2(`function() return require(${luauString4(requireFrom(written(file), written(target)))}) end`);
|
|
3350
|
+
},
|
|
3220
3351
|
resolve: (specifier, dynamic) => {
|
|
3221
3352
|
const found = resolveModulePath(file, specifier, config);
|
|
3222
3353
|
if (!found || found.endsWith(".d.tilua") || !sources.has(found)) return void 0;
|
|
@@ -3268,6 +3399,102 @@ async function bundle(options) {
|
|
|
3268
3399
|
return { files: [], modules: moduleNames, diagnostics };
|
|
3269
3400
|
}
|
|
3270
3401
|
if (shaking) shared.shake(lowered.flatMap((m) => m.statements));
|
|
3402
|
+
const unwritable = (problem) => ({
|
|
3403
|
+
files: [],
|
|
3404
|
+
modules: moduleNames,
|
|
3405
|
+
diagnostics: [...diagnostics, { file: anchor, message: problem, line: 1, column: 1, category: "config" }]
|
|
3406
|
+
});
|
|
3407
|
+
const write = (node) => {
|
|
3408
|
+
const printed2 = printOutput(node, printing);
|
|
3409
|
+
return "problem" in printed2 ? printed2 : printed2.code;
|
|
3410
|
+
};
|
|
3411
|
+
if (perFile) {
|
|
3412
|
+
const imported = [];
|
|
3413
|
+
for (const [file, source] of sources) {
|
|
3414
|
+
for (const { specifier, line, column } of importSites(source.program)) {
|
|
3415
|
+
const target = resolveIn(file)(specifier);
|
|
3416
|
+
if (target === void 0 || !isScript(written(target))) continue;
|
|
3417
|
+
imported.push({
|
|
3418
|
+
file,
|
|
3419
|
+
line,
|
|
3420
|
+
column,
|
|
3421
|
+
category: "module",
|
|
3422
|
+
message: `'${specifier}' is a script the game runs, which nothing can import: move what it shares into a module of its own`
|
|
3423
|
+
});
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
if (imported.length) return { files: [], modules: moduleNames, diagnostics: [...diagnostics, ...imported] };
|
|
3427
|
+
const runtimePath = relative(outDir, runtimeFile).replace(/\\/g, "/");
|
|
3428
|
+
const files2 = [];
|
|
3429
|
+
for (const [file, module] of modules) {
|
|
3430
|
+
const path = outputPath(file);
|
|
3431
|
+
const at = written(file);
|
|
3432
|
+
const script = isScript(at);
|
|
3433
|
+
const prelude = host?.prelude?.(at);
|
|
3434
|
+
const body = [
|
|
3435
|
+
...prelude !== void 0 ? parseLuau2(prelude).body.statements : [],
|
|
3436
|
+
...parseLuau2(`local ${G} = require(${luauString4(requireFrom(at, runtimeFile))})`).body.statements
|
|
3437
|
+
];
|
|
3438
|
+
for (let i = 0; i < module.shared.length; i += 100) {
|
|
3439
|
+
const some = module.shared.slice(i, i + 100);
|
|
3440
|
+
body.push(local(some, some.map((name) => member(member(identifier(G), "shared"), name))));
|
|
3441
|
+
}
|
|
3442
|
+
if (module.usesScriptArgs) body.push(...parseLuau2(`local scriptArgs = ${G}.scriptArgs`).body.statements);
|
|
3443
|
+
body.push(assign(
|
|
3444
|
+
[index(member(identifier(G), "modules"), string(module.name))],
|
|
3445
|
+
[moduleTable(module)]
|
|
3446
|
+
));
|
|
3447
|
+
const value = `${G}.${mapping ? "run" : "require"}(${luauString4(module.name)})`;
|
|
3448
|
+
const returned2 = module.info.exports && !script ? entryReturn(lowerings, module.name, value, () => analysis.exportsOf(file)) : { statements: [], value };
|
|
3449
|
+
if ("problem" in returned2) return stop(returned2.problem.message, file);
|
|
3450
|
+
const ending = parseLuau2(`${returned2.statements.join("\n")}
|
|
3451
|
+
return ${returned2.value}`).body.statements;
|
|
3452
|
+
const chunk = program(body);
|
|
3453
|
+
if (mapping) {
|
|
3454
|
+
const text = write(chunk);
|
|
3455
|
+
if (typeof text !== "string") return unwritable(text.problem);
|
|
3456
|
+
const lines = buildLineMap(chunk, parseLuau2(text), origins);
|
|
3457
|
+
const named = host?.place?.(at) ? `${placeOf(at).join("/")}.luau` : path;
|
|
3458
|
+
body.push(...mapRegistration(G, { path: named, modules: [module] }, lineMapSource(lines, `${G}.lineMap`)));
|
|
3459
|
+
}
|
|
3460
|
+
body.push(...ending);
|
|
3461
|
+
const code = write(chunk);
|
|
3462
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3463
|
+
const from2 = relative(dirname(at), file).replace(/\\/g, "/");
|
|
3464
|
+
files2.push({ path, code: `${code}
|
|
3465
|
+
${WRITTEN_BY_TILUA} from ${from2}: edit that file, not this one.
|
|
3466
|
+
`, modules: [module.name] });
|
|
3467
|
+
}
|
|
3468
|
+
const runtimeProgram = parseLuau2(runtime(G, {
|
|
3469
|
+
several: true,
|
|
3470
|
+
perFile: true,
|
|
3471
|
+
byPath,
|
|
3472
|
+
files: /* @__PURE__ */ new Map(),
|
|
3473
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3474
|
+
mapping
|
|
3475
|
+
}));
|
|
3476
|
+
const helpers2 = shared.chunk(new Set(lowered.flatMap((m) => m.shared)));
|
|
3477
|
+
const helperNames = helpers2.declare.flatMap((statement) => statement.type === "LocalStatement" ? statement.names.map((n) => n.name) : []);
|
|
3478
|
+
runtimeProgram.body.statements.unshift(...helpers2.declare);
|
|
3479
|
+
runtimeProgram.body.statements.push(...helpers2.define);
|
|
3480
|
+
if (helperNames.length) {
|
|
3481
|
+
runtimeProgram.body.statements.push(assign(
|
|
3482
|
+
[member(identifier(G), "shared")],
|
|
3483
|
+
[table(helperNames.map((name) => field(name, identifier(name))))]
|
|
3484
|
+
));
|
|
3485
|
+
}
|
|
3486
|
+
if (lowered.some((m) => m.usesScriptArgs)) {
|
|
3487
|
+
runtimeProgram.body.statements.push(...parseLuau2(`${G}.scriptArgs = {}
|
|
3488
|
+
${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
3489
|
+
}
|
|
3490
|
+
runtimeProgram.body.statements.push(returns([identifier(G)]));
|
|
3491
|
+
const runtimeCode = write(runtimeProgram);
|
|
3492
|
+
if (typeof runtimeCode !== "string") return unwritable(runtimeCode.problem);
|
|
3493
|
+
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3494
|
+
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3495
|
+
`, modules: [] });
|
|
3496
|
+
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3497
|
+
}
|
|
3271
3498
|
const several = mode !== "single";
|
|
3272
3499
|
const layout = layoutOf(mode, modules.get(entry), lowered, options.outFile);
|
|
3273
3500
|
const usesScriptArgs = lowered.some((m) => m.usesScriptArgs);
|
|
@@ -3299,17 +3526,24 @@ async function bundle(options) {
|
|
|
3299
3526
|
const result2 = names.fresh("result");
|
|
3300
3527
|
const entryName = luauString4(sources.get(entry).name);
|
|
3301
3528
|
const returnsExports = modules.get(entry).info.exports;
|
|
3302
|
-
const
|
|
3529
|
+
const returned = returnsExports ? entryReturn(lowerings, sources.get(entry).name, mapping ? result2 : `${G}.require(${entryName})`, () => analysis.exportsOf(entry)) : void 0;
|
|
3530
|
+
if (returned && "problem" in returned) return stop(returned.problem.message);
|
|
3531
|
+
const declarations = returned?.statements.join("\n") ?? "";
|
|
3532
|
+
const entryStatements = parseLuau2(!mapping ? `${declarations}
|
|
3533
|
+
${returned ? `return ${returned.value}` : `${G}.require(${entryName})`}` : `
|
|
3303
3534
|
local ${ok}, ${result2} = xpcall(function()
|
|
3304
3535
|
return ${G}.require(${entryName})
|
|
3305
3536
|
end, ${G}.fail)
|
|
3306
3537
|
if not ${ok} then
|
|
3307
3538
|
error(${result2}, 0)
|
|
3308
3539
|
end
|
|
3309
|
-
${
|
|
3540
|
+
${declarations}
|
|
3541
|
+
${returned ? `return ${returned.value}` : ""}
|
|
3310
3542
|
`).body.statements;
|
|
3311
3543
|
program2.body.statements.push(...entryStatements);
|
|
3312
|
-
|
|
3544
|
+
let printed = write(program2);
|
|
3545
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3546
|
+
const map = mapping ? buildLineMap(program2, parseLuau2(printed), origins) : /* @__PURE__ */ new Map();
|
|
3313
3547
|
if (mapping && (map.size || several)) {
|
|
3314
3548
|
const mapStatements = [assign(
|
|
3315
3549
|
[member(identifier(G), "lines")],
|
|
@@ -3319,7 +3553,9 @@ ${returnsExports ? `return ${result2}` : ""}
|
|
|
3319
3553
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
|
|
3320
3554
|
}
|
|
3321
3555
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...helpers.define);
|
|
3322
|
-
|
|
3556
|
+
printed = write(program2);
|
|
3557
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3558
|
+
const files = [{ path: layout[0].path, code: printed + "\n", modules: layout[0].modules.map((m) => m.name) }];
|
|
3323
3559
|
for (const file of layout.slice(1)) {
|
|
3324
3560
|
const fileHelpers = shared.chunk(new Set(file.modules.flatMap((m) => m.shared)));
|
|
3325
3561
|
const body = [...fileHelpers.declare];
|
|
@@ -3332,14 +3568,34 @@ ${returnsExports ? `return ${result2}` : ""}
|
|
|
3332
3568
|
}
|
|
3333
3569
|
const chunk = program([returns([functionExpression(functionBody([G], body))])]);
|
|
3334
3570
|
if (mapping) {
|
|
3335
|
-
const lines = buildLineMap(chunk, parseLuau2(
|
|
3571
|
+
const lines = buildLineMap(chunk, parseLuau2(print2(chunk, printing)), origins);
|
|
3336
3572
|
body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
|
|
3337
3573
|
}
|
|
3338
3574
|
body.push(...fileHelpers.define);
|
|
3339
|
-
|
|
3575
|
+
const code = write(chunk);
|
|
3576
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3577
|
+
files.push({ path: file.path, code: code + "\n", modules: file.modules.map((m) => m.name) });
|
|
3340
3578
|
}
|
|
3341
3579
|
return { code: files[0].code, files, modules: moduleNames, diagnostics };
|
|
3342
3580
|
}
|
|
3581
|
+
function entryReturn(lowerings, module, value, exports) {
|
|
3582
|
+
const syntax = [...syntaxOf(lowerings)];
|
|
3583
|
+
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
3584
|
+
const { plugin: plugin3, from, options } = lowerings[i];
|
|
3585
|
+
if (!plugin3.entryExports) continue;
|
|
3586
|
+
const answer = plugin3.entryExports({ options: options ?? {}, module, value, exports: exports(), syntax });
|
|
3587
|
+
if (!answer) continue;
|
|
3588
|
+
const statements = [...answer.statements ?? []];
|
|
3589
|
+
try {
|
|
3590
|
+
parseLuau2(`${statements.join("\n")}
|
|
3591
|
+
return ${answer.value}`);
|
|
3592
|
+
} catch (error) {
|
|
3593
|
+
return { problem: { message: `'${from}' answered entryExports with Luau that does not parse: ${error.message}` } };
|
|
3594
|
+
}
|
|
3595
|
+
return { statements, value: answer.value };
|
|
3596
|
+
}
|
|
3597
|
+
return { statements: [], value };
|
|
3598
|
+
}
|
|
3343
3599
|
function moduleTable(module) {
|
|
3344
3600
|
const { names: exported, links, stars } = module.info;
|
|
3345
3601
|
const fields = [];
|
|
@@ -3359,10 +3615,6 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3359
3615
|
const entryStem = outFile !== void 0 ? basename(outFile, extname(outFile)) : posix.basename(entry.name);
|
|
3360
3616
|
const others = modules.filter((m) => m !== entry);
|
|
3361
3617
|
if (mode === "single") return [{ path: `${entryStem}${extension}`, modules: [entry, ...others] }];
|
|
3362
|
-
if (mode === "modules") {
|
|
3363
|
-
const pathOf = (m) => `${m.name.split("/").map((part) => part === ".." ? "__" : part).join("/")}${extension}`;
|
|
3364
|
-
return [entry, ...others].map((m) => ({ path: pathOf(m), modules: [m] }));
|
|
3365
|
-
}
|
|
3366
3618
|
const byName = new Map(modules.map((m) => [m.name, m]));
|
|
3367
3619
|
const reach = (root) => {
|
|
3368
3620
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3398,11 +3650,70 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3398
3650
|
return files;
|
|
3399
3651
|
}
|
|
3400
3652
|
function loadPath(entryPath, file, byPath) {
|
|
3401
|
-
|
|
3402
|
-
|
|
3653
|
+
return byPath ? requirePath(entryPath, file) : posix.relative(posix.dirname(entryPath), file);
|
|
3654
|
+
}
|
|
3655
|
+
function placeInFolder(path) {
|
|
3656
|
+
const parts = path.replace(/\\/g, "/").replace(/\.luau?$/, "").split("/").filter((part) => part !== "");
|
|
3657
|
+
if (parts.at(-1) === "init") parts.pop();
|
|
3658
|
+
return parts;
|
|
3659
|
+
}
|
|
3660
|
+
function pathBetween(from, to, root) {
|
|
3661
|
+
if (root !== void 0 && from[0] !== to[0]) return `${root}/${to.join("/")}`;
|
|
3662
|
+
if (to.length > from.length && from.every((part, i) => to[i] === part)) return `@self/${to.slice(from.length).join("/")}`;
|
|
3663
|
+
const base = from.slice(0, -1);
|
|
3664
|
+
let shared = 0;
|
|
3665
|
+
while (shared < base.length && shared < to.length - 1 && base[shared] === to[shared]) shared++;
|
|
3666
|
+
const up = base.length - shared;
|
|
3667
|
+
return `${up === 0 ? "./" : "../".repeat(up)}${to.slice(shared).join("/")}`;
|
|
3668
|
+
}
|
|
3669
|
+
function importSites(program2) {
|
|
3670
|
+
const sites = [];
|
|
3671
|
+
for (const statement of program2.body.statements) {
|
|
3672
|
+
if (statement.type === "ImportStatement" || statement.type === "ExportAllStatement" || statement.type === "ExportNamedStatement" && statement.source) {
|
|
3673
|
+
const source = statement.source;
|
|
3674
|
+
sites.push({ specifier: source.value, line: source.line.start, column: source.column.start });
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
for (const node of importExpressions(program2)) {
|
|
3678
|
+
if (node.source.type === "StringLiteral") sites.push({ specifier: node.source.value, line: node.source.line.start, column: node.source.column.start });
|
|
3679
|
+
}
|
|
3680
|
+
return sites;
|
|
3681
|
+
}
|
|
3682
|
+
function pathKey(path) {
|
|
3683
|
+
const full = resolve2(path);
|
|
3684
|
+
return process.platform === "win32" ? full.toLowerCase() : full;
|
|
3685
|
+
}
|
|
3686
|
+
function requirePath(from, to) {
|
|
3687
|
+
const path = posix.relative(posix.dirname(from), to);
|
|
3403
3688
|
const bare = path.slice(0, path.length - posix.extname(path).length);
|
|
3404
3689
|
return bare.startsWith("../") ? bare : `./${bare}`;
|
|
3405
3690
|
}
|
|
3691
|
+
function tiluaFiles(folder) {
|
|
3692
|
+
const found = [];
|
|
3693
|
+
const walk2 = (at) => {
|
|
3694
|
+
let entries;
|
|
3695
|
+
try {
|
|
3696
|
+
entries = readdirSync(at, { withFileTypes: true });
|
|
3697
|
+
} catch {
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
for (const item of entries) {
|
|
3701
|
+
if (item.name.startsWith(".")) continue;
|
|
3702
|
+
const path = join(at, item.name);
|
|
3703
|
+
if (item.isDirectory()) {
|
|
3704
|
+
if (item.name !== "node_modules") walk2(path);
|
|
3705
|
+
} else if (item.name.endsWith(".tilua") && !item.name.endsWith(".d.tilua")) {
|
|
3706
|
+
found.push(path);
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
};
|
|
3710
|
+
walk2(folder);
|
|
3711
|
+
return found.sort();
|
|
3712
|
+
}
|
|
3713
|
+
function isOutside(folder, file) {
|
|
3714
|
+
const path = relative(folder, file);
|
|
3715
|
+
return path === "" || path.startsWith("..") || isAbsolute(path);
|
|
3716
|
+
}
|
|
3406
3717
|
function mapRegistration(G, file, map) {
|
|
3407
3718
|
const extension = posix.extname(file.path);
|
|
3408
3719
|
const parts = file.path.slice(0, file.path.length - extension.length).split(/[/.]/).filter((part) => part !== "");
|
|
@@ -3434,6 +3745,7 @@ function loader(G, byPath) {
|
|
|
3434
3745
|
}
|
|
3435
3746
|
function runtime(G, options) {
|
|
3436
3747
|
const { several, mapping } = options;
|
|
3748
|
+
const perFile = options.perFile ?? false;
|
|
3437
3749
|
const files = [...options.files].map(([name, file]) => `[${luauString4(name)}] = ${luauString4(file)}`).join(", ");
|
|
3438
3750
|
return `
|
|
3439
3751
|
local ${G}
|
|
@@ -3645,32 +3957,60 @@ ${several ? `
|
|
|
3645
3957
|
return map[key]
|
|
3646
3958
|
end })
|
|
3647
3959
|
end,` : ""}
|
|
3648
|
-
records = {},${several ? `
|
|
3960
|
+
records = {},${several && !perFile ? `
|
|
3649
3961
|
-- The file each module outside this one is in, as \`load\` is handed it.
|
|
3650
3962
|
files = { ${files} },
|
|
3651
|
-
loaded = {}
|
|
3963
|
+
loaded = {},` : ""}${several && mapping ? `
|
|
3652
3964
|
-- Every file's line map: by the module, and by the file's name.
|
|
3653
3965
|
maps = {},
|
|
3654
|
-
sources = {},` : ""}
|
|
3966
|
+
sources = {},` : ""}${several && !perFile ? `
|
|
3655
3967
|
-- Another of the bundle's files: a function that adds its modules here.
|
|
3656
3968
|
load = function(file)
|
|
3657
3969
|
if ${G}.loaded[file] then
|
|
3658
3970
|
return
|
|
3659
3971
|
end
|
|
3660
3972
|
${G}.loaded[file] = true${loader(G, options.byPath)}
|
|
3973
|
+
end,` : ""}${perFile && mapping ? `
|
|
3974
|
+
-- What a file returns: its module's exports. The first file asked for
|
|
3975
|
+
-- runs under \`xpcall\`, so an error nothing caught is reported in the
|
|
3976
|
+
-- project's files; the files it requires in turn are inside that already.
|
|
3977
|
+
running = false,
|
|
3978
|
+
run = function(name)
|
|
3979
|
+
if ${G}.running then
|
|
3980
|
+
return ${G}.require(name)
|
|
3981
|
+
end
|
|
3982
|
+
${G}.running = true
|
|
3983
|
+
local ok, result = xpcall(${G}.require, ${G}.fail, name)
|
|
3984
|
+
${G}.running = false
|
|
3985
|
+
if not ok then
|
|
3986
|
+
error(result, 0)
|
|
3987
|
+
end
|
|
3988
|
+
return result
|
|
3661
3989
|
end,` : ""}${options.imports ? `
|
|
3662
3990
|
-- \`import("./x")\`: the module's exports, asked for where the code runs
|
|
3663
3991
|
-- rather than before its module does. \`require\` does the rest \u2014 and
|
|
3664
3992
|
-- loads the file the module is in, if it is not this one.
|
|
3665
|
-
import = function(name)
|
|
3666
|
-
return ${G}.require(name)
|
|
3993
|
+
import = function(name${perFile ? ", load" : ""})
|
|
3994
|
+
return ${G}.require(name${perFile ? ", load" : ""})
|
|
3667
3995
|
end,` : ""}
|
|
3668
|
-
require = function(name)
|
|
3996
|
+
require = function(name${perFile ? ", load" : ""})
|
|
3669
3997
|
local record = ${G}.records[name]
|
|
3670
3998
|
if record ~= nil then
|
|
3671
3999
|
return record.exports
|
|
3672
4000
|
end
|
|
3673
|
-
local module = ${G}.modules[name]${
|
|
4001
|
+
local module = ${G}.modules[name]${perFile ? `
|
|
4002
|
+
-- Its file has not run: requiring it adds the module, and runs it.
|
|
4003
|
+
if module == nil and load ~= nil then
|
|
4004
|
+
load()
|
|
4005
|
+
record = ${G}.records[name]
|
|
4006
|
+
if record ~= nil then
|
|
4007
|
+
return record.exports
|
|
4008
|
+
end
|
|
4009
|
+
module = ${G}.modules[name]
|
|
4010
|
+
end
|
|
4011
|
+
if module == nil then
|
|
4012
|
+
error(("Cannot find module '%s': nothing has loaded the file it is in"):format(name), 2)
|
|
4013
|
+
end` : several ? `
|
|
3674
4014
|
if module == nil then
|
|
3675
4015
|
${G}.load(${G}.files[name])
|
|
3676
4016
|
module = ${G}.modules[name]
|
|
@@ -3758,6 +4098,35 @@ function importedSpecifiers(program2) {
|
|
|
3758
4098
|
return program2.body.statements.flatMap((s) => s.type === "ImportStatement" || s.type === "ExportAllStatement" || s.type === "ExportNamedStatement" && s.source ? [s.source.value] : []);
|
|
3759
4099
|
}
|
|
3760
4100
|
var libraryCache = /* @__PURE__ */ new Map();
|
|
4101
|
+
var treeCache;
|
|
4102
|
+
function instanceTree(config, libs, noLib) {
|
|
4103
|
+
const tree = sourceMapOf(config);
|
|
4104
|
+
if (!tree) return void 0;
|
|
4105
|
+
if ("problem" in tree) return tree.named ? { problem: { file: config.path, message: tree.problem } } : void 0;
|
|
4106
|
+
const declares = (name) => libs.some((lib) => lib.body.statements.some((s) => s.type === "DeclareStatement" && s.name === name));
|
|
4107
|
+
if (!tree.named && !declares("game")) return void 0;
|
|
4108
|
+
if (treeCache && treeCache.text === tree.text && treeCache.libs.length === libs.length && treeCache.libs.every((lib, i) => lib === libs[i])) {
|
|
4109
|
+
return { types: treeCache.types };
|
|
4110
|
+
}
|
|
4111
|
+
const empty = parse("");
|
|
4112
|
+
const aliases = analyzeTypes(empty, analyzeScopes(empty, { noLib }), { libs, noLib, diagnostics: false }).aliases;
|
|
4113
|
+
const membersOf = (className) => {
|
|
4114
|
+
const type = aliases.get(className);
|
|
4115
|
+
return new Set(type?.kind === "object" ? type.properties.keys() : ["Name", "ClassName", "Parent", "Archivable"]);
|
|
4116
|
+
};
|
|
4117
|
+
const { types, problem } = sourceMapTypes(tree.text, tree.path, { classes: new Set(aliases.keys()), membersOf });
|
|
4118
|
+
if (!types) return tree.named && problem ? { problem: { file: tree.path, message: problem } } : void 0;
|
|
4119
|
+
const scripts = /* @__PURE__ */ new Map();
|
|
4120
|
+
const cached = {
|
|
4121
|
+
program: types.program,
|
|
4122
|
+
scriptFor: (file) => {
|
|
4123
|
+
if (!scripts.has(file)) scripts.set(file, types.scriptFor(file));
|
|
4124
|
+
return scripts.get(file);
|
|
4125
|
+
}
|
|
4126
|
+
};
|
|
4127
|
+
treeCache = { text: tree.text, libs: [...libs], types: cached, scripts };
|
|
4128
|
+
return { types: cached };
|
|
4129
|
+
}
|
|
3761
4130
|
function parsedLibrary(file) {
|
|
3762
4131
|
let stamp;
|
|
3763
4132
|
try {
|
|
@@ -3776,11 +4145,15 @@ var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
|
3776
4145
|
function analyzeModules(modules, config) {
|
|
3777
4146
|
const out = [];
|
|
3778
4147
|
const analyses = /* @__PURE__ */ new Map();
|
|
3779
|
-
const libraries = config ? resolveTypeLibraries(config) : { files: [], lowerings: [], problems: [] };
|
|
4148
|
+
const libraries = config ? resolveTypeLibraries(config) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3780
4149
|
for (const p of libraries.problems) out.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3781
4150
|
const libs = libraries.files.map(parsedLibrary);
|
|
3782
4151
|
const noLib = config?.noLib ?? false;
|
|
3783
4152
|
const checked = libs.length > 0 || !noLib;
|
|
4153
|
+
const tree = config ? instanceTree(config, libs, noLib) : void 0;
|
|
4154
|
+
if (tree?.problem) out.push({ file: tree.problem.file, message: tree.problem.message, line: 1, column: 1, category: "config" });
|
|
4155
|
+
if (tree?.types) libs.push(tree.types.program);
|
|
4156
|
+
const scriptOf = (file) => tree?.types && config ? tree.types.scriptFor(outputPathOf(config, file)) : void 0;
|
|
3784
4157
|
const globals = libs.flatMap((lib) => lib.body.statements.flatMap((s) => s.type === "DeclareStatement" ? [s.name] : []));
|
|
3785
4158
|
const byFile = new Map(modules.map((m) => [m.file, m]));
|
|
3786
4159
|
const exportsCache = /* @__PURE__ */ new Map();
|
|
@@ -3793,7 +4166,9 @@ function analyzeModules(modules, config) {
|
|
|
3793
4166
|
const done = analyzed.get(file);
|
|
3794
4167
|
if (done) return done;
|
|
3795
4168
|
const remembered = moduleAnalyses.get(file);
|
|
3796
|
-
|
|
4169
|
+
const script = scriptOf(file);
|
|
4170
|
+
const ownLibs = script ? [...libs, script] : libs;
|
|
4171
|
+
if (remembered && remembered.setting === settingFor && ownLibs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === ownLibs[i]) && remembered.program === program2 && [...remembered.read].every(([read3, stamp]) => stampOf(read3) === stamp)) {
|
|
3797
4172
|
analyzed.set(file, remembered.result);
|
|
3798
4173
|
readWhile.set(file, remembered.read);
|
|
3799
4174
|
return remembered.result;
|
|
@@ -3806,7 +4181,7 @@ function analyzeModules(modules, config) {
|
|
|
3806
4181
|
}
|
|
3807
4182
|
const before = partials;
|
|
3808
4183
|
const types = analyzeTypes(program2, scopes, {
|
|
3809
|
-
libs,
|
|
4184
|
+
libs: ownLibs,
|
|
3810
4185
|
resolveModule: resolverFor(file),
|
|
3811
4186
|
noLib,
|
|
3812
4187
|
reportUnknownTypes: checked
|
|
@@ -3815,7 +4190,7 @@ function analyzeModules(modules, config) {
|
|
|
3815
4190
|
const at = d.node;
|
|
3816
4191
|
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type", severity: d.severity });
|
|
3817
4192
|
}
|
|
3818
|
-
const result2 = { types, diagnostics: said };
|
|
4193
|
+
const result2 = { types, diagnostics: said, scopes };
|
|
3819
4194
|
if (partials === before) {
|
|
3820
4195
|
analyzed.set(file, result2);
|
|
3821
4196
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
@@ -3823,7 +4198,7 @@ function analyzeModules(modules, config) {
|
|
|
3823
4198
|
if (own !== void 0) read3.set(file, own);
|
|
3824
4199
|
readWhile.set(file, read3);
|
|
3825
4200
|
if ([...read3.values()].every((stamp) => stamp !== void 0)) {
|
|
3826
|
-
moduleAnalyses.set(file, { setting: settingFor, libs: [...
|
|
4201
|
+
moduleAnalyses.set(file, { setting: settingFor, libs: [...ownLibs], program: program2, read: read3, result: result2 });
|
|
3827
4202
|
}
|
|
3828
4203
|
}
|
|
3829
4204
|
return result2;
|
|
@@ -3872,7 +4247,16 @@ function analyzeModules(modules, config) {
|
|
|
3872
4247
|
analyses.set(module.file, types);
|
|
3873
4248
|
out.push(...diagnostics);
|
|
3874
4249
|
}
|
|
3875
|
-
|
|
4250
|
+
const exportsOf = (file) => {
|
|
4251
|
+
const cached = exportsCache.get(file);
|
|
4252
|
+
if (cached) return cached;
|
|
4253
|
+
const module = byFile.get(file);
|
|
4254
|
+
const { types, scopes } = analyzeModule(file, module.program);
|
|
4255
|
+
const exports = moduleExports(module.program, scopes, types, resolverFor(file));
|
|
4256
|
+
exportsCache.set(file, exports);
|
|
4257
|
+
return exports;
|
|
4258
|
+
};
|
|
4259
|
+
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings], exportsOf };
|
|
3876
4260
|
}
|
|
3877
4261
|
function allStatements(statements) {
|
|
3878
4262
|
const out = [];
|
|
@@ -3894,7 +4278,11 @@ function allStatements(statements) {
|
|
|
3894
4278
|
export {
|
|
3895
4279
|
resolveConfig,
|
|
3896
4280
|
program,
|
|
4281
|
+
syntaxOf,
|
|
3897
4282
|
lower,
|
|
4283
|
+
printOptions,
|
|
4284
|
+
printOutput,
|
|
3898
4285
|
loadLowerings,
|
|
4286
|
+
WRITTEN_BY_TILUA,
|
|
3899
4287
|
bundle
|
|
3900
4288
|
};
|