@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/cli.cjs
CHANGED
|
@@ -13,7 +13,7 @@ var import_node_path3 = require("path");
|
|
|
13
13
|
var import_node_fs3 = require("fs");
|
|
14
14
|
var import_node_path2 = require("path");
|
|
15
15
|
var import_parser7 = require("@tilua/parser");
|
|
16
|
-
var
|
|
16
|
+
var import_luau_parser3 = require("luau-parser");
|
|
17
17
|
|
|
18
18
|
// src/config.ts
|
|
19
19
|
var import_node_path = require("path");
|
|
@@ -50,10 +50,10 @@ var parenthesized = (expression) => ({ type: "ParenthesizedExpression", expressi
|
|
|
50
50
|
var table = (fields) => ({ type: "TableExpression", fields, ...span() });
|
|
51
51
|
var field = (key, value) => (0, import_parser2.isLuauName)(key) ? { type: "TableFieldNamed", name: identifier(key), value } : { type: "TableFieldComputed", key: string(key), value };
|
|
52
52
|
var block = (statements) => ({ type: "Block", statements, ...span() });
|
|
53
|
-
var local = (names,
|
|
53
|
+
var local = (names, init2) => ({
|
|
54
54
|
type: "LocalStatement",
|
|
55
55
|
names: names.map((name) => ({ type: "TypedIdentifier", name, ...span() })),
|
|
56
|
-
init,
|
|
56
|
+
init: init2,
|
|
57
57
|
...span()
|
|
58
58
|
});
|
|
59
59
|
var assign = (targets, values) => ({ type: "AssignmentStatement", targets, values, ...span() });
|
|
@@ -401,6 +401,10 @@ var SharedRuntime = class {
|
|
|
401
401
|
return { declare, define };
|
|
402
402
|
}
|
|
403
403
|
};
|
|
404
|
+
function moduleArguments(context, name) {
|
|
405
|
+
const loader2 = context.loader?.(name);
|
|
406
|
+
return loader2 ? [string(name), loader2] : [string(name)];
|
|
407
|
+
}
|
|
404
408
|
function lower(program2, scopes, options = {}) {
|
|
405
409
|
const result2 = new Lowerer(program2, scopes, options).run();
|
|
406
410
|
dropUnreachable(result2.statements);
|
|
@@ -442,9 +446,9 @@ var Lowerer = class {
|
|
|
442
446
|
if (Array.isArray(value)) return void value.forEach(visit);
|
|
443
447
|
const node = value;
|
|
444
448
|
if (node.type === "VariableDeclaration" && node.name?.type === "IdentifierPattern" && node.name.name) {
|
|
445
|
-
let
|
|
446
|
-
while (
|
|
447
|
-
if (
|
|
449
|
+
let init2 = node.init;
|
|
450
|
+
while (init2?.type === "ParenthesizedExpression") init2 = init2.expression;
|
|
451
|
+
if (init2?.type === "ClassExpression") this.classExpressionNames.set(init2, node.name.name);
|
|
448
452
|
}
|
|
449
453
|
for (const [key, child] of Object.entries(value)) if (key !== "line" && key !== "column") visit(child);
|
|
450
454
|
};
|
|
@@ -717,6 +721,7 @@ var Lowerer = class {
|
|
|
717
721
|
const plugin3 = lowerings[i].plugin;
|
|
718
722
|
if (!plugin3.methodCall) continue;
|
|
719
723
|
const answer = plugin3.methodCall({
|
|
724
|
+
options: lowerings[i].options ?? {},
|
|
720
725
|
method,
|
|
721
726
|
receiver,
|
|
722
727
|
receiverGlobal,
|
|
@@ -748,6 +753,7 @@ var Lowerer = class {
|
|
|
748
753
|
const plugin3 = lowerings[i].plugin;
|
|
749
754
|
if (!plugin3.globalCall) continue;
|
|
750
755
|
const answer = plugin3.globalCall({
|
|
756
|
+
options: lowerings[i].options ?? {},
|
|
751
757
|
name,
|
|
752
758
|
at: this.callSite(node.callee),
|
|
753
759
|
get arguments() {
|
|
@@ -767,6 +773,7 @@ var Lowerer = class {
|
|
|
767
773
|
if (name === void 0) return void 0;
|
|
768
774
|
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
769
775
|
const answer = lowerings[i].plugin.globalValue?.({
|
|
776
|
+
options: lowerings[i].options ?? {},
|
|
770
777
|
name,
|
|
771
778
|
at: this.callSite(node),
|
|
772
779
|
use: (runtime2) => this.loweringRuntime(i, runtime2)
|
|
@@ -1020,12 +1027,12 @@ end`).body.statements, out2);
|
|
|
1020
1027
|
local2 = this.names.fresh(moduleName(key));
|
|
1021
1028
|
moduleLocals.set(key, local2);
|
|
1022
1029
|
locals.push(local2);
|
|
1023
|
-
requires.push(assign([identifier(local2)], [call(context.require,
|
|
1030
|
+
requires.push(assign([identifier(local2)], [call(context.require, moduleArguments(context, key))]));
|
|
1024
1031
|
}
|
|
1025
1032
|
return local2;
|
|
1026
1033
|
};
|
|
1027
1034
|
const load = (key) => {
|
|
1028
|
-
if (!moduleLocals.has(key)) requires.push(callStatement(call(context.require,
|
|
1035
|
+
if (!moduleLocals.has(key)) requires.push(callStatement(call(context.require, moduleArguments(context, key))));
|
|
1029
1036
|
};
|
|
1030
1037
|
const exportBinding = (node, exported) => {
|
|
1031
1038
|
const binding = node && this.bindingByDeclaration.get(node);
|
|
@@ -1134,20 +1141,22 @@ end`).body.statements, out2);
|
|
|
1134
1141
|
continue;
|
|
1135
1142
|
}
|
|
1136
1143
|
if (declaration.type === "ClassDeclaration") {
|
|
1137
|
-
body.push(...this.classDeclaration(declaration, "assign"));
|
|
1144
|
+
body.push(...this.classDeclaration(declaration, "assign").map((s) => this.from(s, declaration)));
|
|
1138
1145
|
continue;
|
|
1139
1146
|
}
|
|
1140
1147
|
switch (declaration.type) {
|
|
1148
|
+
// Stamped with where they were written, as any statement is:
|
|
1149
|
+
// an error in a top-level `const` names its line.
|
|
1141
1150
|
case "VariableDeclaration":
|
|
1142
|
-
body.push(...this.variableDeclaration(declaration, "assign"));
|
|
1151
|
+
body.push(...this.variableDeclaration(declaration, "assign").map((s) => this.from(s, declaration)));
|
|
1143
1152
|
break;
|
|
1144
1153
|
case "ExportDefaultStatement": {
|
|
1145
1154
|
const exported = declaration.declaration;
|
|
1146
1155
|
if (exported.type === "ClassDeclaration") {
|
|
1147
|
-
body.push(...this.classDeclaration(exported, "assign"));
|
|
1148
|
-
body.push(assign([member(exportsTable(), "default")], [this.reference(exported.name)]));
|
|
1156
|
+
body.push(...this.classDeclaration(exported, "assign").map((s) => this.from(s, exported)));
|
|
1157
|
+
body.push(this.from(assign([member(exportsTable(), "default")], [this.reference(exported.name)]), declaration));
|
|
1149
1158
|
} else {
|
|
1150
|
-
body.push(assign([member(exportsTable(), "default")], [this.expression(exported)]));
|
|
1159
|
+
body.push(this.from(assign([member(exportsTable(), "default")], [this.expression(exported)]), declaration));
|
|
1151
1160
|
}
|
|
1152
1161
|
break;
|
|
1153
1162
|
}
|
|
@@ -1185,7 +1194,7 @@ end`).body.statements, out2);
|
|
|
1185
1194
|
this.report(source, `Cannot find module '${source.value}'`);
|
|
1186
1195
|
return nil();
|
|
1187
1196
|
}
|
|
1188
|
-
return call(context.import ?? context.require,
|
|
1197
|
+
return call(context.import ?? context.require, moduleArguments(context, key));
|
|
1189
1198
|
}
|
|
1190
1199
|
isRewritten(node) {
|
|
1191
1200
|
const binding = this.bindingByDeclaration.get(node);
|
|
@@ -1384,9 +1393,9 @@ end`).body.statements, out2);
|
|
|
1384
1393
|
return this.assignment(node);
|
|
1385
1394
|
case "CompoundAssignmentStatement": {
|
|
1386
1395
|
if (node.operator === "??=") return this.nullishAssignment(node);
|
|
1387
|
-
const
|
|
1388
|
-
if (
|
|
1389
|
-
const operator =
|
|
1396
|
+
const join3 = node.operator === "+=" ? this.options.types?.joins.get(node) : void 0;
|
|
1397
|
+
if (join3 === "dynamic") return this.dynamicAddition(node);
|
|
1398
|
+
const operator = join3 === "concat" ? "..=" : node.operator;
|
|
1390
1399
|
if (!this.syntax.has("compoundAssignment")) return this.compoundAssignment51(node, operator);
|
|
1391
1400
|
return [{
|
|
1392
1401
|
type: "CompoundAssignmentStatement",
|
|
@@ -1650,11 +1659,11 @@ end`).body.statements, out2);
|
|
|
1650
1659
|
* carries neither. */
|
|
1651
1660
|
classRuntimeStatements() {
|
|
1652
1661
|
if (!this.classHelpers) return [];
|
|
1653
|
-
const { build, accessors } = this.classHelpers;
|
|
1662
|
+
const { build: build2, accessors } = this.classHelpers;
|
|
1654
1663
|
const metamethods = `{ ${CLASS_METAMETHODS.map((name) => `"${name}"`).join(", ")} }`;
|
|
1655
1664
|
const out2 = [];
|
|
1656
|
-
this.define([
|
|
1657
|
-
local function ${
|
|
1665
|
+
this.define([build2, accessors], (0, import_luau_parser.parse)(`
|
|
1666
|
+
local function ${build2}(base, name)
|
|
1658
1667
|
local class = { __getters = {}, __setters = {} }
|
|
1659
1668
|
class.__index = class
|
|
1660
1669
|
class.ClassObject = class
|
|
@@ -1713,9 +1722,9 @@ end
|
|
|
1713
1722
|
/** `declare` names the local the class table goes in; without it the
|
|
1714
1723
|
* table is assigned to `self`, which a module has already declared. */
|
|
1715
1724
|
classStatements(node, self, declare) {
|
|
1716
|
-
const { build, accessors } = this.classRuntime();
|
|
1725
|
+
const { build: build2, accessors } = this.classRuntime();
|
|
1717
1726
|
const called = node.name?.name ?? (node.type === "ClassExpression" ? this.classExpressionNames.get(node) : void 0) ?? "";
|
|
1718
|
-
const create = call(identifier(
|
|
1727
|
+
const create = call(identifier(build2), [
|
|
1719
1728
|
node.superclass ? this.reference(node.superclass) : nil(),
|
|
1720
1729
|
string(called)
|
|
1721
1730
|
]);
|
|
@@ -2072,9 +2081,9 @@ end
|
|
|
2072
2081
|
return call(this.helper("instanceof"), [this.keptToOne(left), this.keptToOne(right)]);
|
|
2073
2082
|
}
|
|
2074
2083
|
if (node.operator === "+") {
|
|
2075
|
-
const
|
|
2076
|
-
if (
|
|
2077
|
-
if (
|
|
2084
|
+
const join3 = this.options.types?.joins.get(node);
|
|
2085
|
+
if (join3 === "concat") return binary("..", left, right);
|
|
2086
|
+
if (join3 === "dynamic") return call(this.helper("add"), [this.keptToOne(left), this.keptToOne(right)]);
|
|
2078
2087
|
}
|
|
2079
2088
|
if (!this.syntax.has("floorDivision") && node.operator === "//") return this.floorDivide(left, right);
|
|
2080
2089
|
return binary(node.operator, left, right);
|
|
@@ -3041,23 +3050,29 @@ function ownExport(f, name) {
|
|
|
3041
3050
|
// src/linemap.ts
|
|
3042
3051
|
var import_parser6 = require("@tilua/parser");
|
|
3043
3052
|
function statementsOf(node) {
|
|
3044
|
-
|
|
3045
|
-
|
|
3053
|
+
return statementTree(node).statements;
|
|
3054
|
+
}
|
|
3055
|
+
function statementTree(node) {
|
|
3056
|
+
const statements = [];
|
|
3057
|
+
const parents = [];
|
|
3058
|
+
const visit = (value, parent) => {
|
|
3046
3059
|
if (!value || typeof value !== "object") return;
|
|
3047
|
-
if (Array.isArray(value)) return void value.forEach(visit);
|
|
3060
|
+
if (Array.isArray(value)) return void value.forEach((item) => visit(item, parent));
|
|
3048
3061
|
const record = value;
|
|
3062
|
+
let inside = parent;
|
|
3049
3063
|
if (typeof record.type === "string" && record.type.endsWith("Statement")) {
|
|
3050
|
-
|
|
3064
|
+
inside = statements.push(value) - 1;
|
|
3065
|
+
parents.push(parent);
|
|
3051
3066
|
}
|
|
3052
3067
|
for (const [key, child] of Object.entries(record)) {
|
|
3053
|
-
if (key !== "line" && key !== "column") visit(child);
|
|
3068
|
+
if (key !== "line" && key !== "column") visit(child, inside);
|
|
3054
3069
|
}
|
|
3055
3070
|
};
|
|
3056
|
-
visit(node);
|
|
3057
|
-
return
|
|
3071
|
+
visit(node, -1);
|
|
3072
|
+
return { statements, parents };
|
|
3058
3073
|
}
|
|
3059
3074
|
function buildLineMap(emitted, printed, origins) {
|
|
3060
|
-
const before =
|
|
3075
|
+
const { statements: before, parents } = statementTree(emitted);
|
|
3061
3076
|
const after = statementsOf(printed);
|
|
3062
3077
|
if (before.length !== after.length) return /* @__PURE__ */ new Map();
|
|
3063
3078
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3068,12 +3083,75 @@ function buildLineMap(emitted, printed, origins) {
|
|
|
3068
3083
|
const line = after[i].line.start;
|
|
3069
3084
|
if (!map.has(line)) map.set(line, origin);
|
|
3070
3085
|
}
|
|
3086
|
+
const holds = /* @__PURE__ */ new Set();
|
|
3087
|
+
for (let i = 0; i < before.length; i++) {
|
|
3088
|
+
if (!origins.has(before[i])) continue;
|
|
3089
|
+
for (let up = parents[i]; up >= 0 && !holds.has(up); up = parents[up]) holds.add(up);
|
|
3090
|
+
}
|
|
3091
|
+
for (let i = 0; i < before.length; i++) {
|
|
3092
|
+
const origin = origins.get(before[i]);
|
|
3093
|
+
if (!origin || holds.has(i)) continue;
|
|
3094
|
+
for (let line = after[i].line.start + 1; line <= after[i].line.end; line++) {
|
|
3095
|
+
if (!map.has(line)) map.set(line, origin);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3071
3098
|
return map;
|
|
3072
3099
|
}
|
|
3073
|
-
|
|
3100
|
+
var VLQ_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
3101
|
+
function vlq(n) {
|
|
3102
|
+
let value = n < 0 ? -n * 2 + 1 : n * 2;
|
|
3103
|
+
let out2 = "";
|
|
3104
|
+
do {
|
|
3105
|
+
const digit = value % 32;
|
|
3106
|
+
value = Math.floor(value / 32);
|
|
3107
|
+
out2 += VLQ_DIGITS[value > 0 ? digit + 32 : digit];
|
|
3108
|
+
} while (value > 0);
|
|
3109
|
+
return out2;
|
|
3110
|
+
}
|
|
3111
|
+
function lineMapSource(map, unpack) {
|
|
3074
3112
|
const entries = [...map.entries()].sort((a, b) => a[0] - b[0]);
|
|
3075
|
-
const
|
|
3076
|
-
|
|
3113
|
+
const files = [];
|
|
3114
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
3115
|
+
let data = "";
|
|
3116
|
+
let line = 0, file = 0, source = 0;
|
|
3117
|
+
for (const [at, origin] of entries) {
|
|
3118
|
+
const name = origin.file.replace(/\\/g, "/");
|
|
3119
|
+
if (!indexes.has(name)) indexes.set(name, files.push(name));
|
|
3120
|
+
const index2 = indexes.get(name);
|
|
3121
|
+
data += vlq(at - line) + vlq(index2 - file) + vlq(origin.line - source);
|
|
3122
|
+
line = at;
|
|
3123
|
+
file = index2;
|
|
3124
|
+
source = origin.line;
|
|
3125
|
+
}
|
|
3126
|
+
return `${unpack}({${files.map(import_parser6.luauString).join(",")}},${(0, import_parser6.luauString)(data)})`;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
// src/output.ts
|
|
3130
|
+
var import_luau_parser2 = require("luau-parser");
|
|
3131
|
+
var WRITTEN = /* @__PURE__ */ new Set([
|
|
3132
|
+
"compoundAssignment",
|
|
3133
|
+
"continue",
|
|
3134
|
+
"ifExpression",
|
|
3135
|
+
"floorDivision",
|
|
3136
|
+
"attributes",
|
|
3137
|
+
"numberLiterals"
|
|
3138
|
+
]);
|
|
3139
|
+
function printOptions(syntax, format = {}) {
|
|
3140
|
+
return {
|
|
3141
|
+
syntax: [...syntax].some((s) => WRITTEN.has(s)) ? "luau" : "lua51",
|
|
3142
|
+
compact: format.minify ?? false,
|
|
3143
|
+
...format.indent !== void 0 && { indent: format.indent }
|
|
3144
|
+
};
|
|
3145
|
+
}
|
|
3146
|
+
function printOutput(node, options) {
|
|
3147
|
+
try {
|
|
3148
|
+
return { code: (0, import_luau_parser2.print)(node, options) };
|
|
3149
|
+
} catch (error) {
|
|
3150
|
+
if (!(error instanceof import_luau_parser2.PrintError)) throw error;
|
|
3151
|
+
return {
|
|
3152
|
+
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"`
|
|
3153
|
+
};
|
|
3154
|
+
}
|
|
3077
3155
|
}
|
|
3078
3156
|
|
|
3079
3157
|
// src/lowering.ts
|
|
@@ -3092,7 +3170,7 @@ async function loadLowerings(modules) {
|
|
|
3092
3170
|
});
|
|
3093
3171
|
continue;
|
|
3094
3172
|
}
|
|
3095
|
-
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library });
|
|
3173
|
+
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library, options: module2.options });
|
|
3096
3174
|
} catch (error) {
|
|
3097
3175
|
problems.push({
|
|
3098
3176
|
file: module2.file,
|
|
@@ -3104,17 +3182,30 @@ async function loadLowerings(modules) {
|
|
|
3104
3182
|
}
|
|
3105
3183
|
|
|
3106
3184
|
// src/bundle.ts
|
|
3185
|
+
var WRITTEN_BY_TILUA = "-- Written by tilua";
|
|
3107
3186
|
async function bundle(options) {
|
|
3108
|
-
const entry2 = (0, import_node_path2.resolve)(options.entry);
|
|
3109
3187
|
const diagnostics = [];
|
|
3188
|
+
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");
|
|
3110
3189
|
const inline = options.config !== void 0 && typeof options.config !== "string";
|
|
3111
|
-
const { config: config2, problems } = resolveConfig(options.config,
|
|
3190
|
+
const { config: config2, problems } = resolveConfig(options.config, from, options.root ?? (inline ? (0, import_node_path2.dirname)(from) : process.cwd()));
|
|
3112
3191
|
for (const p of problems) diagnostics.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3113
|
-
const root = (0, import_node_path2.resolve)(options.root ?? config2?.directory ?? (0, import_node_path2.dirname)(
|
|
3192
|
+
const root = (0, import_node_path2.resolve)(options.root ?? config2?.directory ?? (0, import_node_path2.dirname)(from));
|
|
3114
3193
|
const nameOf = (file) => (0, import_node_path2.relative)(root, file).replace(/\\/g, "/").replace(/\.tilua$/, "");
|
|
3194
|
+
const mode = options.output ?? config2?.output ?? "single";
|
|
3195
|
+
const perFile = mode === "files";
|
|
3196
|
+
const rootDir = (0, import_node_path2.resolve)(config2?.rootDir ?? root);
|
|
3197
|
+
const entry2 = options.entry !== void 0 ? (0, import_node_path2.resolve)(options.entry) : void 0;
|
|
3198
|
+
const anchor = entry2 ?? config2?.path ?? from;
|
|
3199
|
+
const stop = (message, file = anchor) => ({
|
|
3200
|
+
files: [],
|
|
3201
|
+
modules: [],
|
|
3202
|
+
diagnostics: [...diagnostics, { file, message, line: 1, column: 1, category: "config" }]
|
|
3203
|
+
});
|
|
3204
|
+
if (!perFile && entry2 === void 0) return stop('No entry to build: only "output": "files" builds without one');
|
|
3115
3205
|
const sources = /* @__PURE__ */ new Map();
|
|
3116
3206
|
const directives = /* @__PURE__ */ new Map();
|
|
3117
|
-
const queue = [entry2];
|
|
3207
|
+
const queue = perFile ? tiluaFiles(rootDir) : [entry2];
|
|
3208
|
+
if (perFile && !queue.length) return stop(`No .tilua file under ${(0, import_node_path2.relative)(process.cwd(), rootDir) || "."}`);
|
|
3118
3209
|
while (queue.length) {
|
|
3119
3210
|
const file = queue.shift();
|
|
3120
3211
|
if (sources.has(file)) continue;
|
|
@@ -3132,6 +3223,22 @@ async function bundle(options) {
|
|
|
3132
3223
|
if (target && !target.endsWith(".d.tilua")) queue.push(target);
|
|
3133
3224
|
}
|
|
3134
3225
|
}
|
|
3226
|
+
if (perFile) {
|
|
3227
|
+
const outside = [...sources.keys()].filter((file) => isOutside(rootDir, file));
|
|
3228
|
+
if (outside.length) {
|
|
3229
|
+
return {
|
|
3230
|
+
files: [],
|
|
3231
|
+
modules: [],
|
|
3232
|
+
diagnostics: [...diagnostics, ...outside.map((file) => ({
|
|
3233
|
+
file,
|
|
3234
|
+
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`,
|
|
3235
|
+
line: 1,
|
|
3236
|
+
column: 1,
|
|
3237
|
+
category: "module"
|
|
3238
|
+
}))]
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3135
3242
|
const analysis = analyzeModules([...sources.values()], config2);
|
|
3136
3243
|
const { lowerings, problems: loweringProblems } = await loadLowerings(analysis.lowerings);
|
|
3137
3244
|
for (const p of loweringProblems) {
|
|
@@ -3142,23 +3249,61 @@ async function bundle(options) {
|
|
|
3142
3249
|
const G = names.fresh("G");
|
|
3143
3250
|
const requireExpression = member(identifier(G), "require");
|
|
3144
3251
|
const importExpression = member(identifier(G), "import");
|
|
3145
|
-
const mode = options.output ?? config2?.output ?? "single";
|
|
3146
3252
|
const byPath = syntaxOf(lowerings).has("requireByPath");
|
|
3253
|
+
if (perFile && !byPath) {
|
|
3254
|
+
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)`, config2?.path ?? anchor);
|
|
3255
|
+
}
|
|
3256
|
+
const outputPath = (file) => (0, import_node_path2.relative)(rootDir, file).replace(/\\/g, "/").replace(/\.tilua$/, ".luau");
|
|
3257
|
+
const fileOfModule = new Map([...sources.values()].map((s) => [s.name, s.file]));
|
|
3258
|
+
const outDir = (0, import_node_path2.resolve)(options.outDir ?? config2?.outDir ?? rootDir);
|
|
3259
|
+
const written = (file) => (0, import_node_path2.join)(outDir, outputPath(file));
|
|
3260
|
+
let host;
|
|
3261
|
+
let runtimeFile = (0, import_node_path2.join)(outDir, "_tilua.luau");
|
|
3262
|
+
if (perFile) {
|
|
3263
|
+
const outputs = [...sources.keys()].map(written);
|
|
3264
|
+
const taken = new Set(outputs.map(pathKey));
|
|
3265
|
+
for (let n = 2; taken.has(pathKey(runtimeFile)); n++) runtimeFile = (0, import_node_path2.join)(outDir, `_tilua${n}.luau`);
|
|
3266
|
+
for (let i = lowerings.length - 1; i >= 0 && !host; i--) {
|
|
3267
|
+
const { plugin: plugin3, options: own } = lowerings[i];
|
|
3268
|
+
host = plugin3.files?.({ options: own ?? {}, directory: config2?.directory ?? root, outDir, files: outputs, runtime: runtimeFile });
|
|
3269
|
+
}
|
|
3270
|
+
for (const problem of host?.problems ?? []) {
|
|
3271
|
+
diagnostics.push({
|
|
3272
|
+
file: problem.file ?? config2?.path ?? anchor,
|
|
3273
|
+
message: problem.message,
|
|
3274
|
+
line: 1,
|
|
3275
|
+
column: 1,
|
|
3276
|
+
category: "config",
|
|
3277
|
+
...problem.severity === "warning" && { severity: "warning" }
|
|
3278
|
+
});
|
|
3279
|
+
}
|
|
3280
|
+
if (host?.runtime !== void 0) {
|
|
3281
|
+
if (isOutside(outDir, (0, import_node_path2.resolve)(host.runtime))) return stop(`The runtime has to go inside outDir, not at ${host.runtime}`);
|
|
3282
|
+
if (taken.has(pathKey(host.runtime))) return stop(`The runtime cannot go at ${host.runtime}: a module's file is there`);
|
|
3283
|
+
runtimeFile = (0, import_node_path2.resolve)(host.runtime);
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
const placeOf = (file) => host?.place?.(file) ?? placeInFolder((0, import_node_path2.relative)(outDir, file));
|
|
3287
|
+
const requireFrom = (from2, to) => pathBetween(placeOf(from2), placeOf(to), host?.root);
|
|
3288
|
+
const isScript = (file) => host?.script?.(file) ?? false;
|
|
3147
3289
|
const modules = /* @__PURE__ */ new Map();
|
|
3148
3290
|
const origins = /* @__PURE__ */ new WeakMap();
|
|
3149
3291
|
const shared = new SharedRuntime(names);
|
|
3150
3292
|
const shaking = options.treeShaking ?? config2?.treeShaking ?? false;
|
|
3293
|
+
const format = { indent: options.indent ?? config2?.indent, minify: options.minify ?? config2?.minify ?? false };
|
|
3294
|
+
const printing = printOptions(syntaxOf(lowerings), format);
|
|
3295
|
+
const mapping = !format.minify && (options.lineMap ?? config2?.lineMap ?? true);
|
|
3151
3296
|
const resolveIn = (file) => (specifier) => {
|
|
3152
3297
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config2);
|
|
3153
3298
|
return found !== void 0 && sources.has(found) ? found : void 0;
|
|
3154
3299
|
};
|
|
3155
|
-
const shaken = shaking ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry2) : void 0;
|
|
3156
|
-
const pending = [entry2];
|
|
3300
|
+
const shaken = shaking && entry2 !== void 0 && !perFile ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry2) : void 0;
|
|
3301
|
+
const pending = perFile ? [...sources.keys()] : [entry2];
|
|
3157
3302
|
while (pending.length) {
|
|
3158
3303
|
const file = pending.shift();
|
|
3159
3304
|
if (modules.has(file)) continue;
|
|
3160
3305
|
const source = sources.get(file);
|
|
3161
|
-
const
|
|
3306
|
+
const shown2 = (0, import_node_path2.relative)(root, file).replace(/\\/g, "/");
|
|
3162
3307
|
const imports = /* @__PURE__ */ new Set();
|
|
3163
3308
|
const dynamicImports = /* @__PURE__ */ new Set();
|
|
3164
3309
|
const lowered2 = lower(source.program, source.scopes, {
|
|
@@ -3167,7 +3312,7 @@ async function bundle(options) {
|
|
|
3167
3312
|
lowerings,
|
|
3168
3313
|
noLib: config2?.noLib,
|
|
3169
3314
|
source: source.text,
|
|
3170
|
-
file:
|
|
3315
|
+
file: shown2,
|
|
3171
3316
|
shared,
|
|
3172
3317
|
shaken: shaken && {
|
|
3173
3318
|
...shaken.modules.get(file),
|
|
@@ -3186,9 +3331,16 @@ async function bundle(options) {
|
|
|
3186
3331
|
import: importExpression,
|
|
3187
3332
|
// One file has one line map. Several have one each, and a
|
|
3188
3333
|
// module reads the one of the file it is in.
|
|
3189
|
-
lines: mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
|
|
3190
|
-
fail: `${G}.fail
|
|
3334
|
+
lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
|
|
3335
|
+
fail: mapping ? `${G}.fail` : void 0,
|
|
3191
3336
|
arrays: `${G}.arrays`,
|
|
3337
|
+
// The file a module is in, required from this one by its
|
|
3338
|
+
// path, written out.
|
|
3339
|
+
loader: !perFile ? void 0 : (name) => {
|
|
3340
|
+
const target = fileOfModule.get(name);
|
|
3341
|
+
if (target === void 0) return void 0;
|
|
3342
|
+
return (0, import_luau_parser3.parseExpressionFromSource)(`function() return require(${(0, import_parser7.luauString)(requireFrom(written(file), written(target)))}) end`);
|
|
3343
|
+
},
|
|
3192
3344
|
resolve: (specifier, dynamic) => {
|
|
3193
3345
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config2);
|
|
3194
3346
|
if (!found || found.endsWith(".d.tilua") || !sources.has(found)) return void 0;
|
|
@@ -3202,7 +3354,7 @@ async function bundle(options) {
|
|
|
3202
3354
|
for (const d of lowered2.diagnostics) diagnostics.push({ file, ...d, category: "module" });
|
|
3203
3355
|
for (const statement of allStatements(lowered2.statements)) {
|
|
3204
3356
|
const line = lowered2.origins.get(statement);
|
|
3205
|
-
if (line !== void 0) origins.set(statement, { file:
|
|
3357
|
+
if (line !== void 0) origins.set(statement, { file: shown2, line });
|
|
3206
3358
|
}
|
|
3207
3359
|
modules.set(file, {
|
|
3208
3360
|
name: source.name,
|
|
@@ -3240,6 +3392,102 @@ async function bundle(options) {
|
|
|
3240
3392
|
return { files: [], modules: moduleNames, diagnostics };
|
|
3241
3393
|
}
|
|
3242
3394
|
if (shaking) shared.shake(lowered.flatMap((m) => m.statements));
|
|
3395
|
+
const unwritable = (problem) => ({
|
|
3396
|
+
files: [],
|
|
3397
|
+
modules: moduleNames,
|
|
3398
|
+
diagnostics: [...diagnostics, { file: anchor, message: problem, line: 1, column: 1, category: "config" }]
|
|
3399
|
+
});
|
|
3400
|
+
const write = (node) => {
|
|
3401
|
+
const printed2 = printOutput(node, printing);
|
|
3402
|
+
return "problem" in printed2 ? printed2 : printed2.code;
|
|
3403
|
+
};
|
|
3404
|
+
if (perFile) {
|
|
3405
|
+
const imported = [];
|
|
3406
|
+
for (const [file, source] of sources) {
|
|
3407
|
+
for (const { specifier, line, column } of importSites(source.program)) {
|
|
3408
|
+
const target = resolveIn(file)(specifier);
|
|
3409
|
+
if (target === void 0 || !isScript(written(target))) continue;
|
|
3410
|
+
imported.push({
|
|
3411
|
+
file,
|
|
3412
|
+
line,
|
|
3413
|
+
column,
|
|
3414
|
+
category: "module",
|
|
3415
|
+
message: `'${specifier}' is a script the game runs, which nothing can import: move what it shares into a module of its own`
|
|
3416
|
+
});
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
if (imported.length) return { files: [], modules: moduleNames, diagnostics: [...diagnostics, ...imported] };
|
|
3420
|
+
const runtimePath = (0, import_node_path2.relative)(outDir, runtimeFile).replace(/\\/g, "/");
|
|
3421
|
+
const files2 = [];
|
|
3422
|
+
for (const [file, module2] of modules) {
|
|
3423
|
+
const path = outputPath(file);
|
|
3424
|
+
const at = written(file);
|
|
3425
|
+
const script = isScript(at);
|
|
3426
|
+
const prelude = host?.prelude?.(at);
|
|
3427
|
+
const body = [
|
|
3428
|
+
...prelude !== void 0 ? (0, import_luau_parser3.parse)(prelude).body.statements : [],
|
|
3429
|
+
...(0, import_luau_parser3.parse)(`local ${G} = require(${(0, import_parser7.luauString)(requireFrom(at, runtimeFile))})`).body.statements
|
|
3430
|
+
];
|
|
3431
|
+
for (let i = 0; i < module2.shared.length; i += 100) {
|
|
3432
|
+
const some = module2.shared.slice(i, i + 100);
|
|
3433
|
+
body.push(local(some, some.map((name) => member(member(identifier(G), "shared"), name))));
|
|
3434
|
+
}
|
|
3435
|
+
if (module2.usesScriptArgs) body.push(...(0, import_luau_parser3.parse)(`local scriptArgs = ${G}.scriptArgs`).body.statements);
|
|
3436
|
+
body.push(assign(
|
|
3437
|
+
[index(member(identifier(G), "modules"), string(module2.name))],
|
|
3438
|
+
[moduleTable(module2)]
|
|
3439
|
+
));
|
|
3440
|
+
const value = `${G}.${mapping ? "run" : "require"}(${(0, import_parser7.luauString)(module2.name)})`;
|
|
3441
|
+
const returned2 = module2.info.exports && !script ? entryReturn(lowerings, module2.name, value, () => analysis.exportsOf(file)) : { statements: [], value };
|
|
3442
|
+
if ("problem" in returned2) return stop(returned2.problem.message, file);
|
|
3443
|
+
const ending = (0, import_luau_parser3.parse)(`${returned2.statements.join("\n")}
|
|
3444
|
+
return ${returned2.value}`).body.statements;
|
|
3445
|
+
const chunk = program(body);
|
|
3446
|
+
if (mapping) {
|
|
3447
|
+
const text = write(chunk);
|
|
3448
|
+
if (typeof text !== "string") return unwritable(text.problem);
|
|
3449
|
+
const lines = buildLineMap(chunk, (0, import_luau_parser3.parse)(text), origins);
|
|
3450
|
+
const named = host?.place?.(at) ? `${placeOf(at).join("/")}.luau` : path;
|
|
3451
|
+
body.push(...mapRegistration(G, { path: named, modules: [module2] }, lineMapSource(lines, `${G}.lineMap`)));
|
|
3452
|
+
}
|
|
3453
|
+
body.push(...ending);
|
|
3454
|
+
const code = write(chunk);
|
|
3455
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3456
|
+
const from2 = (0, import_node_path2.relative)((0, import_node_path2.dirname)(at), file).replace(/\\/g, "/");
|
|
3457
|
+
files2.push({ path, code: `${code}
|
|
3458
|
+
${WRITTEN_BY_TILUA} from ${from2}: edit that file, not this one.
|
|
3459
|
+
`, modules: [module2.name] });
|
|
3460
|
+
}
|
|
3461
|
+
const runtimeProgram = (0, import_luau_parser3.parse)(runtime(G, {
|
|
3462
|
+
several: true,
|
|
3463
|
+
perFile: true,
|
|
3464
|
+
byPath,
|
|
3465
|
+
files: /* @__PURE__ */ new Map(),
|
|
3466
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3467
|
+
mapping
|
|
3468
|
+
}));
|
|
3469
|
+
const helpers2 = shared.chunk(new Set(lowered.flatMap((m) => m.shared)));
|
|
3470
|
+
const helperNames = helpers2.declare.flatMap((statement) => statement.type === "LocalStatement" ? statement.names.map((n) => n.name) : []);
|
|
3471
|
+
runtimeProgram.body.statements.unshift(...helpers2.declare);
|
|
3472
|
+
runtimeProgram.body.statements.push(...helpers2.define);
|
|
3473
|
+
if (helperNames.length) {
|
|
3474
|
+
runtimeProgram.body.statements.push(assign(
|
|
3475
|
+
[member(identifier(G), "shared")],
|
|
3476
|
+
[table(helperNames.map((name) => field(name, identifier(name))))]
|
|
3477
|
+
));
|
|
3478
|
+
}
|
|
3479
|
+
if (lowered.some((m) => m.usesScriptArgs)) {
|
|
3480
|
+
runtimeProgram.body.statements.push(...(0, import_luau_parser3.parse)(`${G}.scriptArgs = {}
|
|
3481
|
+
${G}.arrays[${G}.scriptArgs] = true`).body.statements);
|
|
3482
|
+
}
|
|
3483
|
+
runtimeProgram.body.statements.push(returns([identifier(G)]));
|
|
3484
|
+
const runtimeCode = write(runtimeProgram);
|
|
3485
|
+
if (typeof runtimeCode !== "string") return unwritable(runtimeCode.problem);
|
|
3486
|
+
files2.push({ path: runtimePath, code: `${runtimeCode}
|
|
3487
|
+
${WRITTEN_BY_TILUA}: the runtime every file of the project requires.
|
|
3488
|
+
`, modules: [] });
|
|
3489
|
+
return { code: files2[0].code, files: files2, modules: moduleNames, diagnostics };
|
|
3490
|
+
}
|
|
3243
3491
|
const several = mode !== "single";
|
|
3244
3492
|
const layout = layoutOf(mode, modules.get(entry2), lowered, options.outFile);
|
|
3245
3493
|
const usesScriptArgs = lowered.some((m) => m.usesScriptArgs);
|
|
@@ -3247,17 +3495,18 @@ async function bundle(options) {
|
|
|
3247
3495
|
for (const file of layout.slice(1)) {
|
|
3248
3496
|
for (const module2 of file.modules) elsewhere.set(module2.name, loadPath(layout[0].path, file.path, byPath));
|
|
3249
3497
|
}
|
|
3250
|
-
const program2 = (0,
|
|
3498
|
+
const program2 = (0, import_luau_parser3.parse)(runtime(G, {
|
|
3251
3499
|
several,
|
|
3252
3500
|
byPath,
|
|
3253
3501
|
files: elsewhere,
|
|
3254
|
-
imports: lowered.some((m) => m.dynamicImports.size > 0)
|
|
3502
|
+
imports: lowered.some((m) => m.dynamicImports.size > 0),
|
|
3503
|
+
mapping
|
|
3255
3504
|
}));
|
|
3256
3505
|
const assignment = program2.body.statements[1];
|
|
3257
3506
|
if (usesScriptArgs) {
|
|
3258
3507
|
program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
3259
|
-
program2.body.statements.push(...(0,
|
|
3260
|
-
if (several) program2.body.statements.push(...(0,
|
|
3508
|
+
program2.body.statements.push(...(0, import_luau_parser3.parse)(`${G}.arrays[scriptArgs] = true`).body.statements);
|
|
3509
|
+
if (several) program2.body.statements.push(...(0, import_luau_parser3.parse)(`${G}.scriptArgs = scriptArgs`).body.statements);
|
|
3261
3510
|
}
|
|
3262
3511
|
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;
|
|
3263
3512
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -3268,31 +3517,42 @@ async function bundle(options) {
|
|
|
3268
3517
|
program2.body.statements.unshift(...helpers.declare);
|
|
3269
3518
|
const ok = names.fresh("ok");
|
|
3270
3519
|
const result2 = names.fresh("result");
|
|
3271
|
-
const
|
|
3520
|
+
const entryName = (0, import_parser7.luauString)(sources.get(entry2).name);
|
|
3521
|
+
const returnsExports = modules.get(entry2).info.exports;
|
|
3522
|
+
const returned = returnsExports ? entryReturn(lowerings, sources.get(entry2).name, mapping ? result2 : `${G}.require(${entryName})`, () => analysis.exportsOf(entry2)) : void 0;
|
|
3523
|
+
if (returned && "problem" in returned) return stop(returned.problem.message);
|
|
3524
|
+
const declarations = returned?.statements.join("\n") ?? "";
|
|
3525
|
+
const entryStatements = (0, import_luau_parser3.parse)(!mapping ? `${declarations}
|
|
3526
|
+
${returned ? `return ${returned.value}` : `${G}.require(${entryName})`}` : `
|
|
3272
3527
|
local ${ok}, ${result2} = xpcall(function()
|
|
3273
|
-
return ${G}.require(${
|
|
3528
|
+
return ${G}.require(${entryName})
|
|
3274
3529
|
end, ${G}.fail)
|
|
3275
3530
|
if not ${ok} then
|
|
3276
3531
|
error(${result2}, 0)
|
|
3277
3532
|
end
|
|
3278
|
-
${
|
|
3533
|
+
${declarations}
|
|
3534
|
+
${returned ? `return ${returned.value}` : ""}
|
|
3279
3535
|
`).body.statements;
|
|
3280
3536
|
program2.body.statements.push(...entryStatements);
|
|
3281
|
-
|
|
3282
|
-
if (
|
|
3537
|
+
let printed = write(program2);
|
|
3538
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3539
|
+
const map = mapping ? buildLineMap(program2, (0, import_luau_parser3.parse)(printed), origins) : /* @__PURE__ */ new Map();
|
|
3540
|
+
if (mapping && (map.size || several)) {
|
|
3283
3541
|
const mapStatements = [assign(
|
|
3284
3542
|
[member(identifier(G), "lines")],
|
|
3285
|
-
[(0,
|
|
3543
|
+
[(0, import_luau_parser3.parseExpressionFromSource)(lineMapSource(map, `${G}.lineMap`))]
|
|
3286
3544
|
)];
|
|
3287
3545
|
if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
|
|
3288
3546
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
|
|
3289
3547
|
}
|
|
3290
3548
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...helpers.define);
|
|
3291
|
-
|
|
3549
|
+
printed = write(program2);
|
|
3550
|
+
if (typeof printed !== "string") return unwritable(printed.problem);
|
|
3551
|
+
const files = [{ path: layout[0].path, code: printed + "\n", modules: layout[0].modules.map((m) => m.name) }];
|
|
3292
3552
|
for (const file of layout.slice(1)) {
|
|
3293
3553
|
const fileHelpers = shared.chunk(new Set(file.modules.flatMap((m) => m.shared)));
|
|
3294
3554
|
const body = [...fileHelpers.declare];
|
|
3295
|
-
if (file.modules.some((m) => m.usesScriptArgs)) body.push(...(0,
|
|
3555
|
+
if (file.modules.some((m) => m.usesScriptArgs)) body.push(...(0, import_luau_parser3.parse)(`local scriptArgs = ${G}.scriptArgs`).body.statements);
|
|
3296
3556
|
for (const module2 of file.modules) {
|
|
3297
3557
|
body.push(assign(
|
|
3298
3558
|
[index(member(identifier(G), "modules"), string(module2.name))],
|
|
@@ -3300,12 +3560,35 @@ ${modules.get(entry2).info.exports ? `return ${result2}` : ""}
|
|
|
3300
3560
|
));
|
|
3301
3561
|
}
|
|
3302
3562
|
const chunk = program([returns([functionExpression(functionBody([G], body))])]);
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3563
|
+
if (mapping) {
|
|
3564
|
+
const lines = buildLineMap(chunk, (0, import_luau_parser3.parse)((0, import_luau_parser3.print)(chunk, printing)), origins);
|
|
3565
|
+
body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
|
|
3566
|
+
}
|
|
3567
|
+
body.push(...fileHelpers.define);
|
|
3568
|
+
const code = write(chunk);
|
|
3569
|
+
if (typeof code !== "string") return unwritable(code.problem);
|
|
3570
|
+
files.push({ path: file.path, code: code + "\n", modules: file.modules.map((m) => m.name) });
|
|
3306
3571
|
}
|
|
3307
3572
|
return { code: files[0].code, files, modules: moduleNames, diagnostics };
|
|
3308
3573
|
}
|
|
3574
|
+
function entryReturn(lowerings, module2, value, exports2) {
|
|
3575
|
+
const syntax = [...syntaxOf(lowerings)];
|
|
3576
|
+
for (let i = lowerings.length - 1; i >= 0; i--) {
|
|
3577
|
+
const { plugin: plugin3, from, options } = lowerings[i];
|
|
3578
|
+
if (!plugin3.entryExports) continue;
|
|
3579
|
+
const answer = plugin3.entryExports({ options: options ?? {}, module: module2, value, exports: exports2(), syntax });
|
|
3580
|
+
if (!answer) continue;
|
|
3581
|
+
const statements = [...answer.statements ?? []];
|
|
3582
|
+
try {
|
|
3583
|
+
(0, import_luau_parser3.parse)(`${statements.join("\n")}
|
|
3584
|
+
return ${answer.value}`);
|
|
3585
|
+
} catch (error) {
|
|
3586
|
+
return { problem: { message: `'${from}' answered entryExports with Luau that does not parse: ${error.message}` } };
|
|
3587
|
+
}
|
|
3588
|
+
return { statements, value: answer.value };
|
|
3589
|
+
}
|
|
3590
|
+
return { statements: [], value };
|
|
3591
|
+
}
|
|
3309
3592
|
function moduleTable(module2) {
|
|
3310
3593
|
const { names: exported, links, stars } = module2.info;
|
|
3311
3594
|
const fields = [];
|
|
@@ -3325,10 +3608,6 @@ function layoutOf(mode, entry2, modules, outFile) {
|
|
|
3325
3608
|
const entryStem = outFile !== void 0 ? (0, import_node_path2.basename)(outFile, (0, import_node_path2.extname)(outFile)) : import_node_path2.posix.basename(entry2.name);
|
|
3326
3609
|
const others = modules.filter((m) => m !== entry2);
|
|
3327
3610
|
if (mode === "single") return [{ path: `${entryStem}${extension}`, modules: [entry2, ...others] }];
|
|
3328
|
-
if (mode === "modules") {
|
|
3329
|
-
const pathOf = (m) => `${m.name.split("/").map((part) => part === ".." ? "__" : part).join("/")}${extension}`;
|
|
3330
|
-
return [entry2, ...others].map((m) => ({ path: pathOf(m), modules: [m] }));
|
|
3331
|
-
}
|
|
3332
3611
|
const byName = new Map(modules.map((m) => [m.name, m]));
|
|
3333
3612
|
const reach = (root) => {
|
|
3334
3613
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3364,16 +3643,75 @@ function layoutOf(mode, entry2, modules, outFile) {
|
|
|
3364
3643
|
return files;
|
|
3365
3644
|
}
|
|
3366
3645
|
function loadPath(entryPath, file, byPath) {
|
|
3367
|
-
|
|
3368
|
-
|
|
3646
|
+
return byPath ? requirePath(entryPath, file) : import_node_path2.posix.relative(import_node_path2.posix.dirname(entryPath), file);
|
|
3647
|
+
}
|
|
3648
|
+
function placeInFolder(path) {
|
|
3649
|
+
const parts = path.replace(/\\/g, "/").replace(/\.luau?$/, "").split("/").filter((part) => part !== "");
|
|
3650
|
+
if (parts.at(-1) === "init") parts.pop();
|
|
3651
|
+
return parts;
|
|
3652
|
+
}
|
|
3653
|
+
function pathBetween(from, to, root) {
|
|
3654
|
+
if (root !== void 0 && from[0] !== to[0]) return `${root}/${to.join("/")}`;
|
|
3655
|
+
if (to.length > from.length && from.every((part, i) => to[i] === part)) return `@self/${to.slice(from.length).join("/")}`;
|
|
3656
|
+
const base = from.slice(0, -1);
|
|
3657
|
+
let shared = 0;
|
|
3658
|
+
while (shared < base.length && shared < to.length - 1 && base[shared] === to[shared]) shared++;
|
|
3659
|
+
const up = base.length - shared;
|
|
3660
|
+
return `${up === 0 ? "./" : "../".repeat(up)}${to.slice(shared).join("/")}`;
|
|
3661
|
+
}
|
|
3662
|
+
function importSites(program2) {
|
|
3663
|
+
const sites = [];
|
|
3664
|
+
for (const statement of program2.body.statements) {
|
|
3665
|
+
if (statement.type === "ImportStatement" || statement.type === "ExportAllStatement" || statement.type === "ExportNamedStatement" && statement.source) {
|
|
3666
|
+
const source = statement.source;
|
|
3667
|
+
sites.push({ specifier: source.value, line: source.line.start, column: source.column.start });
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
for (const node of (0, import_parser7.importExpressions)(program2)) {
|
|
3671
|
+
if (node.source.type === "StringLiteral") sites.push({ specifier: node.source.value, line: node.source.line.start, column: node.source.column.start });
|
|
3672
|
+
}
|
|
3673
|
+
return sites;
|
|
3674
|
+
}
|
|
3675
|
+
function pathKey(path) {
|
|
3676
|
+
const full = (0, import_node_path2.resolve)(path);
|
|
3677
|
+
return process.platform === "win32" ? full.toLowerCase() : full;
|
|
3678
|
+
}
|
|
3679
|
+
function requirePath(from, to) {
|
|
3680
|
+
const path = import_node_path2.posix.relative(import_node_path2.posix.dirname(from), to);
|
|
3369
3681
|
const bare = path.slice(0, path.length - import_node_path2.posix.extname(path).length);
|
|
3370
3682
|
return bare.startsWith("../") ? bare : `./${bare}`;
|
|
3371
3683
|
}
|
|
3684
|
+
function tiluaFiles(folder) {
|
|
3685
|
+
const found = [];
|
|
3686
|
+
const walk2 = (at) => {
|
|
3687
|
+
let entries;
|
|
3688
|
+
try {
|
|
3689
|
+
entries = (0, import_node_fs3.readdirSync)(at, { withFileTypes: true });
|
|
3690
|
+
} catch {
|
|
3691
|
+
return;
|
|
3692
|
+
}
|
|
3693
|
+
for (const item of entries) {
|
|
3694
|
+
if (item.name.startsWith(".")) continue;
|
|
3695
|
+
const path = (0, import_node_path2.join)(at, item.name);
|
|
3696
|
+
if (item.isDirectory()) {
|
|
3697
|
+
if (item.name !== "node_modules") walk2(path);
|
|
3698
|
+
} else if (item.name.endsWith(".tilua") && !item.name.endsWith(".d.tilua")) {
|
|
3699
|
+
found.push(path);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
};
|
|
3703
|
+
walk2(folder);
|
|
3704
|
+
return found.sort();
|
|
3705
|
+
}
|
|
3706
|
+
function isOutside(folder, file) {
|
|
3707
|
+
const path = (0, import_node_path2.relative)(folder, file);
|
|
3708
|
+
return path === "" || path.startsWith("..") || (0, import_node_path2.isAbsolute)(path);
|
|
3709
|
+
}
|
|
3372
3710
|
function mapRegistration(G, file, map) {
|
|
3373
3711
|
const extension = import_node_path2.posix.extname(file.path);
|
|
3374
3712
|
const parts = file.path.slice(0, file.path.length - extension.length).split(/[/.]/).filter((part) => part !== "");
|
|
3375
3713
|
const entry2 = `${G}.sources[#${G}.sources + 1]`;
|
|
3376
|
-
return (0,
|
|
3714
|
+
return (0, import_luau_parser3.parse)([
|
|
3377
3715
|
`${entry2} = { { ${parts.map(import_parser7.luauString).join(", ")} }, ${map}, ${(0, import_parser7.luauString)(extension.slice(1))} }`,
|
|
3378
3716
|
...file.modules.map((module2) => `${G}.maps[${(0, import_parser7.luauString)(module2.name)}] = ${G}.sources[#${G}.sources][2]`)
|
|
3379
3717
|
].join("\n")).body.statements;
|
|
@@ -3399,7 +3737,8 @@ function loader(G, byPath) {
|
|
|
3399
3737
|
require(file)(${G})`;
|
|
3400
3738
|
}
|
|
3401
3739
|
function runtime(G, options) {
|
|
3402
|
-
const { several } = options;
|
|
3740
|
+
const { several, mapping } = options;
|
|
3741
|
+
const perFile = options.perFile ?? false;
|
|
3403
3742
|
const files = [...options.files].map(([name, file]) => `[${(0, import_parser7.luauString)(name)}] = ${(0, import_parser7.luauString)(file)}`).join(", ");
|
|
3404
3743
|
return `
|
|
3405
3744
|
local ${G}
|
|
@@ -3407,7 +3746,7 @@ ${G} = {
|
|
|
3407
3746
|
modules = {},
|
|
3408
3747
|
-- Every array the program made, so \`typeof\` can tell one from an object.
|
|
3409
3748
|
-- The keys are held weakly: being written down keeps no array alive.
|
|
3410
|
-
arrays = setmetatable({}, { __mode = "k" })
|
|
3749
|
+
arrays = setmetatable({}, { __mode = "k" }),${mapping ? `
|
|
3411
3750
|
-- Filled in just before the entry runs: bundle line -> { file, line }.
|
|
3412
3751
|
lines = nil,
|
|
3413
3752
|
-- What an error nothing caught says, in the project's files: the bundle's
|
|
@@ -3575,32 +3914,96 @@ ${several ? `
|
|
|
3575
3914
|
end
|
|
3576
3915
|
return mapped .. "\\n" .. table.concat(frames, "\\n")
|
|
3577
3916
|
end,
|
|
3578
|
-
|
|
3917
|
+
-- A line map as it is written: the files it names, and base-64 VLQ
|
|
3918
|
+
-- numbers, three to a line \u2014 how far down the bundle, which file, how far
|
|
3919
|
+
-- down that file, each counted from the line before. It is read out the
|
|
3920
|
+
-- first time a line is looked up, which is when something went wrong.
|
|
3921
|
+
lineMap = function(files, data)
|
|
3922
|
+
local map = {}
|
|
3923
|
+
return setmetatable(map, { __index = function(_, key)
|
|
3924
|
+
setmetatable(map, nil)
|
|
3925
|
+
local digits = {}
|
|
3926
|
+
for i = 1, 64 do
|
|
3927
|
+
digits[("${VLQ_DIGITS}"):byte(i)] = i - 1
|
|
3928
|
+
end
|
|
3929
|
+
local at = 1
|
|
3930
|
+
local function read()
|
|
3931
|
+
local value, scale = 0, 1
|
|
3932
|
+
repeat
|
|
3933
|
+
local digit = digits[data:byte(at)]
|
|
3934
|
+
at = at + 1
|
|
3935
|
+
value = value + digit % 32 * scale
|
|
3936
|
+
scale = scale * 32
|
|
3937
|
+
until digit < 32
|
|
3938
|
+
if value % 2 == 1 then
|
|
3939
|
+
return -math.floor(value / 2)
|
|
3940
|
+
end
|
|
3941
|
+
return math.floor(value / 2)
|
|
3942
|
+
end
|
|
3943
|
+
local line, file, source = 0, 0, 0
|
|
3944
|
+
while at <= #data do
|
|
3945
|
+
line = line + read()
|
|
3946
|
+
file = file + read()
|
|
3947
|
+
source = source + read()
|
|
3948
|
+
map[line] = { files[file], source }
|
|
3949
|
+
end
|
|
3950
|
+
return map[key]
|
|
3951
|
+
end })
|
|
3952
|
+
end,` : ""}
|
|
3953
|
+
records = {},${several && !perFile ? `
|
|
3579
3954
|
-- The file each module outside this one is in, as \`load\` is handed it.
|
|
3580
3955
|
files = { ${files} },
|
|
3581
|
-
loaded = {}
|
|
3956
|
+
loaded = {},` : ""}${several && mapping ? `
|
|
3582
3957
|
-- Every file's line map: by the module, and by the file's name.
|
|
3583
3958
|
maps = {},
|
|
3584
|
-
sources = {}
|
|
3959
|
+
sources = {},` : ""}${several && !perFile ? `
|
|
3585
3960
|
-- Another of the bundle's files: a function that adds its modules here.
|
|
3586
3961
|
load = function(file)
|
|
3587
3962
|
if ${G}.loaded[file] then
|
|
3588
3963
|
return
|
|
3589
3964
|
end
|
|
3590
3965
|
${G}.loaded[file] = true${loader(G, options.byPath)}
|
|
3966
|
+
end,` : ""}${perFile && mapping ? `
|
|
3967
|
+
-- What a file returns: its module's exports. The first file asked for
|
|
3968
|
+
-- runs under \`xpcall\`, so an error nothing caught is reported in the
|
|
3969
|
+
-- project's files; the files it requires in turn are inside that already.
|
|
3970
|
+
running = false,
|
|
3971
|
+
run = function(name)
|
|
3972
|
+
if ${G}.running then
|
|
3973
|
+
return ${G}.require(name)
|
|
3974
|
+
end
|
|
3975
|
+
${G}.running = true
|
|
3976
|
+
local ok, result = xpcall(${G}.require, ${G}.fail, name)
|
|
3977
|
+
${G}.running = false
|
|
3978
|
+
if not ok then
|
|
3979
|
+
error(result, 0)
|
|
3980
|
+
end
|
|
3981
|
+
return result
|
|
3591
3982
|
end,` : ""}${options.imports ? `
|
|
3592
3983
|
-- \`import("./x")\`: the module's exports, asked for where the code runs
|
|
3593
3984
|
-- rather than before its module does. \`require\` does the rest \u2014 and
|
|
3594
3985
|
-- loads the file the module is in, if it is not this one.
|
|
3595
|
-
import = function(name)
|
|
3596
|
-
return ${G}.require(name)
|
|
3986
|
+
import = function(name${perFile ? ", load" : ""})
|
|
3987
|
+
return ${G}.require(name${perFile ? ", load" : ""})
|
|
3597
3988
|
end,` : ""}
|
|
3598
|
-
require = function(name)
|
|
3989
|
+
require = function(name${perFile ? ", load" : ""})
|
|
3599
3990
|
local record = ${G}.records[name]
|
|
3600
3991
|
if record ~= nil then
|
|
3601
3992
|
return record.exports
|
|
3602
3993
|
end
|
|
3603
|
-
local module = ${G}.modules[name]${
|
|
3994
|
+
local module = ${G}.modules[name]${perFile ? `
|
|
3995
|
+
-- Its file has not run: requiring it adds the module, and runs it.
|
|
3996
|
+
if module == nil and load ~= nil then
|
|
3997
|
+
load()
|
|
3998
|
+
record = ${G}.records[name]
|
|
3999
|
+
if record ~= nil then
|
|
4000
|
+
return record.exports
|
|
4001
|
+
end
|
|
4002
|
+
module = ${G}.modules[name]
|
|
4003
|
+
end
|
|
4004
|
+
if module == nil then
|
|
4005
|
+
error(("Cannot find module '%s': nothing has loaded the file it is in"):format(name), 2)
|
|
4006
|
+
end` : several ? `
|
|
3604
4007
|
if module == nil then
|
|
3605
4008
|
${G}.load(${G}.files[name])
|
|
3606
4009
|
module = ${G}.modules[name]
|
|
@@ -3706,7 +4109,7 @@ var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
|
3706
4109
|
function analyzeModules(modules, config2) {
|
|
3707
4110
|
const out2 = [];
|
|
3708
4111
|
const analyses = /* @__PURE__ */ new Map();
|
|
3709
|
-
const libraries = config2 ? (0, import_parser7.resolveTypeLibraries)(config2) : { files: [], lowerings: [], problems: [] };
|
|
4112
|
+
const libraries = config2 ? (0, import_parser7.resolveTypeLibraries)(config2) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3710
4113
|
for (const p of libraries.problems) out2.push({ file: p.file, message: p.message, line: p.line ?? 1, column: p.column ?? 1, category: "config" });
|
|
3711
4114
|
const libs = libraries.files.map(parsedLibrary);
|
|
3712
4115
|
const noLib = config2?.noLib ?? false;
|
|
@@ -3745,7 +4148,7 @@ function analyzeModules(modules, config2) {
|
|
|
3745
4148
|
const at = d.node;
|
|
3746
4149
|
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type", severity: d.severity });
|
|
3747
4150
|
}
|
|
3748
|
-
const result2 = { types, diagnostics: said };
|
|
4151
|
+
const result2 = { types, diagnostics: said, scopes };
|
|
3749
4152
|
if (partials === before) {
|
|
3750
4153
|
analyzed.set(file, result2);
|
|
3751
4154
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
@@ -3802,7 +4205,16 @@ function analyzeModules(modules, config2) {
|
|
|
3802
4205
|
analyses.set(module2.file, types);
|
|
3803
4206
|
out2.push(...diagnostics);
|
|
3804
4207
|
}
|
|
3805
|
-
|
|
4208
|
+
const exportsOf = (file) => {
|
|
4209
|
+
const cached = exportsCache.get(file);
|
|
4210
|
+
if (cached) return cached;
|
|
4211
|
+
const module2 = byFile.get(file);
|
|
4212
|
+
const { types, scopes } = analyzeModule(file, module2.program);
|
|
4213
|
+
const exports2 = (0, import_parser7.moduleExports)(module2.program, scopes, types, resolverFor(file));
|
|
4214
|
+
exportsCache.set(file, exports2);
|
|
4215
|
+
return exports2;
|
|
4216
|
+
};
|
|
4217
|
+
return { types: analyses, diagnostics: out2, lowerings: [...libraries.lowerings], exportsOf };
|
|
3806
4218
|
}
|
|
3807
4219
|
function allStatements(statements) {
|
|
3808
4220
|
const out2 = [];
|
|
@@ -3822,25 +4234,35 @@ function allStatements(statements) {
|
|
|
3822
4234
|
}
|
|
3823
4235
|
|
|
3824
4236
|
// src/cli.ts
|
|
3825
|
-
var usage = "usage: tilua <entry> [--out <file>] [--output single|chunks|
|
|
4237
|
+
var usage = "usage: tilua [<entry>] [--out <file>] [--output single|chunks|files] [--config <tilua.config.json>] [--noCheck] [--noLineMap] [--minify] [--watch]\n tilua init";
|
|
3826
4238
|
var args = process.argv.slice(2);
|
|
3827
4239
|
var entry;
|
|
3828
4240
|
var out;
|
|
3829
4241
|
var config;
|
|
3830
4242
|
var typeCheck = true;
|
|
4243
|
+
var lineMap;
|
|
4244
|
+
var minify;
|
|
3831
4245
|
var output;
|
|
4246
|
+
var watching = false;
|
|
3832
4247
|
for (let i = 0; i < args.length; i++) {
|
|
3833
4248
|
const arg = args[i];
|
|
3834
4249
|
if (arg === "--out") out = args[++i];
|
|
3835
4250
|
else if (arg === "--config") config = args[++i];
|
|
3836
4251
|
else if (arg === "--noCheck") typeCheck = false;
|
|
4252
|
+
else if (arg === "--noLineMap") lineMap = false;
|
|
4253
|
+
else if (arg === "--minify") minify = true;
|
|
4254
|
+
else if (arg === "--watch" || arg === "-w") watching = true;
|
|
3837
4255
|
else if (arg === "--target") {
|
|
3838
4256
|
console.error(`--target is gone: the output runs on Lua 5.1 to 5.4, LuaJIT and Luau, and a library says what more its Lua has \u2014 add "luau" to the config's 'types'`);
|
|
3839
4257
|
process.exit(2);
|
|
3840
4258
|
} else if (arg === "--output") {
|
|
3841
4259
|
const value = args[++i];
|
|
3842
|
-
if (value
|
|
3843
|
-
console.error(
|
|
4260
|
+
if (value === "modules") {
|
|
4261
|
+
console.error("--output modules is gone: --output files writes one file per module, each of which returns its exports");
|
|
4262
|
+
process.exit(2);
|
|
4263
|
+
}
|
|
4264
|
+
if (value !== "single" && value !== "chunks" && value !== "files") {
|
|
4265
|
+
console.error(`--output must be 'single', 'chunks' or 'files', not '${value}'`);
|
|
3844
4266
|
process.exit(2);
|
|
3845
4267
|
}
|
|
3846
4268
|
output = value;
|
|
@@ -3849,38 +4271,162 @@ for (let i = 0; i < args.length; i++) {
|
|
|
3849
4271
|
process.exit(0);
|
|
3850
4272
|
} else entry = arg;
|
|
3851
4273
|
}
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
process.
|
|
4274
|
+
var shown = (path) => (0, import_node_path3.relative)(process.cwd(), path) || ".";
|
|
4275
|
+
function init() {
|
|
4276
|
+
const folder = process.cwd();
|
|
4277
|
+
for (const name of ["tilua.config.json", "tilua.config.jsonc"]) {
|
|
4278
|
+
if ((0, import_node_fs4.existsSync)((0, import_node_path3.join)(folder, name))) {
|
|
4279
|
+
console.error(`${name} is already here`);
|
|
4280
|
+
process.exit(1);
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
let rootDir = "src";
|
|
4284
|
+
const project = (0, import_node_path3.join)(folder, "default.project.json");
|
|
4285
|
+
if ((0, import_node_fs4.existsSync)(project)) {
|
|
4286
|
+
const paths = [];
|
|
4287
|
+
const walk2 = (node) => {
|
|
4288
|
+
if (!node || typeof node !== "object") return;
|
|
4289
|
+
const path = node.$path;
|
|
4290
|
+
const named = typeof path === "string" ? path : path?.optional;
|
|
4291
|
+
if (typeof named === "string" && !/\.\w+$/.test(named)) paths.push(named);
|
|
4292
|
+
for (const [key, child] of Object.entries(node)) if (!key.startsWith("$")) walk2(child);
|
|
4293
|
+
};
|
|
4294
|
+
try {
|
|
4295
|
+
walk2(JSON.parse((0, import_node_fs4.readFileSync)(project, "utf8")).tree);
|
|
4296
|
+
} catch (error) {
|
|
4297
|
+
console.error(`default.project.json: ${error.message}`);
|
|
4298
|
+
process.exit(1);
|
|
4299
|
+
}
|
|
4300
|
+
const split = paths.map((path) => path.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "").split("/"));
|
|
4301
|
+
const shared = [];
|
|
4302
|
+
for (let i = 0; split.length && split.every((parts) => parts.length > i && parts[i] === split[0][i]); i++) shared.push(split[0][i]);
|
|
4303
|
+
if (split.length) rootDir = shared.join("/") || ".";
|
|
4304
|
+
} else {
|
|
4305
|
+
console.error('No default.project.json here: rootDir is "src". Change it if the project reads its files from elsewhere.');
|
|
4306
|
+
}
|
|
4307
|
+
const written = { types: ["roblox"], output: "files", rootDir };
|
|
4308
|
+
(0, import_node_fs4.writeFileSync)((0, import_node_path3.join)(folder, "tilua.config.json"), JSON.stringify(written, null, 4) + "\n");
|
|
4309
|
+
console.log("tilua.config.json: a .luau beside each .tilua under " + rootDir);
|
|
4310
|
+
console.log("Next: npm i -D @tilua/compiler @tilua-types/roblox, then run `npx tilua --watch` beside `rojo serve`.");
|
|
4311
|
+
process.exit(0);
|
|
4312
|
+
}
|
|
4313
|
+
function writtenByTilua(folder) {
|
|
4314
|
+
const found = [];
|
|
4315
|
+
const walk2 = (at) => {
|
|
4316
|
+
let items;
|
|
4317
|
+
try {
|
|
4318
|
+
items = (0, import_node_fs4.readdirSync)(at, { withFileTypes: true });
|
|
4319
|
+
} catch {
|
|
4320
|
+
return;
|
|
4321
|
+
}
|
|
4322
|
+
for (const item of items) {
|
|
4323
|
+
if (item.name.startsWith(".") || item.name === "node_modules") continue;
|
|
4324
|
+
const path = (0, import_node_path3.join)(at, item.name);
|
|
4325
|
+
if (item.isDirectory()) walk2(path);
|
|
4326
|
+
else if (/\.luau?$/.test(item.name) && isTilua(path)) found.push(path);
|
|
4327
|
+
}
|
|
4328
|
+
};
|
|
4329
|
+
walk2(folder);
|
|
4330
|
+
return found;
|
|
4331
|
+
}
|
|
4332
|
+
function isTilua(path) {
|
|
4333
|
+
try {
|
|
4334
|
+
const text = (0, import_node_fs4.readFileSync)(path, "utf8").trimEnd();
|
|
4335
|
+
return text.slice(text.lastIndexOf("\n") + 1).startsWith(WRITTEN_BY_TILUA);
|
|
4336
|
+
} catch {
|
|
4337
|
+
return false;
|
|
4338
|
+
}
|
|
3855
4339
|
}
|
|
3856
|
-
async function
|
|
3857
|
-
const found = resolveConfig(config, (0, import_node_path3.resolve)(from)).config;
|
|
4340
|
+
async function build(from) {
|
|
4341
|
+
const found = resolveConfig(config, (0, import_node_path3.resolve)(from ?? "tilua.config.json")).config;
|
|
3858
4342
|
const mode = output ?? found?.output ?? "single";
|
|
3859
|
-
|
|
3860
|
-
|
|
4343
|
+
if (mode !== "files" && from === void 0) {
|
|
4344
|
+
console.error(usage);
|
|
4345
|
+
process.exit(2);
|
|
4346
|
+
}
|
|
4347
|
+
const perFile = mode === "files";
|
|
4348
|
+
const entryFile = perFile || from === void 0 ? void 0 : out ?? from.replace(/\.tilua$/, "") + ".luau";
|
|
4349
|
+
const folder = (0, import_node_path3.resolve)(entryFile !== void 0 ? (0, import_node_path3.dirname)(entryFile) : out ?? found?.outDir ?? process.cwd());
|
|
3861
4350
|
const result2 = await bundle({
|
|
3862
|
-
entry: from,
|
|
4351
|
+
entry: perFile ? void 0 : from,
|
|
3863
4352
|
config,
|
|
3864
4353
|
typeCheck,
|
|
3865
4354
|
output: mode,
|
|
4355
|
+
lineMap,
|
|
4356
|
+
minify,
|
|
4357
|
+
outDir: perFile ? out : void 0,
|
|
3866
4358
|
outFile: entryFile !== void 0 ? (0, import_node_path3.basename)(entryFile) : void 0
|
|
3867
4359
|
});
|
|
3868
4360
|
for (const d of result2.diagnostics) {
|
|
3869
|
-
console.error(`${(
|
|
4361
|
+
console.error(`${shown(d.file)}:${d.line}:${d.column} ${d.severity === "warning" ? "warning: " : ""}${d.message}`);
|
|
3870
4362
|
}
|
|
3871
4363
|
if (result2.code === void 0) {
|
|
3872
|
-
console.error("no
|
|
3873
|
-
|
|
3874
|
-
}
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
4364
|
+
console.error("no output written");
|
|
4365
|
+
return false;
|
|
4366
|
+
}
|
|
4367
|
+
const targets = result2.files.map((file) => ({ ...file, target: (0, import_node_path3.join)(folder, file.path) }));
|
|
4368
|
+
if (perFile) {
|
|
4369
|
+
const theirs = targets.filter((file) => (0, import_node_fs4.existsSync)(file.target) && !isTilua(file.target));
|
|
4370
|
+
for (const file of theirs) {
|
|
4371
|
+
console.error(`${shown(file.target)}: this file was not written by tilua, and a .tilua would replace it \u2014 rename or remove one of them`);
|
|
4372
|
+
}
|
|
4373
|
+
if (theirs.length) return false;
|
|
4374
|
+
}
|
|
4375
|
+
for (const file of targets) {
|
|
4376
|
+
if ((0, import_node_fs4.existsSync)(file.target) && (0, import_node_fs4.readFileSync)(file.target, "utf8") === file.code) continue;
|
|
4377
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(file.target), { recursive: true });
|
|
4378
|
+
(0, import_node_fs4.writeFileSync)(file.target, file.code);
|
|
4379
|
+
console.log(`${shown(file.target)}: ${file.modules.length} module${file.modules.length === 1 ? "" : "s"}`);
|
|
4380
|
+
}
|
|
4381
|
+
if (perFile) {
|
|
4382
|
+
const kept = new Set(targets.map((file) => (0, import_node_path3.resolve)(file.target)));
|
|
4383
|
+
for (const stale of writtenByTilua(folder)) {
|
|
4384
|
+
if (kept.has((0, import_node_path3.resolve)(stale))) continue;
|
|
4385
|
+
(0, import_node_fs4.rmSync)(stale);
|
|
4386
|
+
console.log(`${shown(stale)}: removed, its .tilua is gone`);
|
|
4387
|
+
}
|
|
3880
4388
|
}
|
|
3881
|
-
|
|
4389
|
+
return !result2.diagnostics.some((d) => d.severity !== "warning");
|
|
4390
|
+
}
|
|
4391
|
+
async function watchAndBuild(from) {
|
|
4392
|
+
const found = resolveConfig(config, (0, import_node_path3.resolve)(from ?? "tilua.config.json")).config;
|
|
4393
|
+
const folder = found?.directory ?? (from !== void 0 ? (0, import_node_path3.dirname)((0, import_node_path3.resolve)(from)) : process.cwd());
|
|
4394
|
+
let running = false;
|
|
4395
|
+
let again = false;
|
|
4396
|
+
let timer;
|
|
4397
|
+
const run = async () => {
|
|
4398
|
+
if (running) {
|
|
4399
|
+
again = true;
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
running = true;
|
|
4403
|
+
const ok = await build(from).catch((error) => {
|
|
4404
|
+
console.error(error instanceof Error ? error.message : error);
|
|
4405
|
+
return false;
|
|
4406
|
+
});
|
|
4407
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] ${ok ? "built" : "built with errors"}; watching ${shown(folder)}`);
|
|
4408
|
+
running = false;
|
|
4409
|
+
if (again) {
|
|
4410
|
+
again = false;
|
|
4411
|
+
await run();
|
|
4412
|
+
}
|
|
4413
|
+
};
|
|
4414
|
+
await run();
|
|
4415
|
+
(0, import_node_fs4.watch)(folder, { recursive: true }, (_event, name) => {
|
|
4416
|
+
if (!name) return;
|
|
4417
|
+
const path = name.toString();
|
|
4418
|
+
if (path.split(import_node_path3.sep).includes("node_modules")) return;
|
|
4419
|
+
if (!/\.tilua$|tilua\.config\.jsonc?$|\.project\.json$/.test(path)) return;
|
|
4420
|
+
clearTimeout(timer);
|
|
4421
|
+
timer = setTimeout(() => void run(), 100);
|
|
4422
|
+
});
|
|
4423
|
+
}
|
|
4424
|
+
async function main() {
|
|
4425
|
+
if (entry === "init") init();
|
|
4426
|
+
if (watching) return watchAndBuild(entry);
|
|
4427
|
+
process.exit(await build(entry) ? 0 : 1);
|
|
3882
4428
|
}
|
|
3883
|
-
main(
|
|
4429
|
+
main().catch((error) => {
|
|
3884
4430
|
console.error(error instanceof Error ? error.message : error);
|
|
3885
4431
|
process.exit(1);
|
|
3886
4432
|
});
|