@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
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
WRITTEN_BY_TILUA: () => WRITTEN_BY_TILUA,
|
|
23
24
|
bundle: () => bundle,
|
|
24
25
|
compile: () => compile,
|
|
25
26
|
loadLowerings: () => loadLowerings,
|
|
@@ -36,7 +37,7 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
36
37
|
var import_node_fs3 = require("fs");
|
|
37
38
|
var import_node_path2 = require("path");
|
|
38
39
|
var import_parser7 = require("@tilua/parser");
|
|
39
|
-
var
|
|
40
|
+
var import_luau_parser3 = require("luau-parser");
|
|
40
41
|
|
|
41
42
|
// src/config.ts
|
|
42
43
|
var import_node_path = require("path");
|
|
@@ -424,6 +425,10 @@ var SharedRuntime = class {
|
|
|
424
425
|
return { declare, define };
|
|
425
426
|
}
|
|
426
427
|
};
|
|
428
|
+
function moduleArguments(context, name) {
|
|
429
|
+
const loader2 = context.loader?.(name);
|
|
430
|
+
return loader2 ? [string(name), loader2] : [string(name)];
|
|
431
|
+
}
|
|
427
432
|
function lower(program2, scopes, options = {}) {
|
|
428
433
|
const result2 = new Lowerer(program2, scopes, options).run();
|
|
429
434
|
dropUnreachable(result2.statements);
|
|
@@ -740,6 +745,7 @@ var Lowerer = class {
|
|
|
740
745
|
const plugin3 = lowerings[i].plugin;
|
|
741
746
|
if (!plugin3.methodCall) continue;
|
|
742
747
|
const answer = plugin3.methodCall({
|
|
748
|
+
options: lowerings[i].options ?? {},
|
|
743
749
|
method,
|
|
744
750
|
receiver,
|
|
745
751
|
receiverGlobal,
|
|
@@ -771,6 +777,7 @@ var Lowerer = class {
|
|
|
771
777
|
const plugin3 = lowerings[i].plugin;
|
|
772
778
|
if (!plugin3.globalCall) continue;
|
|
773
779
|
const answer = plugin3.globalCall({
|
|
780
|
+
options: lowerings[i].options ?? {},
|
|
774
781
|
name,
|
|
775
782
|
at: this.callSite(node.callee),
|
|
776
783
|
get arguments() {
|
|
@@ -790,6 +797,7 @@ var Lowerer = class {
|
|
|
790
797
|
if (name === void 0) return void 0;
|
|
791
798
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
792
799
|
const answer = lowerings[i].plugin.globalValue?.({
|
|
800
|
+
options: lowerings[i].options ?? {},
|
|
793
801
|
name,
|
|
794
802
|
at: this.callSite(node),
|
|
795
803
|
use: (runtime2) => this.loweringRuntime(i, runtime2)
|
|
@@ -1043,12 +1051,12 @@ end`).body.statements, out);
|
|
|
1043
1051
|
local2 = this.names.fresh(moduleName(key));
|
|
1044
1052
|
moduleLocals.set(key, local2);
|
|
1045
1053
|
locals.push(local2);
|
|
1046
|
-
requires.push(assign([identifier(local2)], [call(context.require,
|
|
1054
|
+
requires.push(assign([identifier(local2)], [call(context.require, moduleArguments(context, key))]));
|
|
1047
1055
|
}
|
|
1048
1056
|
return local2;
|
|
1049
1057
|
};
|
|
1050
1058
|
const load = (key) => {
|
|
1051
|
-
if (!moduleLocals.has(key)) requires.push(callStatement(call(context.require,
|
|
1059
|
+
if (!moduleLocals.has(key)) requires.push(callStatement(call(context.require, moduleArguments(context, key))));
|
|
1052
1060
|
};
|
|
1053
1061
|
const exportBinding = (node, exported) => {
|
|
1054
1062
|
const binding = node && this.bindingByDeclaration.get(node);
|
|
@@ -1157,20 +1165,22 @@ end`).body.statements, out);
|
|
|
1157
1165
|
continue;
|
|
1158
1166
|
}
|
|
1159
1167
|
if (declaration.type === "ClassDeclaration") {
|
|
1160
|
-
body.push(...this.classDeclaration(declaration, "assign"));
|
|
1168
|
+
body.push(...this.classDeclaration(declaration, "assign").map((s) => this.from(s, declaration)));
|
|
1161
1169
|
continue;
|
|
1162
1170
|
}
|
|
1163
1171
|
switch (declaration.type) {
|
|
1172
|
+
// Stamped with where they were written, as any statement is:
|
|
1173
|
+
// an error in a top-level `const` names its line.
|
|
1164
1174
|
case "VariableDeclaration":
|
|
1165
|
-
body.push(...this.variableDeclaration(declaration, "assign"));
|
|
1175
|
+
body.push(...this.variableDeclaration(declaration, "assign").map((s) => this.from(s, declaration)));
|
|
1166
1176
|
break;
|
|
1167
1177
|
case "ExportDefaultStatement": {
|
|
1168
1178
|
const exported = declaration.declaration;
|
|
1169
1179
|
if (exported.type === "ClassDeclaration") {
|
|
1170
|
-
body.push(...this.classDeclaration(exported, "assign"));
|
|
1171
|
-
body.push(assign([member(exportsTable(), "default")], [this.reference(exported.name)]));
|
|
1180
|
+
body.push(...this.classDeclaration(exported, "assign").map((s) => this.from(s, exported)));
|
|
1181
|
+
body.push(this.from(assign([member(exportsTable(), "default")], [this.reference(exported.name)]), declaration));
|
|
1172
1182
|
} else {
|
|
1173
|
-
body.push(assign([member(exportsTable(), "default")], [this.expression(exported)]));
|
|
1183
|
+
body.push(this.from(assign([member(exportsTable(), "default")], [this.expression(exported)]), declaration));
|
|
1174
1184
|
}
|
|
1175
1185
|
break;
|
|
1176
1186
|
}
|
|
@@ -1208,7 +1218,7 @@ end`).body.statements, out);
|
|
|
1208
1218
|
this.report(source, `Cannot find module '${source.value}'`);
|
|
1209
1219
|
return nil();
|
|
1210
1220
|
}
|
|
1211
|
-
return call(context.import ?? context.require,
|
|
1221
|
+
return call(context.import ?? context.require, moduleArguments(context, key));
|
|
1212
1222
|
}
|
|
1213
1223
|
isRewritten(node) {
|
|
1214
1224
|
const binding = this.bindingByDeclaration.get(node);
|
|
@@ -1407,9 +1417,9 @@ end`).body.statements, out);
|
|
|
1407
1417
|
return this.assignment(node);
|
|
1408
1418
|
case "CompoundAssignmentStatement": {
|
|
1409
1419
|
if (node.operator === "??=") return this.nullishAssignment(node);
|
|
1410
|
-
const
|
|
1411
|
-
if (
|
|
1412
|
-
const operator =
|
|
1420
|
+
const join2 = node.operator === "+=" ? this.options.types?.joins.get(node) : void 0;
|
|
1421
|
+
if (join2 === "dynamic") return this.dynamicAddition(node);
|
|
1422
|
+
const operator = join2 === "concat" ? "..=" : node.operator;
|
|
1413
1423
|
if (!this.syntax.has("compoundAssignment")) return this.compoundAssignment51(node, operator);
|
|
1414
1424
|
return [{
|
|
1415
1425
|
type: "CompoundAssignmentStatement",
|
|
@@ -2095,9 +2105,9 @@ end
|
|
|
2095
2105
|
return call(this.helper("instanceof"), [this.keptToOne(left), this.keptToOne(right)]);
|
|
2096
2106
|
}
|
|
2097
2107
|
if (node.operator === "+") {
|
|
2098
|
-
const
|
|
2099
|
-
if (
|
|
2100
|
-
if (
|
|
2108
|
+
const join2 = this.options.types?.joins.get(node);
|
|
2109
|
+
if (join2 === "concat") return binary("..", left, right);
|
|
2110
|
+
if (join2 === "dynamic") return call(this.helper("add"), [this.keptToOne(left), this.keptToOne(right)]);
|
|
2101
2111
|
}
|
|
2102
2112
|
if (!this.syntax.has("floorDivision") && node.operator === "//") return this.floorDivide(left, right);
|
|
2103
2113
|
return binary(node.operator, left, right);
|
|
@@ -3064,23 +3074,29 @@ function ownExport(f, name) {
|
|
|
3064
3074
|
// src/linemap.ts
|
|
3065
3075
|
var import_parser6 = require("@tilua/parser");
|
|
3066
3076
|
function statementsOf(node) {
|
|
3067
|
-
|
|
3068
|
-
|
|
3077
|
+
return statementTree(node).statements;
|
|
3078
|
+
}
|
|
3079
|
+
function statementTree(node) {
|
|
3080
|
+
const statements = [];
|
|
3081
|
+
const parents = [];
|
|
3082
|
+
const visit = (value, parent) => {
|
|
3069
3083
|
if (!value || typeof value !== "object") return;
|
|
3070
|
-
if (Array.isArray(value)) return void value.forEach(visit);
|
|
3084
|
+
if (Array.isArray(value)) return void value.forEach((item) => visit(item, parent));
|
|
3071
3085
|
const record = value;
|
|
3086
|
+
let inside = parent;
|
|
3072
3087
|
if (typeof record.type === "string" && record.type.endsWith("Statement")) {
|
|
3073
|
-
|
|
3088
|
+
inside = statements.push(value) - 1;
|
|
3089
|
+
parents.push(parent);
|
|
3074
3090
|
}
|
|
3075
3091
|
for (const [key, child] of Object.entries(record)) {
|
|
3076
|
-
if (key !== "line" && key !== "column") visit(child);
|
|
3092
|
+
if (key !== "line" && key !== "column") visit(child, inside);
|
|
3077
3093
|
}
|
|
3078
3094
|
};
|
|
3079
|
-
visit(node);
|
|
3080
|
-
return
|
|
3095
|
+
visit(node, -1);
|
|
3096
|
+
return { statements, parents };
|
|
3081
3097
|
}
|
|
3082
3098
|
function buildLineMap(emitted, printed, origins) {
|
|
3083
|
-
const before =
|
|
3099
|
+
const { statements: before, parents } = statementTree(emitted);
|
|
3084
3100
|
const after = statementsOf(printed);
|
|
3085
3101
|
if (before.length !== after.length) return /* @__PURE__ */ new Map();
|
|
3086
3102
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3091,6 +3107,18 @@ function buildLineMap(emitted, printed, origins) {
|
|
|
3091
3107
|
const line = after[i].line.start;
|
|
3092
3108
|
if (!map.has(line)) map.set(line, origin);
|
|
3093
3109
|
}
|
|
3110
|
+
const holds = /* @__PURE__ */ new Set();
|
|
3111
|
+
for (let i = 0; i < before.length; i++) {
|
|
3112
|
+
if (!origins.has(before[i])) continue;
|
|
3113
|
+
for (let up = parents[i]; up >= 0 && !holds.has(up); up = parents[up]) holds.add(up);
|
|
3114
|
+
}
|
|
3115
|
+
for (let i = 0; i < before.length; i++) {
|
|
3116
|
+
const origin = origins.get(before[i]);
|
|
3117
|
+
if (!origin || holds.has(i)) continue;
|
|
3118
|
+
for (let line = after[i].line.start + 1; line <= after[i].line.end; line++) {
|
|
3119
|
+
if (!map.has(line)) map.set(line, origin);
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3094
3122
|
return map;
|
|
3095
3123
|
}
|
|
3096
3124
|
var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -3122,6 +3150,34 @@ function lineMapSource(map, unpack) {
|
|
|
3122
3150
|
return `${unpack}({${files.map(import_parser6.luauString).join(",")}},${(0, import_parser6.luauString)(data)})`;
|
|
3123
3151
|
}
|
|
3124
3152
|
|
|
3153
|
+
// src/output.ts
|
|
3154
|
+
var import_luau_parser2 = require("luau-parser");
|
|
3155
|
+
var WRITTEN = /* @__PURE__ */ new Set([
|
|
3156
|
+
"compoundAssignment",
|
|
3157
|
+
"continue",
|
|
3158
|
+
"ifExpression",
|
|
3159
|
+
"floorDivision",
|
|
3160
|
+
"attributes",
|
|
3161
|
+
"numberLiterals"
|
|
3162
|
+
]);
|
|
3163
|
+
function printOptions(syntax, format = {}) {
|
|
3164
|
+
return {
|
|
3165
|
+
syntax: [...syntax].some((s) => WRITTEN.has(s)) ? "luau" : "lua51",
|
|
3166
|
+
compact: format.minify ?? false,
|
|
3167
|
+
...format.indent !== void 0 && { indent: format.indent }
|
|
3168
|
+
};
|
|
3169
|
+
}
|
|
3170
|
+
function printOutput(node, options) {
|
|
3171
|
+
try {
|
|
3172
|
+
return { code: (0, import_luau_parser2.print)(node, options) };
|
|
3173
|
+
} catch (error) {
|
|
3174
|
+
if (!(error instanceof import_luau_parser2.PrintError)) throw error;
|
|
3175
|
+
return {
|
|
3176
|
+
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"`
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3125
3181
|
// src/lowering.ts
|
|
3126
3182
|
var import_node_url = require("url");
|
|
3127
3183
|
async function loadLowerings(modules) {
|
|
@@ -3138,7 +3194,7 @@ async function loadLowerings(modules) {
|
|
|
3138
3194
|
});
|
|
3139
3195
|
continue;
|
|
3140
3196
|
}
|
|
3141
|
-
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library });
|
|
3197
|
+
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library, options: module2.options });
|
|
3142
3198
|
} catch (error) {
|
|
3143
3199
|
problems.push({
|
|
3144
3200
|
file: module2.file,
|
|
@@ -3150,17 +3206,30 @@ async function loadLowerings(modules) {
|
|
|
3150
3206
|
}
|
|
3151
3207
|
|
|
3152
3208
|
// src/bundle.ts
|
|
3209
|
+
var WRITTEN_BY_TILUA = "-- Written by tilua";
|
|
3153
3210
|
async function bundle(options) {
|
|
3154
|
-
const entry = (0, import_node_path2.resolve)(options.entry);
|
|
3155
3211
|
const diagnostics = [];
|
|
3212
|
+
const from = options.entry !== void 0 ? (0, import_node_path2.resolve)(options.entry) : (0, import_node_path2.resolve)(options.root ?? process.cwd(), "tilua.config.json");
|
|
3156
3213
|
const inline = options.config !== void 0 && typeof options.config !== "string";
|
|
3157
|
-
const { config, problems } = resolveConfig(options.config,
|
|
3214
|
+
const { config, problems } = resolveConfig(options.config, from, options.root ?? (inline ? (0, import_node_path2.dirname)(from) : process.cwd()));
|
|
3158
3215
|
for (const p of problems) diagnostics.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3159
|
-
const root = (0, import_node_path2.resolve)(options.root ?? config?.directory ?? (0, import_node_path2.dirname)(
|
|
3216
|
+
const root = (0, import_node_path2.resolve)(options.root ?? config?.directory ?? (0, import_node_path2.dirname)(from));
|
|
3160
3217
|
const nameOf = (file) => (0, import_node_path2.relative)(root, file).replace(/\\/g, "/").replace(/\.tilua$/, "");
|
|
3218
|
+
const mode = options.output ?? config?.output ?? "single";
|
|
3219
|
+
const perFile = mode === "files";
|
|
3220
|
+
const rootDir = (0, import_node_path2.resolve)(config?.rootDir ?? root);
|
|
3221
|
+
const entry = options.entry !== void 0 ? (0, import_node_path2.resolve)(options.entry) : void 0;
|
|
3222
|
+
const anchor = entry ?? config?.path ?? from;
|
|
3223
|
+
const stop = (message, file = anchor) => ({
|
|
3224
|
+
files: [],
|
|
3225
|
+
modules: [],
|
|
3226
|
+
diagnostics: [...diagnostics, { file, message, line: 1, column: 1, category: "config" }]
|
|
3227
|
+
});
|
|
3228
|
+
if (!perFile && entry === void 0) return stop('No entry to build: only "output": "files" builds without one');
|
|
3161
3229
|
const sources = /* @__PURE__ */ new Map();
|
|
3162
3230
|
const directives = /* @__PURE__ */ new Map();
|
|
3163
|
-
const queue = [entry];
|
|
3231
|
+
const queue = perFile ? tiluaFiles(rootDir) : [entry];
|
|
3232
|
+
if (perFile && !queue.length) return stop(`No .tilua file under ${(0, import_node_path2.relative)(process.cwd(), rootDir) || "."}`);
|
|
3164
3233
|
while (queue.length) {
|
|
3165
3234
|
const file = queue.shift();
|
|
3166
3235
|
if (sources.has(file)) continue;
|
|
@@ -3178,6 +3247,22 @@ async function bundle(options) {
|
|
|
3178
3247
|
if (target && !target.endsWith(".d.tilua")) queue.push(target);
|
|
3179
3248
|
}
|
|
3180
3249
|
}
|
|
3250
|
+
if (perFile) {
|
|
3251
|
+
const outside = [...sources.keys()].filter((file) => isOutside(rootDir, file));
|
|
3252
|
+
if (outside.length) {
|
|
3253
|
+
return {
|
|
3254
|
+
files: [],
|
|
3255
|
+
modules: [],
|
|
3256
|
+
diagnostics: [...diagnostics, ...outside.map((file) => ({
|
|
3257
|
+
file,
|
|
3258
|
+
message: `This file is imported, but it is outside rootDir (${(0, import_node_path2.relative)(root, rootDir) || "."}), where every file of "files" output has to be`,
|
|
3259
|
+
line: 1,
|
|
3260
|
+
column: 1,
|
|
3261
|
+
category: "module"
|
|
3262
|
+
}))]
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3181
3266
|
const analysis = analyzeModules([...sources.values()], config);
|
|
3182
3267
|
const { lowerings, problems: loweringProblems } = await loadLowerings(analysis.lowerings);
|
|
3183
3268
|
for (const p of loweringProblems) {
|
|
@@ -3188,19 +3273,56 @@ async function bundle(options) {
|
|
|
3188
3273
|
const G = names.fresh("G");
|
|
3189
3274
|
const requireExpression = member(identifier(G), "require");
|
|
3190
3275
|
const importExpression = member(identifier(G), "import");
|
|
3191
|
-
const mode = options.output ?? config?.output ?? "single";
|
|
3192
3276
|
const byPath = syntaxOf(lowerings).has("requireByPath");
|
|
3277
|
+
if (perFile && !byPath) {
|
|
3278
|
+
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);
|
|
3279
|
+
}
|
|
3280
|
+
const outputPath = (file) => (0, import_node_path2.relative)(rootDir, file).replace(/\\/g, "/").replace(/\.tilua$/, ".luau");
|
|
3281
|
+
const fileOfModule = new Map([...sources.values()].map((s) => [s.name, s.file]));
|
|
3282
|
+
const outDir = (0, import_node_path2.resolve)(options.outDir ?? config?.outDir ?? rootDir);
|
|
3283
|
+
const written = (file) => (0, import_node_path2.join)(outDir, outputPath(file));
|
|
3284
|
+
let host;
|
|
3285
|
+
let runtimeFile = (0, import_node_path2.join)(outDir, "_tilua.luau");
|
|
3286
|
+
if (perFile) {
|
|
3287
|
+
const outputs = [...sources.keys()].map(written);
|
|
3288
|
+
const taken = new Set(outputs.map(pathKey));
|
|
3289
|
+
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = (0, import_node_path2.join)(outDir, `_tilua${n}.luau`);
|
|
3290
|
+
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3291
|
+
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3292
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3293
|
+
}
|
|
3294
|
+
for (const problem of host?.problems ?? []) {
|
|
3295
|
+
diagnostics.push({
|
|
3296
|
+
file: problem.file ?? config?.path ?? anchor,
|
|
3297
|
+
message: problem.message,
|
|
3298
|
+
line: 1,
|
|
3299
|
+
column: 1,
|
|
3300
|
+
category: "config",
|
|
3301
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3302
|
+
});
|
|
3303
|
+
}
|
|
3304
|
+
if (host?.runtime !== void 0) {
|
|
3305
|
+
if (isOutside(outDir, (0, import_node_path2.resolve)(host.runtime))) return stop(`The runtime has to go inside outDir, not at ${host.runtime}`);
|
|
3306
|
+
if (taken.has(pathKey(host.runtime))) return stop(`The runtime cannot go at ${host.runtime}: a module's file is there`);
|
|
3307
|
+
runtimeFile = (0, import_node_path2.resolve)(host.runtime);
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
const placeOf = (file) => host?.place?.(file) ?? placeInFolder((0, import_node_path2.relative)(outDir, file));
|
|
3311
|
+
const requireFrom = (from2, to) => pathBetween(placeOf(from2), placeOf(to), host?.root);
|
|
3312
|
+
const isScript = (file) => host?.script?.(file) ?? false;
|
|
3193
3313
|
const modules = /* @__PURE__ */ new Map();
|
|
3194
3314
|
const origins = /* @__PURE__ */ new WeakMap();
|
|
3195
3315
|
const shared = new SharedRuntime(names);
|
|
3196
3316
|
const shaking = options.treeShaking ?? config?.treeShaking ?? false;
|
|
3197
|
-
const
|
|
3317
|
+
const format = { indent: options.indent ?? config?.indent, minify: options.minify ?? config?.minify ?? false };
|
|
3318
|
+
const printing = printOptions(syntaxOf(lowerings), format);
|
|
3319
|
+
const mapping = !format.minify && (options.lineMap ?? config?.lineMap ?? true);
|
|
3198
3320
|
const resolveIn = (file) => (specifier) => {
|
|
3199
3321
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config);
|
|
3200
3322
|
return found !== void 0 && sources.has(found) ? found : void 0;
|
|
3201
3323
|
};
|
|
3202
|
-
const shaken = shaking ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry) : void 0;
|
|
3203
|
-
const pending = [entry];
|
|
3324
|
+
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;
|
|
3325
|
+
const pending = perFile ? [...sources.keys()] : [entry];
|
|
3204
3326
|
while (pending.length) {
|
|
3205
3327
|
const file = pending.shift();
|
|
3206
3328
|
if (modules.has(file)) continue;
|
|
@@ -3236,6 +3358,13 @@ async function bundle(options) {
|
|
|
3236
3358
|
lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
|
|
3237
3359
|
fail: mapping ? `${G}.fail` : void 0,
|
|
3238
3360
|
arrays: `${G}.arrays`,
|
|
3361
|
+
// The file a module is in, required from this one by its
|
|
3362
|
+
// path, written out.
|
|
3363
|
+
loader: !perFile ? void 0 : (name) => {
|
|
3364
|
+
const target = fileOfModule.get(name);
|
|
3365
|
+
if (target === void 0) return void 0;
|
|
3366
|
+
return (0, import_luau_parser3.parseExpressionFromSource)(`function() return require(${(0, import_parser7.luauString)(requireFrom(written(file), written(target)))}) end`);
|
|
3367
|
+
},
|
|
3239
3368
|
resolve: (specifier, dynamic) => {
|
|
3240
3369
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config);
|
|
3241
3370
|
if (!found || found.endsWith(".d.tilua") || !sources.has(found)) return void 0;
|
|
@@ -3287,6 +3416,102 @@ async function bundle(options) {
|
|
|
3287
3416
|
return { files: [], modules: moduleNames, diagnostics };
|
|
3288
3417
|
}
|
|
3289
3418
|
if (shaking) shared.shake(lowered.flatMap((m) => m.statements));
|
|
3419
|
+
const unwritable = (problem) => ({
|
|
3420
|
+
files: [],
|
|
3421
|
+
modules: moduleNames,
|
|
3422
|
+
diagnostics: [...diagnostics, { file: anchor, message: problem, line: 1, column: 1, category: "config" }]
|
|
3423
|
+
});
|
|
3424
|
+
const write = (node) => {
|
|
3425
|
+
const printed2 = printOutput(node, printing);
|
|
3426
|
+
return "problem" in printed2 ? printed2 : printed2.code;
|
|
3427
|
+
};
|
|
3428
|
+
if (perFile) {
|
|
3429
|
+
const imported = [];
|
|
3430
|
+
for (const [file, source] of sources) {
|
|
3431
|
+
for (const { specifier, line, column } of importSites(source.program)) {
|
|
3432
|
+
const target = resolveIn(file)(specifier);
|
|
3433
|
+
if (target === void 0 || !isScript(written(target))) continue;
|
|
3434
|
+
imported.push({
|
|
3435
|
+
file,
|
|
3436
|
+
line,
|
|
3437
|
+
column,
|
|
3438
|
+
category: "module",
|
|
3439
|
+
message: `'${specifier}' is a script the game runs, which nothing can import: move what it shares into a module of its own`
|
|
3440
|
+
});
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
if (imported.length) return { files: [], modules: moduleNames, diagnostics: [...diagnostics, ...imported] };
|
|
3444
|
+
const runtimePath = (0, import_node_path2.relative)(outDir, runtimeFile).replace(/\\/g, "/");
|
|
3445
|
+
const files2 = [];
|
|
3446
|
+
for (const [file, module2] of modules) {
|
|
3447
|
+
const path = outputPath(file);
|
|
3448
|
+
const at = written(file);
|
|
3449
|
+
const script = isScript(at);
|
|
3450
|
+
const prelude = host?.prelude?.(at);
|
|
3451
|
+
const body = [
|
|
3452
|
+
...prelude !== void 0 ? (0, import_luau_parser3.parse)(prelude).body.statements : [],
|
|
3453
|
+
...(0, import_luau_parser3.parse)(`local ${G} = require(${(0, import_parser7.luauString)(requireFrom(at, runtimeFile))})`).body.statements
|
|
3454
|
+
];
|
|
3455
|
+
for (let i = 0; i < module2.shared.length; i += 100) {
|
|
3456
|
+
const some = module2.shared.slice(i, i + 100);
|
|
3457
|
+
body.push(local(some, some.map((name) => member(member(identifier(G), "shared"), name))));
|
|
3458
|
+
}
|
|
3459
|
+
if (module2.usesScriptArgs) body.push(...(0, import_luau_parser3.parse)(`local scriptArgs = ${G}.scriptArgs`).body.statements);
|
|
3460
|
+
body.push(assign(
|
|
3461
|
+
[index(member(identifier(G), "modules"), string(module2.name))],
|
|
3462
|
+
[moduleTable(module2)]
|
|
3463
|
+
));
|
|
3464
|
+
const value = `${G}.${mapping ? "run" : "require"}(${(0, import_parser7.luauString)(module2.name)})`;
|
|
3465
|
+
const returned2 = module2.info.exports && !script ? entryReturn(lowerings, module2.name, value, () => analysis.exportsOf(file)) : { statements: [], value };
|
|
3466
|
+
if ("problem" in returned2) return stop(returned2.problem.message, file);
|
|
3467
|
+
const ending = (0, import_luau_parser3.parse)(`${returned2.statements.join("\n")}
|
|
3468
|
+
return ${returned2.value}`).body.statements;
|
|
3469
|
+
const chunk = program(body);
|
|
3470
|
+
if (mapping) {
|
|
3471
|
+
const text = write(chunk);
|
|
3472
|
+
if (typeof text !== "string") return unwritable(text.problem);
|
|
3473
|
+
const lines = buildLineMap(chunk, (0, import_luau_parser3.parse)(text), origins);
|
|
3474
|
+
const named = host?.place?.(at) ? `${placeOf(at).join("/")}.luau` : path;
|
|
3475
|
+
body.push(...mapRegistration(G, { path: named, modules: [module2] }, lineMapSource(lines, `${G}.lineMap`)));
|
|
3476
|
+
}
|
|
3477
|
+
body.push(...ending);
|
|
3478
|
+
const code = write(chunk);
|
|
3479
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3480
|
+
const from2 = (0, import_node_path2.relative)((0, import_node_path2.dirname)(at), file).replace(/\\/g, "/");
|
|
3481
|
+
files2.push({ path, code: `${code}
|
|
3482
|
+
${WRITTEN_BY_TILUA} from ${from2}: edit that file, not this one.
|
|
3483
|
+
`, modules: [module2.name] });
|
|
3484
|
+
}
|
|
3485
|
+
const runtimeProgram = (0, import_luau_parser3.parse)(runtime(G, {
|
|
3486
|
+
several: true,
|
|
3487
|
+
perFile: true,
|
|
3488
|
+
byPath,
|
|
3489
|
+
files: /* @__PURE__ */ new Map(),
|
|
3490
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3491
|
+
mapping
|
|
3492
|
+
}));
|
|
3493
|
+
const helpers2 = shared.chunk(new Set(lowered.flatMap((m) => m.shared)));
|
|
3494
|
+
const helperNames = helpers2.declare.flatMap((statement) => statement.type === "LocalStatement" ? statement.names.map((n) => n.name) : []);
|
|
3495
|
+
runtimeProgram.body.statements.unshift(...helpers2.declare);
|
|
3496
|
+
runtimeProgram.body.statements.push(...helpers2.define);
|
|
3497
|
+
if (helperNames.length) {
|
|
3498
|
+
runtimeProgram.body.statements.push(assign(
|
|
3499
|
+
[member(identifier(G), "shared")],
|
|
3500
|
+
[table(helperNames.map((name) => field(name, identifier(name))))]
|
|
3501
|
+
));
|
|
3502
|
+
}
|
|
3503
|
+
if (lowered.some((m) => m.usesScriptArgs)) {
|
|
3504
|
+
runtimeProgram.body.statements.push(...(0, import_luau_parser3.parse)(`${G}.scriptArgs = {}
|
|
3505
|
+
${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
3506
|
+
}
|
|
3507
|
+
runtimeProgram.body.statements.push(returns([identifier(G)]));
|
|
3508
|
+
const runtimeCode = write(runtimeProgram);
|
|
3509
|
+
if (typeof runtimeCode !== "string") return unwritable(runtimeCode.problem);
|
|
3510
|
+
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3511
|
+
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3512
|
+
`, modules: [] });
|
|
3513
|
+
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3514
|
+
}
|
|
3290
3515
|
const several = mode !== "single";
|
|
3291
3516
|
const layout = layoutOf(mode, modules.get(entry), lowered, options.outFile);
|
|
3292
3517
|
const usesScriptArgs = lowered.some((m) => m.usesScriptArgs);
|
|
@@ -3294,7 +3519,7 @@ async function bundle(options) {
|
|
|
3294
3519
|
for (const file of layout.slice(1)) {
|
|
3295
3520
|
for (const module2 of file.modules) elsewhere.set(module2.name, loadPath(layout[0].path, file.path, byPath));
|
|
3296
3521
|
}
|
|
3297
|
-
const program2 = (0,
|
|
3522
|
+
const program2 = (0, import_luau_parser3.parse)(runtime(G, {
|
|
3298
3523
|
several,
|
|
3299
3524
|
byPath,
|
|
3300
3525
|
files: elsewhere,
|
|
@@ -3304,8 +3529,8 @@ async function bundle(options) {
|
|
|
3304
3529
|
const assignment = program2.body.statements[1];
|
|
3305
3530
|
if (usesScriptArgs) {
|
|
3306
3531
|
program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
3307
|
-
program2.body.statements.push(...(0,
|
|
3308
|
-
if (several) program2.body.statements.push(...(0,
|
|
3532
|
+
program2.body.statements.push(...(0, import_luau_parser3.parse)(`${G}.arrays[scriptArgs] = true`).body.statements);
|
|
3533
|
+
if (several) program2.body.statements.push(...(0, import_luau_parser3.parse)(`${G}.scriptArgs = scriptArgs`).body.statements);
|
|
3309
3534
|
}
|
|
3310
3535
|
const modulesTable = assignment.type === "AssignmentStatement" && assignment.values[0].type === "TableExpression" ? assignment.values[0].fields.find((f) => f.type === "TableFieldNamed" && f.name.name === "modules")?.value : void 0;
|
|
3311
3536
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -3318,31 +3543,40 @@ async function bundle(options) {
|
|
|
3318
3543
|
const result2 = names.fresh("result");
|
|
3319
3544
|
const entryName = (0, import_parser7.luauString)(sources.get(entry).name);
|
|
3320
3545
|
const returnsExports = modules.get(entry).info.exports;
|
|
3321
|
-
const
|
|
3546
|
+
const returned = returnsExports ? entryReturn(lowerings, sources.get(entry).name, mapping ? result2 : `${G}.require(${entryName})`, () => analysis.exportsOf(entry)) : void 0;
|
|
3547
|
+
if (returned && "problem" in returned) return stop(returned.problem.message);
|
|
3548
|
+
const declarations = returned?.statements.join("\n") ?? "";
|
|
3549
|
+
const entryStatements = (0, import_luau_parser3.parse)(!mapping ? `${declarations}
|
|
3550
|
+
${returned ? `return ${returned.value}` : `${G}.require(${entryName})`}` : `
|
|
3322
3551
|
local ${ok}, ${result2} = xpcall(function()
|
|
3323
3552
|
return ${G}.require(${entryName})
|
|
3324
3553
|
end, ${G}.fail)
|
|
3325
3554
|
if not ${ok} then
|
|
3326
3555
|
error(${result2}, 0)
|
|
3327
3556
|
end
|
|
3328
|
-
${
|
|
3557
|
+
${declarations}
|
|
3558
|
+
${returned ? `return ${returned.value}` : ""}
|
|
3329
3559
|
`).body.statements;
|
|
3330
3560
|
program2.body.statements.push(...entryStatements);
|
|
3331
|
-
|
|
3561
|
+
let printed = write(program2);
|
|
3562
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3563
|
+
const map = mapping ? buildLineMap(program2, (0, import_luau_parser3.parse)(printed), origins) : /* @__PURE__ */ new Map();
|
|
3332
3564
|
if (mapping && (map.size || several)) {
|
|
3333
3565
|
const mapStatements = [assign(
|
|
3334
3566
|
[member(identifier(G), "lines")],
|
|
3335
|
-
[(0,
|
|
3567
|
+
[(0, import_luau_parser3.parseExpressionFromSource)(lineMapSource(map, `${G}.lineMap`))]
|
|
3336
3568
|
)];
|
|
3337
3569
|
if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
|
|
3338
3570
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
|
|
3339
3571
|
}
|
|
3340
3572
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...helpers.define);
|
|
3341
|
-
|
|
3573
|
+
printed = write(program2);
|
|
3574
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3575
|
+
const files = [{ path: layout[0].path, code: printed + "\n", modules: layout[0].modules.map((m) => m.name) }];
|
|
3342
3576
|
for (const file of layout.slice(1)) {
|
|
3343
3577
|
const fileHelpers = shared.chunk(new Set(file.modules.flatMap((m) => m.shared)));
|
|
3344
3578
|
const body = [...fileHelpers.declare];
|
|
3345
|
-
if (file.modules.some((m) => m.usesScriptArgs)) body.push(...(0,
|
|
3579
|
+
if (file.modules.some((m) => m.usesScriptArgs)) body.push(...(0, import_luau_parser3.parse)(`local scriptArgs = ${G}.scriptArgs`).body.statements);
|
|
3346
3580
|
for (const module2 of file.modules) {
|
|
3347
3581
|
body.push(assign(
|
|
3348
3582
|
[index(member(identifier(G), "modules"), string(module2.name))],
|
|
@@ -3351,14 +3585,34 @@ ${returnsExports ? `return ${result2}` : ""}
|
|
|
3351
3585
|
}
|
|
3352
3586
|
const chunk = program([returns([functionExpression(functionBody([G], body))])]);
|
|
3353
3587
|
if (mapping) {
|
|
3354
|
-
const lines = buildLineMap(chunk, (0,
|
|
3588
|
+
const lines = buildLineMap(chunk, (0, import_luau_parser3.parse)((0, import_luau_parser3.print)(chunk, printing)), origins);
|
|
3355
3589
|
body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
|
|
3356
3590
|
}
|
|
3357
3591
|
body.push(...fileHelpers.define);
|
|
3358
|
-
|
|
3592
|
+
const code = write(chunk);
|
|
3593
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3594
|
+
files.push({ path: file.path, code: code + "\n", modules: file.modules.map((m) => m.name) });
|
|
3359
3595
|
}
|
|
3360
3596
|
return { code: files[0].code, files, modules: moduleNames, diagnostics };
|
|
3361
3597
|
}
|
|
3598
|
+
function entryReturn(lowerings, module2, value, exports2) {
|
|
3599
|
+
const syntax = [...syntaxOf(lowerings)];
|
|
3600
|
+
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
3601
|
+
const { plugin: plugin3, from, options } = lowerings[i];
|
|
3602
|
+
if (!plugin3.entryExports) continue;
|
|
3603
|
+
const answer = plugin3.entryExports({ options: options ?? {}, module: module2, value, exports: exports2(), syntax });
|
|
3604
|
+
if (!answer) continue;
|
|
3605
|
+
const statements = [...answer.statements ?? []];
|
|
3606
|
+
try {
|
|
3607
|
+
(0, import_luau_parser3.parse)(`${statements.join("\n")}
|
|
3608
|
+
return ${answer.value}`);
|
|
3609
|
+
} catch (error) {
|
|
3610
|
+
return { problem: { message: `'${from}' answered entryExports with Luau that does not parse: ${error.message}` } };
|
|
3611
|
+
}
|
|
3612
|
+
return { statements, value: answer.value };
|
|
3613
|
+
}
|
|
3614
|
+
return { statements: [], value };
|
|
3615
|
+
}
|
|
3362
3616
|
function moduleTable(module2) {
|
|
3363
3617
|
const { names: exported, links, stars } = module2.info;
|
|
3364
3618
|
const fields = [];
|
|
@@ -3378,10 +3632,6 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3378
3632
|
const entryStem = outFile !== void 0 ? (0, import_node_path2.basename)(outFile, (0, import_node_path2.extname)(outFile)) : import_node_path2.posix.basename(entry.name);
|
|
3379
3633
|
const others = modules.filter((m) => m !== entry);
|
|
3380
3634
|
if (mode === "single") return [{ path: `${entryStem}${extension}`, modules: [entry, ...others] }];
|
|
3381
|
-
if (mode === "modules") {
|
|
3382
|
-
const pathOf = (m) => `${m.name.split("/").map((part) => part === ".." ? "__" : part).join("/")}${extension}`;
|
|
3383
|
-
return [entry, ...others].map((m) => ({ path: pathOf(m), modules: [m] }));
|
|
3384
|
-
}
|
|
3385
3635
|
const byName = new Map(modules.map((m) => [m.name, m]));
|
|
3386
3636
|
const reach = (root) => {
|
|
3387
3637
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3417,16 +3667,75 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3417
3667
|
return files;
|
|
3418
3668
|
}
|
|
3419
3669
|
function loadPath(entryPath, file, byPath) {
|
|
3420
|
-
|
|
3421
|
-
|
|
3670
|
+
return byPath ? requirePath(entryPath, file) : import_node_path2.posix.relative(import_node_path2.posix.dirname(entryPath), file);
|
|
3671
|
+
}
|
|
3672
|
+
function placeInFolder(path) {
|
|
3673
|
+
const parts = path.replace(/\\/g, "/").replace(/\.luau?$/, "").split("/").filter((part) => part !== "");
|
|
3674
|
+
if (parts.at(-1) === "init") parts.pop();
|
|
3675
|
+
return parts;
|
|
3676
|
+
}
|
|
3677
|
+
function pathBetween(from, to, root) {
|
|
3678
|
+
if (root !== void 0 && from[0] !== to[0]) return `${root}/${to.join("/")}`;
|
|
3679
|
+
if (to.length > from.length && from.every((part, i) => to[i] === part)) return `@self/${to.slice(from.length).join("/")}`;
|
|
3680
|
+
const base = from.slice(0, -1);
|
|
3681
|
+
let shared = 0;
|
|
3682
|
+
while (shared < base.length && shared < to.length - 1 && base[shared] === to[shared]) shared++;
|
|
3683
|
+
const up = base.length - shared;
|
|
3684
|
+
return `${up === 0 ? "./" : "../".repeat(up)}${to.slice(shared).join("/")}`;
|
|
3685
|
+
}
|
|
3686
|
+
function importSites(program2) {
|
|
3687
|
+
const sites = [];
|
|
3688
|
+
for (const statement of program2.body.statements) {
|
|
3689
|
+
if (statement.type === "ImportStatement" || statement.type === "ExportAllStatement" || statement.type === "ExportNamedStatement" && statement.source) {
|
|
3690
|
+
const source = statement.source;
|
|
3691
|
+
sites.push({ specifier: source.value, line: source.line.start, column: source.column.start });
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
for (const node of (0, import_parser7.importExpressions)(program2)) {
|
|
3695
|
+
if (node.source.type === "StringLiteral") sites.push({ specifier: node.source.value, line: node.source.line.start, column: node.source.column.start });
|
|
3696
|
+
}
|
|
3697
|
+
return sites;
|
|
3698
|
+
}
|
|
3699
|
+
function pathKey(path) {
|
|
3700
|
+
const full = (0, import_node_path2.resolve)(path);
|
|
3701
|
+
return process.platform === "win32" ? full.toLowerCase() : full;
|
|
3702
|
+
}
|
|
3703
|
+
function requirePath(from, to) {
|
|
3704
|
+
const path = import_node_path2.posix.relative(import_node_path2.posix.dirname(from), to);
|
|
3422
3705
|
const bare = path.slice(0, path.length - import_node_path2.posix.extname(path).length);
|
|
3423
3706
|
return bare.startsWith("../") ? bare : `./${bare}`;
|
|
3424
3707
|
}
|
|
3708
|
+
function tiluaFiles(folder) {
|
|
3709
|
+
const found = [];
|
|
3710
|
+
const walk2 = (at) => {
|
|
3711
|
+
let entries;
|
|
3712
|
+
try {
|
|
3713
|
+
entries = (0, import_node_fs3.readdirSync)(at, { withFileTypes: true });
|
|
3714
|
+
} catch {
|
|
3715
|
+
return;
|
|
3716
|
+
}
|
|
3717
|
+
for (const item of entries) {
|
|
3718
|
+
if (item.name.startsWith(".")) continue;
|
|
3719
|
+
const path = (0, import_node_path2.join)(at, item.name);
|
|
3720
|
+
if (item.isDirectory()) {
|
|
3721
|
+
if (item.name !== "node_modules") walk2(path);
|
|
3722
|
+
} else if (item.name.endsWith(".tilua") && !item.name.endsWith(".d.tilua")) {
|
|
3723
|
+
found.push(path);
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
};
|
|
3727
|
+
walk2(folder);
|
|
3728
|
+
return found.sort();
|
|
3729
|
+
}
|
|
3730
|
+
function isOutside(folder, file) {
|
|
3731
|
+
const path = (0, import_node_path2.relative)(folder, file);
|
|
3732
|
+
return path === "" || path.startsWith("..") || (0, import_node_path2.isAbsolute)(path);
|
|
3733
|
+
}
|
|
3425
3734
|
function mapRegistration(G, file, map) {
|
|
3426
3735
|
const extension = import_node_path2.posix.extname(file.path);
|
|
3427
3736
|
const parts = file.path.slice(0, file.path.length - extension.length).split(/[/.]/).filter((part) => part !== "");
|
|
3428
3737
|
const entry = `${G}.sources[#${G}.sources + 1]`;
|
|
3429
|
-
return (0,
|
|
3738
|
+
return (0, import_luau_parser3.parse)([
|
|
3430
3739
|
`${entry} = { { ${parts.map(import_parser7.luauString).join(", ")} }, ${map}, ${(0, import_parser7.luauString)(extension.slice(1))} }`,
|
|
3431
3740
|
...file.modules.map((module2) => `${G}.maps[${(0, import_parser7.luauString)(module2.name)}] = ${G}.sources[#${G}.sources][2]`)
|
|
3432
3741
|
].join("\n")).body.statements;
|
|
@@ -3453,6 +3762,7 @@ function loader(G, byPath) {
|
|
|
3453
3762
|
}
|
|
3454
3763
|
function runtime(G, options) {
|
|
3455
3764
|
const { several, mapping } = options;
|
|
3765
|
+
const perFile = options.perFile ?? false;
|
|
3456
3766
|
const files = [...options.files].map(([name, file]) => `[${(0, import_parser7.luauString)(name)}] = ${(0, import_parser7.luauString)(file)}`).join(", ");
|
|
3457
3767
|
return `
|
|
3458
3768
|
local ${G}
|
|
@@ -3664,32 +3974,60 @@ ${several ? `
|
|
|
3664
3974
|
return map[key]
|
|
3665
3975
|
end })
|
|
3666
3976
|
end,` : ""}
|
|
3667
|
-
records = {},${several ? `
|
|
3977
|
+
records = {},${several && !perFile ? `
|
|
3668
3978
|
-- The file each module outside this one is in, as \`load\` is handed it.
|
|
3669
3979
|
files = { ${files} },
|
|
3670
|
-
loaded = {}
|
|
3980
|
+
loaded = {},` : ""}${several && mapping ? `
|
|
3671
3981
|
-- Every file's line map: by the module, and by the file's name.
|
|
3672
3982
|
maps = {},
|
|
3673
|
-
sources = {},` : ""}
|
|
3983
|
+
sources = {},` : ""}${several && !perFile ? `
|
|
3674
3984
|
-- Another of the bundle's files: a function that adds its modules here.
|
|
3675
3985
|
load = function(file)
|
|
3676
3986
|
if ${G}.loaded[file] then
|
|
3677
3987
|
return
|
|
3678
3988
|
end
|
|
3679
3989
|
${G}.loaded[file] = true${loader(G, options.byPath)}
|
|
3990
|
+
end,` : ""}${perFile && mapping ? `
|
|
3991
|
+
-- What a file returns: its module's exports. The first file asked for
|
|
3992
|
+
-- runs under \`xpcall\`, so an error nothing caught is reported in the
|
|
3993
|
+
-- project's files; the files it requires in turn are inside that already.
|
|
3994
|
+
running = false,
|
|
3995
|
+
run = function(name)
|
|
3996
|
+
if ${G}.running then
|
|
3997
|
+
return ${G}.require(name)
|
|
3998
|
+
end
|
|
3999
|
+
${G}.running = true
|
|
4000
|
+
local ok, result = xpcall(${G}.require, ${G}.fail, name)
|
|
4001
|
+
${G}.running = false
|
|
4002
|
+
if not ok then
|
|
4003
|
+
error(result, 0)
|
|
4004
|
+
end
|
|
4005
|
+
return result
|
|
3680
4006
|
end,` : ""}${options.imports ? `
|
|
3681
4007
|
-- \`import("./x")\`: the module's exports, asked for where the code runs
|
|
3682
4008
|
-- rather than before its module does. \`require\` does the rest \u2014 and
|
|
3683
4009
|
-- loads the file the module is in, if it is not this one.
|
|
3684
|
-
import = function(name)
|
|
3685
|
-
return ${G}.require(name)
|
|
4010
|
+
import = function(name${perFile ? ", load" : ""})
|
|
4011
|
+
return ${G}.require(name${perFile ? ", load" : ""})
|
|
3686
4012
|
end,` : ""}
|
|
3687
|
-
require = function(name)
|
|
4013
|
+
require = function(name${perFile ? ", load" : ""})
|
|
3688
4014
|
local record = ${G}.records[name]
|
|
3689
4015
|
if record ~= nil then
|
|
3690
4016
|
return record.exports
|
|
3691
4017
|
end
|
|
3692
|
-
local module = ${G}.modules[name]${
|
|
4018
|
+
local module = ${G}.modules[name]${perFile ? `
|
|
4019
|
+
-- Its file has not run: requiring it adds the module, and runs it.
|
|
4020
|
+
if module == nil and load ~= nil then
|
|
4021
|
+
load()
|
|
4022
|
+
record = ${G}.records[name]
|
|
4023
|
+
if record ~= nil then
|
|
4024
|
+
return record.exports
|
|
4025
|
+
end
|
|
4026
|
+
module = ${G}.modules[name]
|
|
4027
|
+
end
|
|
4028
|
+
if module == nil then
|
|
4029
|
+
error(("Cannot find module '%s': nothing has loaded the file it is in"):format(name), 2)
|
|
4030
|
+
end` : several ? `
|
|
3693
4031
|
if module == nil then
|
|
3694
4032
|
${G}.load(${G}.files[name])
|
|
3695
4033
|
module = ${G}.modules[name]
|
|
@@ -3777,6 +4115,35 @@ function importedSpecifiers(program2) {
|
|
|
3777
4115
|
return program2.body.statements.flatMap((s) => s.type === "ImportStatement" || s.type === "ExportAllStatement" || s.type === "ExportNamedStatement" && s.source ? [s.source.value] : []);
|
|
3778
4116
|
}
|
|
3779
4117
|
var libraryCache = /* @__PURE__ */ new Map();
|
|
4118
|
+
var treeCache;
|
|
4119
|
+
function instanceTree(config, libs, noLib) {
|
|
4120
|
+
const tree = (0, import_parser7.sourceMapOf)(config);
|
|
4121
|
+
if (!tree) return void 0;
|
|
4122
|
+
if ("problem" in tree) return tree.named ? { problem: { file: config.path, message: tree.problem } } : void 0;
|
|
4123
|
+
const declares = (name) => libs.some((lib) => lib.body.statements.some((s) => s.type === "DeclareStatement" && s.name === name));
|
|
4124
|
+
if (!tree.named && !declares("game")) return void 0;
|
|
4125
|
+
if (treeCache && treeCache.text === tree.text && treeCache.libs.length === libs.length && treeCache.libs.every((lib, i) => lib === libs[i])) {
|
|
4126
|
+
return { types: treeCache.types };
|
|
4127
|
+
}
|
|
4128
|
+
const empty = (0, import_parser7.parse)("");
|
|
4129
|
+
const aliases = (0, import_parser7.analyzeTypes)(empty, (0, import_parser7.analyzeScopes)(empty, { noLib }), { libs, noLib, diagnostics: false }).aliases;
|
|
4130
|
+
const membersOf = (className) => {
|
|
4131
|
+
const type = aliases.get(className);
|
|
4132
|
+
return new Set(type?.kind === "object" ? type.properties.keys() : ["Name", "ClassName", "Parent", "Archivable"]);
|
|
4133
|
+
};
|
|
4134
|
+
const { types, problem } = (0, import_parser7.sourceMapTypes)(tree.text, tree.path, { classes: new Set(aliases.keys()), membersOf });
|
|
4135
|
+
if (!types) return tree.named && problem ? { problem: { file: tree.path, message: problem } } : void 0;
|
|
4136
|
+
const scripts = /* @__PURE__ */ new Map();
|
|
4137
|
+
const cached = {
|
|
4138
|
+
program: types.program,
|
|
4139
|
+
scriptFor: (file) => {
|
|
4140
|
+
if (!scripts.has(file)) scripts.set(file, types.scriptFor(file));
|
|
4141
|
+
return scripts.get(file);
|
|
4142
|
+
}
|
|
4143
|
+
};
|
|
4144
|
+
treeCache = { text: tree.text, libs: [...libs], types: cached, scripts };
|
|
4145
|
+
return { types: cached };
|
|
4146
|
+
}
|
|
3780
4147
|
function parsedLibrary(file) {
|
|
3781
4148
|
let stamp;
|
|
3782
4149
|
try {
|
|
@@ -3795,11 +4162,15 @@ var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
|
3795
4162
|
function analyzeModules(modules, config) {
|
|
3796
4163
|
const out = [];
|
|
3797
4164
|
const analyses = /* @__PURE__ */ new Map();
|
|
3798
|
-
const libraries = config ? (0, import_parser7.resolveTypeLibraries)(config) : { files: [], lowerings: [], problems: [] };
|
|
4165
|
+
const libraries = config ? (0, import_parser7.resolveTypeLibraries)(config) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3799
4166
|
for (const p of libraries.problems) out.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3800
4167
|
const libs = libraries.files.map(parsedLibrary);
|
|
3801
4168
|
const noLib = config?.noLib ?? false;
|
|
3802
4169
|
const checked = libs.length > 0 || !noLib;
|
|
4170
|
+
const tree = config ? instanceTree(config, libs, noLib) : void 0;
|
|
4171
|
+
if (tree?.problem) out.push({ file: tree.problem.file, message: tree.problem.message, line: 1, column: 1, category: "config" });
|
|
4172
|
+
if (tree?.types) libs.push(tree.types.program);
|
|
4173
|
+
const scriptOf = (file) => tree?.types && config ? tree.types.scriptFor((0, import_parser7.outputPathOf)(config, file)) : void 0;
|
|
3803
4174
|
const globals = libs.flatMap((lib) => lib.body.statements.flatMap((s) => s.type === "DeclareStatement" ? [s.name] : []));
|
|
3804
4175
|
const byFile = new Map(modules.map((m) => [m.file, m]));
|
|
3805
4176
|
const exportsCache = /* @__PURE__ */ new Map();
|
|
@@ -3812,7 +4183,9 @@ function analyzeModules(modules, config) {
|
|
|
3812
4183
|
const done = analyzed.get(file);
|
|
3813
4184
|
if (done) return done;
|
|
3814
4185
|
const remembered = moduleAnalyses.get(file);
|
|
3815
|
-
|
|
4186
|
+
const script = scriptOf(file);
|
|
4187
|
+
const ownLibs = script ? [...libs, script] : libs;
|
|
4188
|
+
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)) {
|
|
3816
4189
|
analyzed.set(file, remembered.result);
|
|
3817
4190
|
readWhile.set(file, remembered.read);
|
|
3818
4191
|
return remembered.result;
|
|
@@ -3825,7 +4198,7 @@ function analyzeModules(modules, config) {
|
|
|
3825
4198
|
}
|
|
3826
4199
|
const before = partials;
|
|
3827
4200
|
const types = (0, import_parser7.analyzeTypes)(program2, scopes, {
|
|
3828
|
-
libs,
|
|
4201
|
+
libs: ownLibs,
|
|
3829
4202
|
resolveModule: resolverFor(file),
|
|
3830
4203
|
noLib,
|
|
3831
4204
|
reportUnknownTypes: checked
|
|
@@ -3834,7 +4207,7 @@ function analyzeModules(modules, config) {
|
|
|
3834
4207
|
const at = d.node;
|
|
3835
4208
|
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type", severity: d.severity });
|
|
3836
4209
|
}
|
|
3837
|
-
const result2 = { types, diagnostics: said };
|
|
4210
|
+
const result2 = { types, diagnostics: said, scopes };
|
|
3838
4211
|
if (partials === before) {
|
|
3839
4212
|
analyzed.set(file, result2);
|
|
3840
4213
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
@@ -3842,7 +4215,7 @@ function analyzeModules(modules, config) {
|
|
|
3842
4215
|
if (own !== void 0) read3.set(file, own);
|
|
3843
4216
|
readWhile.set(file, read3);
|
|
3844
4217
|
if ([...read3.values()].every((stamp) => stamp !== void 0)) {
|
|
3845
|
-
moduleAnalyses.set(file, { setting: settingFor, libs: [...
|
|
4218
|
+
moduleAnalyses.set(file, { setting: settingFor, libs: [...ownLibs], program: program2, read: read3, result: result2 });
|
|
3846
4219
|
}
|
|
3847
4220
|
}
|
|
3848
4221
|
return result2;
|
|
@@ -3891,7 +4264,16 @@ function analyzeModules(modules, config) {
|
|
|
3891
4264
|
analyses.set(module2.file, types);
|
|
3892
4265
|
out.push(...diagnostics);
|
|
3893
4266
|
}
|
|
3894
|
-
|
|
4267
|
+
const exportsOf = (file) => {
|
|
4268
|
+
const cached = exportsCache.get(file);
|
|
4269
|
+
if (cached) return cached;
|
|
4270
|
+
const module2 = byFile.get(file);
|
|
4271
|
+
const { types, scopes } = analyzeModule(file, module2.program);
|
|
4272
|
+
const exports2 = (0, import_parser7.moduleExports)(module2.program, scopes, types, resolverFor(file));
|
|
4273
|
+
exportsCache.set(file, exports2);
|
|
4274
|
+
return exports2;
|
|
4275
|
+
};
|
|
4276
|
+
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings], exportsOf };
|
|
3895
4277
|
}
|
|
3896
4278
|
function allStatements(statements) {
|
|
3897
4279
|
const out = [];
|
|
@@ -3914,7 +4296,6 @@ function allStatements(statements) {
|
|
|
3914
4296
|
var import_node_fs4 = require("fs");
|
|
3915
4297
|
var import_node_path3 = require("path");
|
|
3916
4298
|
var import_parser8 = require("@tilua/parser");
|
|
3917
|
-
var import_luau_parser3 = require("luau-parser");
|
|
3918
4299
|
async function compile(source, config) {
|
|
3919
4300
|
let program2;
|
|
3920
4301
|
try {
|
|
@@ -3934,7 +4315,7 @@ async function compile(source, config) {
|
|
|
3934
4315
|
line: d.node.line.start,
|
|
3935
4316
|
column: d.node.column.start
|
|
3936
4317
|
}));
|
|
3937
|
-
const libraries = resolved ? (0, import_parser8.resolveTypeLibraries)(resolved) : { files: [], lowerings: [], problems: [] };
|
|
4318
|
+
const libraries = resolved ? (0, import_parser8.resolveTypeLibraries)(resolved) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3938
4319
|
const { lowerings, problems: loweringProblems } = await loadLowerings(libraries.lowerings);
|
|
3939
4320
|
for (const p of [...problems, ...libraries.problems]) {
|
|
3940
4321
|
diagnostics.push({ message: p.message, line: p.line ?? 1, column: p.column ?? 1 });
|
|
@@ -3949,10 +4330,16 @@ async function compile(source, config) {
|
|
|
3949
4330
|
});
|
|
3950
4331
|
diagnostics.push(...lowered.diagnostics);
|
|
3951
4332
|
if (diagnostics.length) return { diagnostics };
|
|
3952
|
-
|
|
4333
|
+
const printed = printOutput(program(lowered.statements), printOptions(syntaxOf(lowerings), {
|
|
4334
|
+
indent: resolved?.indent,
|
|
4335
|
+
minify: resolved?.minify
|
|
4336
|
+
}));
|
|
4337
|
+
if ("problem" in printed) return { diagnostics: [{ message: printed.problem, line: 1, column: 1 }] };
|
|
4338
|
+
return { code: printed.code + "\n", diagnostics };
|
|
3953
4339
|
}
|
|
3954
4340
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3955
4341
|
0 && (module.exports = {
|
|
4342
|
+
WRITTEN_BY_TILUA,
|
|
3956
4343
|
bundle,
|
|
3957
4344
|
compile,
|
|
3958
4345
|
loadLowerings,
|