@tilua/compiler 8.1.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 +108 -13
- package/dist/{chunk-WOBHMGGC.js → chunk-VUIF62OE.js} +406 -56
- package/dist/cli.cjs +572 -95
- package/dist/cli.js +156 -24
- package/dist/index.cjs +415 -63
- package/dist/index.d.cts +52 -9
- package/dist/index.d.ts +52 -9
- package/dist/index.js +14 -5
- package/package.json +3 -3
package/dist/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,6 +3083,18 @@ 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+/";
|
|
@@ -3099,6 +3126,34 @@ function lineMapSource(map, unpack) {
|
|
|
3099
3126
|
return `${unpack}({${files.map(import_parser6.luauString).join(",")}},${(0, import_parser6.luauString)(data)})`;
|
|
3100
3127
|
}
|
|
3101
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
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3102
3157
|
// src/lowering.ts
|
|
3103
3158
|
var import_node_url = require("url");
|
|
3104
3159
|
async function loadLowerings(modules) {
|
|
@@ -3115,7 +3170,7 @@ async function loadLowerings(modules) {
|
|
|
3115
3170
|
});
|
|
3116
3171
|
continue;
|
|
3117
3172
|
}
|
|
3118
|
-
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library });
|
|
3173
|
+
lowerings.push({ plugin: plugin3, from: module2.from, library: module2.library, options: module2.options });
|
|
3119
3174
|
} catch (error) {
|
|
3120
3175
|
problems.push({
|
|
3121
3176
|
file: module2.file,
|
|
@@ -3127,17 +3182,30 @@ async function loadLowerings(modules) {
|
|
|
3127
3182
|
}
|
|
3128
3183
|
|
|
3129
3184
|
// src/bundle.ts
|
|
3185
|
+
var WRITTEN_BY_TILUA = "-- Written by tilua";
|
|
3130
3186
|
async function bundle(options) {
|
|
3131
|
-
const entry2 = (0, import_node_path2.resolve)(options.entry);
|
|
3132
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");
|
|
3133
3189
|
const inline = options.config !== void 0 && typeof options.config !== "string";
|
|
3134
|
-
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()));
|
|
3135
3191
|
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 ?? 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));
|
|
3137
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');
|
|
3138
3205
|
const sources = /* @__PURE__ */ new Map();
|
|
3139
3206
|
const directives = /* @__PURE__ */ new Map();
|
|
3140
|
-
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) || "."}`);
|
|
3141
3209
|
while (queue.length) {
|
|
3142
3210
|
const file = queue.shift();
|
|
3143
3211
|
if (sources.has(file)) continue;
|
|
@@ -3155,6 +3223,22 @@ async function bundle(options) {
|
|
|
3155
3223
|
if (target && !target.endsWith(".d.tilua")) queue.push(target);
|
|
3156
3224
|
}
|
|
3157
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
|
+
}
|
|
3158
3242
|
const analysis = analyzeModules([...sources.values()], config2);
|
|
3159
3243
|
const { lowerings, problems: loweringProblems } = await loadLowerings(analysis.lowerings);
|
|
3160
3244
|
for (const p of loweringProblems) {
|
|
@@ -3165,24 +3249,61 @@ async function bundle(options) {
|
|
|
3165
3249
|
const G = names.fresh("G");
|
|
3166
3250
|
const requireExpression = member(identifier(G), "require");
|
|
3167
3251
|
const importExpression = member(identifier(G), "import");
|
|
3168
|
-
const mode = options.output ?? config2?.output ?? "single";
|
|
3169
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;
|
|
3170
3289
|
const modules = /* @__PURE__ */ new Map();
|
|
3171
3290
|
const origins = /* @__PURE__ */ new WeakMap();
|
|
3172
3291
|
const shared = new SharedRuntime(names);
|
|
3173
3292
|
const shaking = options.treeShaking ?? config2?.treeShaking ?? false;
|
|
3174
|
-
const
|
|
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);
|
|
3175
3296
|
const resolveIn = (file) => (specifier) => {
|
|
3176
3297
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config2);
|
|
3177
3298
|
return found !== void 0 && sources.has(found) ? found : void 0;
|
|
3178
3299
|
};
|
|
3179
|
-
const shaken = shaking ? treeShake([...sources.values()].map((s) => ({ file: s.file, program: s.program, scopes: s.scopes, resolve: resolveIn(s.file) })), entry2) : void 0;
|
|
3180
|
-
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];
|
|
3181
3302
|
while (pending.length) {
|
|
3182
3303
|
const file = pending.shift();
|
|
3183
3304
|
if (modules.has(file)) continue;
|
|
3184
3305
|
const source = sources.get(file);
|
|
3185
|
-
const
|
|
3306
|
+
const shown2 = (0, import_node_path2.relative)(root, file).replace(/\\/g, "/");
|
|
3186
3307
|
const imports = /* @__PURE__ */ new Set();
|
|
3187
3308
|
const dynamicImports = /* @__PURE__ */ new Set();
|
|
3188
3309
|
const lowered2 = lower(source.program, source.scopes, {
|
|
@@ -3191,7 +3312,7 @@ async function bundle(options) {
|
|
|
3191
3312
|
lowerings,
|
|
3192
3313
|
noLib: config2?.noLib,
|
|
3193
3314
|
source: source.text,
|
|
3194
|
-
file:
|
|
3315
|
+
file: shown2,
|
|
3195
3316
|
shared,
|
|
3196
3317
|
shaken: shaken && {
|
|
3197
3318
|
...shaken.modules.get(file),
|
|
@@ -3213,6 +3334,13 @@ async function bundle(options) {
|
|
|
3213
3334
|
lines: !mapping ? void 0 : mode === "single" ? `${G}.lines` : `${G}.maps[${(0, import_parser7.luauString)(source.name)}]`,
|
|
3214
3335
|
fail: mapping ? `${G}.fail` : void 0,
|
|
3215
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
|
+
},
|
|
3216
3344
|
resolve: (specifier, dynamic) => {
|
|
3217
3345
|
const found = (0, import_parser7.resolveModulePath)(file, specifier, config2);
|
|
3218
3346
|
if (!found || found.endsWith(".d.tilua") || !sources.has(found)) return void 0;
|
|
@@ -3226,7 +3354,7 @@ async function bundle(options) {
|
|
|
3226
3354
|
for (const d of lowered2.diagnostics) diagnostics.push({ file, ...d, category: "module" });
|
|
3227
3355
|
for (const statement of allStatements(lowered2.statements)) {
|
|
3228
3356
|
const line = lowered2.origins.get(statement);
|
|
3229
|
-
if (line !== void 0) origins.set(statement, { file:
|
|
3357
|
+
if (line !== void 0) origins.set(statement, { file: shown2, line });
|
|
3230
3358
|
}
|
|
3231
3359
|
modules.set(file, {
|
|
3232
3360
|
name: source.name,
|
|
@@ -3264,6 +3392,102 @@ async function bundle(options) {
|
|
|
3264
3392
|
return { files: [], modules: moduleNames, diagnostics };
|
|
3265
3393
|
}
|
|
3266
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
|
+
}
|
|
3267
3491
|
const several = mode !== "single";
|
|
3268
3492
|
const layout = layoutOf(mode, modules.get(entry2), lowered, options.outFile);
|
|
3269
3493
|
const usesScriptArgs = lowered.some((m) => m.usesScriptArgs);
|
|
@@ -3271,7 +3495,7 @@ async function bundle(options) {
|
|
|
3271
3495
|
for (const file of layout.slice(1)) {
|
|
3272
3496
|
for (const module2 of file.modules) elsewhere.set(module2.name, loadPath(layout[0].path, file.path, byPath));
|
|
3273
3497
|
}
|
|
3274
|
-
const program2 = (0,
|
|
3498
|
+
const program2 = (0, import_luau_parser3.parse)(runtime(G, {
|
|
3275
3499
|
several,
|
|
3276
3500
|
byPath,
|
|
3277
3501
|
files: elsewhere,
|
|
@@ -3281,8 +3505,8 @@ async function bundle(options) {
|
|
|
3281
3505
|
const assignment = program2.body.statements[1];
|
|
3282
3506
|
if (usesScriptArgs) {
|
|
3283
3507
|
program2.body.statements.unshift(local(["scriptArgs"], [table([{ type: "TableFieldPositional", value: { type: "VarargExpression" } }])]));
|
|
3284
|
-
program2.body.statements.push(...(0,
|
|
3285
|
-
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);
|
|
3286
3510
|
}
|
|
3287
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;
|
|
3288
3512
|
if (!modulesTable) throw new Error("@tilua/compiler: the bundle runtime has no modules table");
|
|
@@ -3295,31 +3519,40 @@ async function bundle(options) {
|
|
|
3295
3519
|
const result2 = names.fresh("result");
|
|
3296
3520
|
const entryName = (0, import_parser7.luauString)(sources.get(entry2).name);
|
|
3297
3521
|
const returnsExports = modules.get(entry2).info.exports;
|
|
3298
|
-
const
|
|
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})`}` : `
|
|
3299
3527
|
local ${ok}, ${result2} = xpcall(function()
|
|
3300
3528
|
return ${G}.require(${entryName})
|
|
3301
3529
|
end, ${G}.fail)
|
|
3302
3530
|
if not ${ok} then
|
|
3303
3531
|
error(${result2}, 0)
|
|
3304
3532
|
end
|
|
3305
|
-
${
|
|
3533
|
+
${declarations}
|
|
3534
|
+
${returned ? `return ${returned.value}` : ""}
|
|
3306
3535
|
`).body.statements;
|
|
3307
3536
|
program2.body.statements.push(...entryStatements);
|
|
3308
|
-
|
|
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();
|
|
3309
3540
|
if (mapping && (map.size || several)) {
|
|
3310
3541
|
const mapStatements = [assign(
|
|
3311
3542
|
[member(identifier(G), "lines")],
|
|
3312
|
-
[(0,
|
|
3543
|
+
[(0, import_luau_parser3.parseExpressionFromSource)(lineMapSource(map, `${G}.lineMap`))]
|
|
3313
3544
|
)];
|
|
3314
3545
|
if (several) mapStatements.push(...mapRegistration(G, layout[0], `${G}.lines`));
|
|
3315
3546
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...mapStatements);
|
|
3316
3547
|
}
|
|
3317
3548
|
program2.body.statements.splice(program2.body.statements.length - entryStatements.length, 0, ...helpers.define);
|
|
3318
|
-
|
|
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) }];
|
|
3319
3552
|
for (const file of layout.slice(1)) {
|
|
3320
3553
|
const fileHelpers = shared.chunk(new Set(file.modules.flatMap((m) => m.shared)));
|
|
3321
3554
|
const body = [...fileHelpers.declare];
|
|
3322
|
-
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);
|
|
3323
3556
|
for (const module2 of file.modules) {
|
|
3324
3557
|
body.push(assign(
|
|
3325
3558
|
[index(member(identifier(G), "modules"), string(module2.name))],
|
|
@@ -3328,14 +3561,34 @@ ${returnsExports ? `return ${result2}` : ""}
|
|
|
3328
3561
|
}
|
|
3329
3562
|
const chunk = program([returns([functionExpression(functionBody([G], body))])]);
|
|
3330
3563
|
if (mapping) {
|
|
3331
|
-
const lines = buildLineMap(chunk, (0,
|
|
3564
|
+
const lines = buildLineMap(chunk, (0, import_luau_parser3.parse)((0, import_luau_parser3.print)(chunk, printing)), origins);
|
|
3332
3565
|
body.push(...mapRegistration(G, file, lineMapSource(lines, `${G}.lineMap`)));
|
|
3333
3566
|
}
|
|
3334
3567
|
body.push(...fileHelpers.define);
|
|
3335
|
-
|
|
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) });
|
|
3336
3571
|
}
|
|
3337
3572
|
return { code: files[0].code, files, modules: moduleNames, diagnostics };
|
|
3338
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
|
+
}
|
|
3339
3592
|
function moduleTable(module2) {
|
|
3340
3593
|
const { names: exported, links, stars } = module2.info;
|
|
3341
3594
|
const fields = [];
|
|
@@ -3355,10 +3608,6 @@ function layoutOf(mode, entry2, modules, outFile) {
|
|
|
3355
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);
|
|
3356
3609
|
const others = modules.filter((m) => m !== entry2);
|
|
3357
3610
|
if (mode === "single") return [{ path: `${entryStem}${extension}`, modules: [entry2, ...others] }];
|
|
3358
|
-
if (mode === "modules") {
|
|
3359
|
-
const pathOf = (m) => `${m.name.split("/").map((part) => part === ".." ? "__" : part).join("/")}${extension}`;
|
|
3360
|
-
return [entry2, ...others].map((m) => ({ path: pathOf(m), modules: [m] }));
|
|
3361
|
-
}
|
|
3362
3611
|
const byName = new Map(modules.map((m) => [m.name, m]));
|
|
3363
3612
|
const reach = (root) => {
|
|
3364
3613
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3394,16 +3643,75 @@ function layoutOf(mode, entry2, modules, outFile) {
|
|
|
3394
3643
|
return files;
|
|
3395
3644
|
}
|
|
3396
3645
|
function loadPath(entryPath, file, byPath) {
|
|
3397
|
-
|
|
3398
|
-
|
|
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);
|
|
3399
3681
|
const bare = path.slice(0, path.length - import_node_path2.posix.extname(path).length);
|
|
3400
3682
|
return bare.startsWith("../") ? bare : `./${bare}`;
|
|
3401
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
|
+
}
|
|
3402
3710
|
function mapRegistration(G, file, map) {
|
|
3403
3711
|
const extension = import_node_path2.posix.extname(file.path);
|
|
3404
3712
|
const parts = file.path.slice(0, file.path.length - extension.length).split(/[/.]/).filter((part) => part !== "");
|
|
3405
3713
|
const entry2 = `${G}.sources[#${G}.sources + 1]`;
|
|
3406
|
-
return (0,
|
|
3714
|
+
return (0, import_luau_parser3.parse)([
|
|
3407
3715
|
`${entry2} = { { ${parts.map(import_parser7.luauString).join(", ")} }, ${map}, ${(0, import_parser7.luauString)(extension.slice(1))} }`,
|
|
3408
3716
|
...file.modules.map((module2) => `${G}.maps[${(0, import_parser7.luauString)(module2.name)}] = ${G}.sources[#${G}.sources][2]`)
|
|
3409
3717
|
].join("\n")).body.statements;
|
|
@@ -3430,6 +3738,7 @@ function loader(G, byPath) {
|
|
|
3430
3738
|
}
|
|
3431
3739
|
function runtime(G, options) {
|
|
3432
3740
|
const { several, mapping } = options;
|
|
3741
|
+
const perFile = options.perFile ?? false;
|
|
3433
3742
|
const files = [...options.files].map(([name, file]) => `[${(0, import_parser7.luauString)(name)}] = ${(0, import_parser7.luauString)(file)}`).join(", ");
|
|
3434
3743
|
return `
|
|
3435
3744
|
local ${G}
|
|
@@ -3641,32 +3950,60 @@ ${several ? `
|
|
|
3641
3950
|
return map[key]
|
|
3642
3951
|
end })
|
|
3643
3952
|
end,` : ""}
|
|
3644
|
-
records = {},${several ? `
|
|
3953
|
+
records = {},${several && !perFile ? `
|
|
3645
3954
|
-- The file each module outside this one is in, as \`load\` is handed it.
|
|
3646
3955
|
files = { ${files} },
|
|
3647
|
-
loaded = {}
|
|
3956
|
+
loaded = {},` : ""}${several && mapping ? `
|
|
3648
3957
|
-- Every file's line map: by the module, and by the file's name.
|
|
3649
3958
|
maps = {},
|
|
3650
|
-
sources = {},` : ""}
|
|
3959
|
+
sources = {},` : ""}${several && !perFile ? `
|
|
3651
3960
|
-- Another of the bundle's files: a function that adds its modules here.
|
|
3652
3961
|
load = function(file)
|
|
3653
3962
|
if ${G}.loaded[file] then
|
|
3654
3963
|
return
|
|
3655
3964
|
end
|
|
3656
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
|
|
3657
3982
|
end,` : ""}${options.imports ? `
|
|
3658
3983
|
-- \`import("./x")\`: the module's exports, asked for where the code runs
|
|
3659
3984
|
-- rather than before its module does. \`require\` does the rest \u2014 and
|
|
3660
3985
|
-- loads the file the module is in, if it is not this one.
|
|
3661
|
-
import = function(name)
|
|
3662
|
-
return ${G}.require(name)
|
|
3986
|
+
import = function(name${perFile ? ", load" : ""})
|
|
3987
|
+
return ${G}.require(name${perFile ? ", load" : ""})
|
|
3663
3988
|
end,` : ""}
|
|
3664
|
-
require = function(name)
|
|
3989
|
+
require = function(name${perFile ? ", load" : ""})
|
|
3665
3990
|
local record = ${G}.records[name]
|
|
3666
3991
|
if record ~= nil then
|
|
3667
3992
|
return record.exports
|
|
3668
3993
|
end
|
|
3669
|
-
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 ? `
|
|
3670
4007
|
if module == nil then
|
|
3671
4008
|
${G}.load(${G}.files[name])
|
|
3672
4009
|
module = ${G}.modules[name]
|
|
@@ -3772,7 +4109,7 @@ var moduleAnalyses = /* @__PURE__ */ new Map();
|
|
|
3772
4109
|
function analyzeModules(modules, config2) {
|
|
3773
4110
|
const out2 = [];
|
|
3774
4111
|
const analyses = /* @__PURE__ */ new Map();
|
|
3775
|
-
const libraries = config2 ? (0, import_parser7.resolveTypeLibraries)(config2) : { files: [], lowerings: [], problems: [] };
|
|
4112
|
+
const libraries = config2 ? (0, import_parser7.resolveTypeLibraries)(config2) : { files: [], lowerings: [], options: [], problems: [] };
|
|
3776
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" });
|
|
3777
4114
|
const libs = libraries.files.map(parsedLibrary);
|
|
3778
4115
|
const noLib = config2?.noLib ?? false;
|
|
@@ -3811,7 +4148,7 @@ function analyzeModules(modules, config2) {
|
|
|
3811
4148
|
const at = d.node;
|
|
3812
4149
|
said.push({ file, message: d.message, line: at.line.start, column: at.column.start, category: "type", severity: d.severity });
|
|
3813
4150
|
}
|
|
3814
|
-
const result2 = { types, diagnostics: said };
|
|
4151
|
+
const result2 = { types, diagnostics: said, scopes };
|
|
3815
4152
|
if (partials === before) {
|
|
3816
4153
|
analyzed.set(file, result2);
|
|
3817
4154
|
const read3 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
|
|
@@ -3868,7 +4205,16 @@ function analyzeModules(modules, config2) {
|
|
|
3868
4205
|
analyses.set(module2.file, types);
|
|
3869
4206
|
out2.push(...diagnostics);
|
|
3870
4207
|
}
|
|
3871
|
-
|
|
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 };
|
|
3872
4218
|
}
|
|
3873
4219
|
function allStatements(statements) {
|
|
3874
4220
|
const out2 = [];
|
|
@@ -3888,27 +4234,35 @@ function allStatements(statements) {
|
|
|
3888
4234
|
}
|
|
3889
4235
|
|
|
3890
4236
|
// src/cli.ts
|
|
3891
|
-
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";
|
|
3892
4238
|
var args = process.argv.slice(2);
|
|
3893
4239
|
var entry;
|
|
3894
4240
|
var out;
|
|
3895
4241
|
var config;
|
|
3896
4242
|
var typeCheck = true;
|
|
3897
4243
|
var lineMap;
|
|
4244
|
+
var minify;
|
|
3898
4245
|
var output;
|
|
4246
|
+
var watching = false;
|
|
3899
4247
|
for (let i = 0; i < args.length; i++) {
|
|
3900
4248
|
const arg = args[i];
|
|
3901
4249
|
if (arg === "--out") out = args[++i];
|
|
3902
4250
|
else if (arg === "--config") config = args[++i];
|
|
3903
4251
|
else if (arg === "--noCheck") typeCheck = false;
|
|
3904
4252
|
else if (arg === "--noLineMap") lineMap = false;
|
|
4253
|
+
else if (arg === "--minify") minify = true;
|
|
4254
|
+
else if (arg === "--watch" || arg === "-w") watching = true;
|
|
3905
4255
|
else if (arg === "--target") {
|
|
3906
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'`);
|
|
3907
4257
|
process.exit(2);
|
|
3908
4258
|
} else if (arg === "--output") {
|
|
3909
4259
|
const value = args[++i];
|
|
3910
|
-
if (value
|
|
3911
|
-
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}'`);
|
|
3912
4266
|
process.exit(2);
|
|
3913
4267
|
}
|
|
3914
4268
|
output = value;
|
|
@@ -3917,39 +4271,162 @@ for (let i = 0; i < args.length; i++) {
|
|
|
3917
4271
|
process.exit(0);
|
|
3918
4272
|
} else entry = arg;
|
|
3919
4273
|
}
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
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
|
+
}
|
|
3923
4339
|
}
|
|
3924
|
-
async function
|
|
3925
|
-
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;
|
|
3926
4342
|
const mode = output ?? found?.output ?? "single";
|
|
3927
|
-
|
|
3928
|
-
|
|
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());
|
|
3929
4350
|
const result2 = await bundle({
|
|
3930
|
-
entry: from,
|
|
4351
|
+
entry: perFile ? void 0 : from,
|
|
3931
4352
|
config,
|
|
3932
4353
|
typeCheck,
|
|
3933
4354
|
output: mode,
|
|
3934
4355
|
lineMap,
|
|
4356
|
+
minify,
|
|
4357
|
+
outDir: perFile ? out : void 0,
|
|
3935
4358
|
outFile: entryFile !== void 0 ? (0, import_node_path3.basename)(entryFile) : void 0
|
|
3936
4359
|
});
|
|
3937
4360
|
for (const d of result2.diagnostics) {
|
|
3938
|
-
console.error(`${(
|
|
4361
|
+
console.error(`${shown(d.file)}:${d.line}:${d.column} ${d.severity === "warning" ? "warning: " : ""}${d.message}`);
|
|
3939
4362
|
}
|
|
3940
4363
|
if (result2.code === void 0) {
|
|
3941
|
-
console.error("no
|
|
3942
|
-
|
|
3943
|
-
}
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
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
|
+
}
|
|
3949
4388
|
}
|
|
3950
|
-
|
|
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);
|
|
3951
4428
|
}
|
|
3952
|
-
main(
|
|
4429
|
+
main().catch((error) => {
|
|
3953
4430
|
console.error(error instanceof Error ? error.message : error);
|
|
3954
4431
|
process.exit(1);
|
|
3955
4432
|
});
|