@tilua/compiler 8.0.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -13
- package/dist/{chunk-TOP7NC3Z.js → chunk-VUIF62OE.js} +483 -67
- package/dist/cli.cjs +651 -105
- package/dist/cli.js +159 -24
- package/dist/index.cjs +491 -73
- package/dist/index.d.cts +59 -9
- package/dist/index.d.ts +59 -9
- package/dist/index.js +14 -5
- package/package.json +3 -3
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,12 +3107,75 @@ 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+/";
|
|
3125
|
+
function vlq(n) {
|
|
3126
|
+
let value = n < 0 ? -n * 2 + 1 : n * 2;
|
|
3127
|
+
let out = "";
|
|
3128
|
+
do {
|
|
3129
|
+
const digit = value % 32;
|
|
3130
|
+
value = Math.floor(value / 32);
|
|
3131
|
+
out += VLQ_DIGITS[value > 0 ? digit + 32 : digit];
|
|
3132
|
+
} while (value > 0);
|
|
3133
|
+
return out;
|
|
3134
|
+
}
|
|
3135
|
+
function lineMapSource(map, unpack) {
|
|
3097
3136
|
const entries = [...map.entries()].sort((a, b) => a[0] - b[0]);
|
|
3098
|
-
const
|
|
3099
|
-
|
|
3137
|
+
const files = [];
|
|
3138
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
3139
|
+
let data = "";
|
|
3140
|
+
let line = 0, file = 0, source = 0;
|
|
3141
|
+
for (const [at, origin] of entries) {
|
|
3142
|
+
const name = origin.file.replace(/\\/g, "/");
|
|
3143
|
+
if (!indexes.has(name)) indexes.set(name, files.push(name));
|
|
3144
|
+
const index2 = indexes.get(name);
|
|
3145
|
+
data += vlq(at - line) + vlq(index2 - file) + vlq(origin.line - source);
|
|
3146
|
+
line = at;
|
|
3147
|
+
file = index2;
|
|
3148
|
+
source = origin.line;
|
|
3149
|
+
}
|
|
3150
|
+
return `${unpack}({${files.map(import_parser6.luauString).join(",")}},${(0, import_parser6.luauString)(data)})`;
|
|
3151
|
+
}
|
|
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
|
+
}
|
|
3100
3179
|
}
|
|
3101
3180
|
|
|
3102
3181
|
// src/lowering.ts
|
|
@@ -3115,7 +3194,7 @@ async function loadLowerings(modules) {
|
|
|
3115
3194
|
});
|
|
3116
3195
|
continue;
|
|
3117
3196
|
}
|
|
3118
|
-
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library });
|
|
3197
|
+
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library, options: module2.options });
|
|
3119
3198
|
} catch (error) {
|
|
3120
3199
|
problems.push({
|
|
3121
3200
|
file: module2.file,
|
|
@@ -3127,17 +3206,30 @@ async function loadLowerings(modules) {
|
|
|
3127
3206
|
}
|
|
3128
3207
|
|
|
3129
3208
|
// src/bundle.ts
|
|
3209
|
+
var WRITTEN_BY_TILUA = "-- Written by tilua";
|
|
3130
3210
|
async function bundle(options) {
|
|
3131
|
-
const entry = (0, import_node_path2.resolve)(options.entry);
|
|
3132
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");
|
|
3133
3213
|
const inline = options.config !== void 0 && typeof options.config !== "string";
|
|
3134
|
-
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()));
|
|
3135
3215
|
for (const p of problems) diagnostics.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3136
|
-
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));
|
|
3137
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');
|
|
3138
3229
|
const sources = /* @__PURE__ */ new Map();
|
|
3139
3230
|
const directives = /* @__PURE__ */ new Map();
|
|
3140
|
-
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) || "."}`);
|
|
3141
3233
|
while (queue.length) {
|
|
3142
3234
|
const file = queue.shift();
|
|
3143
3235
|
if (sources.has(file)) continue;
|
|
@@ -3155,6 +3247,22 @@ async function bundle(options) {
|
|
|
3155
3247
|
if (target && !target.endsWith(".d.tilua")) queue.push(target);
|
|
3156
3248
|
}
|
|
3157
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
|
+
}
|
|
3158
3266
|
const analysis = analyzeModules([...sources.values()], config);
|
|
3159
3267
|
const { lowerings, problems: loweringProblems } = await loadLowerings(analysis.lowerings);
|
|
3160
3268
|
for (const p of loweringProblems) {
|
|
@@ -3165,18 +3273,56 @@ async function bundle(options) {
|
|
|
3165
3273
|
const G = names.fresh("G");
|
|
3166
3274
|
const requireExpression = member(identifier(G), "require");
|
|
3167
3275
|
const importExpression = member(identifier(G), "import");
|
|
3168
|
-
const mode = options.output ?? config?.output ?? "single";
|
|
3169
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;
|
|
3170
3313
|
const modules = /* @__PURE__ */ new Map();
|
|
3171
3314
|
const origins = /* @__PURE__ */ new WeakMap();
|
|
3172
3315
|
const shared = new SharedRuntime(names);
|
|
3173
3316
|
const shaking = options.treeShaking ?? config?.treeShaking ?? false;
|
|
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);
|
|
3174
3320
|
const resolveIn = (file) => (specifier) => {
|
|
3175
3321
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config);
|
|
3176
3322
|
return found !== void 0 && sources.has(found) ? found : void 0;
|
|
3177
3323
|
};
|
|
3178
|
-
const shaken = shaking ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry) : void 0;
|
|
3179
|
-
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];
|
|
3180
3326
|
while (pending.length) {
|
|
3181
3327
|
const file = pending.shift();
|
|
3182
3328
|
if (modules.has(file)) continue;
|
|
@@ -3209,9 +3355,16 @@ async function bundle(options) {
|
|
|
3209
3355
|
import: importExpression,
|
|
3210
3356
|
// One file has one line map. Several have one each, and a
|
|
3211
3357
|
// module reads the one of the file it is in.
|
|
3212
|
-
lines: mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
|
|
3213
|
-
fail: `${G}.fail
|
|
3358
|
+
lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
|
|
3359
|
+
fail: mapping ? `${G}.fail` : void 0,
|
|
3214
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
|
+
},
|
|
3215
3368
|
resolve: (specifier, dynamic) => {
|
|
3216
3369
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config);
|
|
3217
3370
|
if (!found || found.endsWith(".d.tilua") || !sources.has(found)) return void 0;
|
|
@@ -3263,6 +3416,102 @@ async function bundle(options) {
|
|
|
3263
3416
|
return { files: [], modules: moduleNames, diagnostics };
|
|
3264
3417
|
}
|
|
3265
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
|
+
}
|
|
3266
3515
|
const several = mode !== "single";
|
|
3267
3516
|
const layout = layoutOf(mode, modules.get(entry), lowered, options.outFile);
|
|
3268
3517
|
const usesScriptArgs = lowered.some((m) => m.usesScriptArgs);
|
|
@@ -3270,17 +3519,18 @@ async function bundle(options) {
|
|
|
3270
3519
|
for (const file of layout.slice(1)) {
|
|
3271
3520
|
for (const module2 of file.modules) elsewhere.set(module2.name, loadPath(layout[0].path, file.path, byPath));
|
|
3272
3521
|
}
|
|
3273
|
-
const program2 = (0,
|
|
3522
|
+
const program2 = (0, import_luau_parser3.parse)(runtime(G, {
|
|
3274
3523
|
several,
|
|
3275
3524
|
byPath,
|
|
3276
3525
|
files: elsewhere,
|
|
3277
|
-
imports: lowered.some((m) => m.dynamicImports.size > 0)
|
|
3526
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3527
|
+
mapping
|
|
3278
3528
|
}));
|
|
3279
3529
|
const assignment = program2.body.statements[1];
|
|
3280
3530
|
if (usesScriptArgs) {
|
|
3281
3531
|
program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
3282
|
-
program2.body.statements.push(...(0,
|
|
3283
|
-
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);
|
|
3284
3534
|
}
|
|
3285
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;
|
|
3286
3536
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -3291,31 +3541,42 @@ async function bundle(options) {
|
|
|
3291
3541
|
program2.body.statements.unshift(...helpers.declare);
|
|
3292
3542
|
const ok = names.fresh("ok");
|
|
3293
3543
|
const result2 = names.fresh("result");
|
|
3294
|
-
const
|
|
3544
|
+
const entryName = (0, import_parser7.luauString)(sources.get(entry).name);
|
|
3545
|
+
const returnsExports = modules.get(entry).info.exports;
|
|
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})`}` : `
|
|
3295
3551
|
local ${ok}, ${result2} = xpcall(function()
|
|
3296
|
-
return ${G}.require(${
|
|
3552
|
+
return ${G}.require(${entryName})
|
|
3297
3553
|
end, ${G}.fail)
|
|
3298
3554
|
if not ${ok} then
|
|
3299
3555
|
error(${result2}, 0)
|
|
3300
3556
|
end
|
|
3301
|
-
${
|
|
3557
|
+
${declarations}
|
|
3558
|
+
${returned ? `return ${returned.value}` : ""}
|
|
3302
3559
|
`).body.statements;
|
|
3303
3560
|
program2.body.statements.push(...entryStatements);
|
|
3304
|
-
|
|
3305
|
-
if (
|
|
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();
|
|
3564
|
+
if (mapping && (map.size || several)) {
|
|
3306
3565
|
const mapStatements = [assign(
|
|
3307
3566
|
[member(identifier(G), "lines")],
|
|
3308
|
-
[(0,
|
|
3567
|
+
[(0, import_luau_parser3.parseExpressionFromSource)(lineMapSource(map, `${G}.lineMap`))]
|
|
3309
3568
|
)];
|
|
3310
3569
|
if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
|
|
3311
3570
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
|
|
3312
3571
|
}
|
|
3313
3572
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...helpers.define);
|
|
3314
|
-
|
|
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) }];
|
|
3315
3576
|
for (const file of layout.slice(1)) {
|
|
3316
3577
|
const fileHelpers = shared.chunk(new Set(file.modules.flatMap((m) => m.shared)));
|
|
3317
3578
|
const body = [...fileHelpers.declare];
|
|
3318
|
-
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);
|
|
3319
3580
|
for (const module2 of file.modules) {
|
|
3320
3581
|
body.push(assign(
|
|
3321
3582
|
[index(member(identifier(G), "modules"), string(module2.name))],
|
|
@@ -3323,12 +3584,35 @@ ${modules.get(entry).info.exports ? `return ${result2}` : ""}
|
|
|
3323
3584
|
));
|
|
3324
3585
|
}
|
|
3325
3586
|
const chunk = program([returns([functionExpression(functionBody([G], body))])]);
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3587
|
+
if (mapping) {
|
|
3588
|
+
const lines = buildLineMap(chunk, (0, import_luau_parser3.parse)((0, import_luau_parser3.print)(chunk, printing)), origins);
|
|
3589
|
+
body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
|
|
3590
|
+
}
|
|
3591
|
+
body.push(...fileHelpers.define);
|
|
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) });
|
|
3329
3595
|
}
|
|
3330
3596
|
return { code: files[0].code, files, modules: moduleNames, diagnostics };
|
|
3331
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
|
+
}
|
|
3332
3616
|
function moduleTable(module2) {
|
|
3333
3617
|
const { names: exported, links, stars } = module2.info;
|
|
3334
3618
|
const fields = [];
|
|
@@ -3348,10 +3632,6 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3348
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);
|
|
3349
3633
|
const others = modules.filter((m) => m !== entry);
|
|
3350
3634
|
if (mode === "single") return [{ path: `${entryStem}${extension}`, modules: [entry, ...others] }];
|
|
3351
|
-
if (mode === "modules") {
|
|
3352
|
-
const pathOf = (m) => `${m.name.split("/").map((part) => part === ".." ? "__" : part).join("/")}${extension}`;
|
|
3353
|
-
return [entry, ...others].map((m) => ({ path: pathOf(m), modules: [m] }));
|
|
3354
|
-
}
|
|
3355
3635
|
const byName = new Map(modules.map((m) => [m.name, m]));
|
|
3356
3636
|
const reach = (root) => {
|
|
3357
3637
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3387,16 +3667,75 @@ function layoutOf(mode, entry, modules, outFile) {
|
|
|
3387
3667
|
return files;
|
|
3388
3668
|
}
|
|
3389
3669
|
function loadPath(entryPath, file, byPath) {
|
|
3390
|
-
|
|
3391
|
-
|
|
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);
|
|
3392
3705
|
const bare = path.slice(0, path.length - import_node_path2.posix.extname(path).length);
|
|
3393
3706
|
return bare.startsWith("../") ? bare : `./${bare}`;
|
|
3394
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
|
+
}
|
|
3395
3734
|
function mapRegistration(G, file, map) {
|
|
3396
3735
|
const extension = import_node_path2.posix.extname(file.path);
|
|
3397
3736
|
const parts = file.path.slice(0, file.path.length - extension.length).split(/[/.]/).filter((part) => part !== "");
|
|
3398
3737
|
const entry = `${G}.sources[#${G}.sources + 1]`;
|
|
3399
|
-
return (0,
|
|
3738
|
+
return (0, import_luau_parser3.parse)([
|
|
3400
3739
|
`${entry} = { { ${parts.map(import_parser7.luauString).join(", ")} }, ${map}, ${(0, import_parser7.luauString)(extension.slice(1))} }`,
|
|
3401
3740
|
...file.modules.map((module2) => `${G}.maps[${(0, import_parser7.luauString)(module2.name)}] = ${G}.sources[#${G}.sources][2]`)
|
|
3402
3741
|
].join("\n")).body.statements;
|
|
@@ -3422,7 +3761,8 @@ function loader(G, byPath) {
|
|
|
3422
3761
|
require(file)(${G})`;
|
|
3423
3762
|
}
|
|
3424
3763
|
function runtime(G, options) {
|
|
3425
|
-
const { several } = options;
|
|
3764
|
+
const { several, mapping } = options;
|
|
3765
|
+
const perFile = options.perFile ?? false;
|
|
3426
3766
|
const files = [...options.files].map(([name, file]) => `[${(0, import_parser7.luauString)(name)}] = ${(0, import_parser7.luauString)(file)}`).join(", ");
|
|
3427
3767
|
return `
|
|
3428
3768
|
local ${G}
|
|
@@ -3430,7 +3770,7 @@ ${G} = {
|
|
|
3430
3770
|
modules = {},
|
|
3431
3771
|
-- Every array the program made, so \`typeof\` can tell one from an object.
|
|
3432
3772
|
-- The keys are held weakly: being written down keeps no array alive.
|
|
3433
|
-
arrays = setmetatable({}, { __mode = "k" })
|
|
3773
|
+
arrays = setmetatable({}, { __mode = "k" }),${mapping ? `
|
|
3434
3774
|
-- Filled in just before the entry runs: bundle line -> { file, line }.
|
|
3435
3775
|
lines = nil,
|
|
3436
3776
|
-- What an error nothing caught says, in the project's files: the bundle's
|
|
@@ -3598,32 +3938,96 @@ ${several ? `
|
|
|
3598
3938
|
end
|
|
3599
3939
|
return mapped .. "\\n" .. table.concat(frames, "\\n")
|
|
3600
3940
|
end,
|
|
3601
|
-
|
|
3941
|
+
-- A line map as it is written: the files it names, and base-64 VLQ
|
|
3942
|
+
-- numbers, three to a line \u2014 how far down the bundle, which file, how far
|
|
3943
|
+
-- down that file, each counted from the line before. It is read out the
|
|
3944
|
+
-- first time a line is looked up, which is when something went wrong.
|
|
3945
|
+
lineMap = function(files, data)
|
|
3946
|
+
local map = {}
|
|
3947
|
+
return setmetatable(map, { __index = function(_, key)
|
|
3948
|
+
setmetatable(map, nil)
|
|
3949
|
+
local digits = {}
|
|
3950
|
+
for i = 1, 64 do
|
|
3951
|
+
digits[("${VLQ_DIGITS}"):byte(i)] = i - 1
|
|
3952
|
+
end
|
|
3953
|
+
local at = 1
|
|
3954
|
+
local function read()
|
|
3955
|
+
local value, scale = 0, 1
|
|
3956
|
+
repeat
|
|
3957
|
+
local digit = digits[data:byte(at)]
|
|
3958
|
+
at = at + 1
|
|
3959
|
+
value = value + digit % 32 * scale
|
|
3960
|
+
scale = scale * 32
|
|
3961
|
+
until digit < 32
|
|
3962
|
+
if value % 2 == 1 then
|
|
3963
|
+
return -math.floor(value / 2)
|
|
3964
|
+
end
|
|
3965
|
+
return math.floor(value / 2)
|
|
3966
|
+
end
|
|
3967
|
+
local line, file, source = 0, 0, 0
|
|
3968
|
+
while at <= #data do
|
|
3969
|
+
line = line + read()
|
|
3970
|
+
file = file + read()
|
|
3971
|
+
source = source + read()
|
|
3972
|
+
map[line] = { files[file], source }
|
|
3973
|
+
end
|
|
3974
|
+
return map[key]
|
|
3975
|
+
end })
|
|
3976
|
+
end,` : ""}
|
|
3977
|
+
records = {},${several && !perFile ? `
|
|
3602
3978
|
-- The file each module outside this one is in, as \`load\` is handed it.
|
|
3603
3979
|
files = { ${files} },
|
|
3604
|
-
loaded = {}
|
|
3980
|
+
loaded = {},` : ""}${several && mapping ? `
|
|
3605
3981
|
-- Every file's line map: by the module, and by the file's name.
|
|
3606
3982
|
maps = {},
|
|
3607
|
-
sources = {}
|
|
3983
|
+
sources = {},` : ""}${several && !perFile ? `
|
|
3608
3984
|
-- Another of the bundle's files: a function that adds its modules here.
|
|
3609
3985
|
load = function(file)
|
|
3610
3986
|
if ${G}.loaded[file] then
|
|
3611
3987
|
return
|
|
3612
3988
|
end
|
|
3613
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
|
|
3614
4006
|
end,` : ""}${options.imports ? `
|
|
3615
4007
|
-- \`import("./x")\`: the module's exports, asked for where the code runs
|
|
3616
4008
|
-- rather than before its module does. \`require\` does the rest \u2014 and
|
|
3617
4009
|
-- loads the file the module is in, if it is not this one.
|
|
3618
|
-
import = function(name)
|
|
3619
|
-
return ${G}.require(name)
|
|
4010
|
+
import = function(name${perFile ? ", load" : ""})
|
|
4011
|
+
return ${G}.require(name${perFile ? ", load" : ""})
|
|
3620
4012
|
end,` : ""}
|
|
3621
|
-
require = function(name)
|
|
4013
|
+
require = function(name${perFile ? ", load" : ""})
|
|
3622
4014
|
local record = ${G}.records[name]
|
|
3623
4015
|
if record ~= nil then
|
|
3624
4016
|
return record.exports
|
|
3625
4017
|
end
|
|
3626
|
-
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 ? `
|
|
3627
4031
|
if module == nil then
|
|
3628
4032
|
${G}.load(${G}.files[name])
|
|
3629
4033
|
module = ${G}.modules[name]
|
|
@@ -3729,7 +4133,7 @@ var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
|
3729
4133
|
function analyzeModules(modules, config) {
|
|
3730
4134
|
const out = [];
|
|
3731
4135
|
const analyses = /* @__PURE__ */ new Map();
|
|
3732
|
-
const libraries = config ? (0, import_parser7.resolveTypeLibraries)(config) : { files: [], lowerings: [], problems: [] };
|
|
4136
|
+
const libraries = config ? (0, import_parser7.resolveTypeLibraries)(config) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3733
4137
|
for (const p of libraries.problems) out.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3734
4138
|
const libs = libraries.files.map(parsedLibrary);
|
|
3735
4139
|
const noLib = config?.noLib ?? false;
|
|
@@ -3768,7 +4172,7 @@ function analyzeModules(modules, config) {
|
|
|
3768
4172
|
const at = d.node;
|
|
3769
4173
|
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type", severity: d.severity });
|
|
3770
4174
|
}
|
|
3771
|
-
const result2 = { types, diagnostics: said };
|
|
4175
|
+
const result2 = { types, diagnostics: said, scopes };
|
|
3772
4176
|
if (partials === before) {
|
|
3773
4177
|
analyzed.set(file, result2);
|
|
3774
4178
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
@@ -3825,7 +4229,16 @@ function analyzeModules(modules, config) {
|
|
|
3825
4229
|
analyses.set(module2.file, types);
|
|
3826
4230
|
out.push(...diagnostics);
|
|
3827
4231
|
}
|
|
3828
|
-
|
|
4232
|
+
const exportsOf = (file) => {
|
|
4233
|
+
const cached = exportsCache.get(file);
|
|
4234
|
+
if (cached) return cached;
|
|
4235
|
+
const module2 = byFile.get(file);
|
|
4236
|
+
const { types, scopes } = analyzeModule(file, module2.program);
|
|
4237
|
+
const exports2 = (0, import_parser7.moduleExports)(module2.program, scopes, types, resolverFor(file));
|
|
4238
|
+
exportsCache.set(file, exports2);
|
|
4239
|
+
return exports2;
|
|
4240
|
+
};
|
|
4241
|
+
return { types: analyses, diagnostics: out, lowerings: [...libraries.lowerings], exportsOf };
|
|
3829
4242
|
}
|
|
3830
4243
|
function allStatements(statements) {
|
|
3831
4244
|
const out = [];
|
|
@@ -3848,7 +4261,6 @@ function allStatements(statements) {
|
|
|
3848
4261
|
var import_node_fs4 = require("fs");
|
|
3849
4262
|
var import_node_path3 = require("path");
|
|
3850
4263
|
var import_parser8 = require("@tilua/parser");
|
|
3851
|
-
var import_luau_parser3 = require("luau-parser");
|
|
3852
4264
|
async function compile(source, config) {
|
|
3853
4265
|
let program2;
|
|
3854
4266
|
try {
|
|
@@ -3868,7 +4280,7 @@ async function compile(source, config) {
|
|
|
3868
4280
|
line: d.node.line.start,
|
|
3869
4281
|
column: d.node.column.start
|
|
3870
4282
|
}));
|
|
3871
|
-
const libraries = resolved ? (0, import_parser8.resolveTypeLibraries)(resolved) : { files: [], lowerings: [], problems: [] };
|
|
4283
|
+
const libraries = resolved ? (0, import_parser8.resolveTypeLibraries)(resolved) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3872
4284
|
const { lowerings, problems: loweringProblems } = await loadLowerings(libraries.lowerings);
|
|
3873
4285
|
for (const p of [...problems, ...libraries.problems]) {
|
|
3874
4286
|
diagnostics.push({ message: p.message, line: p.line ?? 1, column: p.column ?? 1 });
|
|
@@ -3883,10 +4295,16 @@ async function compile(source, config) {
|
|
|
3883
4295
|
});
|
|
3884
4296
|
diagnostics.push(...lowered.diagnostics);
|
|
3885
4297
|
if (diagnostics.length) return { diagnostics };
|
|
3886
|
-
|
|
4298
|
+
const printed = printOutput(program(lowered.statements), printOptions(syntaxOf(lowerings), {
|
|
4299
|
+
indent: resolved?.indent,
|
|
4300
|
+
minify: resolved?.minify
|
|
4301
|
+
}));
|
|
4302
|
+
if ("problem" in printed) return { diagnostics: [{ message: printed.problem, line: 1, column: 1 }] };
|
|
4303
|
+
return { code: printed.code + "\n", diagnostics };
|
|
3887
4304
|
}
|
|
3888
4305
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3889
4306
|
0 && (module.exports = {
|
|
4307
|
+
WRITTEN_BY_TILUA,
|
|
3890
4308
|
bundle,
|
|
3891
4309
|
compile,
|
|
3892
4310
|
loadLowerings,
|