@thigasdevelopment/luam 0.19.6 → 0.19.10
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/luam.mjs +1556 -369
- package/package.json +1 -1
package/luam.mjs
CHANGED
|
@@ -431,7 +431,7 @@ var require_help = __commonJS({
|
|
|
431
431
|
if (option.argChoices) {
|
|
432
432
|
extraInfo.push(
|
|
433
433
|
// use stringify to match the display of the default value
|
|
434
|
-
`choices: ${option.argChoices.map((
|
|
434
|
+
`choices: ${option.argChoices.map((choice2) => JSON.stringify(choice2)).join(", ")}`
|
|
435
435
|
);
|
|
436
436
|
}
|
|
437
437
|
if (option.defaultValue !== void 0) {
|
|
@@ -464,7 +464,7 @@ var require_help = __commonJS({
|
|
|
464
464
|
if (argument.argChoices) {
|
|
465
465
|
extraInfo.push(
|
|
466
466
|
// use stringify to match the display of the default value
|
|
467
|
-
`choices: ${argument.argChoices.map((
|
|
467
|
+
`choices: ${argument.argChoices.map((choice2) => JSON.stringify(choice2)).join(", ")}`
|
|
468
468
|
);
|
|
469
469
|
}
|
|
470
470
|
if (argument.defaultValue !== void 0) {
|
|
@@ -3121,13 +3121,24 @@ function reportAssignedConflict(assigned, fromDirective, mapped, diagnostics) {
|
|
|
3121
3121
|
const message = `${origin} "${assigned}" environment but the directive declares "${fromDirective}". The directive wins.`;
|
|
3122
3122
|
diagnostics.push(createDiagnostic("checker", "env-path-directive-conflict", message, FILE_START, "warning"));
|
|
3123
3123
|
}
|
|
3124
|
-
function
|
|
3124
|
+
function reportLockedConflict(assigned, fromDirective, diagnostics) {
|
|
3125
|
+
const subject = `A library declares this file as "${assigned}" but the directive declares "${fromDirective}"`;
|
|
3126
|
+
const message = `${subject}. A library declares its layout once, in the "luam" field of its "package.json". Remove the directive.`;
|
|
3127
|
+
diagnostics.push(createDiagnostic("checker", "env-library-directive", message, FILE_START));
|
|
3128
|
+
}
|
|
3129
|
+
function resolveEnvironment(filePath, directives, fromMapping = null, locked = false) {
|
|
3125
3130
|
const diagnostics = [];
|
|
3126
3131
|
const fromPath = filePath === null ? null : environmentFromPath(filePath);
|
|
3127
3132
|
const found = collectDirectiveEnvironments(directives);
|
|
3128
3133
|
const fromDirective = found[0] ?? null;
|
|
3129
3134
|
const assigned = fromMapping ?? fromPath;
|
|
3130
3135
|
reportConflictingDirectives(found, diagnostics);
|
|
3136
|
+
if (locked && assigned !== null) {
|
|
3137
|
+
if (fromDirective !== null && fromDirective !== assigned) {
|
|
3138
|
+
reportLockedConflict(assigned, fromDirective, diagnostics);
|
|
3139
|
+
}
|
|
3140
|
+
return { environment: assigned, fromPath, fromMapping, fromDirective, diagnostics };
|
|
3141
|
+
}
|
|
3131
3142
|
if (assigned !== null && fromDirective !== null) {
|
|
3132
3143
|
reportAssignedConflict(assigned, fromDirective, fromMapping !== null, diagnostics);
|
|
3133
3144
|
}
|
|
@@ -4449,8 +4460,8 @@ function parseSuffixed(stream) {
|
|
|
4449
4460
|
}
|
|
4450
4461
|
function parseUnary(stream) {
|
|
4451
4462
|
const token = stream.current();
|
|
4452
|
-
const
|
|
4453
|
-
if (!
|
|
4463
|
+
const isUnary2 = (token.kind === "operator" || token.kind === "keyword") && UNARY_OPERATORS.has(token.value);
|
|
4464
|
+
if (!isUnary2) {
|
|
4454
4465
|
return parseSuffixed(stream);
|
|
4455
4466
|
}
|
|
4456
4467
|
stream.next();
|
|
@@ -5175,6 +5186,8 @@ var ESCAPING_PATH = "config-escaping-path";
|
|
|
5175
5186
|
var UNKNOWN_HELPER = "config-unknown-helper";
|
|
5176
5187
|
var INVALID_PATTERN = "config-invalid-pattern";
|
|
5177
5188
|
var INVALID_DEPENDENCY = "config-invalid-dependency";
|
|
5189
|
+
var INVALID_LIBRARY = "config-library-invalid";
|
|
5190
|
+
var DUPLICATE_LIBRARY = "config-library-duplicate";
|
|
5178
5191
|
var INVALID_ENGINE_VERSION = "config-invalid-engine-version";
|
|
5179
5192
|
var REMOVED_FIELD = "config-removed-field";
|
|
5180
5193
|
var ALLOWED_STATEMENTS = 'A manifest holds only "local" declarations and assignments to configuration fields.';
|
|
@@ -5802,6 +5815,12 @@ var MANIFEST_FIELDS = [
|
|
|
5802
5815
|
owner: "dependencies",
|
|
5803
5816
|
allowEmpty: true
|
|
5804
5817
|
}),
|
|
5818
|
+
field("libraries", STRING_LIST, "Luam library packages compiled into the resource, in the order they are emitted.", {
|
|
5819
|
+
defaultValue: [],
|
|
5820
|
+
rule: "package-name",
|
|
5821
|
+
owner: "libraries",
|
|
5822
|
+
allowEmpty: true
|
|
5823
|
+
}),
|
|
5805
5824
|
field("contracts", STRING_TYPE, "Directory the export contract is written to and dependency contracts are read from.", {
|
|
5806
5825
|
defaultValue: DEFAULT_CONTRACTS_DIR,
|
|
5807
5826
|
rule: "contained-path",
|
|
@@ -5966,8 +5985,8 @@ function isNumber(type) {
|
|
|
5966
5985
|
function isText(type) {
|
|
5967
5986
|
return type.kind === "string" || type.kind === "string-literal" || type.kind === "any";
|
|
5968
5987
|
}
|
|
5969
|
-
function fail(operator, expected, left, right,
|
|
5970
|
-
const culprit =
|
|
5988
|
+
function fail(operator, expected, left, right, describe3) {
|
|
5989
|
+
const culprit = describe3(isNumber(left) || isText(left) ? right : left);
|
|
5971
5990
|
return { evaluated: null, error: `"${operator}" expects ${expected} on both sides but received ${culprit}.` };
|
|
5972
5991
|
}
|
|
5973
5992
|
function arithmetic(operator, left, right) {
|
|
@@ -6006,22 +6025,22 @@ function applyOr(left, right) {
|
|
|
6006
6025
|
const value = isTruthy(left.value) ? left.value : right.value;
|
|
6007
6026
|
return { value, type: unionOf([left.truthy, right.type]), truthy: unionOf([left.truthy, right.truthy]), falsy: right.falsy };
|
|
6008
6027
|
}
|
|
6009
|
-
function applyOrdering(operator, left, right,
|
|
6028
|
+
function applyOrdering(operator, left, right, describe3) {
|
|
6010
6029
|
const numeric = isNumber(left.type) && isNumber(right.type);
|
|
6011
6030
|
const textual = isText(left.type) && isText(right.type);
|
|
6012
6031
|
if (!numeric && !textual) {
|
|
6013
|
-
return fail(operator, "two numbers or two strings", left.type, right.type,
|
|
6032
|
+
return fail(operator, "two numbers or two strings", left.type, right.type, describe3);
|
|
6014
6033
|
}
|
|
6015
6034
|
return { evaluated: booleanValue(compare(operator, left.value, right.value)), error: null };
|
|
6016
6035
|
}
|
|
6017
|
-
function applyConcat(left, right,
|
|
6036
|
+
function applyConcat(left, right, describe3) {
|
|
6018
6037
|
const usable = (type) => isText(type) || isNumber(type);
|
|
6019
6038
|
if (!usable(left.type) || !usable(right.type)) {
|
|
6020
|
-
return fail("..", "a string or a number", left.type, right.type,
|
|
6039
|
+
return fail("..", "a string or a number", left.type, right.type, describe3);
|
|
6021
6040
|
}
|
|
6022
6041
|
return { evaluated: stringValue(`${left.value}${right.value}`), error: null };
|
|
6023
6042
|
}
|
|
6024
|
-
function applyBinary(operator, left, right,
|
|
6043
|
+
function applyBinary(operator, left, right, describe3) {
|
|
6025
6044
|
if (operator === "and") {
|
|
6026
6045
|
return { evaluated: applyAnd(left, right), error: null };
|
|
6027
6046
|
}
|
|
@@ -6033,23 +6052,23 @@ function applyBinary(operator, left, right, describe2) {
|
|
|
6033
6052
|
return { evaluated: booleanValue(operator === "==" ? same : !same), error: null };
|
|
6034
6053
|
}
|
|
6035
6054
|
if (ORDERING.includes(operator)) {
|
|
6036
|
-
return applyOrdering(operator, left, right,
|
|
6055
|
+
return applyOrdering(operator, left, right, describe3);
|
|
6037
6056
|
}
|
|
6038
6057
|
if (operator === "..") {
|
|
6039
|
-
return applyConcat(left, right,
|
|
6058
|
+
return applyConcat(left, right, describe3);
|
|
6040
6059
|
}
|
|
6041
6060
|
if (!isNumber(left.type) || !isNumber(right.type)) {
|
|
6042
|
-
return fail(operator, "a number", left.type, right.type,
|
|
6061
|
+
return fail(operator, "a number", left.type, right.type, describe3);
|
|
6043
6062
|
}
|
|
6044
6063
|
return { evaluated: numberValue(arithmetic(operator, left.value, right.value)), error: null };
|
|
6045
6064
|
}
|
|
6046
|
-
function applyUnary(operator, operand,
|
|
6065
|
+
function applyUnary(operator, operand, describe3) {
|
|
6047
6066
|
if (operator === "not") {
|
|
6048
6067
|
return { evaluated: booleanValue(!isTruthy(operand.value)), error: null };
|
|
6049
6068
|
}
|
|
6050
6069
|
if (operator === "-") {
|
|
6051
6070
|
if (!isNumber(operand.type)) {
|
|
6052
|
-
return { evaluated: null, error: `"-" expects a number but received ${
|
|
6071
|
+
return { evaluated: null, error: `"-" expects a number but received ${describe3(operand.type)}.` };
|
|
6053
6072
|
}
|
|
6054
6073
|
return { evaluated: numberValue(-operand.value), error: null };
|
|
6055
6074
|
}
|
|
@@ -6385,6 +6404,130 @@ function watchRoots(patterns) {
|
|
|
6385
6404
|
return roots.filter((root) => !roots.some((other) => other.length < root.length && root.startsWith(`${other}/`)));
|
|
6386
6405
|
}
|
|
6387
6406
|
|
|
6407
|
+
// ../compiler/src/project/library.ts
|
|
6408
|
+
function compareLibraryOrigins(left, right) {
|
|
6409
|
+
return left.packageIndex - right.packageIndex || left.index - right.index;
|
|
6410
|
+
}
|
|
6411
|
+
var LIBRARIES_DIRECTORY = "libs";
|
|
6412
|
+
var LIBRARY_FIELD = "luam";
|
|
6413
|
+
var MISSING_LIBRARY = "config-library-missing";
|
|
6414
|
+
var INVALID_LIBRARY2 = "config-library-invalid";
|
|
6415
|
+
var ESCAPING_LIBRARY = "config-library-escape";
|
|
6416
|
+
var MISSING_REQUIREMENT = "config-library-requirement-missing";
|
|
6417
|
+
var PACKAGE_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
6418
|
+
var SHAPE = `"${LIBRARY_FIELD}" must be a table with "sources" naming patterns per side and an optional "requires" list.`;
|
|
6419
|
+
function isPackageName(value) {
|
|
6420
|
+
return PACKAGE_NAME.test(value);
|
|
6421
|
+
}
|
|
6422
|
+
function libraryDirectory(name) {
|
|
6423
|
+
return name.replace(/^@/, "").replace(/\//g, "-");
|
|
6424
|
+
}
|
|
6425
|
+
function libraryFilePath(name, relativePath2) {
|
|
6426
|
+
return `${name}/${normalizePattern(relativePath2)}`;
|
|
6427
|
+
}
|
|
6428
|
+
function libraryOutputPath(name, environment, relativePath2) {
|
|
6429
|
+
const file = normalizePattern(relativePath2).replace(/\.luam$/, ".lua");
|
|
6430
|
+
return `${LIBRARIES_DIRECTORY}/${libraryDirectory(name)}/${environment}/${file}`;
|
|
6431
|
+
}
|
|
6432
|
+
function installCommand(name) {
|
|
6433
|
+
return `npm install ${name}`;
|
|
6434
|
+
}
|
|
6435
|
+
function isRecord(value) {
|
|
6436
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6437
|
+
}
|
|
6438
|
+
function stringList(value) {
|
|
6439
|
+
if (!Array.isArray(value)) {
|
|
6440
|
+
return null;
|
|
6441
|
+
}
|
|
6442
|
+
return value.every((entry) => typeof entry === "string") ? [...value] : null;
|
|
6443
|
+
}
|
|
6444
|
+
function patternProblems(name, environment, patterns, problems) {
|
|
6445
|
+
for (const pattern of patterns) {
|
|
6446
|
+
const problem = patternProblem(pattern);
|
|
6447
|
+
if (problem === null) {
|
|
6448
|
+
continue;
|
|
6449
|
+
}
|
|
6450
|
+
const code = problem === "absolute" || problem === "traversal" ? ESCAPING_LIBRARY : INVALID_LIBRARY2;
|
|
6451
|
+
const subject = `"${name}" declares the "${environment}" pattern "${pattern}", which ${patternProblemText(problem)}`;
|
|
6452
|
+
problems.push({ code, message: `${subject}. Every pattern stays inside the package directory.` });
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6455
|
+
function readSources(name, value, problems) {
|
|
6456
|
+
if (!isRecord(value)) {
|
|
6457
|
+
problems.push({ code: INVALID_LIBRARY2, message: `"${name}" declares no "sources" table in its "${LIBRARY_FIELD}" field. ${SHAPE}` });
|
|
6458
|
+
return null;
|
|
6459
|
+
}
|
|
6460
|
+
const mapping = emptySourceMapping();
|
|
6461
|
+
for (const environment of SOURCE_SIDES) {
|
|
6462
|
+
const declared = value[environment];
|
|
6463
|
+
if (declared === void 0) {
|
|
6464
|
+
continue;
|
|
6465
|
+
}
|
|
6466
|
+
const patterns = stringList(declared);
|
|
6467
|
+
if (patterns === null) {
|
|
6468
|
+
problems.push({ code: INVALID_LIBRARY2, message: `"${name}" declares "sources.${environment}" as something other than a list of patterns. ${SHAPE}` });
|
|
6469
|
+
continue;
|
|
6470
|
+
}
|
|
6471
|
+
patternProblems(name, environment, patterns, problems);
|
|
6472
|
+
mapping[environment] = patterns.map(normalizePattern);
|
|
6473
|
+
}
|
|
6474
|
+
if (SOURCE_SIDES.every((environment) => mapping[environment].length === 0)) {
|
|
6475
|
+
problems.push({ code: INVALID_LIBRARY2, message: `"${name}" declares no source patterns for any side. ${SHAPE}` });
|
|
6476
|
+
return null;
|
|
6477
|
+
}
|
|
6478
|
+
return mapping;
|
|
6479
|
+
}
|
|
6480
|
+
function readRequires(name, value, problems) {
|
|
6481
|
+
if (value === void 0) {
|
|
6482
|
+
return [];
|
|
6483
|
+
}
|
|
6484
|
+
const requires = stringList(value);
|
|
6485
|
+
if (requires === null) {
|
|
6486
|
+
problems.push({ code: INVALID_LIBRARY2, message: `"${name}" declares "requires" as something other than a list of package names. ${SHAPE}` });
|
|
6487
|
+
return [];
|
|
6488
|
+
}
|
|
6489
|
+
for (const entry of requires) {
|
|
6490
|
+
if (!isPackageName(entry)) {
|
|
6491
|
+
problems.push({ code: INVALID_LIBRARY2, message: `"${name}" requires "${entry}", which is not a package name.` });
|
|
6492
|
+
}
|
|
6493
|
+
}
|
|
6494
|
+
return requires.filter(isPackageName);
|
|
6495
|
+
}
|
|
6496
|
+
function readLibraryDeclaration(name, manifest) {
|
|
6497
|
+
const problems = [];
|
|
6498
|
+
if (!isRecord(manifest)) {
|
|
6499
|
+
return { declaration: null, problems: [{ code: INVALID_LIBRARY2, message: `"${name}" has an unreadable "package.json". ${SHAPE}` }] };
|
|
6500
|
+
}
|
|
6501
|
+
const field2 = manifest[LIBRARY_FIELD];
|
|
6502
|
+
if (field2 === void 0) {
|
|
6503
|
+
const message = `"${name}" is listed in "libraries" but its "package.json" declares no "${LIBRARY_FIELD}" field, so it is not a Luam library.`;
|
|
6504
|
+
return { declaration: null, problems: [{ code: INVALID_LIBRARY2, message }] };
|
|
6505
|
+
}
|
|
6506
|
+
if (!isRecord(field2)) {
|
|
6507
|
+
return { declaration: null, problems: [{ code: INVALID_LIBRARY2, message: `"${name}" declares a "${LIBRARY_FIELD}" field that is not a table. ${SHAPE}` }] };
|
|
6508
|
+
}
|
|
6509
|
+
const sources = readSources(name, field2.sources, problems);
|
|
6510
|
+
const requires = readRequires(name, field2.requires, problems);
|
|
6511
|
+
if (sources === null) {
|
|
6512
|
+
return { declaration: null, problems };
|
|
6513
|
+
}
|
|
6514
|
+
return { declaration: { name, sources, requires }, problems };
|
|
6515
|
+
}
|
|
6516
|
+
function missingRequirements(declarations) {
|
|
6517
|
+
const listed = new Set(declarations.map((declaration) => declaration.name));
|
|
6518
|
+
const problems = [];
|
|
6519
|
+
for (const declaration of declarations) {
|
|
6520
|
+
for (const required of declaration.requires) {
|
|
6521
|
+
if (listed.has(required)) {
|
|
6522
|
+
continue;
|
|
6523
|
+
}
|
|
6524
|
+
const subject = `"${declaration.name}" requires "${required}", which "libraries" does not list`;
|
|
6525
|
+
problems.push({ code: MISSING_REQUIREMENT, message: `${subject}. Add it to "libraries" and install it with "${installCommand(required)}".` });
|
|
6526
|
+
}
|
|
6527
|
+
}
|
|
6528
|
+
return problems;
|
|
6529
|
+
}
|
|
6530
|
+
|
|
6388
6531
|
// ../compiler/src/manifest/manifest-rules.ts
|
|
6389
6532
|
var START = createPosition(1, 1, 0);
|
|
6390
6533
|
var RESOURCE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
@@ -6477,6 +6620,9 @@ var RuleWalk = class {
|
|
|
6477
6620
|
if (entry.rule === "dependency-name" && !isValidResourceName(value)) {
|
|
6478
6621
|
this.report(INVALID_DEPENDENCY, `"${path}" must be a valid MTA resource name but received "${value}".`, key);
|
|
6479
6622
|
}
|
|
6623
|
+
if (entry.rule === "package-name" && !isPackageName(value)) {
|
|
6624
|
+
this.report(INVALID_LIBRARY, `"${path}" must be the name of an installed npm package but received "${value}".`, key);
|
|
6625
|
+
}
|
|
6480
6626
|
}
|
|
6481
6627
|
version(entry, value, path, key) {
|
|
6482
6628
|
if (entry.rule !== "engine-version" || value === LATEST_ENGINE_VERSION || ENGINE_VERSION.test(value)) {
|
|
@@ -6513,6 +6659,7 @@ function normalizeManifest(value, positions) {
|
|
|
6513
6659
|
}
|
|
6514
6660
|
|
|
6515
6661
|
// ../compiler/src/manifest/manifest-analysis.ts
|
|
6662
|
+
var MANIFEST_SCHEMA = { fields: MANIFEST_FIELDS, removed: REMOVED_FIELDS, normalize: normalizeManifest };
|
|
6516
6663
|
var START2 = createPosition(1, 1, 0);
|
|
6517
6664
|
function statementError(kind) {
|
|
6518
6665
|
return `A manifest cannot contain ${kind}. ${ALLOWED_STATEMENTS}`;
|
|
@@ -6542,7 +6689,7 @@ function readLocal(pass, statement) {
|
|
|
6542
6689
|
pass.declareLocal(declaration.name, value === void 0 ? nilValue() : pass.evaluate(value, null), declaration.position);
|
|
6543
6690
|
}
|
|
6544
6691
|
}
|
|
6545
|
-
function readAssignment(pass, statement, assignments, value) {
|
|
6692
|
+
function readAssignment(pass, statement, assignments, value, schema) {
|
|
6546
6693
|
const [target] = statement.targets;
|
|
6547
6694
|
const [expression] = statement.values;
|
|
6548
6695
|
if (statement.operator !== "=" || statement.targets.length !== 1 || statement.values.length !== 1 || target === void 0 || expression === void 0) {
|
|
@@ -6553,11 +6700,11 @@ function readAssignment(pass, statement, assignments, value) {
|
|
|
6553
6700
|
pass.report(INVALID_STATEMENT, statementError("an assignment to anything but a configuration field"), target.position);
|
|
6554
6701
|
return;
|
|
6555
6702
|
}
|
|
6556
|
-
const field2 = findField(
|
|
6703
|
+
const field2 = findField(schema.fields, target.name);
|
|
6557
6704
|
if (field2 === null) {
|
|
6558
|
-
const replacement =
|
|
6705
|
+
const replacement = schema.removed[target.name];
|
|
6559
6706
|
if (replacement === void 0) {
|
|
6560
|
-
pass.report(UNKNOWN_FIELD, unknownNameMessage(target.name), target.position);
|
|
6707
|
+
pass.report(UNKNOWN_FIELD, (schema.unknownName ?? unknownNameMessage)(target.name), target.position);
|
|
6561
6708
|
} else {
|
|
6562
6709
|
pass.report(REMOVED_FIELD, `"${target.name}" is no longer a manifest field. ${replacement}`, target.position);
|
|
6563
6710
|
}
|
|
@@ -6566,25 +6713,25 @@ function readAssignment(pass, statement, assignments, value) {
|
|
|
6566
6713
|
assignments.push({ name: target.name, position: target.position, value: expression });
|
|
6567
6714
|
value[target.name] = pass.expression(expression, { field: field2, path: target.name, key: target.name }).value;
|
|
6568
6715
|
}
|
|
6569
|
-
function readStatement(pass, statement, assignments, value) {
|
|
6716
|
+
function readStatement(pass, statement, assignments, value, schema) {
|
|
6570
6717
|
if (statement.kind === "local-statement") {
|
|
6571
6718
|
readLocal(pass, statement);
|
|
6572
6719
|
return;
|
|
6573
6720
|
}
|
|
6574
6721
|
if (statement.kind === "assignment-statement") {
|
|
6575
|
-
readAssignment(pass, statement, assignments, value);
|
|
6722
|
+
readAssignment(pass, statement, assignments, value, schema);
|
|
6576
6723
|
return;
|
|
6577
6724
|
}
|
|
6578
6725
|
pass.report(INVALID_STATEMENT, statementError(STATEMENT_NAMES[statement.kind] ?? "this statement"), statement.position);
|
|
6579
6726
|
}
|
|
6580
|
-
function reportMissing(diagnostics, value) {
|
|
6581
|
-
for (const field2 of requiredFields(
|
|
6727
|
+
function reportMissing(diagnostics, value, schema) {
|
|
6728
|
+
for (const field2 of requiredFields(schema.fields)) {
|
|
6582
6729
|
if (value[field2.name] === void 0) {
|
|
6583
6730
|
diagnostics.push(manifestError(MISSING_FIELD, `The manifest requires a "${field2.name}" field. ${field2.summary}`, START2));
|
|
6584
6731
|
}
|
|
6585
6732
|
}
|
|
6586
6733
|
}
|
|
6587
|
-
function analyzeManifest(source, context) {
|
|
6734
|
+
function analyzeManifest(source, context, schema = MANIFEST_SCHEMA) {
|
|
6588
6735
|
const parsed = parse(source);
|
|
6589
6736
|
const pass = new ManifestPass(context);
|
|
6590
6737
|
const assignments = [];
|
|
@@ -6593,15 +6740,15 @@ function analyzeManifest(source, context) {
|
|
|
6593
6740
|
pass.report(INVALID_STATEMENT, statementError(`the "#!${directive}" directive`), START2);
|
|
6594
6741
|
}
|
|
6595
6742
|
for (const statement of parsed.program.body) {
|
|
6596
|
-
readStatement(pass, statement, assignments, raw);
|
|
6743
|
+
readStatement(pass, statement, assignments, raw, schema);
|
|
6597
6744
|
}
|
|
6598
|
-
reportMissing(pass.diagnostics, raw);
|
|
6745
|
+
reportMissing(pass.diagnostics, raw, schema);
|
|
6599
6746
|
pass.diagnostics.push(...pass.locals.unused());
|
|
6600
|
-
const normalized =
|
|
6747
|
+
const normalized = schema.normalize(raw, pass.positions);
|
|
6601
6748
|
return {
|
|
6602
6749
|
program: parsed.program,
|
|
6603
6750
|
tokens: parsed.tokens,
|
|
6604
|
-
diagnostics: sortDiagnostics([...parsed.diagnostics, ...pass.diagnostics, ...normalized.diagnostics]),
|
|
6751
|
+
diagnostics: sortDiagnostics([...parsed.diagnostics, ...pass.diagnostics, ...normalized.diagnostics]).map(schema.retag ?? ((entry) => entry)),
|
|
6605
6752
|
value: normalized.value,
|
|
6606
6753
|
raw,
|
|
6607
6754
|
positions: pass.positions,
|
|
@@ -6673,6 +6820,9 @@ function readAssetMappings(value) {
|
|
|
6673
6820
|
function readDependencies(value) {
|
|
6674
6821
|
return [...new Set(readStrings(value, "dependencies"))].sort();
|
|
6675
6822
|
}
|
|
6823
|
+
function readLibraries(value) {
|
|
6824
|
+
return readStrings(value, "libraries");
|
|
6825
|
+
}
|
|
6676
6826
|
function readEngine(value) {
|
|
6677
6827
|
const source = readTable(value, "engine") ?? EMPTY;
|
|
6678
6828
|
return { minVersion: readString(source, "minVersion") ?? DEFAULT_ENGINE.minVersion };
|
|
@@ -6732,10 +6882,20 @@ function checkDependencies(name, dependencies, context) {
|
|
|
6732
6882
|
}
|
|
6733
6883
|
}
|
|
6734
6884
|
}
|
|
6885
|
+
function checkLibraries(libraries, context) {
|
|
6886
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6887
|
+
for (const [index, library] of libraries.entries()) {
|
|
6888
|
+
if (seen.has(library)) {
|
|
6889
|
+
context.error(DUPLICATE_LIBRARY, `"libraries" lists "${library}" more than once. Keep one entry.`, `libraries.${index}`);
|
|
6890
|
+
}
|
|
6891
|
+
seen.add(library);
|
|
6892
|
+
}
|
|
6893
|
+
}
|
|
6735
6894
|
function validateConfig(value, positions) {
|
|
6736
6895
|
const context = new ValidationContext(positions);
|
|
6737
6896
|
const name = readString(value, "name") ?? "";
|
|
6738
6897
|
const dependencies = readDependencies(value);
|
|
6898
|
+
const libraries = readLibraries(value);
|
|
6739
6899
|
const config = {
|
|
6740
6900
|
name,
|
|
6741
6901
|
author: readString(value, "author"),
|
|
@@ -6745,6 +6905,7 @@ function validateConfig(value, positions) {
|
|
|
6745
6905
|
sources: readSourceMapping(value),
|
|
6746
6906
|
assets: readAssetMappings(value),
|
|
6747
6907
|
dependencies,
|
|
6908
|
+
libraries,
|
|
6748
6909
|
contracts: readString(value, "contracts") ?? "",
|
|
6749
6910
|
engine: readEngine(value),
|
|
6750
6911
|
environment: readEnvironmentFiles(value),
|
|
@@ -6757,6 +6918,7 @@ function validateConfig(value, positions) {
|
|
|
6757
6918
|
development: readDevelopment(readTable(value, "development"))
|
|
6758
6919
|
};
|
|
6759
6920
|
checkDependencies(name, dependencies, context);
|
|
6921
|
+
checkLibraries(libraries, context);
|
|
6760
6922
|
return { config, diagnostics: context.diagnostics };
|
|
6761
6923
|
}
|
|
6762
6924
|
|
|
@@ -6810,7 +6972,7 @@ import { tmpdir } from "node:os";
|
|
|
6810
6972
|
import { join as join2 } from "node:path";
|
|
6811
6973
|
|
|
6812
6974
|
// src/cli/version.ts
|
|
6813
|
-
var VERSION = true ? "0.19.
|
|
6975
|
+
var VERSION = true ? "0.19.10" : "0.0.0-dev";
|
|
6814
6976
|
var PROGRAM_NAME = "luam";
|
|
6815
6977
|
var PROGRAM_DESCRIPTION = "luam \u2014 the Luam compiler for Multi Theft Auto resources.";
|
|
6816
6978
|
|
|
@@ -7344,6 +7506,9 @@ function manifestOption() {
|
|
|
7344
7506
|
function colorOption() {
|
|
7345
7507
|
return new Option("--no-color", "Print plain output with no colour and no emoji.");
|
|
7346
7508
|
}
|
|
7509
|
+
function jsonOption() {
|
|
7510
|
+
return new Option("--json", "Write one machine-readable document to stdout instead of the human report.");
|
|
7511
|
+
}
|
|
7347
7512
|
function offlineOption() {
|
|
7348
7513
|
return new Option("--offline", "Skip the MTA release lookup and use the cached version, if there is one.");
|
|
7349
7514
|
}
|
|
@@ -7459,15 +7624,15 @@ function knowsResource(contracts, resource) {
|
|
|
7459
7624
|
}
|
|
7460
7625
|
function buildResourceAbi(resource, contributions) {
|
|
7461
7626
|
const exports = contributions.map((contribution) => {
|
|
7462
|
-
const
|
|
7627
|
+
const signature2 = contribution.signature;
|
|
7463
7628
|
return {
|
|
7464
7629
|
name: contribution.name,
|
|
7465
7630
|
side: contribution.side,
|
|
7466
7631
|
http: contribution.http,
|
|
7467
|
-
parameters:
|
|
7468
|
-
minimumArguments:
|
|
7469
|
-
variadic:
|
|
7470
|
-
returns:
|
|
7632
|
+
parameters: signature2?.parameters ?? [],
|
|
7633
|
+
minimumArguments: signature2?.minimumArguments ?? 0,
|
|
7634
|
+
variadic: signature2?.variadic ?? true,
|
|
7635
|
+
returns: signature2?.returns ?? "any"
|
|
7471
7636
|
};
|
|
7472
7637
|
});
|
|
7473
7638
|
return { abi: ABI_VERSION, resource, exports };
|
|
@@ -7524,6 +7689,175 @@ function readHelperSource(helper, file) {
|
|
|
7524
7689
|
return readFileSync4(resolveHelperPath(helper, file), "utf8");
|
|
7525
7690
|
}
|
|
7526
7691
|
|
|
7692
|
+
// src/build/library-resolution.ts
|
|
7693
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
7694
|
+
import { resolve as resolve6 } from "node:path";
|
|
7695
|
+
|
|
7696
|
+
// src/build/project-files.ts
|
|
7697
|
+
import { readdirSync, statSync as statSync2 } from "node:fs";
|
|
7698
|
+
import { join as join3, relative, resolve as resolve5 } from "node:path";
|
|
7699
|
+
function isDirectory(path) {
|
|
7700
|
+
try {
|
|
7701
|
+
return statSync2(path).isDirectory();
|
|
7702
|
+
} catch {
|
|
7703
|
+
return false;
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
function relativePath(root, absolute) {
|
|
7707
|
+
return normalizePattern(relative(root, absolute));
|
|
7708
|
+
}
|
|
7709
|
+
function walk(root, directory, excluded, tree) {
|
|
7710
|
+
let entries3;
|
|
7711
|
+
try {
|
|
7712
|
+
entries3 = readdirSync(directory, { withFileTypes: true });
|
|
7713
|
+
} catch (error) {
|
|
7714
|
+
tree.errors.push(`"${relativePath(root, directory)}" could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
7715
|
+
return;
|
|
7716
|
+
}
|
|
7717
|
+
for (const entry of entries3) {
|
|
7718
|
+
const absolute = join3(directory, entry.name);
|
|
7719
|
+
const path = relativePath(root, absolute);
|
|
7720
|
+
if (path.length === 0 || isExcludedPath(path, excluded)) {
|
|
7721
|
+
continue;
|
|
7722
|
+
}
|
|
7723
|
+
if (entry.isDirectory()) {
|
|
7724
|
+
walk(root, absolute, excluded, tree);
|
|
7725
|
+
} else if (entry.isFile()) {
|
|
7726
|
+
tree.files.push(path);
|
|
7727
|
+
}
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
function listProjectFiles(root, roots, excluded = []) {
|
|
7731
|
+
const tree = { files: [], errors: [] };
|
|
7732
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7733
|
+
for (const start of [...new Set(roots)].sort()) {
|
|
7734
|
+
const absolute = resolve5(root, start);
|
|
7735
|
+
if (!isDirectory(absolute) || seen.has(absolute)) {
|
|
7736
|
+
continue;
|
|
7737
|
+
}
|
|
7738
|
+
seen.add(absolute);
|
|
7739
|
+
walk(root, absolute, excluded, tree);
|
|
7740
|
+
}
|
|
7741
|
+
return { files: [...new Set(tree.files)].sort(), errors: tree.errors };
|
|
7742
|
+
}
|
|
7743
|
+
|
|
7744
|
+
// ../compiler/src/project/source-kind.ts
|
|
7745
|
+
var SOURCE_EXTENSION = ".luam";
|
|
7746
|
+
var DECLARATION_EXTENSION = ".d.luam";
|
|
7747
|
+
var TEST_EXTENSION = ".test.luam";
|
|
7748
|
+
function isDeclarationPath(path) {
|
|
7749
|
+
return normalizePath(path).endsWith(DECLARATION_EXTENSION);
|
|
7750
|
+
}
|
|
7751
|
+
function isSourcePath(path) {
|
|
7752
|
+
return normalizePath(path).endsWith(SOURCE_EXTENSION);
|
|
7753
|
+
}
|
|
7754
|
+
function isTestPath(path) {
|
|
7755
|
+
return normalizePath(path).endsWith(TEST_EXTENSION);
|
|
7756
|
+
}
|
|
7757
|
+
|
|
7758
|
+
// src/build/library-resolution.ts
|
|
7759
|
+
var LUA_EXTENSION = ".lua";
|
|
7760
|
+
var PACKAGE_MANIFEST = "package.json";
|
|
7761
|
+
var MODULES_DIRECTORY = "node_modules";
|
|
7762
|
+
function packageRoot(root, name) {
|
|
7763
|
+
return resolve6(root, MODULES_DIRECTORY, ...name.split("/"));
|
|
7764
|
+
}
|
|
7765
|
+
function readPackageManifest(path) {
|
|
7766
|
+
try {
|
|
7767
|
+
return JSON.parse(readFileSync5(path, "utf8"));
|
|
7768
|
+
} catch {
|
|
7769
|
+
return null;
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7772
|
+
var SIDE_ORDER = ["shared", "server", "client"];
|
|
7773
|
+
function orderedPatterns(declaration) {
|
|
7774
|
+
return SIDE_ORDER.flatMap((environment) => declaration.sources[environment].map((pattern) => ({ environment, pattern })));
|
|
7775
|
+
}
|
|
7776
|
+
function matchFile(path, patterns) {
|
|
7777
|
+
const order = patterns.findIndex((entry) => matchesPattern(entry.pattern, path));
|
|
7778
|
+
const matched = patterns[order];
|
|
7779
|
+
if (matched === void 0) {
|
|
7780
|
+
return null;
|
|
7781
|
+
}
|
|
7782
|
+
return { relativePath: path, environment: matched.environment, order };
|
|
7783
|
+
}
|
|
7784
|
+
function matchedFiles(root, declaration, diagnostics) {
|
|
7785
|
+
const patterns = orderedPatterns(declaration);
|
|
7786
|
+
const roots = [...new Set(patterns.map((entry) => entry.pattern))];
|
|
7787
|
+
const tree = listProjectFiles(root, watchRoots(roots));
|
|
7788
|
+
const matched = [];
|
|
7789
|
+
for (const path of tree.files) {
|
|
7790
|
+
if (isTestPath(path) || !path.endsWith(SOURCE_EXTENSION) && !path.endsWith(LUA_EXTENSION)) {
|
|
7791
|
+
continue;
|
|
7792
|
+
}
|
|
7793
|
+
const found = matchFile(path, patterns);
|
|
7794
|
+
if (found !== null) {
|
|
7795
|
+
matched.push(found);
|
|
7796
|
+
}
|
|
7797
|
+
}
|
|
7798
|
+
for (const message of tree.errors) {
|
|
7799
|
+
diagnostics.push(cliError(INVALID_LIBRARY2, `"${declaration.name}" could not be read: ${message}`));
|
|
7800
|
+
}
|
|
7801
|
+
return matched.sort((left, right) => left.order - right.order || left.relativePath.localeCompare(right.relativePath));
|
|
7802
|
+
}
|
|
7803
|
+
function readLibraryFile(root, relativePath2, name, diagnostics) {
|
|
7804
|
+
try {
|
|
7805
|
+
return readFileSync5(resolve6(root, relativePath2), "utf8");
|
|
7806
|
+
} catch (error) {
|
|
7807
|
+
const reason2 = error instanceof Error ? error.message : String(error);
|
|
7808
|
+
diagnostics.push(cliError(INVALID_LIBRARY2, `"${libraryFilePath(name, relativePath2)}" could not be read: ${reason2}`));
|
|
7809
|
+
return null;
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7812
|
+
function collectFiles(root, declaration, packageIndex, resolved2) {
|
|
7813
|
+
const matched = matchedFiles(root, declaration, resolved2.diagnostics);
|
|
7814
|
+
for (const [index, entry] of matched.entries()) {
|
|
7815
|
+
const content = readLibraryFile(root, entry.relativePath, declaration.name, resolved2.diagnostics);
|
|
7816
|
+
if (content === null) {
|
|
7817
|
+
continue;
|
|
7818
|
+
}
|
|
7819
|
+
const origin = { package: declaration.name, root, relativePath: entry.relativePath, packageIndex, index };
|
|
7820
|
+
if (entry.relativePath.endsWith(LUA_EXTENSION)) {
|
|
7821
|
+
resolved2.verbatim.push({ origin, environment: entry.environment, content });
|
|
7822
|
+
continue;
|
|
7823
|
+
}
|
|
7824
|
+
resolved2.files.push({ path: libraryFilePath(declaration.name, entry.relativePath), source: content, environment: entry.environment, origin });
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
function resolveLibrary(root, name, packageIndex, resolved2) {
|
|
7828
|
+
const directory = packageRoot(root, name);
|
|
7829
|
+
const manifestPath = resolve6(directory, PACKAGE_MANIFEST);
|
|
7830
|
+
if (!existsSync4(manifestPath)) {
|
|
7831
|
+
const subject = `"${name}" is listed in "libraries" but is not installed`;
|
|
7832
|
+
resolved2.diagnostics.push(cliError(MISSING_LIBRARY, `${subject}. Install it with "${installCommand(name)}" and build again.`));
|
|
7833
|
+
return;
|
|
7834
|
+
}
|
|
7835
|
+
const declaration = readLibraryDeclaration(name, readPackageManifest(manifestPath));
|
|
7836
|
+
for (const problem of declaration.problems) {
|
|
7837
|
+
resolved2.diagnostics.push(cliError(problem.code, problem.message));
|
|
7838
|
+
}
|
|
7839
|
+
if (declaration.declaration === null) {
|
|
7840
|
+
return;
|
|
7841
|
+
}
|
|
7842
|
+
resolved2.libraries.push({ declaration: declaration.declaration, root: directory });
|
|
7843
|
+
collectFiles(directory, declaration.declaration, packageIndex, resolved2);
|
|
7844
|
+
}
|
|
7845
|
+
function resolveLibraries(root, names) {
|
|
7846
|
+
const resolved2 = { libraries: [], files: [], verbatim: [], diagnostics: [] };
|
|
7847
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7848
|
+
for (const name of names) {
|
|
7849
|
+
if (seen.has(name)) {
|
|
7850
|
+
continue;
|
|
7851
|
+
}
|
|
7852
|
+
seen.add(name);
|
|
7853
|
+
resolveLibrary(root, name, seen.size - 1, resolved2);
|
|
7854
|
+
}
|
|
7855
|
+
for (const problem of missingRequirements(resolved2.libraries.map((library) => library.declaration))) {
|
|
7856
|
+
resolved2.diagnostics.push(cliError(problem.code, problem.message));
|
|
7857
|
+
}
|
|
7858
|
+
return resolved2;
|
|
7859
|
+
}
|
|
7860
|
+
|
|
7527
7861
|
// src/build/build-phase.ts
|
|
7528
7862
|
var COUNTED_PHASES = /* @__PURE__ */ new Set(["compile", "write"]);
|
|
7529
7863
|
var PHASE_LABELS = {
|
|
@@ -7590,60 +7924,12 @@ function createPhaseTracker(listener = null) {
|
|
|
7590
7924
|
}
|
|
7591
7925
|
|
|
7592
7926
|
// src/build/project-inputs.ts
|
|
7593
|
-
import { existsSync as
|
|
7594
|
-
import { resolve as
|
|
7927
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
|
|
7928
|
+
import { resolve as resolve8 } from "node:path";
|
|
7595
7929
|
|
|
7596
7930
|
// src/build/asset-resolution.ts
|
|
7597
7931
|
import { statSync as statSync3 } from "node:fs";
|
|
7598
|
-
import { resolve as
|
|
7599
|
-
|
|
7600
|
-
// src/build/project-files.ts
|
|
7601
|
-
import { readdirSync, statSync as statSync2 } from "node:fs";
|
|
7602
|
-
import { join as join3, relative, resolve as resolve5 } from "node:path";
|
|
7603
|
-
function isDirectory(path) {
|
|
7604
|
-
try {
|
|
7605
|
-
return statSync2(path).isDirectory();
|
|
7606
|
-
} catch {
|
|
7607
|
-
return false;
|
|
7608
|
-
}
|
|
7609
|
-
}
|
|
7610
|
-
function relativePath(root, absolute) {
|
|
7611
|
-
return normalizePattern(relative(root, absolute));
|
|
7612
|
-
}
|
|
7613
|
-
function walk(root, directory, excluded, tree) {
|
|
7614
|
-
let entries3;
|
|
7615
|
-
try {
|
|
7616
|
-
entries3 = readdirSync(directory, { withFileTypes: true });
|
|
7617
|
-
} catch (error) {
|
|
7618
|
-
tree.errors.push(`"${relativePath(root, directory)}" could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
7619
|
-
return;
|
|
7620
|
-
}
|
|
7621
|
-
for (const entry of entries3) {
|
|
7622
|
-
const absolute = join3(directory, entry.name);
|
|
7623
|
-
const path = relativePath(root, absolute);
|
|
7624
|
-
if (path.length === 0 || isExcludedPath(path, excluded)) {
|
|
7625
|
-
continue;
|
|
7626
|
-
}
|
|
7627
|
-
if (entry.isDirectory()) {
|
|
7628
|
-
walk(root, absolute, excluded, tree);
|
|
7629
|
-
} else if (entry.isFile()) {
|
|
7630
|
-
tree.files.push(path);
|
|
7631
|
-
}
|
|
7632
|
-
}
|
|
7633
|
-
}
|
|
7634
|
-
function listProjectFiles(root, roots, excluded = []) {
|
|
7635
|
-
const tree = { files: [], errors: [] };
|
|
7636
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7637
|
-
for (const start of [...new Set(roots)].sort()) {
|
|
7638
|
-
const absolute = resolve5(root, start);
|
|
7639
|
-
if (!isDirectory(absolute) || seen.has(absolute)) {
|
|
7640
|
-
continue;
|
|
7641
|
-
}
|
|
7642
|
-
seen.add(absolute);
|
|
7643
|
-
walk(root, absolute, excluded, tree);
|
|
7644
|
-
}
|
|
7645
|
-
return { files: [...new Set(tree.files)].sort(), errors: tree.errors };
|
|
7646
|
-
}
|
|
7932
|
+
import { resolve as resolve7 } from "node:path";
|
|
7647
7933
|
|
|
7648
7934
|
// ../compiler/src/project/resource-map.ts
|
|
7649
7935
|
var RESOURCE_MAP_VERSION = 1;
|
|
@@ -7717,11 +8003,12 @@ var ENVIRONMENTS2 = ["shared", "server", "client"];
|
|
|
7717
8003
|
function bundlePath(environment) {
|
|
7718
8004
|
return `${BUNDLE_DIRECTORY}/${environment}.lua`;
|
|
7719
8005
|
}
|
|
7720
|
-
function collectBundles(helpers, scripts, pinned) {
|
|
8006
|
+
function collectBundles(helpers, scripts, pinned, libraries = []) {
|
|
7721
8007
|
const pinnedPaths = new Set(pinned.map((script) => script.path));
|
|
7722
8008
|
return ENVIRONMENTS2.flatMap((environment) => {
|
|
7723
8009
|
const environmentHelpers = helpers.filter((helper) => helper.environment === environment).map((helper) => ({ kind: "helper", helper }));
|
|
7724
8010
|
const orderedModules = [
|
|
8011
|
+
...libraries.filter((script) => script.environment === environment),
|
|
7725
8012
|
...pinned.filter((script) => script.environment === environment),
|
|
7726
8013
|
...scripts.filter((script) => script.environment === environment && !pinnedPaths.has(script.path))
|
|
7727
8014
|
].map((module) => ({ kind: "module", module }));
|
|
@@ -7779,6 +8066,9 @@ var OCCUPIED_SIDES = {
|
|
|
7779
8066
|
function occupiedSides(contribution) {
|
|
7780
8067
|
return OCCUPIED_SIDES[contribution.side];
|
|
7781
8068
|
}
|
|
8069
|
+
function sidesOf(environment) {
|
|
8070
|
+
return OCCUPIED_SIDES[environment];
|
|
8071
|
+
}
|
|
7782
8072
|
function exportSignature(type) {
|
|
7783
8073
|
if (type === void 0 || type.kind !== "function") {
|
|
7784
8074
|
return null;
|
|
@@ -7801,10 +8091,11 @@ function toContributions(directives, environment, globals) {
|
|
|
7801
8091
|
var INDENT = " ";
|
|
7802
8092
|
var RESOURCE_TYPE = "script";
|
|
7803
8093
|
var DEFAULT_SIDE = "server";
|
|
7804
|
-
var
|
|
7805
|
-
var SCRIPT_GROUPS = ["library", "configuration", "source"];
|
|
8094
|
+
var SIDE_ORDER2 = { shared: 0, server: 1, client: 2 };
|
|
8095
|
+
var SCRIPT_GROUPS = ["library", "libraries", "configuration", "source"];
|
|
7806
8096
|
var GROUP_COMMENTS = {
|
|
7807
8097
|
library: "Runtime library",
|
|
8098
|
+
libraries: "Libraries",
|
|
7808
8099
|
configuration: "Configuration",
|
|
7809
8100
|
source: "Source scripts"
|
|
7810
8101
|
};
|
|
@@ -7867,7 +8158,7 @@ function versionElement(version) {
|
|
|
7867
8158
|
return `${INDENT}<min_mta_version ${attribute("server", version)} ${attribute("client", version)} />`;
|
|
7868
8159
|
}
|
|
7869
8160
|
function exportElements(contributions) {
|
|
7870
|
-
return [...contributions].sort((left, right) =>
|
|
8161
|
+
return [...contributions].sort((left, right) => SIDE_ORDER2[left.side] - SIDE_ORDER2[right.side] || left.name.localeCompare(right.name)).map(exportElement);
|
|
7871
8162
|
}
|
|
7872
8163
|
function scriptSections(scripts) {
|
|
7873
8164
|
return SCRIPT_GROUPS.flatMap((group) => section(GROUP_COMMENTS[group], scripts.filter((script) => script.group === group).map(scriptElement)));
|
|
@@ -7951,16 +8242,39 @@ function collectDevelopmentLogHelpers(options) {
|
|
|
7951
8242
|
replacements
|
|
7952
8243
|
}));
|
|
7953
8244
|
}
|
|
8245
|
+
function emitted(modules) {
|
|
8246
|
+
return modules.filter((module) => module.code !== null);
|
|
8247
|
+
}
|
|
7954
8248
|
function collectScripts(modules) {
|
|
7955
|
-
return modules.filter((module) => module.
|
|
8249
|
+
return emitted(modules).filter((module) => module.origin === null).map((module) => ({ path: outputPath(module.path), source: module.path, environment: module.environment, content: module.code, lines: module.lines })).sort((left, right) => ENVIRONMENT_ORDER[left.environment] - ENVIRONMENT_ORDER[right.environment] || left.path.localeCompare(right.path));
|
|
8250
|
+
}
|
|
8251
|
+
function libraryScript(origin, environment, content, lines) {
|
|
8252
|
+
const script = {
|
|
8253
|
+
path: libraryOutputPath(origin.package, environment, origin.relativePath),
|
|
8254
|
+
source: libraryFilePath(origin.package, origin.relativePath),
|
|
8255
|
+
environment,
|
|
8256
|
+
content,
|
|
8257
|
+
lines
|
|
8258
|
+
};
|
|
8259
|
+
return { origin, script };
|
|
8260
|
+
}
|
|
8261
|
+
function collectLibraryScripts(modules, files = []) {
|
|
8262
|
+
const compiled = emitted(modules).filter((module) => module.origin !== null).map((module) => libraryScript(module.origin, module.environment, module.code, module.lines));
|
|
8263
|
+
const verbatim = files.map((file) => libraryScript(file.origin, file.environment, file.content, []));
|
|
8264
|
+
return [...compiled, ...verbatim].sort((left, right) => compareLibraryOrigins(left.origin, right.origin)).map((entry) => entry.script);
|
|
7956
8265
|
}
|
|
7957
8266
|
var MISSING_LOAD_ORDER = 'is listed in "loadOrder" but no source file or asset matches it. Remove the entry or correct the path.';
|
|
8267
|
+
var LIBRARY_LOAD_ORDER = 'is listed in "loadOrder" but belongs to a library. Library scripts load in the order "libraries" declares. Remove the entry.';
|
|
7958
8268
|
function missingEntry(entry) {
|
|
7959
8269
|
return { path: entry, diagnostic: createDiagnostic("project", "project-load-order-missing", `"${entry}" ${MISSING_LOAD_ORDER}`, FILE_START) };
|
|
7960
8270
|
}
|
|
7961
|
-
function
|
|
8271
|
+
function libraryEntry(entry) {
|
|
8272
|
+
return { path: entry, diagnostic: createDiagnostic("project", "project-load-order-library", `"${entry}" ${LIBRARY_LOAD_ORDER}`, FILE_START) };
|
|
8273
|
+
}
|
|
8274
|
+
function resolveLoadOrder(entries3, scripts, assets, libraries = []) {
|
|
7962
8275
|
const byScript = new Map(scripts.map((script) => [normalizePath(script.source), script]));
|
|
7963
8276
|
const byAsset = new Map(assets.map((asset) => [normalizePath(asset.source), asset]));
|
|
8277
|
+
const byLibrary = new Set(libraries.map((script) => normalizePath(script.source)));
|
|
7964
8278
|
const resolved2 = { scripts: [], assets: [], diagnostics: [] };
|
|
7965
8279
|
const seen = /* @__PURE__ */ new Set();
|
|
7966
8280
|
for (const entry of entries3) {
|
|
@@ -7972,7 +8286,7 @@ function resolveLoadOrder(entries3, scripts, assets) {
|
|
|
7972
8286
|
}
|
|
7973
8287
|
seen.add(path);
|
|
7974
8288
|
if (script === void 0 && asset === void 0) {
|
|
7975
|
-
resolved2.diagnostics.push(missingEntry(entry));
|
|
8289
|
+
resolved2.diagnostics.push(byLibrary.has(path) ? libraryEntry(entry) : missingEntry(entry));
|
|
7976
8290
|
continue;
|
|
7977
8291
|
}
|
|
7978
8292
|
if (script !== void 0) {
|
|
@@ -8133,9 +8447,9 @@ function withEnvironmentFile(helpers, file) {
|
|
|
8133
8447
|
function helperEntry(helper) {
|
|
8134
8448
|
return { src: helper.path, environment: helper.environment, group: "library" };
|
|
8135
8449
|
}
|
|
8136
|
-
function manifestScripts(helpers, configuration, sources) {
|
|
8450
|
+
function manifestScripts(helpers, libraries, configuration, sources) {
|
|
8137
8451
|
const settings = configuration === null ? [] : [{ src: configuration.path, environment: "shared", group: "configuration" }];
|
|
8138
|
-
return [...helpers.map(helperEntry), ...settings, ...sources];
|
|
8452
|
+
return [...helpers.map(helperEntry), ...libraries, ...settings, ...sources];
|
|
8139
8453
|
}
|
|
8140
8454
|
function collectContributions(project) {
|
|
8141
8455
|
return project.modules.flatMap((module) => module.contributions);
|
|
@@ -8208,32 +8522,35 @@ function assembleResource(project, options, onStep) {
|
|
|
8208
8522
|
const collected = [...collectHelpers(project.modules, options.helpers ?? []), ...collectDevelopmentLogHelpers(options.developmentLogs)];
|
|
8209
8523
|
const helpers = withEnvironmentFile(collected, options.environmentFile);
|
|
8210
8524
|
const scripts = collectScripts(project.modules);
|
|
8525
|
+
const libraries = collectLibraryScripts(project.modules, options.libraryFiles ?? []);
|
|
8211
8526
|
const configuration = configurationScript(options.configuration);
|
|
8212
8527
|
const deployment = configuration === null ? [] : [configuration];
|
|
8213
|
-
const
|
|
8214
|
-
const order = resolveLoadOrder(options.loadOrder ?? [], scripts,
|
|
8528
|
+
const sorted2 = [...options.assets ?? []].sort((left, right) => left.path.localeCompare(right.path));
|
|
8529
|
+
const order = resolveLoadOrder(options.loadOrder ?? [], scripts, sorted2, libraries);
|
|
8215
8530
|
const layout = options.layout ?? "tree";
|
|
8216
|
-
const bundles = layout === "bundle" ? collectBundles(helpers, scripts, order.scripts) : [];
|
|
8217
|
-
const duplicates = layout === "tree" ? findDuplicateOutputs([...scripts, ...deployment],
|
|
8218
|
-
const collisions = layout === "bundle" ? bundleDiagnostics(project, bundles, scripts,
|
|
8531
|
+
const bundles = layout === "bundle" ? collectBundles(helpers, scripts, order.scripts, libraries) : [];
|
|
8532
|
+
const duplicates = layout === "tree" ? findDuplicateOutputs([...libraries, ...scripts, ...deployment], sorted2) : [...findDuplicateOutputs([...libraries, ...scripts], []), ...findDuplicateOutputs(deployment, sorted2)];
|
|
8533
|
+
const collisions = layout === "bundle" ? bundleDiagnostics(project, bundles, scripts, sorted2) : [];
|
|
8219
8534
|
const diagnostics = sortFileDiagnostics([...project.diagnostics, ...duplicates, ...collisions, ...order.diagnostics]);
|
|
8220
8535
|
if (duplicates.length > 0 || collisions.length > 0 || order.diagnostics.length > 0) {
|
|
8221
8536
|
return { build: null, diagnostics };
|
|
8222
8537
|
}
|
|
8223
8538
|
onStep?.("assembly");
|
|
8224
|
-
const assets = orderAssets(
|
|
8539
|
+
const assets = orderAssets(sorted2, order.assets);
|
|
8225
8540
|
const sources = layout === "tree" ? sourceEntries(scripts, order.scripts).map((entry) => ({ ...entry, group: "source" })) : bundles.map((bundle) => ({ src: bundle.path, environment: bundle.environment, group: "source" }));
|
|
8226
8541
|
const manifestHelpers = layout === "tree" ? helpers : [];
|
|
8542
|
+
const vendored = layout === "tree" ? libraries.map((script) => ({ src: script.path, environment: script.environment, group: "libraries" })) : [];
|
|
8227
8543
|
const manifest = generateManifest(
|
|
8228
8544
|
manifestInfo(options),
|
|
8229
|
-
manifestScripts(manifestHelpers, configuration, sources),
|
|
8545
|
+
manifestScripts(manifestHelpers, vendored, configuration, sources),
|
|
8230
8546
|
manifestFiles(assets),
|
|
8231
8547
|
collectContributions(project),
|
|
8232
8548
|
{ oop: options.oop === true, minMtaVersion: options.minMtaVersion ?? null, dependencies: options.dependencies ?? [] }
|
|
8233
8549
|
);
|
|
8234
8550
|
onStep?.("manifest");
|
|
8235
|
-
const
|
|
8236
|
-
|
|
8551
|
+
const written = [...libraries, ...scripts];
|
|
8552
|
+
const map = layout === "tree" ? treeResourceMap(options.resourceName ?? "", written) : null;
|
|
8553
|
+
return { build: { manifest, scripts: layout === "tree" ? written : [], helpers, configuration, assets, bundles, layout, map }, diagnostics };
|
|
8237
8554
|
}
|
|
8238
8555
|
|
|
8239
8556
|
// src/build/asset-resolution.ts
|
|
@@ -8243,14 +8560,14 @@ var MANIFEST_OUTPUT = "meta.xml";
|
|
|
8243
8560
|
var HERE = ".";
|
|
8244
8561
|
function isDirectory2(root, path) {
|
|
8245
8562
|
try {
|
|
8246
|
-
return statSync3(
|
|
8563
|
+
return statSync3(resolve7(root, path)).isDirectory();
|
|
8247
8564
|
} catch {
|
|
8248
8565
|
return false;
|
|
8249
8566
|
}
|
|
8250
8567
|
}
|
|
8251
8568
|
function exists(root, path) {
|
|
8252
8569
|
try {
|
|
8253
|
-
statSync3(
|
|
8570
|
+
statSync3(resolve7(root, path));
|
|
8254
8571
|
return true;
|
|
8255
8572
|
} catch {
|
|
8256
8573
|
return false;
|
|
@@ -8318,10 +8635,10 @@ var CONFIGURATION_FILE = "config.lua";
|
|
|
8318
8635
|
var MALFORMED_ENV = "build-env-malformed";
|
|
8319
8636
|
var MISSING_ENV = "config-missing-env-file";
|
|
8320
8637
|
function readTextFile(path) {
|
|
8321
|
-
return
|
|
8638
|
+
return existsSync5(path) ? readFileSync6(path, "utf8") : null;
|
|
8322
8639
|
}
|
|
8323
8640
|
function readEnvironment(root, file, required, diagnostics) {
|
|
8324
|
-
const source = readTextFile(
|
|
8641
|
+
const source = readTextFile(resolve8(root, file));
|
|
8325
8642
|
if (source === null) {
|
|
8326
8643
|
if (required) {
|
|
8327
8644
|
diagnostics.push(cliError(MISSING_ENV, `"${file}" is configured under "environment" but does not exist. Create it or remove the setting.`));
|
|
@@ -8335,7 +8652,7 @@ function readEnvironment(root, file, required, diagnostics) {
|
|
|
8335
8652
|
return parsed;
|
|
8336
8653
|
}
|
|
8337
8654
|
function readConfiguration(root, diagnostics) {
|
|
8338
|
-
const content = readTextFile(
|
|
8655
|
+
const content = readTextFile(resolve8(root, CONFIGURATION_FILE));
|
|
8339
8656
|
if (content === null) {
|
|
8340
8657
|
return null;
|
|
8341
8658
|
}
|
|
@@ -8354,14 +8671,14 @@ function readProjectInputs(root, options) {
|
|
|
8354
8671
|
}
|
|
8355
8672
|
|
|
8356
8673
|
// src/build/source-discovery.ts
|
|
8357
|
-
import { readFileSync as
|
|
8358
|
-
import { resolve as
|
|
8674
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
8675
|
+
import { resolve as resolve9 } from "node:path";
|
|
8359
8676
|
|
|
8360
8677
|
// ../compiler/src/project/source-mapping.ts
|
|
8361
8678
|
function createSourceResolver(mapping) {
|
|
8362
8679
|
const matchers = new Map(SOURCE_SIDES.map((environment) => [environment, createPatternMatcher(mapping[environment])]));
|
|
8363
8680
|
const patterns = SOURCE_SIDES.flatMap((environment) => [...matchers.get(environment)?.patterns ?? []]);
|
|
8364
|
-
function
|
|
8681
|
+
function resolve24(path) {
|
|
8365
8682
|
const normalized = normalizePattern(path);
|
|
8366
8683
|
const matches = [];
|
|
8367
8684
|
for (const environment of SOURCE_SIDES) {
|
|
@@ -8375,25 +8692,14 @@ function createSourceResolver(mapping) {
|
|
|
8375
8692
|
return {
|
|
8376
8693
|
patterns,
|
|
8377
8694
|
roots: watchRoots(patterns),
|
|
8378
|
-
resolve:
|
|
8379
|
-
side: (path) =>
|
|
8695
|
+
resolve: resolve24,
|
|
8696
|
+
side: (path) => resolve24(path).environment
|
|
8380
8697
|
};
|
|
8381
8698
|
}
|
|
8382
8699
|
function describeMatches(matches) {
|
|
8383
8700
|
return matches.map((match) => `"${match.environment}" through "${match.pattern}"`).join(" and ");
|
|
8384
8701
|
}
|
|
8385
8702
|
|
|
8386
|
-
// ../compiler/src/project/source-kind.ts
|
|
8387
|
-
var SOURCE_EXTENSION = ".luam";
|
|
8388
|
-
var DECLARATION_EXTENSION = ".d.luam";
|
|
8389
|
-
var TEST_EXTENSION = ".test.luam";
|
|
8390
|
-
function isDeclarationPath(path) {
|
|
8391
|
-
return normalizePath(path).endsWith(DECLARATION_EXTENSION);
|
|
8392
|
-
}
|
|
8393
|
-
function isTestPath(path) {
|
|
8394
|
-
return normalizePath(path).endsWith(TEST_EXTENSION);
|
|
8395
|
-
}
|
|
8396
|
-
|
|
8397
8703
|
// src/build/source-discovery.ts
|
|
8398
8704
|
var MISSING_SOURCE = "config-missing-source";
|
|
8399
8705
|
var NO_SOURCES = "config-no-sources";
|
|
@@ -8419,7 +8725,7 @@ function checkLiterals(root, resolver, found, diagnostics) {
|
|
|
8419
8725
|
}
|
|
8420
8726
|
function readSource(root, path, diagnostics) {
|
|
8421
8727
|
try {
|
|
8422
|
-
return
|
|
8728
|
+
return readFileSync7(resolve9(root, path), "utf8");
|
|
8423
8729
|
} catch (error) {
|
|
8424
8730
|
diagnostics.push(cliError(UNREADABLE_SOURCE, `The source file "${path}" could not be read: ${error instanceof Error ? error.message : String(error)}`));
|
|
8425
8731
|
return null;
|
|
@@ -14990,12 +15296,12 @@ function failed(type) {
|
|
|
14990
15296
|
function entries2(parts) {
|
|
14991
15297
|
return `{ ${parts.join(", ")} }`;
|
|
14992
15298
|
}
|
|
14993
|
-
function combine(parts,
|
|
15299
|
+
function combine(parts, render3) {
|
|
14994
15300
|
const broken = parts.find((part) => part.lua === null);
|
|
14995
15301
|
if (broken !== void 0) {
|
|
14996
15302
|
return broken;
|
|
14997
15303
|
}
|
|
14998
|
-
return { lua:
|
|
15304
|
+
return { lua: render3(parts.map((part) => part.lua)), unreifiable: null };
|
|
14999
15305
|
}
|
|
15000
15306
|
function namedDescriptor(context, type, name, seen) {
|
|
15001
15307
|
if (context.declarations.lookupClass(name) !== null) {
|
|
@@ -18610,60 +18916,60 @@ function selectCandidate(context, expression, forms) {
|
|
|
18610
18916
|
});
|
|
18611
18917
|
return found[0] ?? null;
|
|
18612
18918
|
}
|
|
18613
|
-
function specialize(
|
|
18919
|
+
function specialize(signature2, candidate) {
|
|
18614
18920
|
const callback = candidate.form.callbackArgument;
|
|
18615
18921
|
if (callback !== void 0) {
|
|
18616
|
-
const parameters = [...
|
|
18922
|
+
const parameters = [...signature2.parameters];
|
|
18617
18923
|
parameters[callback] = candidate.handler;
|
|
18618
|
-
return { ...
|
|
18924
|
+
return { ...signature2, parameters };
|
|
18619
18925
|
}
|
|
18620
18926
|
const payload = candidate.form.payloadArgument;
|
|
18621
18927
|
if (payload === void 0) {
|
|
18622
18928
|
return null;
|
|
18623
18929
|
}
|
|
18624
18930
|
return createFunction(
|
|
18625
|
-
[...
|
|
18626
|
-
|
|
18931
|
+
[...signature2.parameters.slice(0, payload), ...candidate.handler.parameters],
|
|
18932
|
+
signature2.returnType,
|
|
18627
18933
|
payload + candidate.handler.minimumArguments,
|
|
18628
18934
|
candidate.handler.isVariadic,
|
|
18629
18935
|
void 0,
|
|
18630
18936
|
candidate.handler.variadicType
|
|
18631
18937
|
);
|
|
18632
18938
|
}
|
|
18633
|
-
function specializeEventCall(context, expression,
|
|
18634
|
-
if (
|
|
18939
|
+
function specializeEventCall(context, expression, signature2) {
|
|
18940
|
+
if (signature2.kind !== "function" || expression.method !== null || expression.callee.kind !== "identifier") {
|
|
18635
18941
|
return null;
|
|
18636
18942
|
}
|
|
18637
18943
|
const forms = eventCallForms(expression.callee.name);
|
|
18638
18944
|
const candidate = selectCandidate(context, expression, forms);
|
|
18639
|
-
return candidate === null ? null : specialize(
|
|
18945
|
+
return candidate === null ? null : specialize(signature2, candidate);
|
|
18640
18946
|
}
|
|
18641
18947
|
|
|
18642
18948
|
// ../compiler/src/checker/generic-call.ts
|
|
18643
18949
|
function countArguments(total) {
|
|
18644
18950
|
return total === 1 ? "1 type argument" : `${total} type arguments`;
|
|
18645
18951
|
}
|
|
18646
|
-
function substituteSignature(
|
|
18647
|
-
const parameters =
|
|
18648
|
-
const returnType = substituteType(
|
|
18649
|
-
const variadicType =
|
|
18650
|
-
return createFunction(parameters, returnType,
|
|
18952
|
+
function substituteSignature(signature2, substitutions) {
|
|
18953
|
+
const parameters = signature2.parameters.map((parameter) => substituteType(parameter, substitutions));
|
|
18954
|
+
const returnType = substituteType(signature2.returnType, substitutions);
|
|
18955
|
+
const variadicType = signature2.variadicType === void 0 ? void 0 : substituteType(signature2.variadicType, substitutions);
|
|
18956
|
+
return createFunction(parameters, returnType, signature2.minimumArguments, signature2.isVariadic, signature2.parameterNames, variadicType);
|
|
18651
18957
|
}
|
|
18652
|
-
function specializeCall(context, owner,
|
|
18653
|
-
const names =
|
|
18958
|
+
function specializeCall(context, owner, signature2, argumentTypes, typeArguments, position2) {
|
|
18959
|
+
const names = signature2.typeParameters ?? [];
|
|
18654
18960
|
if (names.length === 0) {
|
|
18655
18961
|
if (typeArguments.length > 0) {
|
|
18656
18962
|
context.report("check-generic-arity", `${owner} does not accept type arguments.`, position2);
|
|
18657
18963
|
}
|
|
18658
|
-
return
|
|
18964
|
+
return signature2;
|
|
18659
18965
|
}
|
|
18660
18966
|
const explicit = typeArguments.map((argument) => context.resolveAnnotation(argument));
|
|
18661
18967
|
if (typeArguments.length > 0 && explicit.length !== names.length) {
|
|
18662
18968
|
context.report("check-generic-arity", `${owner} expects ${countArguments(names.length)} but received ${explicit.length}.`, position2);
|
|
18663
18969
|
}
|
|
18664
|
-
const resolved2 = typeArguments.length > 0 ? names.map((unused, index) => explicit[index] ?? ANY_TYPE) : inferTypeArguments(names,
|
|
18665
|
-
reportConstraintViolations(context, owner, names,
|
|
18666
|
-
return substituteSignature(
|
|
18970
|
+
const resolved2 = typeArguments.length > 0 ? names.map((unused, index) => explicit[index] ?? ANY_TYPE) : inferTypeArguments(names, signature2.parameters, argumentTypes);
|
|
18971
|
+
reportConstraintViolations(context, owner, names, signature2.typeConstraints ?? [], resolved2, position2);
|
|
18972
|
+
return substituteSignature(signature2, new Map(names.map((name, index) => [name, resolved2[index] ?? ANY_TYPE])));
|
|
18667
18973
|
}
|
|
18668
18974
|
|
|
18669
18975
|
// ../compiler/src/checker/method-receiver.ts
|
|
@@ -18675,13 +18981,13 @@ function resolveNonNominalMethod(receiver, method) {
|
|
|
18675
18981
|
const member = receiver.members.get(method);
|
|
18676
18982
|
return member !== void 0 && member.kind === "function" ? member : null;
|
|
18677
18983
|
}
|
|
18678
|
-
function withoutSelfParameter(
|
|
18679
|
-
const names =
|
|
18984
|
+
function withoutSelfParameter(signature2) {
|
|
18985
|
+
const names = signature2.parameterNames;
|
|
18680
18986
|
if (names === void 0 || names[0] !== SELF_PARAMETER) {
|
|
18681
|
-
return
|
|
18987
|
+
return signature2;
|
|
18682
18988
|
}
|
|
18683
|
-
const minimum = Math.max(0,
|
|
18684
|
-
return createFunction(
|
|
18989
|
+
const minimum = Math.max(0, signature2.minimumArguments - 1);
|
|
18990
|
+
return createFunction(signature2.parameters.slice(1), signature2.returnType, minimum, signature2.isVariadic, names.slice(1), signature2.variadicType);
|
|
18685
18991
|
}
|
|
18686
18992
|
|
|
18687
18993
|
// ../compiler/src/checker/resource-exports.ts
|
|
@@ -18979,6 +19285,7 @@ function resolveMtaMember(context, className, name, position2) {
|
|
|
18979
19285
|
}
|
|
18980
19286
|
|
|
18981
19287
|
// ../compiler/src/checker/members.ts
|
|
19288
|
+
var SELF_RECEIVER = "self";
|
|
18982
19289
|
function checkEnumMember(context, name, members, expression) {
|
|
18983
19290
|
if (members.includes(expression.property)) {
|
|
18984
19291
|
return NUMBER_TYPE;
|
|
@@ -19039,6 +19346,35 @@ function resolveStaticMember(context, className, expression) {
|
|
|
19039
19346
|
context.report("check-unknown-member", `Class "${className}" has no static member "${expression.property}".${hint}`, expression.position);
|
|
19040
19347
|
return ANY_TYPE;
|
|
19041
19348
|
}
|
|
19349
|
+
function isFullyDeclared(context, className) {
|
|
19350
|
+
const visited = /* @__PURE__ */ new Set();
|
|
19351
|
+
let current = context.declarations.lookupClass(className);
|
|
19352
|
+
while (current !== null && !visited.has(current.name)) {
|
|
19353
|
+
visited.add(current.name);
|
|
19354
|
+
if (current.hasUnresolvedParent === true || current.interfaces.some((name) => context.declarations.lookupInterface(name) === null)) {
|
|
19355
|
+
return false;
|
|
19356
|
+
}
|
|
19357
|
+
if (current.superClass === null) {
|
|
19358
|
+
return true;
|
|
19359
|
+
}
|
|
19360
|
+
current = context.declarations.lookupClass(current.superClass);
|
|
19361
|
+
}
|
|
19362
|
+
return current !== null;
|
|
19363
|
+
}
|
|
19364
|
+
function isSelfReceiver(receiver) {
|
|
19365
|
+
return receiver.kind === "identifier" && receiver.name === SELF_RECEIVER;
|
|
19366
|
+
}
|
|
19367
|
+
function reportUnknownClassMember(context, className, property, position2) {
|
|
19368
|
+
const names = context.declarations.collectMembers(className).map((member) => `"${member.name}"`);
|
|
19369
|
+
const known = names.length === 0 ? "It declares no members." : `Declared members: ${names.join(", ")}.`;
|
|
19370
|
+
context.report("check-unknown-member", `Class "${className}" has no member "${property}". ${known}`, position2);
|
|
19371
|
+
}
|
|
19372
|
+
function checkClassMember(context, className, expression) {
|
|
19373
|
+
if (!isSelfReceiver(expression.object)) {
|
|
19374
|
+
reportUnknownClassMember(context, className, expression.property, expression.position);
|
|
19375
|
+
}
|
|
19376
|
+
return ANY_TYPE;
|
|
19377
|
+
}
|
|
19042
19378
|
function resolveNamedMember(context, receiver, expression) {
|
|
19043
19379
|
const name = receiver.name;
|
|
19044
19380
|
const enumeration = context.declarations.lookupEnum(name);
|
|
@@ -19064,13 +19400,39 @@ function resolveNamedMember(context, receiver, expression) {
|
|
|
19064
19400
|
if (context.awaitsDeclaration(name)) {
|
|
19065
19401
|
return ANY_TYPE;
|
|
19066
19402
|
}
|
|
19067
|
-
|
|
19403
|
+
if (context.declarations.lookupClass(name) !== null) {
|
|
19404
|
+
return isFullyDeclared(context, name) ? checkClassMember(context, name, expression) : null;
|
|
19405
|
+
}
|
|
19406
|
+
const contract = context.declarations.lookupInterface(name);
|
|
19068
19407
|
if (contract === null) {
|
|
19069
19408
|
return null;
|
|
19070
19409
|
}
|
|
19071
19410
|
const members = new Map(context.declarations.collectMembers(name).map((member2) => [member2.name, member2]));
|
|
19072
19411
|
return checkInterfaceMember(context, name, members, expression);
|
|
19073
19412
|
}
|
|
19413
|
+
function reportUnknownMethod(context, receiver, callee, method, position2) {
|
|
19414
|
+
const name = receiver.name;
|
|
19415
|
+
if (context.declarations.lookupEnum(name) !== null || context.awaitsDeclaration(name) || isSelfReceiver(callee)) {
|
|
19416
|
+
return;
|
|
19417
|
+
}
|
|
19418
|
+
const staticMember = context.declarations.lookupStaticMember(name, method);
|
|
19419
|
+
if (staticMember !== null) {
|
|
19420
|
+
const message = `"${method}" is a static member of class "${name}". Call it as "${name}.${method}(...)".`;
|
|
19421
|
+
context.report("check-static-receiver", message, position2);
|
|
19422
|
+
return;
|
|
19423
|
+
}
|
|
19424
|
+
if (context.declarations.lookupClass(name) !== null) {
|
|
19425
|
+
if (isFullyDeclared(context, name)) {
|
|
19426
|
+
reportUnknownClassMember(context, name, method, position2);
|
|
19427
|
+
}
|
|
19428
|
+
return;
|
|
19429
|
+
}
|
|
19430
|
+
if (context.declarations.lookupInterface(name) === null) {
|
|
19431
|
+
return;
|
|
19432
|
+
}
|
|
19433
|
+
const keys = context.declarations.collectMembers(name).map((member) => `"${member.name}"`).join(", ");
|
|
19434
|
+
context.report("check-unknown-member", `Interface "${name}" has no member "${method}". Declared members: ${keys}.`, position2);
|
|
19435
|
+
}
|
|
19074
19436
|
var NATIVE_CONSTRUCTOR = "new";
|
|
19075
19437
|
function nativeConstructor(context, name) {
|
|
19076
19438
|
const symbol = context.binder.lookup(name);
|
|
@@ -19127,9 +19489,9 @@ function checkNewExpression(context, expression) {
|
|
|
19127
19489
|
const constructor = context.declarations.lookupMember(expression.className, "constructor");
|
|
19128
19490
|
if (constructor !== null && constructor.type.kind === "function") {
|
|
19129
19491
|
const substitutions = info === null ? /* @__PURE__ */ new Map() : classSubstitutions(info, typeArguments);
|
|
19130
|
-
const
|
|
19131
|
-
if (
|
|
19132
|
-
checkSignature(context, expression.args,
|
|
19492
|
+
const signature2 = substituteType(constructor.type, substitutions);
|
|
19493
|
+
if (signature2.kind === "function") {
|
|
19494
|
+
checkSignature(context, expression.args, signature2, expression.position);
|
|
19133
19495
|
}
|
|
19134
19496
|
} else {
|
|
19135
19497
|
expression.args.forEach((argument) => checkExpression(context, argument));
|
|
@@ -19658,7 +20020,7 @@ function reportMissingReturn(context, declared, position2) {
|
|
|
19658
20020
|
const repair = declared.kind === "tuple" ? "Add a return on every path." : `Add a return on every path, or declare "${name}?".`;
|
|
19659
20021
|
context.report("check-missing-return", `This function declares "${name}" but can end without returning a value. ${repair}`, position2);
|
|
19660
20022
|
}
|
|
19661
|
-
function checkFunctionBody(context, parameters, returnAnnotation, body,
|
|
20023
|
+
function checkFunctionBody(context, parameters, returnAnnotation, body, signature2, selfType2, position2 = ORIGIN) {
|
|
19662
20024
|
forgetAssignedPaths(context, body);
|
|
19663
20025
|
const entry = context.flowState;
|
|
19664
20026
|
context.setFlow(cloneFlow(entry));
|
|
@@ -19669,7 +20031,7 @@ function checkFunctionBody(context, parameters, returnAnnotation, body, signatur
|
|
|
19669
20031
|
}
|
|
19670
20032
|
let parameterIndex = 0;
|
|
19671
20033
|
for (const parameter of parameters) {
|
|
19672
|
-
const type = parameter.isVararg ? ANY_TYPE :
|
|
20034
|
+
const type = parameter.isVararg ? ANY_TYPE : signature2.parameters[parameterIndex] ?? ANY_TYPE;
|
|
19673
20035
|
context.binder.declare({ name: parameter.name, type, isLocal: true, position: parameter.position, origin: "parameter" });
|
|
19674
20036
|
if (!parameter.isVararg) {
|
|
19675
20037
|
parameterIndex += 1;
|
|
@@ -19682,7 +20044,7 @@ function checkFunctionBody(context, parameters, returnAnnotation, body, signatur
|
|
|
19682
20044
|
}
|
|
19683
20045
|
const inferred = context.popReturnType();
|
|
19684
20046
|
if (returnAnnotation === null) {
|
|
19685
|
-
|
|
20047
|
+
signature2.returnType = inferred;
|
|
19686
20048
|
}
|
|
19687
20049
|
context.binder.popScope();
|
|
19688
20050
|
context.setFlow(entry);
|
|
@@ -19982,32 +20344,32 @@ function countArguments2(total) {
|
|
|
19982
20344
|
}
|
|
19983
20345
|
function checkSignature(context, args, declared, position2, owner = "This call", typeArguments = []) {
|
|
19984
20346
|
const argumentTypes = checkValueList(context, args, declared.parameters);
|
|
19985
|
-
const
|
|
19986
|
-
if (argumentTypes.length <
|
|
19987
|
-
const message = `This call expects at least ${countArguments2(
|
|
20347
|
+
const signature2 = specializeCall(context, owner, declared, argumentTypes, typeArguments, position2);
|
|
20348
|
+
if (argumentTypes.length < signature2.minimumArguments) {
|
|
20349
|
+
const message = `This call expects at least ${countArguments2(signature2.minimumArguments)} but received ${argumentTypes.length}.`;
|
|
19988
20350
|
context.report("check-argument-count", message, position2);
|
|
19989
20351
|
}
|
|
19990
|
-
if (!
|
|
19991
|
-
const message = `This call expects at most ${countArguments2(
|
|
20352
|
+
if (!signature2.isVariadic && argumentTypes.length > signature2.parameters.length) {
|
|
20353
|
+
const message = `This call expects at most ${countArguments2(signature2.parameters.length)} but received ${argumentTypes.length}.`;
|
|
19992
20354
|
context.report("check-argument-count", message, position2);
|
|
19993
20355
|
}
|
|
19994
|
-
|
|
20356
|
+
signature2.parameters.forEach((parameter, index) => {
|
|
19995
20357
|
const argumentType = argumentTypes[index];
|
|
19996
20358
|
const argument = args[index];
|
|
19997
20359
|
if (argumentType !== void 0 && argument !== void 0) {
|
|
19998
20360
|
context.expectAssignable(argumentType, parameter, argument.position, `Argument ${index + 1}`);
|
|
19999
20361
|
}
|
|
20000
20362
|
});
|
|
20001
|
-
if (
|
|
20002
|
-
for (let index =
|
|
20363
|
+
if (signature2.isVariadic && signature2.variadicType !== void 0) {
|
|
20364
|
+
for (let index = signature2.parameters.length; index < argumentTypes.length; index += 1) {
|
|
20003
20365
|
const argumentType = argumentTypes[index];
|
|
20004
20366
|
const argument = args[Math.min(index, args.length - 1)];
|
|
20005
20367
|
if (argumentType !== void 0 && argument !== void 0) {
|
|
20006
|
-
context.expectAssignable(argumentType,
|
|
20368
|
+
context.expectAssignable(argumentType, signature2.variadicType, argument.position, `Argument ${index + 1}`);
|
|
20007
20369
|
}
|
|
20008
20370
|
}
|
|
20009
20371
|
}
|
|
20010
|
-
return
|
|
20372
|
+
return signature2.returnType;
|
|
20011
20373
|
}
|
|
20012
20374
|
function callOwner(expression) {
|
|
20013
20375
|
const name = expression.method ?? (expression.callee.kind === "identifier" ? expression.callee.name : null);
|
|
@@ -20029,12 +20391,12 @@ function isLegacySuperCall(expression) {
|
|
|
20029
20391
|
}
|
|
20030
20392
|
function checkMethodCall(context, expression, method, receiver) {
|
|
20031
20393
|
if (receiver.kind !== "named") {
|
|
20032
|
-
const
|
|
20033
|
-
if (
|
|
20394
|
+
const signature2 = resolveNonNominalMethod(receiver, method);
|
|
20395
|
+
if (signature2 === null) {
|
|
20034
20396
|
checkValueList(context, expression.args);
|
|
20035
20397
|
return ANY_TYPE;
|
|
20036
20398
|
}
|
|
20037
|
-
return checkSignature(context, expression.args, withoutSelfParameter(
|
|
20399
|
+
return checkSignature(context, expression.args, withoutSelfParameter(signature2), expression.position, callOwner(expression), expression.typeArguments);
|
|
20038
20400
|
}
|
|
20039
20401
|
const declared = memberOf(context, receiver, method);
|
|
20040
20402
|
if (declared?.type.kind === "function") {
|
|
@@ -20044,6 +20406,9 @@ function checkMethodCall(context, expression, method, receiver) {
|
|
|
20044
20406
|
return checkSignature(context, expression.args, declared.type, expression.position, callOwner(expression), expression.typeArguments);
|
|
20045
20407
|
}
|
|
20046
20408
|
if (!isMtaElement(context, receiver.name)) {
|
|
20409
|
+
if (declared === null) {
|
|
20410
|
+
reportUnknownMethod(context, receiver, expression.callee, method, expression.position);
|
|
20411
|
+
}
|
|
20047
20412
|
checkValueList(context, expression.args);
|
|
20048
20413
|
return ANY_TYPE;
|
|
20049
20414
|
}
|
|
@@ -20104,8 +20469,8 @@ function checkTable(context, expression) {
|
|
|
20104
20469
|
}
|
|
20105
20470
|
return checkExpression(context, field2.value);
|
|
20106
20471
|
});
|
|
20107
|
-
const
|
|
20108
|
-
if (
|
|
20472
|
+
const isRecord2 = expression.fields.every((field2) => field2.name !== null);
|
|
20473
|
+
if (isRecord2) {
|
|
20109
20474
|
const members = /* @__PURE__ */ new Map();
|
|
20110
20475
|
expression.fields.forEach((field2, index) => {
|
|
20111
20476
|
if (field2.name !== null) {
|
|
@@ -20328,18 +20693,22 @@ function checkMethodBody(context, info, member) {
|
|
|
20328
20693
|
if (explicitSelf !== void 0) {
|
|
20329
20694
|
context.report("check-explicit-self-parameter", 'Class methods receive "self" automatically; remove it from the parameter list.', explicitSelf.position);
|
|
20330
20695
|
}
|
|
20331
|
-
const
|
|
20332
|
-
if (
|
|
20696
|
+
const signature2 = (member.isStatic ? info.statics : info.members).get(member.name)?.type;
|
|
20697
|
+
if (signature2?.kind !== "function") {
|
|
20333
20698
|
return;
|
|
20334
20699
|
}
|
|
20335
20700
|
if (member.isStatic) {
|
|
20336
|
-
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body,
|
|
20701
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, null, member.position);
|
|
20337
20702
|
return;
|
|
20338
20703
|
}
|
|
20339
20704
|
context.pushClassMethod({ className: info.name, methodName: member.name });
|
|
20340
|
-
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body,
|
|
20705
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, selfType(info), member.position);
|
|
20341
20706
|
context.popClassMethod();
|
|
20342
20707
|
}
|
|
20708
|
+
function assignSuperClass(context, info, statement) {
|
|
20709
|
+
info.superClass = resolveSuperClass(context, statement);
|
|
20710
|
+
info.hasUnresolvedParent = statement.superClass !== null && info.superClass === null;
|
|
20711
|
+
}
|
|
20343
20712
|
function resolveSuperClass(context, statement) {
|
|
20344
20713
|
if (statement.superClass === null) {
|
|
20345
20714
|
return null;
|
|
@@ -20394,7 +20763,7 @@ function declareLocalClass(context, statement) {
|
|
|
20394
20763
|
if (info === null) {
|
|
20395
20764
|
return null;
|
|
20396
20765
|
}
|
|
20397
|
-
|
|
20766
|
+
assignSuperClass(context, info, statement);
|
|
20398
20767
|
resolveClassHeader(context, info, statement);
|
|
20399
20768
|
return info;
|
|
20400
20769
|
}
|
|
@@ -20508,7 +20877,7 @@ function breakCycle(context, info) {
|
|
|
20508
20877
|
function predeclareModule(context, body) {
|
|
20509
20878
|
const declared = declareHeaders(context, body);
|
|
20510
20879
|
for (const entry of declared) {
|
|
20511
|
-
entry.info
|
|
20880
|
+
assignSuperClass(context, entry.info, entry.statement);
|
|
20512
20881
|
resolveClassHeader(context, entry.info, entry.statement);
|
|
20513
20882
|
}
|
|
20514
20883
|
for (const entry of declared) {
|
|
@@ -20685,9 +21054,9 @@ function finalizeEmission(code, markers, sourceLineOffset = 0) {
|
|
|
20685
21054
|
continue;
|
|
20686
21055
|
}
|
|
20687
21056
|
const marker = markers[Number(match[1])];
|
|
20688
|
-
const
|
|
21057
|
+
const emitted2 = line2.replace(pattern, "");
|
|
20689
21058
|
if (marker === void 0) {
|
|
20690
|
-
output.push(
|
|
21059
|
+
output.push(emitted2);
|
|
20691
21060
|
continue;
|
|
20692
21061
|
}
|
|
20693
21062
|
while (output.length + 1 < marker.sourceLine - sourceLineOffset) {
|
|
@@ -20697,7 +21066,7 @@ function finalizeEmission(code, markers, sourceLineOffset = 0) {
|
|
|
20697
21066
|
if (marker.symbol !== void 0) {
|
|
20698
21067
|
mapping.symbol = marker.symbol;
|
|
20699
21068
|
}
|
|
20700
|
-
output.push(
|
|
21069
|
+
output.push(emitted2);
|
|
20701
21070
|
const sameSegment = previous !== null && previous.symbol === mapping.symbol && previous.sourceLine - previous.generatedLine === mapping.sourceLine - mapping.generatedLine;
|
|
20702
21071
|
if (!sameSegment) {
|
|
20703
21072
|
mappings.push(mapping);
|
|
@@ -20838,10 +21207,10 @@ function emitFunctionBody(state, parameters, body, header) {
|
|
|
20838
21207
|
const lines = emitBlock(state, body);
|
|
20839
21208
|
state.loopWrap = previous;
|
|
20840
21209
|
state.indent -= 1;
|
|
20841
|
-
const
|
|
21210
|
+
const signature2 = `${header}(${emitParameters(parameters)})`;
|
|
20842
21211
|
const closing = indentLine(state, "end");
|
|
20843
|
-
return lines.length === 0 ? `${
|
|
20844
|
-
${closing}` : `${
|
|
21212
|
+
return lines.length === 0 ? `${signature2}
|
|
21213
|
+
${closing}` : `${signature2}
|
|
20845
21214
|
${lines.join("\n")}
|
|
20846
21215
|
${closing}`;
|
|
20847
21216
|
}
|
|
@@ -21535,8 +21904,8 @@ function erasedEdit(source, span) {
|
|
|
21535
21904
|
}
|
|
21536
21905
|
function canonicalEdit(input, statement, span) {
|
|
21537
21906
|
const { source } = input;
|
|
21538
|
-
const
|
|
21539
|
-
const trimmed = span.end < source.length &&
|
|
21907
|
+
const emitted2 = emit2({ ...input.program, body: [statement] }, input.types, input.references, input.generatedMembers, statement.position.line - 1, input.staticAccess);
|
|
21908
|
+
const trimmed = span.end < source.length && emitted2.code.endsWith("\n") ? emitted2.code.slice(0, -1) : emitted2.code;
|
|
21540
21909
|
if (trimmed.length === 0) {
|
|
21541
21910
|
return erasedEdit(source, span);
|
|
21542
21911
|
}
|
|
@@ -21547,7 +21916,7 @@ function canonicalEdit(input, statement, span) {
|
|
|
21547
21916
|
return null;
|
|
21548
21917
|
}
|
|
21549
21918
|
const padded = missing2 > 0 && source.slice(span.end).trim().length > 0 ? `${replacement}${"\n".repeat(missing2)}` : replacement;
|
|
21550
|
-
return { start: span.start, end: span.end, replacement: padded, lines:
|
|
21919
|
+
return { start: span.start, end: span.end, replacement: padded, lines: emitted2.lines };
|
|
21551
21920
|
}
|
|
21552
21921
|
|
|
21553
21922
|
// ../compiler/src/emitter/preserve-decorators.ts
|
|
@@ -22020,7 +22389,7 @@ function compile(source, options = {}) {
|
|
|
22020
22389
|
const settings = options.compilerOptions ?? DEFAULT_COMPILER_OPTIONS;
|
|
22021
22390
|
const parsed = parse(source);
|
|
22022
22391
|
const mode = resolveStrictMode(parsed.directives, settings.strict);
|
|
22023
|
-
const resolved2 = resolveEnvironment(options.filePath ?? null, parsed.directives, options.environment ?? null);
|
|
22392
|
+
const resolved2 = resolveEnvironment(options.filePath ?? null, parsed.directives, options.environment ?? null, options.environmentLocked === true);
|
|
22024
22393
|
const environment = resolved2.environment;
|
|
22025
22394
|
const isDeclarationFile = options.filePath !== void 0 && isDeclarationPath(options.filePath);
|
|
22026
22395
|
const checked = check(parsed.program, mode, environment, {
|
|
@@ -22050,7 +22419,7 @@ function compile(source, options = {}) {
|
|
|
22050
22419
|
return { ...shared, code: null, requiredHelpers: [], lines: [] };
|
|
22051
22420
|
}
|
|
22052
22421
|
const references = reachedNames(checked.references, options.projectReferences);
|
|
22053
|
-
const
|
|
22422
|
+
const emitted2 = emit2(parsed.program, checked.types, references, checked.generatedMembers, 0, checked.staticAccess);
|
|
22054
22423
|
const preserved = emitPreservingSource({
|
|
22055
22424
|
source,
|
|
22056
22425
|
program: parsed.program,
|
|
@@ -22063,7 +22432,7 @@ function compile(source, options = {}) {
|
|
|
22063
22432
|
staticAccess: checked.staticAccess,
|
|
22064
22433
|
development: options.development === true
|
|
22065
22434
|
});
|
|
22066
|
-
const required = new Set(
|
|
22435
|
+
const required = new Set(emitted2.requiredHelpers);
|
|
22067
22436
|
for (const name of checked.references) {
|
|
22068
22437
|
const helper = checked.declaredGlobals.has(name) ? null : helperForGlobal(name);
|
|
22069
22438
|
if (helper !== null) {
|
|
@@ -22072,9 +22441,9 @@ function compile(source, options = {}) {
|
|
|
22072
22441
|
}
|
|
22073
22442
|
return {
|
|
22074
22443
|
...shared,
|
|
22075
|
-
code: preserved?.code ??
|
|
22444
|
+
code: preserved?.code ?? emitted2.code,
|
|
22076
22445
|
requiredHelpers: expandHelpers(required).sort(),
|
|
22077
|
-
lines: preserved?.lines ??
|
|
22446
|
+
lines: preserved?.lines ?? emitted2.lines
|
|
22078
22447
|
};
|
|
22079
22448
|
}
|
|
22080
22449
|
|
|
@@ -22291,11 +22660,20 @@ function baseKey(context) {
|
|
|
22291
22660
|
const contracts = context.contracts.map((contract) => serializeAbi(contract)).join(";");
|
|
22292
22661
|
return `${optionsKey(context.options)}|${mode}|${JSON.stringify(context.project.globals)}|${[...context.references].sort().join(",")}|${hashString(contracts)}`;
|
|
22293
22662
|
}
|
|
22663
|
+
function isVisible(environment, isLibrary2, provider) {
|
|
22664
|
+
return canReference(environment, provider.environment) && (!isLibrary2 || provider.isLibrary);
|
|
22665
|
+
}
|
|
22666
|
+
function scopeKey(environment, isLibrary2) {
|
|
22667
|
+
return `${environment}|${isLibrary2 ? "library" : "project"}`;
|
|
22668
|
+
}
|
|
22669
|
+
var SCOPES = [false, true];
|
|
22294
22670
|
function environmentKeys(collected) {
|
|
22295
|
-
const keys =
|
|
22671
|
+
const keys = /* @__PURE__ */ new Map();
|
|
22296
22672
|
for (const environment of ALL_ENVIRONMENTS) {
|
|
22297
|
-
const
|
|
22298
|
-
|
|
22673
|
+
for (const isLibrary2 of SCOPES) {
|
|
22674
|
+
const visible = collected.filter((entry) => isVisible(environment, isLibrary2, entry));
|
|
22675
|
+
keys.set(scopeKey(environment, isLibrary2), hashString(visible.map((entry) => `${entry.path}=${entry.fingerprint}`).join(";")));
|
|
22676
|
+
}
|
|
22299
22677
|
}
|
|
22300
22678
|
return keys;
|
|
22301
22679
|
}
|
|
@@ -22303,15 +22681,19 @@ function createResolver(collected) {
|
|
|
22303
22681
|
const visible = /* @__PURE__ */ new Map();
|
|
22304
22682
|
const merged = /* @__PURE__ */ new Map();
|
|
22305
22683
|
for (const environment of ALL_ENVIRONMENTS) {
|
|
22306
|
-
|
|
22307
|
-
|
|
22308
|
-
|
|
22684
|
+
for (const isLibrary2 of SCOPES) {
|
|
22685
|
+
const key = scopeKey(environment, isLibrary2);
|
|
22686
|
+
const entries3 = collected.filter((entry) => isVisible(environment, isLibrary2, entry) && !declaresNothing(entry.declarations));
|
|
22687
|
+
visible.set(key, entries3);
|
|
22688
|
+
merged.set(key, mergeAmbient(entries3.map((entry) => entry.declarations)));
|
|
22689
|
+
}
|
|
22309
22690
|
}
|
|
22310
22691
|
return (entry) => {
|
|
22692
|
+
const key = scopeKey(entry.environment, entry.isLibrary);
|
|
22311
22693
|
if (declaresNothing(entry.declarations)) {
|
|
22312
|
-
return merged.get(
|
|
22694
|
+
return merged.get(key) ?? EMPTY_AMBIENT;
|
|
22313
22695
|
}
|
|
22314
|
-
const entries3 = visible.get(
|
|
22696
|
+
const entries3 = visible.get(key) ?? [];
|
|
22315
22697
|
return mergeAmbient(entries3.filter((candidate) => candidate.path !== entry.path).map((candidate) => candidate.declarations));
|
|
22316
22698
|
};
|
|
22317
22699
|
}
|
|
@@ -22321,7 +22703,7 @@ function createAmbientScope(collected, context) {
|
|
|
22321
22703
|
const fallback = environmentKeys(collected);
|
|
22322
22704
|
return {
|
|
22323
22705
|
graph,
|
|
22324
|
-
keyFor: (entry) => hashString(`${base}|${graph.keyOf(entry.path) ?? fallback
|
|
22706
|
+
keyFor: (entry) => hashString(`${base}|${graph.keyOf(entry.path) ?? fallback.get(scopeKey(entry.environment, entry.isLibrary)) ?? ""}`),
|
|
22325
22707
|
resolve: createResolver(collected)
|
|
22326
22708
|
};
|
|
22327
22709
|
}
|
|
@@ -22366,13 +22748,96 @@ function validateContributions(modules) {
|
|
|
22366
22748
|
}
|
|
22367
22749
|
return diagnostics;
|
|
22368
22750
|
}
|
|
22751
|
+
var LIBRARY_COLLISION = "project-library-collision";
|
|
22752
|
+
var LIBRARY_SHADOWS_API = "project-library-shadows-api";
|
|
22753
|
+
function describeOwner(owner) {
|
|
22754
|
+
return owner.module.origin === null ? `the project file "${owner.module.path}"` : `the library "${owner.module.origin.package}"`;
|
|
22755
|
+
}
|
|
22756
|
+
function describeSides(sides) {
|
|
22757
|
+
return sides.length > 1 ? '"shared"' : `"${sides[0] ?? "shared"}"`;
|
|
22758
|
+
}
|
|
22759
|
+
function collisionDiagnostic(collision) {
|
|
22760
|
+
const { name, intruder, other } = collision;
|
|
22761
|
+
const subject = `"${name}" is declared by ${describeOwner(intruder)} and by ${describeOwner(other)} on the ${describeSides(collision.sides)} side`;
|
|
22762
|
+
const message = `${subject}. MTA keeps one global per name, so one silently replaces the other. Stop using one of them.`;
|
|
22763
|
+
return { path: intruder.module.path, diagnostic: createDiagnostic("project", LIBRARY_COLLISION, message, intruder.position) };
|
|
22764
|
+
}
|
|
22765
|
+
function recordCollision(collisions, name, side2, first, next) {
|
|
22766
|
+
if (first.module.origin === null && next.module.origin === null) {
|
|
22767
|
+
return;
|
|
22768
|
+
}
|
|
22769
|
+
const intruder = next.module.origin === null ? first : next;
|
|
22770
|
+
const other = intruder === next ? first : next;
|
|
22771
|
+
const key = `${name}:${intruder.module.path}:${other.module.path}`;
|
|
22772
|
+
const found = collisions.get(key);
|
|
22773
|
+
if (found === void 0) {
|
|
22774
|
+
collisions.set(key, { name, intruder, other, sides: [side2] });
|
|
22775
|
+
return;
|
|
22776
|
+
}
|
|
22777
|
+
found.sides.push(side2);
|
|
22778
|
+
}
|
|
22779
|
+
function validateLibraryGlobals(modules) {
|
|
22780
|
+
const owners = /* @__PURE__ */ new Map();
|
|
22781
|
+
const collisions = /* @__PURE__ */ new Map();
|
|
22782
|
+
if (!modules.some((module) => module.origin !== null)) {
|
|
22783
|
+
return [];
|
|
22784
|
+
}
|
|
22785
|
+
for (const module of modules) {
|
|
22786
|
+
for (const [name, position2] of module.declaredGlobals) {
|
|
22787
|
+
for (const side2 of sidesOf(module.environment)) {
|
|
22788
|
+
const key = `${side2}:${name}`;
|
|
22789
|
+
const first = owners.get(key);
|
|
22790
|
+
if (first === void 0) {
|
|
22791
|
+
owners.set(key, { module, position: position2 });
|
|
22792
|
+
continue;
|
|
22793
|
+
}
|
|
22794
|
+
recordCollision(collisions, name, side2, first, { module, position: position2 });
|
|
22795
|
+
}
|
|
22796
|
+
}
|
|
22797
|
+
}
|
|
22798
|
+
return [...collisions.values()].map(collisionDiagnostic);
|
|
22799
|
+
}
|
|
22800
|
+
function shadowsApi(name, sides) {
|
|
22801
|
+
return sides.find((side2) => builtinSymbols(side2).has(name)) ?? null;
|
|
22802
|
+
}
|
|
22803
|
+
function validateLibraryApiShadowing(modules) {
|
|
22804
|
+
const diagnostics = [];
|
|
22805
|
+
for (const module of modules) {
|
|
22806
|
+
if (module.origin === null) {
|
|
22807
|
+
continue;
|
|
22808
|
+
}
|
|
22809
|
+
for (const [name, position2] of module.declaredGlobals) {
|
|
22810
|
+
const side2 = shadowsApi(name, sidesOf(module.environment));
|
|
22811
|
+
if (side2 === null) {
|
|
22812
|
+
continue;
|
|
22813
|
+
}
|
|
22814
|
+
const subject = `The library "${module.origin.package}" declares "${name}", which the MTA API defines for the "${side2}" side`;
|
|
22815
|
+
const message = `${subject}. Every file in the resource sees the library's version. Keep it only if the library means to wrap it.`;
|
|
22816
|
+
diagnostics.push({ path: module.path, diagnostic: createDiagnostic("project", LIBRARY_SHADOWS_API, message, position2, "warning") });
|
|
22817
|
+
}
|
|
22818
|
+
}
|
|
22819
|
+
return diagnostics;
|
|
22820
|
+
}
|
|
22821
|
+
function projectReferenceDiagnostic(module, symbol, position2) {
|
|
22822
|
+
const subject = `"${symbol.name}" is declared by the project file "${symbol.path}" and cannot be used from the library "${module.origin?.package ?? ""}"`;
|
|
22823
|
+
const message = `${subject}. A library sees only its own files and the libraries it requires.`;
|
|
22824
|
+
return { path: module.path, diagnostic: createDiagnostic("project", "project-library-project-reference", message, position2) };
|
|
22825
|
+
}
|
|
22369
22826
|
function validateModuleReferences(modules) {
|
|
22370
22827
|
const symbols = buildSymbolTable(modules);
|
|
22828
|
+
const libraries = new Set(modules.filter((module) => module.origin !== null).map((module) => module.path));
|
|
22371
22829
|
const diagnostics = [];
|
|
22372
22830
|
for (const module of modules) {
|
|
22373
22831
|
for (const [name, position2] of module.externalReferences) {
|
|
22374
22832
|
const symbol = symbols.get(name);
|
|
22375
|
-
if (symbol === void 0 || symbol.path === module.path
|
|
22833
|
+
if (symbol === void 0 || symbol.path === module.path) {
|
|
22834
|
+
continue;
|
|
22835
|
+
}
|
|
22836
|
+
if (module.origin !== null && !libraries.has(symbol.path)) {
|
|
22837
|
+
diagnostics.push(projectReferenceDiagnostic(module, symbol, position2));
|
|
22838
|
+
continue;
|
|
22839
|
+
}
|
|
22840
|
+
if (canReference(module.environment, symbol.environment)) {
|
|
22376
22841
|
continue;
|
|
22377
22842
|
}
|
|
22378
22843
|
diagnostics.push(referenceDiagnostic(module, symbol, position2));
|
|
@@ -22389,6 +22854,7 @@ function compileModule(file, ambient, context) {
|
|
|
22389
22854
|
const result = compile(file.source, {
|
|
22390
22855
|
filePath: file.path,
|
|
22391
22856
|
...file.environment === void 0 ? {} : { environment: file.environment },
|
|
22857
|
+
environmentLocked: file.origin !== void 0,
|
|
22392
22858
|
ambient,
|
|
22393
22859
|
contracts: context.contracts,
|
|
22394
22860
|
project: isTestPath(file.path) ? context.testProject : context.project,
|
|
@@ -22398,6 +22864,7 @@ function compileModule(file, ambient, context) {
|
|
|
22398
22864
|
});
|
|
22399
22865
|
return {
|
|
22400
22866
|
path: file.path,
|
|
22867
|
+
origin: file.origin ?? null,
|
|
22401
22868
|
environment: result.environment,
|
|
22402
22869
|
isDeclaration: isDeclarationPath(file.path),
|
|
22403
22870
|
code: result.code,
|
|
@@ -22427,7 +22894,7 @@ function createProjectCache() {
|
|
|
22427
22894
|
const declarationCache = /* @__PURE__ */ new Map();
|
|
22428
22895
|
const moduleCache = /* @__PURE__ */ new Map();
|
|
22429
22896
|
function declarationsFor(file, options, reused) {
|
|
22430
|
-
const hash = hashString(`${file.environment ?? ""}|${optionsKey(options)}|${file.source}`);
|
|
22897
|
+
const hash = hashString(`${file.environment ?? ""}|${file.origin?.root ?? ""}|${optionsKey(options)}|${file.source}`);
|
|
22431
22898
|
const cached = declarationCache.get(file.path);
|
|
22432
22899
|
if (cached !== void 0 && cached.hash === hash) {
|
|
22433
22900
|
reused.count += 1;
|
|
@@ -22436,11 +22903,13 @@ function createProjectCache() {
|
|
|
22436
22903
|
const result = compile(file.source, {
|
|
22437
22904
|
filePath: file.path,
|
|
22438
22905
|
...file.environment === void 0 ? {} : { environment: file.environment },
|
|
22906
|
+
environmentLocked: file.origin !== void 0,
|
|
22439
22907
|
compilerOptions: options,
|
|
22440
22908
|
emitCode: false
|
|
22441
22909
|
});
|
|
22442
22910
|
const entry = {
|
|
22443
22911
|
path: file.path,
|
|
22912
|
+
isLibrary: file.origin !== void 0,
|
|
22444
22913
|
hash,
|
|
22445
22914
|
environment: result.environment,
|
|
22446
22915
|
declarations: result.declarations,
|
|
@@ -22491,7 +22960,8 @@ function createProjectCache() {
|
|
|
22491
22960
|
});
|
|
22492
22961
|
const references = validateModuleReferences(modules);
|
|
22493
22962
|
const contributions = validateContributions(modules);
|
|
22494
|
-
const
|
|
22963
|
+
const libraries = [...validateLibraryGlobals(modules), ...validateLibraryApiShadowing(modules)];
|
|
22964
|
+
const collectedDiagnostics = sortFileDiagnostics([...flattenDiagnostics(modules), ...references, ...contributions, ...libraries]);
|
|
22495
22965
|
const diagnostics = compilerOptions.warningsAsErrors ? promoteWarnings(collectedDiagnostics) : collectedDiagnostics;
|
|
22496
22966
|
const paths = new Set(files.map((file) => file.path));
|
|
22497
22967
|
prune(declarationCache, paths);
|
|
@@ -22519,7 +22989,7 @@ function helperList(config, inputs) {
|
|
|
22519
22989
|
const helpers = [...config.helpers, "env"];
|
|
22520
22990
|
return helpers.sort();
|
|
22521
22991
|
}
|
|
22522
|
-
function resourceOptions(config, inputs, minMtaVersion, developmentLogs, layout) {
|
|
22992
|
+
function resourceOptions(config, inputs, minMtaVersion, developmentLogs, layout, libraryFiles) {
|
|
22523
22993
|
const options = {
|
|
22524
22994
|
oop: config.compilerOptions.oop,
|
|
22525
22995
|
dependencies: config.dependencies,
|
|
@@ -22528,6 +22998,7 @@ function resourceOptions(config, inputs, minMtaVersion, developmentLogs, layout)
|
|
|
22528
22998
|
configuration: inputs.configuration,
|
|
22529
22999
|
environmentFile: config.environment.file,
|
|
22530
23000
|
loadOrder: config.loadOrder,
|
|
23001
|
+
libraryFiles,
|
|
22531
23002
|
minMtaVersion,
|
|
22532
23003
|
developmentLogs,
|
|
22533
23004
|
layout,
|
|
@@ -22570,9 +23041,11 @@ function runCompile(root, config, options = {}) {
|
|
|
22570
23041
|
const excluded = [config.outDir, config.contracts];
|
|
22571
23042
|
const sources = discoverSources(root, config.sources, excluded);
|
|
22572
23043
|
const inputs = readProjectInputs(root, { assets: config.assets, environment: config.environment, excluded });
|
|
22573
|
-
const
|
|
23044
|
+
const libraries = resolveLibraries(root, config.libraries);
|
|
23045
|
+
const projectFiles = [...sources.files, ...options.additionalFiles ?? []].sort((left, right) => left.path.localeCompare(right.path));
|
|
23046
|
+
const files = [...libraries.files, ...projectFiles];
|
|
22574
23047
|
const contracts = readDependencyContracts(root, config);
|
|
22575
|
-
const diagnostics = [...sources.diagnostics, ...inputs.diagnostics, ...contracts.diagnostics];
|
|
23048
|
+
const diagnostics = [...sources.diagnostics, ...inputs.diagnostics, ...libraries.diagnostics, ...contracts.diagnostics];
|
|
22576
23049
|
if (hasCliErrors(diagnostics)) {
|
|
22577
23050
|
tracker.end("failed");
|
|
22578
23051
|
return {
|
|
@@ -22601,7 +23074,7 @@ function runCompile(root, config, options = {}) {
|
|
|
22601
23074
|
tracker.begin("assembly");
|
|
22602
23075
|
const assembly = assembleResource(
|
|
22603
23076
|
project,
|
|
22604
|
-
resourceOptions(config, inputs, options.minMtaVersion ?? null, options.developmentLogs ?? null, options.layout ?? "tree"),
|
|
23077
|
+
resourceOptions(config, inputs, options.minMtaVersion ?? null, options.developmentLogs ?? null, options.layout ?? "tree", libraries.verbatim),
|
|
22605
23078
|
(step) => {
|
|
22606
23079
|
if (step === "assembly") {
|
|
22607
23080
|
tracker.begin("manifest");
|
|
@@ -22626,8 +23099,8 @@ function runCompile(root, config, options = {}) {
|
|
|
22626
23099
|
}
|
|
22627
23100
|
|
|
22628
23101
|
// src/build/resource-map-file.ts
|
|
22629
|
-
import { existsSync as
|
|
22630
|
-
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join4, posix, relative as relative2, resolve as
|
|
23102
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, readdirSync as readdirSync2, unlinkSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
23103
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join4, posix, relative as relative2, resolve as resolve10 } from "node:path";
|
|
22631
23104
|
var RESOURCE_MAP_SUFFIX = ".luam-map.json";
|
|
22632
23105
|
function isObject(value) {
|
|
22633
23106
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -22692,28 +23165,28 @@ function reason(error) {
|
|
|
22692
23165
|
return error instanceof Error ? error.message : String(error);
|
|
22693
23166
|
}
|
|
22694
23167
|
function resourceMapPath(root, config) {
|
|
22695
|
-
return
|
|
23168
|
+
return resolve10(root, config.outDir, `${config.name}${RESOURCE_MAP_SUFFIX}`);
|
|
22696
23169
|
}
|
|
22697
23170
|
function explicitResourceMapPath(root, path) {
|
|
22698
|
-
return isAbsolute3(path) ? path :
|
|
23171
|
+
return isAbsolute3(path) ? path : resolve10(root, path);
|
|
22699
23172
|
}
|
|
22700
23173
|
function writeResourceMap(root, config, map) {
|
|
22701
23174
|
const path = resourceMapPath(root, config);
|
|
22702
23175
|
if (map === null) {
|
|
22703
|
-
if (
|
|
23176
|
+
if (existsSync6(path)) {
|
|
22704
23177
|
unlinkSync(path);
|
|
22705
23178
|
}
|
|
22706
23179
|
return;
|
|
22707
23180
|
}
|
|
22708
23181
|
mkdirSync3(dirname3(path), { recursive: true });
|
|
22709
23182
|
const content = serializeResourceMap(map);
|
|
22710
|
-
if (!
|
|
23183
|
+
if (!existsSync6(path) || readFileSync8(path, "utf8") !== content) {
|
|
22711
23184
|
writeFileSync4(path, content, "utf8");
|
|
22712
23185
|
}
|
|
22713
23186
|
}
|
|
22714
23187
|
function readResourceMap(path) {
|
|
22715
23188
|
try {
|
|
22716
|
-
const value = JSON.parse(
|
|
23189
|
+
const value = JSON.parse(readFileSync8(path, "utf8"));
|
|
22717
23190
|
if (isObject(value) && Number.isInteger(value.version) && value.version !== RESOURCE_MAP_VERSION) {
|
|
22718
23191
|
return { map: null, error: `Resource map version ${String(value.version)} is not supported.` };
|
|
22719
23192
|
}
|
|
@@ -22747,7 +23220,7 @@ function collectResourceMaps(directory, found) {
|
|
|
22747
23220
|
}
|
|
22748
23221
|
}
|
|
22749
23222
|
function discoverResourceMap(root) {
|
|
22750
|
-
if (!
|
|
23223
|
+
if (!existsSync6(root)) {
|
|
22751
23224
|
return { path: null, candidates: [] };
|
|
22752
23225
|
}
|
|
22753
23226
|
const found = [];
|
|
@@ -22757,8 +23230,8 @@ function discoverResourceMap(root) {
|
|
|
22757
23230
|
}
|
|
22758
23231
|
|
|
22759
23232
|
// src/build/resource-writer.ts
|
|
22760
|
-
import { existsSync as
|
|
22761
|
-
import { dirname as dirname4, isAbsolute as isAbsolute4, relative as relative4, resolve as
|
|
23233
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
23234
|
+
import { dirname as dirname4, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve12 } from "node:path";
|
|
22762
23235
|
|
|
22763
23236
|
// src/build/lua-tokens.ts
|
|
22764
23237
|
var WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\r", "\v", "\f"]);
|
|
@@ -22961,8 +23434,8 @@ function minifyLuaFiles(files) {
|
|
|
22961
23434
|
}
|
|
22962
23435
|
|
|
22963
23436
|
// src/build/resource-prune.ts
|
|
22964
|
-
import { existsSync as
|
|
22965
|
-
import { join as join5, relative as relative3, resolve as
|
|
23437
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3, rmdirSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
23438
|
+
import { join as join5, relative as relative3, resolve as resolve11 } from "node:path";
|
|
22966
23439
|
var GENERATED_MANIFEST = "meta.xml";
|
|
22967
23440
|
var GENERATED_EXTENSION = ".lua";
|
|
22968
23441
|
var PROTECTED = /* @__PURE__ */ new Set([ENVIRONMENT_FILE, ".env.local"]);
|
|
@@ -22979,17 +23452,17 @@ function isGenerated(relativePath2, options) {
|
|
|
22979
23452
|
return options.generatedRoots.some((root) => isUnderRoot(relativePath2, root));
|
|
22980
23453
|
}
|
|
22981
23454
|
function removeEmptyDirectories(targetDir, directory) {
|
|
22982
|
-
if (
|
|
23455
|
+
if (resolve11(directory) === resolve11(targetDir)) {
|
|
22983
23456
|
return;
|
|
22984
23457
|
}
|
|
22985
23458
|
if (readdirSync3(directory).length > 0) {
|
|
22986
23459
|
return;
|
|
22987
23460
|
}
|
|
22988
23461
|
rmdirSync(directory);
|
|
22989
|
-
removeEmptyDirectories(targetDir,
|
|
23462
|
+
removeEmptyDirectories(targetDir, resolve11(directory, ".."));
|
|
22990
23463
|
}
|
|
22991
23464
|
function pruneResource(targetDir, keep, options) {
|
|
22992
|
-
if (!
|
|
23465
|
+
if (!existsSync7(targetDir)) {
|
|
22993
23466
|
return [];
|
|
22994
23467
|
}
|
|
22995
23468
|
const removed = [];
|
|
@@ -23039,7 +23512,7 @@ function resourceFiles(build) {
|
|
|
23039
23512
|
return files;
|
|
23040
23513
|
}
|
|
23041
23514
|
function resolveInside(targetDir, path) {
|
|
23042
|
-
const absolute =
|
|
23515
|
+
const absolute = resolve12(targetDir, path);
|
|
23043
23516
|
const inside = relative4(targetDir, absolute);
|
|
23044
23517
|
if (inside.startsWith("..") || isAbsolute4(inside)) {
|
|
23045
23518
|
throw new Error(`The generated file "${path}" resolves outside the resource directory "${targetDir}".`);
|
|
@@ -23047,7 +23520,7 @@ function resolveInside(targetDir, path) {
|
|
|
23047
23520
|
return absolute;
|
|
23048
23521
|
}
|
|
23049
23522
|
function writeIfChanged(absolute, content) {
|
|
23050
|
-
if (
|
|
23523
|
+
if (existsSync8(absolute) && readFileSync9(absolute).equals(content)) {
|
|
23051
23524
|
return false;
|
|
23052
23525
|
}
|
|
23053
23526
|
mkdirSync4(dirname4(absolute), { recursive: true });
|
|
@@ -23059,7 +23532,7 @@ function writeEnvironmentFile(targetDir, template) {
|
|
|
23059
23532
|
return false;
|
|
23060
23533
|
}
|
|
23061
23534
|
const absolute = resolveInside(targetDir, ENVIRONMENT_FILE);
|
|
23062
|
-
if (
|
|
23535
|
+
if (existsSync8(absolute)) {
|
|
23063
23536
|
return false;
|
|
23064
23537
|
}
|
|
23065
23538
|
mkdirSync4(dirname4(absolute), { recursive: true });
|
|
@@ -23087,7 +23560,7 @@ function writeResource(targetDir, build, options) {
|
|
|
23087
23560
|
advance(path);
|
|
23088
23561
|
}
|
|
23089
23562
|
for (const asset of build.assets) {
|
|
23090
|
-
if (writeIfChanged(resolveInside(targetDir, asset.path),
|
|
23563
|
+
if (writeIfChanged(resolveInside(targetDir, asset.path), readFileSync9(resolve12(options.root, asset.source)))) {
|
|
23091
23564
|
written.push(asset.path);
|
|
23092
23565
|
advance(asset.path);
|
|
23093
23566
|
continue;
|
|
@@ -23117,7 +23590,7 @@ function destinationRoot(mapping) {
|
|
|
23117
23590
|
}
|
|
23118
23591
|
function generatedRoots(config) {
|
|
23119
23592
|
const roots = config.assets.map(destinationRoot).filter((root) => root.length > 0);
|
|
23120
|
-
return [.../* @__PURE__ */ new Set([...roots, LIBRARY_DIRECTORY])];
|
|
23593
|
+
return [.../* @__PURE__ */ new Set([...roots, LIBRARY_DIRECTORY, LIBRARIES_DIRECTORY])];
|
|
23121
23594
|
}
|
|
23122
23595
|
function trackedWriteOptions(root, config, environmentTemplate, tracker) {
|
|
23123
23596
|
return {
|
|
@@ -23204,16 +23677,16 @@ function reportBuildOutcome(context, outcome, action) {
|
|
|
23204
23677
|
}
|
|
23205
23678
|
|
|
23206
23679
|
// src/commands/resource-targets.ts
|
|
23207
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
23680
|
+
import { isAbsolute as isAbsolute5, resolve as resolve13 } from "node:path";
|
|
23208
23681
|
function resolveBuildTarget(root, config) {
|
|
23209
|
-
return
|
|
23682
|
+
return resolve13(root, config.outDir, config.name);
|
|
23210
23683
|
}
|
|
23211
23684
|
function resolveServerTarget(root, config) {
|
|
23212
23685
|
if (config.serverPath === null) {
|
|
23213
23686
|
return null;
|
|
23214
23687
|
}
|
|
23215
|
-
const serverRoot = isAbsolute5(config.serverPath) ? config.serverPath :
|
|
23216
|
-
return
|
|
23688
|
+
const serverRoot = isAbsolute5(config.serverPath) ? config.serverPath : resolve13(root, config.serverPath);
|
|
23689
|
+
return resolve13(serverRoot, config.resourcesDir, config.name);
|
|
23217
23690
|
}
|
|
23218
23691
|
|
|
23219
23692
|
// src/reporting/progress-renderer.ts
|
|
@@ -23258,7 +23731,7 @@ function createProgressRenderer(reporter, options = {}) {
|
|
|
23258
23731
|
paint(reporter.style.eraseLine());
|
|
23259
23732
|
dirty = false;
|
|
23260
23733
|
}
|
|
23261
|
-
function
|
|
23734
|
+
function render3(event) {
|
|
23262
23735
|
const columns = Math.max(20, reporter.capability.columns - 1);
|
|
23263
23736
|
const line2 = activeLine(reporter, event);
|
|
23264
23737
|
paint(`${reporter.style.eraseLine()}${line2.slice(0, columns)}`);
|
|
@@ -23278,7 +23751,7 @@ function createProgressRenderer(reporter, options = {}) {
|
|
|
23278
23751
|
if (frames > 0 && now() - lastPaintAt < throttleMs) {
|
|
23279
23752
|
return;
|
|
23280
23753
|
}
|
|
23281
|
-
|
|
23754
|
+
render3(event);
|
|
23282
23755
|
}
|
|
23283
23756
|
return {
|
|
23284
23757
|
listen: (event) => {
|
|
@@ -23321,6 +23794,7 @@ async function runBuildCommand(context, options = {}) {
|
|
|
23321
23794
|
if (outcome.build === null) {
|
|
23322
23795
|
reportBuildOutcome(context, outcome, "Build");
|
|
23323
23796
|
reportPhaseTimings(reporter, tracker.durations(), totalDuration(tracker.durations()));
|
|
23797
|
+
options.onOutcome?.(outcome);
|
|
23324
23798
|
return EXIT_DIAGNOSTICS;
|
|
23325
23799
|
}
|
|
23326
23800
|
const target = resolveBuildTarget(context.root, context.config);
|
|
@@ -23333,6 +23807,7 @@ async function runBuildCommand(context, options = {}) {
|
|
|
23333
23807
|
tracker.end("failed");
|
|
23334
23808
|
renderer.clear();
|
|
23335
23809
|
reporter.error(`Build wrote nothing to "${target}". ${error instanceof Error ? error.message : String(error)}`);
|
|
23810
|
+
options.onOutcome?.(outcome);
|
|
23336
23811
|
return EXIT_DIAGNOSTICS;
|
|
23337
23812
|
}
|
|
23338
23813
|
writeResourceMap(context.root, context.config, writtenMap(outcome.map, minify));
|
|
@@ -23345,13 +23820,93 @@ async function runBuildCommand(context, options = {}) {
|
|
|
23345
23820
|
const counts = `${result.unchanged} unchanged, ${result.removed.length} removed`;
|
|
23346
23821
|
reporter.info(`Wrote ${pluralize(result.written.length, "file")} to "${target}" (${counts}).`);
|
|
23347
23822
|
reportPhaseTimings(reporter, tracker.durations(), totalDuration(tracker.durations()));
|
|
23823
|
+
options.onOutcome?.(outcome);
|
|
23348
23824
|
return EXIT_OK;
|
|
23349
23825
|
}
|
|
23350
23826
|
|
|
23827
|
+
// src/reporting/json-report.ts
|
|
23828
|
+
var REPORT_SCHEMA_VERSION = 1;
|
|
23829
|
+
function fromCli(diagnostic) {
|
|
23830
|
+
return { path: null, line: null, column: null, endLine: null, endColumn: null, ...diagnostic };
|
|
23831
|
+
}
|
|
23832
|
+
function fromFile(entry) {
|
|
23833
|
+
const { position: position2, end, severity, code, message } = entry.diagnostic;
|
|
23834
|
+
return {
|
|
23835
|
+
path: entry.path,
|
|
23836
|
+
line: position2.line,
|
|
23837
|
+
column: position2.column,
|
|
23838
|
+
endLine: end === null ? null : end.line,
|
|
23839
|
+
endColumn: end === null ? null : end.column,
|
|
23840
|
+
severity,
|
|
23841
|
+
code,
|
|
23842
|
+
message
|
|
23843
|
+
};
|
|
23844
|
+
}
|
|
23845
|
+
function buildReport(command, outcome, success) {
|
|
23846
|
+
const cli = countCliDiagnostics(outcome.diagnostics);
|
|
23847
|
+
const files = countFileDiagnostics(outcome.fileDiagnostics);
|
|
23848
|
+
return {
|
|
23849
|
+
version: REPORT_SCHEMA_VERSION,
|
|
23850
|
+
luam: VERSION,
|
|
23851
|
+
command,
|
|
23852
|
+
success,
|
|
23853
|
+
diagnostics: [...outcome.diagnostics.map(fromCli), ...outcome.fileDiagnostics.map(fromFile)],
|
|
23854
|
+
summary: {
|
|
23855
|
+
errors: cli.errors + files.errors,
|
|
23856
|
+
warnings: cli.warnings + files.warnings,
|
|
23857
|
+
files: outcome.fileCount,
|
|
23858
|
+
durationMs: Math.round(outcome.durationMs)
|
|
23859
|
+
}
|
|
23860
|
+
};
|
|
23861
|
+
}
|
|
23862
|
+
function writeReport(logger, report2) {
|
|
23863
|
+
logger.info(JSON.stringify(report2));
|
|
23864
|
+
}
|
|
23865
|
+
|
|
23866
|
+
// src/reporting/silent.ts
|
|
23867
|
+
function createSilentLogger() {
|
|
23868
|
+
return {
|
|
23869
|
+
info: () => void 0,
|
|
23870
|
+
warn: () => void 0,
|
|
23871
|
+
error: () => void 0
|
|
23872
|
+
};
|
|
23873
|
+
}
|
|
23874
|
+
function createSilentReporter() {
|
|
23875
|
+
return createReporter(createSilentLogger(), PLAIN_CAPABILITY, () => void 0);
|
|
23876
|
+
}
|
|
23877
|
+
|
|
23878
|
+
// src/commands/json-command.ts
|
|
23879
|
+
function emptyReport(command, success) {
|
|
23880
|
+
return {
|
|
23881
|
+
version: REPORT_SCHEMA_VERSION,
|
|
23882
|
+
luam: VERSION,
|
|
23883
|
+
command,
|
|
23884
|
+
success,
|
|
23885
|
+
diagnostics: [],
|
|
23886
|
+
summary: { errors: success ? 0 : 1, warnings: 0, files: 0, durationMs: 0 }
|
|
23887
|
+
};
|
|
23888
|
+
}
|
|
23889
|
+
function captureJson(context) {
|
|
23890
|
+
let captured = null;
|
|
23891
|
+
return {
|
|
23892
|
+
context: { ...context, logger: createSilentLogger(), reporter: createSilentReporter() },
|
|
23893
|
+
outcome: () => captured,
|
|
23894
|
+
record: (outcome) => {
|
|
23895
|
+
captured = outcome;
|
|
23896
|
+
}
|
|
23897
|
+
};
|
|
23898
|
+
}
|
|
23899
|
+
function emitJson(logger, command, capture, code) {
|
|
23900
|
+
const outcome = capture.outcome();
|
|
23901
|
+
const success = code === EXIT_OK;
|
|
23902
|
+
writeReport(logger, outcome === null ? emptyReport(command, success) : buildReport(command, outcome, success));
|
|
23903
|
+
return code;
|
|
23904
|
+
}
|
|
23905
|
+
|
|
23351
23906
|
// src/cli/registry/build-registration.ts
|
|
23352
23907
|
function registerBuildCommand(program2, runtime) {
|
|
23353
23908
|
const command = program2.command("build").description("Compile the project and write the resource to the output directory.");
|
|
23354
|
-
addMinifyOptions(addLayoutOptions(addProjectOptions(command))).addOption(noMapOption()).addOption(offlineOption());
|
|
23909
|
+
addMinifyOptions(addLayoutOptions(addProjectOptions(command))).addOption(noMapOption()).addOption(offlineOption()).addOption(jsonOption());
|
|
23355
23910
|
command.action(async (options) => {
|
|
23356
23911
|
const project = createProjectContext(runtime, "build", options);
|
|
23357
23912
|
if (project.context === null) {
|
|
@@ -23359,39 +23914,236 @@ function registerBuildCommand(program2, runtime) {
|
|
|
23359
23914
|
return;
|
|
23360
23915
|
}
|
|
23361
23916
|
const bundled = options.bundle ?? project.context.config.output.bundle;
|
|
23362
|
-
|
|
23917
|
+
const build = {
|
|
23363
23918
|
layout: bundled ? "bundle" : "tree",
|
|
23364
23919
|
map: options.map && project.context.config.output.map,
|
|
23365
23920
|
minify: options.minify ?? project.context.config.output.minify
|
|
23366
|
-
}
|
|
23921
|
+
};
|
|
23922
|
+
if (options.json !== true) {
|
|
23923
|
+
runtime.exitCode = await runBuildCommand(project.context, build);
|
|
23924
|
+
return;
|
|
23925
|
+
}
|
|
23926
|
+
const capture = captureJson(project.context);
|
|
23927
|
+
runtime.exitCode = emitJson(runtime.logger, "build", capture, await runBuildCommand(capture.context, { ...build, onOutcome: capture.record }));
|
|
23928
|
+
});
|
|
23929
|
+
}
|
|
23930
|
+
|
|
23931
|
+
// src/reporting/rebuild-separator.ts
|
|
23932
|
+
var RULE_WIDTH = 40;
|
|
23933
|
+
function formatTimestamp(at) {
|
|
23934
|
+
return at.toISOString().slice(11, 19);
|
|
23935
|
+
}
|
|
23936
|
+
function reportRebuildSeparator(reporter, at = /* @__PURE__ */ new Date()) {
|
|
23937
|
+
const rule = (reporter.capability.unicode ? "\u2500" : "-").repeat(RULE_WIDTH);
|
|
23938
|
+
reporter.raw("");
|
|
23939
|
+
reporter.detail(`${rule} rebuild at ${formatTimestamp(at)}`);
|
|
23940
|
+
}
|
|
23941
|
+
|
|
23942
|
+
// src/watch/abort-wait.ts
|
|
23943
|
+
function untilAborted(signal) {
|
|
23944
|
+
return new Promise((resolveLoop) => {
|
|
23945
|
+
if (signal?.aborted === true) {
|
|
23946
|
+
resolveLoop();
|
|
23947
|
+
return;
|
|
23948
|
+
}
|
|
23949
|
+
const stop = () => {
|
|
23950
|
+
process.off("SIGINT", stop);
|
|
23951
|
+
signal?.removeEventListener("abort", stop);
|
|
23952
|
+
resolveLoop();
|
|
23953
|
+
};
|
|
23954
|
+
if (signal !== null) {
|
|
23955
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
23956
|
+
}
|
|
23957
|
+
process.on("SIGINT", stop);
|
|
23367
23958
|
});
|
|
23368
23959
|
}
|
|
23369
23960
|
|
|
23961
|
+
// src/watch/manifest-watcher.ts
|
|
23962
|
+
import { existsSync as existsSync10, watch as watch2 } from "node:fs";
|
|
23963
|
+
|
|
23964
|
+
// src/watch/source-watcher.ts
|
|
23965
|
+
import { existsSync as existsSync9, watch } from "node:fs";
|
|
23966
|
+
import { relative as relative5, resolve as resolve14 } from "node:path";
|
|
23967
|
+
var DEFAULT_DEBOUNCE_MS = 120;
|
|
23968
|
+
function watchSources(root, sources, onChange, debounceMs = DEFAULT_DEBOUNCE_MS) {
|
|
23969
|
+
const resolver = createSourceResolver(sources);
|
|
23970
|
+
const watchers = [];
|
|
23971
|
+
let timer = null;
|
|
23972
|
+
const schedule = () => {
|
|
23973
|
+
if (timer !== null) {
|
|
23974
|
+
clearTimeout(timer);
|
|
23975
|
+
}
|
|
23976
|
+
timer = setTimeout(() => {
|
|
23977
|
+
timer = null;
|
|
23978
|
+
onChange();
|
|
23979
|
+
}, debounceMs);
|
|
23980
|
+
};
|
|
23981
|
+
const isWatched = (directory, filename) => {
|
|
23982
|
+
const path = normalizePattern(relative5(root, resolve14(directory, filename)));
|
|
23983
|
+
return path.endsWith(SOURCE_EXTENSION) && resolver.resolve(path).matches.length > 0;
|
|
23984
|
+
};
|
|
23985
|
+
for (const entry of resolver.roots) {
|
|
23986
|
+
const absolute = resolve14(root, entry);
|
|
23987
|
+
if (!existsSync9(absolute)) {
|
|
23988
|
+
continue;
|
|
23989
|
+
}
|
|
23990
|
+
watchers.push(
|
|
23991
|
+
watch(absolute, { recursive: true }, (_event, filename) => {
|
|
23992
|
+
if (filename !== null && isWatched(absolute, filename.toString())) {
|
|
23993
|
+
schedule();
|
|
23994
|
+
}
|
|
23995
|
+
})
|
|
23996
|
+
);
|
|
23997
|
+
}
|
|
23998
|
+
return {
|
|
23999
|
+
close: () => {
|
|
24000
|
+
if (timer !== null) {
|
|
24001
|
+
clearTimeout(timer);
|
|
24002
|
+
timer = null;
|
|
24003
|
+
}
|
|
24004
|
+
for (const watcher of watchers) {
|
|
24005
|
+
watcher.close();
|
|
24006
|
+
}
|
|
24007
|
+
}
|
|
24008
|
+
};
|
|
24009
|
+
}
|
|
24010
|
+
function watchedRoots(sources) {
|
|
24011
|
+
return createSourceResolver(sources).roots;
|
|
24012
|
+
}
|
|
24013
|
+
|
|
24014
|
+
// src/watch/manifest-watcher.ts
|
|
24015
|
+
function watchManifest(path, onChange, debounceMs = DEFAULT_DEBOUNCE_MS) {
|
|
24016
|
+
let timer = null;
|
|
24017
|
+
let watcher = null;
|
|
24018
|
+
const clear = () => {
|
|
24019
|
+
if (timer !== null) {
|
|
24020
|
+
clearTimeout(timer);
|
|
24021
|
+
timer = null;
|
|
24022
|
+
}
|
|
24023
|
+
};
|
|
24024
|
+
if (existsSync10(path)) {
|
|
24025
|
+
watcher = watch2(path, () => {
|
|
24026
|
+
clear();
|
|
24027
|
+
timer = setTimeout(() => {
|
|
24028
|
+
timer = null;
|
|
24029
|
+
onChange();
|
|
24030
|
+
}, debounceMs);
|
|
24031
|
+
});
|
|
24032
|
+
}
|
|
24033
|
+
return {
|
|
24034
|
+
close: () => {
|
|
24035
|
+
clear();
|
|
24036
|
+
watcher?.close();
|
|
24037
|
+
}
|
|
24038
|
+
};
|
|
24039
|
+
}
|
|
24040
|
+
|
|
23370
24041
|
// src/commands/check-command.ts
|
|
23371
|
-
function runCheckCommand(context) {
|
|
24042
|
+
function runCheckCommand(context, options = {}) {
|
|
23372
24043
|
const reporter = commandReporter(context);
|
|
23373
24044
|
const renderer = createProgressRenderer(reporter);
|
|
23374
24045
|
const tracker = createPhaseTracker(renderer.listen);
|
|
23375
|
-
const
|
|
24046
|
+
const cache3 = options.cache;
|
|
24047
|
+
const outcome = runCompile(context.root, context.config, cache3 === void 0 ? { tracker } : { tracker, cache: cache3 });
|
|
23376
24048
|
renderer.clear();
|
|
23377
24049
|
const passed = reportBuildOutcome(context, outcome, "Check");
|
|
23378
24050
|
reportPhaseTimings(reporter, tracker.durations(), totalDuration(tracker.durations()));
|
|
24051
|
+
options.onOutcome?.(outcome);
|
|
23379
24052
|
return passed ? EXIT_OK : EXIT_DIAGNOSTICS;
|
|
23380
24053
|
}
|
|
24054
|
+
async function runCheckWatch(context, options) {
|
|
24055
|
+
const reporter = commandReporter(context);
|
|
24056
|
+
let config = context.config;
|
|
24057
|
+
let cache3 = createProjectCache();
|
|
24058
|
+
const sources = [];
|
|
24059
|
+
let running = false;
|
|
24060
|
+
let queued = false;
|
|
24061
|
+
const announce = () => {
|
|
24062
|
+
const roots = watchedRoots(config.sources).map((entry) => `"${entry.length === 0 ? "." : entry}"`);
|
|
24063
|
+
reporter.info(`Watching ${roots.join(", ")} for changes. Press Ctrl+C to stop.`);
|
|
24064
|
+
};
|
|
24065
|
+
const recheck = () => {
|
|
24066
|
+
if (running) {
|
|
24067
|
+
queued = true;
|
|
24068
|
+
return;
|
|
24069
|
+
}
|
|
24070
|
+
running = true;
|
|
24071
|
+
do {
|
|
24072
|
+
queued = false;
|
|
24073
|
+
reportRebuildSeparator(reporter);
|
|
24074
|
+
runCheckCommand({ ...context, config }, { cache: cache3 });
|
|
24075
|
+
} while (queued);
|
|
24076
|
+
running = false;
|
|
24077
|
+
};
|
|
24078
|
+
const listen = () => {
|
|
24079
|
+
for (const watcher of sources.splice(0)) {
|
|
24080
|
+
watcher.close();
|
|
24081
|
+
}
|
|
24082
|
+
sources.push(watchSources(context.root, config.sources, recheck));
|
|
24083
|
+
};
|
|
24084
|
+
const reconfigure = () => {
|
|
24085
|
+
const reloaded = options.reload();
|
|
24086
|
+
if (reloaded !== null) {
|
|
24087
|
+
config = reloaded;
|
|
24088
|
+
}
|
|
24089
|
+
cache3 = createProjectCache();
|
|
24090
|
+
listen();
|
|
24091
|
+
recheck();
|
|
24092
|
+
announce();
|
|
24093
|
+
};
|
|
24094
|
+
runCheckCommand(context, { cache: cache3 });
|
|
24095
|
+
listen();
|
|
24096
|
+
const manifest = watchManifest(options.manifestPath, reconfigure);
|
|
24097
|
+
announce();
|
|
24098
|
+
await untilAborted(options.signal);
|
|
24099
|
+
manifest.close();
|
|
24100
|
+
for (const watcher of sources.splice(0)) {
|
|
24101
|
+
watcher.close();
|
|
24102
|
+
}
|
|
24103
|
+
return EXIT_OK;
|
|
24104
|
+
}
|
|
23381
24105
|
|
|
23382
24106
|
// src/cli/registry/check-registration.ts
|
|
23383
24107
|
function registerCheckCommand(program2, runtime) {
|
|
23384
24108
|
const command = program2.command("check").description("Compile the project and report diagnostics without writing files.");
|
|
23385
|
-
addProjectOptions(command);
|
|
23386
|
-
command.action((options) => {
|
|
24109
|
+
addProjectOptions(command).addOption(new Option("--watch", "Keep the command running and re-check on source changes.")).addOption(new Option("--no-watch", "Run the command once and exit.")).addOption(jsonOption());
|
|
24110
|
+
command.action(async (options) => {
|
|
24111
|
+
if (options.json === true && options.watch === true) {
|
|
24112
|
+
runtime.reporter.error('"--json" writes one document and "--watch" never stops. Run "luam check --json" without "--watch".');
|
|
24113
|
+
runtime.exitCode = EXIT_USAGE;
|
|
24114
|
+
return;
|
|
24115
|
+
}
|
|
23387
24116
|
const project = createProjectContext(runtime, "check", options);
|
|
23388
|
-
|
|
24117
|
+
if (project.context === null) {
|
|
24118
|
+
runtime.exitCode = project.error;
|
|
24119
|
+
return;
|
|
24120
|
+
}
|
|
24121
|
+
if (options.json === true) {
|
|
24122
|
+
const capture = captureJson(project.context);
|
|
24123
|
+
runtime.exitCode = emitJson(runtime.logger, "check", capture, runCheckCommand(capture.context, { onOutcome: capture.record }));
|
|
24124
|
+
return;
|
|
24125
|
+
}
|
|
24126
|
+
if (options.watch !== true) {
|
|
24127
|
+
runtime.exitCode = runCheckCommand(project.context);
|
|
24128
|
+
return;
|
|
24129
|
+
}
|
|
24130
|
+
const root = project.context.root;
|
|
24131
|
+
const manifestPath = resolveManifestPath(root, options.manifest ?? null);
|
|
24132
|
+
const reload = () => {
|
|
24133
|
+
const loaded = loadManifest(root, { path: options.manifest ?? null, mode: manifestMode("check"), env: runtime.env });
|
|
24134
|
+
reportManifestDiagnostics(runtime.reporter, loaded.path, loaded.source, loaded.diagnostics);
|
|
24135
|
+
if (loaded.config === null) {
|
|
24136
|
+
runtime.reporter.error(`Manifest "${loaded.path}" is invalid. Keeping the previous configuration.`);
|
|
24137
|
+
}
|
|
24138
|
+
return loaded.config;
|
|
24139
|
+
};
|
|
24140
|
+
runtime.exitCode = await runCheckWatch(project.context, { signal: runtime.overrides.signal ?? null, manifestPath, reload });
|
|
23389
24141
|
});
|
|
23390
24142
|
}
|
|
23391
24143
|
|
|
23392
24144
|
// src/commands/config-command.ts
|
|
23393
|
-
import { existsSync as
|
|
23394
|
-
import { dirname as dirname5, relative as
|
|
24145
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "node:fs";
|
|
24146
|
+
import { dirname as dirname5, relative as relative6, resolve as resolve15 } from "node:path";
|
|
23395
24147
|
|
|
23396
24148
|
// ../compiler/src/project/config-reader.ts
|
|
23397
24149
|
var Reader = class {
|
|
@@ -23605,33 +24357,33 @@ function isGeneratedDeclaration(text) {
|
|
|
23605
24357
|
var DEFAULT_CONFIG_SOURCE = "config.lua";
|
|
23606
24358
|
var DEFAULT_CONFIG_OUTPUT = "config.d.luam";
|
|
23607
24359
|
function escapes(root, path) {
|
|
23608
|
-
const inside =
|
|
23609
|
-
return inside.startsWith("..") ||
|
|
24360
|
+
const inside = relative6(root, path);
|
|
24361
|
+
return inside.startsWith("..") || resolve15(root, inside) !== path;
|
|
23610
24362
|
}
|
|
23611
24363
|
function readSource2(root, source, reporter) {
|
|
23612
|
-
const path =
|
|
24364
|
+
const path = resolve15(root, source);
|
|
23613
24365
|
if (escapes(root, path)) {
|
|
23614
24366
|
reporter.error(`Config declarations read only inside the project, but "${source}" points outside it.`);
|
|
23615
24367
|
return null;
|
|
23616
24368
|
}
|
|
23617
|
-
if (!
|
|
24369
|
+
if (!existsSync11(path)) {
|
|
23618
24370
|
reporter.error(`Config declarations found no file at "${source}".`);
|
|
23619
24371
|
return null;
|
|
23620
24372
|
}
|
|
23621
24373
|
try {
|
|
23622
|
-
return
|
|
24374
|
+
return readFileSync10(path, "utf8");
|
|
23623
24375
|
} catch {
|
|
23624
24376
|
reporter.error(`Config declarations could not read "${source}".`);
|
|
23625
24377
|
return null;
|
|
23626
24378
|
}
|
|
23627
24379
|
}
|
|
23628
24380
|
function writable(root, out, reporter) {
|
|
23629
|
-
const path =
|
|
24381
|
+
const path = resolve15(root, out);
|
|
23630
24382
|
if (escapes(root, path)) {
|
|
23631
24383
|
reporter.error(`Config declarations write only inside the project, but "${out}" points outside it.`);
|
|
23632
24384
|
return null;
|
|
23633
24385
|
}
|
|
23634
|
-
if (
|
|
24386
|
+
if (existsSync11(path) && !isGeneratedDeclaration(readFileSync10(path, "utf8"))) {
|
|
23635
24387
|
reporter.error(`"${out}" was not generated by this command and was left alone. Choose another path with --out.`);
|
|
23636
24388
|
return null;
|
|
23637
24389
|
}
|
|
@@ -23764,85 +24516,7 @@ function createEnsureRunner(context, options = {}) {
|
|
|
23764
24516
|
};
|
|
23765
24517
|
}
|
|
23766
24518
|
|
|
23767
|
-
// src/reporting/rebuild-separator.ts
|
|
23768
|
-
var RULE_WIDTH = 40;
|
|
23769
|
-
function formatTimestamp(at) {
|
|
23770
|
-
return at.toISOString().slice(11, 19);
|
|
23771
|
-
}
|
|
23772
|
-
function reportRebuildSeparator(reporter, at = /* @__PURE__ */ new Date()) {
|
|
23773
|
-
const rule = (reporter.capability.unicode ? "\u2500" : "-").repeat(RULE_WIDTH);
|
|
23774
|
-
reporter.raw("");
|
|
23775
|
-
reporter.detail(`${rule} rebuild at ${formatTimestamp(at)}`);
|
|
23776
|
-
}
|
|
23777
|
-
|
|
23778
|
-
// src/watch/source-watcher.ts
|
|
23779
|
-
import { existsSync as existsSync9, watch } from "node:fs";
|
|
23780
|
-
import { relative as relative6, resolve as resolve14 } from "node:path";
|
|
23781
|
-
var DEFAULT_DEBOUNCE_MS = 120;
|
|
23782
|
-
function watchSources(root, sources, onChange, debounceMs = DEFAULT_DEBOUNCE_MS) {
|
|
23783
|
-
const resolver = createSourceResolver(sources);
|
|
23784
|
-
const watchers = [];
|
|
23785
|
-
let timer = null;
|
|
23786
|
-
const schedule = () => {
|
|
23787
|
-
if (timer !== null) {
|
|
23788
|
-
clearTimeout(timer);
|
|
23789
|
-
}
|
|
23790
|
-
timer = setTimeout(() => {
|
|
23791
|
-
timer = null;
|
|
23792
|
-
onChange();
|
|
23793
|
-
}, debounceMs);
|
|
23794
|
-
};
|
|
23795
|
-
const isWatched = (directory, filename) => {
|
|
23796
|
-
const path = normalizePattern(relative6(root, resolve14(directory, filename)));
|
|
23797
|
-
return path.endsWith(SOURCE_EXTENSION) && resolver.resolve(path).matches.length > 0;
|
|
23798
|
-
};
|
|
23799
|
-
for (const entry of resolver.roots) {
|
|
23800
|
-
const absolute = resolve14(root, entry);
|
|
23801
|
-
if (!existsSync9(absolute)) {
|
|
23802
|
-
continue;
|
|
23803
|
-
}
|
|
23804
|
-
watchers.push(
|
|
23805
|
-
watch(absolute, { recursive: true }, (_event, filename) => {
|
|
23806
|
-
if (filename !== null && isWatched(absolute, filename.toString())) {
|
|
23807
|
-
schedule();
|
|
23808
|
-
}
|
|
23809
|
-
})
|
|
23810
|
-
);
|
|
23811
|
-
}
|
|
23812
|
-
return {
|
|
23813
|
-
close: () => {
|
|
23814
|
-
if (timer !== null) {
|
|
23815
|
-
clearTimeout(timer);
|
|
23816
|
-
timer = null;
|
|
23817
|
-
}
|
|
23818
|
-
for (const watcher of watchers) {
|
|
23819
|
-
watcher.close();
|
|
23820
|
-
}
|
|
23821
|
-
}
|
|
23822
|
-
};
|
|
23823
|
-
}
|
|
23824
|
-
function watchedRoots(sources) {
|
|
23825
|
-
return createSourceResolver(sources).roots;
|
|
23826
|
-
}
|
|
23827
|
-
|
|
23828
24519
|
// src/commands/ensure-command.ts
|
|
23829
|
-
function untilAborted(signal) {
|
|
23830
|
-
return new Promise((resolveLoop) => {
|
|
23831
|
-
if (signal?.aborted === true) {
|
|
23832
|
-
resolveLoop();
|
|
23833
|
-
return;
|
|
23834
|
-
}
|
|
23835
|
-
const stop = () => {
|
|
23836
|
-
process.off("SIGINT", stop);
|
|
23837
|
-
signal?.removeEventListener("abort", stop);
|
|
23838
|
-
resolveLoop();
|
|
23839
|
-
};
|
|
23840
|
-
if (signal !== null) {
|
|
23841
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
23842
|
-
}
|
|
23843
|
-
process.on("SIGINT", stop);
|
|
23844
|
-
});
|
|
23845
|
-
}
|
|
23846
24520
|
async function watchLoop(context, runner, options) {
|
|
23847
24521
|
const reporter = commandReporter(context);
|
|
23848
24522
|
let running = false;
|
|
@@ -24005,12 +24679,12 @@ function parseMtaLogLine(line2, activeResource, fallback = /* @__PURE__ */ new D
|
|
|
24005
24679
|
}
|
|
24006
24680
|
|
|
24007
24681
|
// src/logging/server-log-follower.ts
|
|
24008
|
-
import { closeSync, existsSync as
|
|
24009
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
24682
|
+
import { closeSync, existsSync as existsSync12, openSync, readSync, statSync as statSync4 } from "node:fs";
|
|
24683
|
+
import { isAbsolute as isAbsolute6, resolve as resolve16 } from "node:path";
|
|
24010
24684
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
24011
24685
|
function resolveServerLogPath(root, serverPath) {
|
|
24012
|
-
const server = isAbsolute6(serverPath) ? serverPath :
|
|
24013
|
-
return
|
|
24686
|
+
const server = isAbsolute6(serverPath) ? serverPath : resolve16(root, serverPath);
|
|
24687
|
+
return resolve16(server, "mods/deathmatch/logs/server.log");
|
|
24014
24688
|
}
|
|
24015
24689
|
function identity(path) {
|
|
24016
24690
|
const stats = statSync4(path);
|
|
@@ -24035,7 +24709,7 @@ function followServerLog(path, onLine, options = {}) {
|
|
|
24035
24709
|
let initialized = false;
|
|
24036
24710
|
let closed = false;
|
|
24037
24711
|
const poll = () => {
|
|
24038
|
-
if (closed || !
|
|
24712
|
+
if (closed || !existsSync12(path)) {
|
|
24039
24713
|
return;
|
|
24040
24714
|
}
|
|
24041
24715
|
try {
|
|
@@ -24151,7 +24825,7 @@ function connectServerConsoleInput(input, output, interrupt) {
|
|
|
24151
24825
|
|
|
24152
24826
|
// src/server/server-executable-resolver.ts
|
|
24153
24827
|
import { realpathSync, statSync as statSync5 } from "node:fs";
|
|
24154
|
-
import { isAbsolute as isAbsolute7, relative as relative7, resolve as
|
|
24828
|
+
import { isAbsolute as isAbsolute7, relative as relative7, resolve as resolve17 } from "node:path";
|
|
24155
24829
|
function isInside(root, path) {
|
|
24156
24830
|
const pathFromRoot = relative7(root, path);
|
|
24157
24831
|
return pathFromRoot.length === 0 || !pathFromRoot.startsWith("..") && !isAbsolute7(pathFromRoot);
|
|
@@ -24166,14 +24840,14 @@ function candidates2(platform) {
|
|
|
24166
24840
|
throw new Error(`Local MTA server startup is not supported on platform "${platform}". Use Windows or Linux.`);
|
|
24167
24841
|
}
|
|
24168
24842
|
function resolveServerExecutable(options) {
|
|
24169
|
-
const serverRoot =
|
|
24843
|
+
const serverRoot = resolve17(options.root, options.serverPath);
|
|
24170
24844
|
const names = options.configured === null ? candidates2(options.platform ?? process.platform) : [options.configured];
|
|
24171
24845
|
const attempted = [];
|
|
24172
|
-
if (options.configured !== null && (isAbsolute7(options.configured) || !isInside(serverRoot,
|
|
24846
|
+
if (options.configured !== null && (isAbsolute7(options.configured) || !isInside(serverRoot, resolve17(serverRoot, options.configured)))) {
|
|
24173
24847
|
throw new Error(`Configured development.server.executable must stay inside serverPath but received "${options.configured}".`);
|
|
24174
24848
|
}
|
|
24175
24849
|
for (const name of names) {
|
|
24176
|
-
const path =
|
|
24850
|
+
const path = resolve17(serverRoot, name);
|
|
24177
24851
|
attempted.push(path);
|
|
24178
24852
|
try {
|
|
24179
24853
|
if (!statSync5(path).isFile()) {
|
|
@@ -24533,8 +25207,520 @@ function registerEnsureCommand(program2, runtime) {
|
|
|
24533
25207
|
});
|
|
24534
25208
|
}
|
|
24535
25209
|
|
|
25210
|
+
// src/commands/format-command.ts
|
|
25211
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
|
|
25212
|
+
import { resolve as resolve19 } from "node:path";
|
|
25213
|
+
|
|
25214
|
+
// src/format/format-selection.ts
|
|
25215
|
+
import { statSync as statSync6 } from "node:fs";
|
|
25216
|
+
import { relative as relative8, resolve as resolve18 } from "node:path";
|
|
25217
|
+
var UNREADABLE_PATH = "format-path-unreadable";
|
|
25218
|
+
function entryKind(absolute) {
|
|
25219
|
+
try {
|
|
25220
|
+
const stats = statSync6(absolute);
|
|
25221
|
+
return stats.isDirectory() ? "directory" : "file";
|
|
25222
|
+
} catch {
|
|
25223
|
+
return null;
|
|
25224
|
+
}
|
|
25225
|
+
}
|
|
25226
|
+
function sorted(files) {
|
|
25227
|
+
return [...new Set(files)].sort((left, right) => left.localeCompare(right));
|
|
25228
|
+
}
|
|
25229
|
+
function selectProjectFiles(root, config) {
|
|
25230
|
+
const resolver = createSourceResolver(config.sources);
|
|
25231
|
+
const tree = listProjectFiles(root, ["."], [config.outDir]);
|
|
25232
|
+
const files = tree.files.filter((path) => isSourcePath(path) && (isDeclarationPath(path) || resolver.resolve(path).matches.length > 0));
|
|
25233
|
+
return { files: sorted(files), diagnostics: tree.errors.map((message) => cliError(UNREADABLE_PATH, message)) };
|
|
25234
|
+
}
|
|
25235
|
+
function selectPathFiles(root, paths) {
|
|
25236
|
+
const files = [];
|
|
25237
|
+
const diagnostics = [];
|
|
25238
|
+
for (const entry of paths) {
|
|
25239
|
+
const absolute = resolve18(root, entry);
|
|
25240
|
+
const path = normalizePattern(relative8(root, absolute));
|
|
25241
|
+
const kind = path.startsWith("..") ? null : entryKind(absolute);
|
|
25242
|
+
if (kind === null) {
|
|
25243
|
+
diagnostics.push(cliError(UNREADABLE_PATH, `"${normalizePattern(entry)}" does not exist in "${normalizePattern(root)}".`));
|
|
25244
|
+
continue;
|
|
25245
|
+
}
|
|
25246
|
+
if (kind === "file") {
|
|
25247
|
+
if (isSourcePath(path)) {
|
|
25248
|
+
files.push(path);
|
|
25249
|
+
} else {
|
|
25250
|
+
diagnostics.push(cliError(UNREADABLE_PATH, `"${path}" is not a Luam source file.`));
|
|
25251
|
+
}
|
|
25252
|
+
continue;
|
|
25253
|
+
}
|
|
25254
|
+
const tree = listProjectFiles(root, [path]);
|
|
25255
|
+
files.push(...tree.files.filter(isSourcePath));
|
|
25256
|
+
diagnostics.push(...tree.errors.map((message) => cliError(UNREADABLE_PATH, message)));
|
|
25257
|
+
}
|
|
25258
|
+
return { files: sorted(files), diagnostics };
|
|
25259
|
+
}
|
|
25260
|
+
|
|
25261
|
+
// src/format/formatter-file-system.ts
|
|
25262
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
|
|
25263
|
+
import { dirname as dirname6, join as join6 } from "node:path";
|
|
25264
|
+
var NODE_FORMATTER_FILES = {
|
|
25265
|
+
exists: (path) => existsSync13(path),
|
|
25266
|
+
read: (path) => readFileSync11(path, "utf8"),
|
|
25267
|
+
join: (directory, name) => join6(directory, name),
|
|
25268
|
+
parent: (directory) => dirname6(directory)
|
|
25269
|
+
};
|
|
25270
|
+
|
|
25271
|
+
// ../compiler/src/format/format-indent.ts
|
|
25272
|
+
var OPENERS = /* @__PURE__ */ new Set(["(", "[", "{", "then", "do", "repeat", "function"]);
|
|
25273
|
+
var CLOSERS = /* @__PURE__ */ new Set([")", "]", "}", "end", "until"]);
|
|
25274
|
+
function opensOf(piece) {
|
|
25275
|
+
if (piece.kind === "comment") {
|
|
25276
|
+
return 0;
|
|
25277
|
+
}
|
|
25278
|
+
return piece.value === "else" || OPENERS.has(piece.value) ? 1 : 0;
|
|
25279
|
+
}
|
|
25280
|
+
function closesOf(piece) {
|
|
25281
|
+
if (piece.kind === "comment") {
|
|
25282
|
+
return 0;
|
|
25283
|
+
}
|
|
25284
|
+
return piece.value === "else" || piece.value === "elseif" || CLOSERS.has(piece.value) ? 1 : 0;
|
|
25285
|
+
}
|
|
25286
|
+
function leadingRun(pieces) {
|
|
25287
|
+
let length = 0;
|
|
25288
|
+
while (length < pieces.length) {
|
|
25289
|
+
const piece = pieces[length];
|
|
25290
|
+
if (piece === void 0 || closesOf(piece) === 0) {
|
|
25291
|
+
break;
|
|
25292
|
+
}
|
|
25293
|
+
length += 1;
|
|
25294
|
+
}
|
|
25295
|
+
return length;
|
|
25296
|
+
}
|
|
25297
|
+
function indentOf2(depth, pieces) {
|
|
25298
|
+
const leading = leadingRun(pieces);
|
|
25299
|
+
const indent = Math.max(0, leading === 0 ? depth : depth - 1);
|
|
25300
|
+
const opened = pieces.reduce((total, piece, index) => total + opensOf(piece) - (index < leading ? 0 : closesOf(piece)), 0);
|
|
25301
|
+
return { indent, next: opened > 0 ? indent + 1 : indent };
|
|
25302
|
+
}
|
|
25303
|
+
|
|
25304
|
+
// ../compiler/src/format/format-options.ts
|
|
25305
|
+
var DEFAULT_FORMAT_OPTIONS = {
|
|
25306
|
+
indent: "space",
|
|
25307
|
+
indentWidth: 4,
|
|
25308
|
+
keywordParenSpace: true,
|
|
25309
|
+
maxBlankLines: 1,
|
|
25310
|
+
lineEnding: "infer"
|
|
25311
|
+
};
|
|
25312
|
+
var MAX_INDENT_WIDTH = 8;
|
|
25313
|
+
var MAX_BLANK_LINES = 4;
|
|
25314
|
+
function resolveFormatOptions(options = {}) {
|
|
25315
|
+
return { ...DEFAULT_FORMAT_OPTIONS, ...options };
|
|
25316
|
+
}
|
|
25317
|
+
function indentUnit(options) {
|
|
25318
|
+
return options.indent === "tab" ? " " : " ".repeat(options.indentWidth);
|
|
25319
|
+
}
|
|
25320
|
+
function newlineOf(source, options) {
|
|
25321
|
+
if (options.lineEnding === "lf") {
|
|
25322
|
+
return "\n";
|
|
25323
|
+
}
|
|
25324
|
+
if (options.lineEnding === "crlf") {
|
|
25325
|
+
return "\r\n";
|
|
25326
|
+
}
|
|
25327
|
+
return source.includes("\r\n") ? "\r\n" : "\n";
|
|
25328
|
+
}
|
|
25329
|
+
|
|
25330
|
+
// ../compiler/src/format/format-pieces.ts
|
|
25331
|
+
function isTypeOffset(erasures, offset) {
|
|
25332
|
+
return erasures.some((span) => offset >= span.start && offset < span.end);
|
|
25333
|
+
}
|
|
25334
|
+
function tokenPiece(source, token, erasures) {
|
|
25335
|
+
return {
|
|
25336
|
+
kind: token.kind,
|
|
25337
|
+
value: source.slice(token.position.offset, token.end.offset),
|
|
25338
|
+
offset: token.position.offset,
|
|
25339
|
+
line: token.position.line,
|
|
25340
|
+
endLine: token.end.line,
|
|
25341
|
+
isType: isTypeOffset(erasures, token.position.offset)
|
|
25342
|
+
};
|
|
25343
|
+
}
|
|
25344
|
+
function commentPiece(source, comment) {
|
|
25345
|
+
return {
|
|
25346
|
+
kind: "comment",
|
|
25347
|
+
value: source.slice(comment.position.offset, comment.end.offset).trimEnd(),
|
|
25348
|
+
offset: comment.position.offset,
|
|
25349
|
+
line: comment.position.line,
|
|
25350
|
+
endLine: comment.end.line,
|
|
25351
|
+
isType: false
|
|
25352
|
+
};
|
|
25353
|
+
}
|
|
25354
|
+
function piecesOf(source, tokens, comments, erasures) {
|
|
25355
|
+
const pieces = [
|
|
25356
|
+
...tokens.filter((token) => token.kind !== "eof").map((token) => tokenPiece(source, token, erasures)),
|
|
25357
|
+
...comments.map((comment) => commentPiece(source, comment))
|
|
25358
|
+
];
|
|
25359
|
+
return pieces.sort((left, right) => left.offset - right.offset);
|
|
25360
|
+
}
|
|
25361
|
+
function linesOf(pieces) {
|
|
25362
|
+
const lines = [];
|
|
25363
|
+
let previous = null;
|
|
25364
|
+
for (const piece of pieces) {
|
|
25365
|
+
const current = lines[lines.length - 1];
|
|
25366
|
+
if (previous !== null && current !== void 0 && piece.line === previous.endLine) {
|
|
25367
|
+
current.pieces.push(piece);
|
|
25368
|
+
} else {
|
|
25369
|
+
lines.push({ pieces: [piece], blankLines: previous === null ? 0 : Math.max(0, piece.line - previous.endLine - 1) });
|
|
25370
|
+
}
|
|
25371
|
+
previous = piece;
|
|
25372
|
+
}
|
|
25373
|
+
return lines;
|
|
25374
|
+
}
|
|
25375
|
+
|
|
25376
|
+
// ../compiler/src/format/format-spacing.ts
|
|
25377
|
+
var FUNCTION_TYPE2 = "fun";
|
|
25378
|
+
var VALUE_KINDS = /* @__PURE__ */ new Set(["identifier", "number", "string", "template"]);
|
|
25379
|
+
var VALUE_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "nil", "end"]);
|
|
25380
|
+
var TIGHT_BEFORE = /* @__PURE__ */ new Set([",", ";", ")", "]", ".", "?", ":", "++", "--"]);
|
|
25381
|
+
var TIGHT_AFTER = /* @__PURE__ */ new Set(["(", "[", ".", "@", "#", "..."]);
|
|
25382
|
+
var CALL_PREFIX = /* @__PURE__ */ new Set([")", "]"]);
|
|
25383
|
+
var TYPE_BRACKETS = /* @__PURE__ */ new Set(["<", ">"]);
|
|
25384
|
+
function endsValue(piece) {
|
|
25385
|
+
if (piece.kind === "keyword") {
|
|
25386
|
+
return VALUE_KEYWORDS.has(piece.value);
|
|
25387
|
+
}
|
|
25388
|
+
return VALUE_KINDS.has(piece.kind) || piece.value === ")" || piece.value === "]" || piece.value === "}";
|
|
25389
|
+
}
|
|
25390
|
+
function isName(piece) {
|
|
25391
|
+
return piece.kind === "identifier" || piece.kind === "keyword" && isLuamKeyword(piece.value);
|
|
25392
|
+
}
|
|
25393
|
+
function bindsTight(piece) {
|
|
25394
|
+
return isName(piece) || CALL_PREFIX.has(piece.value) || piece.isType && piece.value === ">";
|
|
25395
|
+
}
|
|
25396
|
+
function isUnary(pieces, index) {
|
|
25397
|
+
const piece = pieces[index];
|
|
25398
|
+
if (piece === void 0) {
|
|
25399
|
+
return false;
|
|
25400
|
+
}
|
|
25401
|
+
if (piece.value === "#") {
|
|
25402
|
+
return true;
|
|
25403
|
+
}
|
|
25404
|
+
if (piece.value !== "-") {
|
|
25405
|
+
return false;
|
|
25406
|
+
}
|
|
25407
|
+
const previous = index === 0 ? void 0 : pieces[index - 1];
|
|
25408
|
+
return previous === void 0 || !endsValue(previous);
|
|
25409
|
+
}
|
|
25410
|
+
function isMethodColon(pieces, index) {
|
|
25411
|
+
const next = pieces[index + 1];
|
|
25412
|
+
const after = pieces[index + 2];
|
|
25413
|
+
if (next === void 0 || !isName(next) || next.value === FUNCTION_TYPE2) {
|
|
25414
|
+
return false;
|
|
25415
|
+
}
|
|
25416
|
+
return after !== void 0 && after.value === "(";
|
|
25417
|
+
}
|
|
25418
|
+
function spaceBefore(pieces, index, options) {
|
|
25419
|
+
const piece = pieces[index];
|
|
25420
|
+
const previous = pieces[index - 1];
|
|
25421
|
+
if (piece === void 0 || previous === void 0) {
|
|
25422
|
+
return false;
|
|
25423
|
+
}
|
|
25424
|
+
if (piece.kind === "comment" || previous.kind === "comment") {
|
|
25425
|
+
return true;
|
|
25426
|
+
}
|
|
25427
|
+
if (piece.value === "}") {
|
|
25428
|
+
return previous.value !== "{";
|
|
25429
|
+
}
|
|
25430
|
+
if (piece.isType && piece.value === "<" && previous.kind === "keyword" && previous.value === "function") {
|
|
25431
|
+
return true;
|
|
25432
|
+
}
|
|
25433
|
+
if (TIGHT_BEFORE.has(piece.value) || piece.isType && TYPE_BRACKETS.has(piece.value)) {
|
|
25434
|
+
return false;
|
|
25435
|
+
}
|
|
25436
|
+
if (previous.isType && previous.value === "<") {
|
|
25437
|
+
return false;
|
|
25438
|
+
}
|
|
25439
|
+
if (previous.value === ":") {
|
|
25440
|
+
return !isMethodColon(pieces, index - 1);
|
|
25441
|
+
}
|
|
25442
|
+
if (TIGHT_AFTER.has(previous.value) || isUnary(pieces, index - 1)) {
|
|
25443
|
+
return false;
|
|
25444
|
+
}
|
|
25445
|
+
if (piece.value === "(") {
|
|
25446
|
+
return !bindsTight(previous) && (options.keywordParenSpace || previous.kind !== "keyword");
|
|
25447
|
+
}
|
|
25448
|
+
if (piece.value === "[") {
|
|
25449
|
+
return !bindsTight(previous);
|
|
25450
|
+
}
|
|
25451
|
+
return true;
|
|
25452
|
+
}
|
|
25453
|
+
function renderLine(pieces, options) {
|
|
25454
|
+
let text = "";
|
|
25455
|
+
for (const [index, piece] of pieces.entries()) {
|
|
25456
|
+
text += spaceBefore(pieces, index, options) ? ` ${piece.value}` : piece.value;
|
|
25457
|
+
}
|
|
25458
|
+
return text;
|
|
25459
|
+
}
|
|
25460
|
+
|
|
25461
|
+
// ../compiler/src/format/format.ts
|
|
25462
|
+
function signature(pieces) {
|
|
25463
|
+
return JSON.stringify(pieces.map((piece) => [piece.kind, piece.value]));
|
|
25464
|
+
}
|
|
25465
|
+
function render2(source, options) {
|
|
25466
|
+
const parsed = parse(source);
|
|
25467
|
+
if (parsed.diagnostics.length > 0) {
|
|
25468
|
+
return null;
|
|
25469
|
+
}
|
|
25470
|
+
const pieces = piecesOf(source, parsed.tokens, parsed.comments, parsed.erasures);
|
|
25471
|
+
const rendered = [];
|
|
25472
|
+
const unit = indentUnit(options);
|
|
25473
|
+
let depth = 0;
|
|
25474
|
+
for (const line2 of linesOf(pieces)) {
|
|
25475
|
+
const { indent, next } = indentOf2(depth, line2.pieces);
|
|
25476
|
+
const first = line2.pieces[0];
|
|
25477
|
+
const last = line2.pieces[line2.pieces.length - 1];
|
|
25478
|
+
const blanks = rendered.length === 0 ? 0 : Math.min(line2.blankLines, options.maxBlankLines);
|
|
25479
|
+
for (let count = 0; count < blanks; count += 1) {
|
|
25480
|
+
rendered.push({ text: "", line: 0, endLine: 0 });
|
|
25481
|
+
}
|
|
25482
|
+
rendered.push({ text: `${unit.repeat(indent)}${renderLine(line2.pieces, options)}`, line: first?.line ?? 0, endLine: last?.endLine ?? 0 });
|
|
25483
|
+
depth = next;
|
|
25484
|
+
}
|
|
25485
|
+
return { pieces, rendered, newline: newlineOf(source, options) };
|
|
25486
|
+
}
|
|
25487
|
+
function assemble(rendered, newline) {
|
|
25488
|
+
return rendered.length === 0 ? "" : `${rendered.map((entry) => entry.text).join(newline)}${newline}`;
|
|
25489
|
+
}
|
|
25490
|
+
function verified(formatted, options) {
|
|
25491
|
+
const text = assemble(formatted.rendered, formatted.newline);
|
|
25492
|
+
const round = render2(text, options);
|
|
25493
|
+
if (round === null || signature(round.pieces) !== signature(formatted.pieces)) {
|
|
25494
|
+
return null;
|
|
25495
|
+
}
|
|
25496
|
+
return text;
|
|
25497
|
+
}
|
|
25498
|
+
function formatSource(source, options = {}) {
|
|
25499
|
+
const resolved2 = resolveFormatOptions(options);
|
|
25500
|
+
const formatted = render2(source, resolved2);
|
|
25501
|
+
return formatted === null ? null : verified(formatted, resolved2);
|
|
25502
|
+
}
|
|
25503
|
+
|
|
25504
|
+
// ../compiler/src/format/formatter-fields.ts
|
|
25505
|
+
var FORMATTER_FILE_NAME = ".luam.formatter";
|
|
25506
|
+
var INDENT_STYLES = ["space", "tab"];
|
|
25507
|
+
var LINE_ENDINGS = ["infer", "lf", "crlf"];
|
|
25508
|
+
var FORMATTER_FIELDS = [
|
|
25509
|
+
field("indent", STRING_TYPE, 'The indent character. "space" indents with spaces, "tab" with tabs.', {
|
|
25510
|
+
defaultValue: DEFAULT_FORMAT_OPTIONS.indent,
|
|
25511
|
+
values: INDENT_STYLES
|
|
25512
|
+
}),
|
|
25513
|
+
field("indentWidth", NUMBER_TYPE, `Spaces per indent level, from 1 to ${MAX_INDENT_WIDTH}. Ignored when "indent" is "tab".`, {
|
|
25514
|
+
defaultValue: DEFAULT_FORMAT_OPTIONS.indentWidth
|
|
25515
|
+
}),
|
|
25516
|
+
field("keywordParenSpace", BOOLEAN_TYPE, 'Whether a "(" that follows a keyword is preceded by a space, as in "function (".', {
|
|
25517
|
+
defaultValue: DEFAULT_FORMAT_OPTIONS.keywordParenSpace
|
|
25518
|
+
}),
|
|
25519
|
+
field("maxBlankLines", NUMBER_TYPE, `Consecutive blank lines kept, from 0 to ${MAX_BLANK_LINES}.`, {
|
|
25520
|
+
defaultValue: DEFAULT_FORMAT_OPTIONS.maxBlankLines
|
|
25521
|
+
}),
|
|
25522
|
+
field("lineEnding", STRING_TYPE, 'The line ending. "infer" follows the file, "lf" and "crlf" pin it.', {
|
|
25523
|
+
defaultValue: DEFAULT_FORMAT_OPTIONS.lineEnding,
|
|
25524
|
+
values: LINE_ENDINGS
|
|
25525
|
+
})
|
|
25526
|
+
];
|
|
25527
|
+
var FORMATTER_FIELD_NAMES = FORMATTER_FIELDS.map((entry) => entry.name);
|
|
25528
|
+
|
|
25529
|
+
// ../compiler/src/format/formatter-file.ts
|
|
25530
|
+
var FORMATTER_UNKNOWN_FIELD = "formatter-unknown-field";
|
|
25531
|
+
var FORMATTER_INVALID_VALUE = "formatter-invalid-value";
|
|
25532
|
+
var FORMATTER_PARSE_ERROR = "formatter-parse-error";
|
|
25533
|
+
var START4 = createPosition(1, 1, 0);
|
|
25534
|
+
function boundedInteger(value, name, low, high, positions, diagnostics) {
|
|
25535
|
+
if (value === void 0) {
|
|
25536
|
+
return null;
|
|
25537
|
+
}
|
|
25538
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < low || value > high) {
|
|
25539
|
+
diagnostics.push(manifestError(FORMATTER_INVALID_VALUE, `"${name}" must be a whole number from ${low} to ${high}.`, positionAt(positions, name)));
|
|
25540
|
+
return null;
|
|
25541
|
+
}
|
|
25542
|
+
return value;
|
|
25543
|
+
}
|
|
25544
|
+
function choice(value, allowed) {
|
|
25545
|
+
return typeof value === "string" && allowed.includes(value) ? value : null;
|
|
25546
|
+
}
|
|
25547
|
+
function retag(diagnostic) {
|
|
25548
|
+
if (diagnostic.stage === "lexer" || diagnostic.stage === "parser") {
|
|
25549
|
+
return { ...diagnostic, stage: "manifest", code: FORMATTER_PARSE_ERROR };
|
|
25550
|
+
}
|
|
25551
|
+
return { ...diagnostic, code: diagnostic.code === UNKNOWN_FIELD ? FORMATTER_UNKNOWN_FIELD : FORMATTER_INVALID_VALUE };
|
|
25552
|
+
}
|
|
25553
|
+
function unknownFieldMessage(name) {
|
|
25554
|
+
const known = FORMATTER_FIELD_NAMES.map((entry) => `"${entry}"`).join(", ");
|
|
25555
|
+
return `"${name}" is not a "${FORMATTER_FILE_NAME}" field. The fields are ${known}.`;
|
|
25556
|
+
}
|
|
25557
|
+
var FORMATTER_SCHEMA = {
|
|
25558
|
+
fields: FORMATTER_FIELDS,
|
|
25559
|
+
removed: {},
|
|
25560
|
+
normalize: (value) => ({ value, diagnostics: [] }),
|
|
25561
|
+
retag,
|
|
25562
|
+
unknownName: unknownFieldMessage
|
|
25563
|
+
};
|
|
25564
|
+
function analyzeFormatterFile(source, root) {
|
|
25565
|
+
const analysis = analyzeManifest(source, { mode: "format", root, env: {} }, FORMATTER_SCHEMA);
|
|
25566
|
+
const diagnostics = [...analysis.diagnostics];
|
|
25567
|
+
const raw = analysis.value;
|
|
25568
|
+
const width = boundedInteger(raw["indentWidth"], "indentWidth", 1, MAX_INDENT_WIDTH, analysis.positions, diagnostics);
|
|
25569
|
+
const blanks = boundedInteger(raw["maxBlankLines"], "maxBlankLines", 0, MAX_BLANK_LINES, analysis.positions, diagnostics);
|
|
25570
|
+
const keywordParenSpace = raw["keywordParenSpace"];
|
|
25571
|
+
return {
|
|
25572
|
+
options: {
|
|
25573
|
+
indent: choice(raw["indent"], INDENT_STYLES) ?? DEFAULT_FORMAT_OPTIONS.indent,
|
|
25574
|
+
indentWidth: width ?? DEFAULT_FORMAT_OPTIONS.indentWidth,
|
|
25575
|
+
keywordParenSpace: typeof keywordParenSpace === "boolean" ? keywordParenSpace : DEFAULT_FORMAT_OPTIONS.keywordParenSpace,
|
|
25576
|
+
maxBlankLines: blanks ?? DEFAULT_FORMAT_OPTIONS.maxBlankLines,
|
|
25577
|
+
lineEnding: choice(raw["lineEnding"], LINE_ENDINGS) ?? DEFAULT_FORMAT_OPTIONS.lineEnding
|
|
25578
|
+
},
|
|
25579
|
+
diagnostics
|
|
25580
|
+
};
|
|
25581
|
+
}
|
|
25582
|
+
function formatterFileError(message) {
|
|
25583
|
+
return manifestError(FORMATTER_PARSE_ERROR, message, START4);
|
|
25584
|
+
}
|
|
25585
|
+
|
|
25586
|
+
// ../compiler/src/format/formatter-discovery.ts
|
|
25587
|
+
var LIBRARY_DIRECTORY2 = "node_modules";
|
|
25588
|
+
var DEFAULT_FORMATTER_OPTIONS = { path: null, options: DEFAULT_FORMAT_OPTIONS, diagnostics: [], valid: true };
|
|
25589
|
+
function insideLibrary(directory) {
|
|
25590
|
+
return directory.split(/[\\/]/).includes(LIBRARY_DIRECTORY2);
|
|
25591
|
+
}
|
|
25592
|
+
function findFormatterFile(files, start) {
|
|
25593
|
+
let directory = start;
|
|
25594
|
+
for (; ; ) {
|
|
25595
|
+
if (insideLibrary(directory)) {
|
|
25596
|
+
return null;
|
|
25597
|
+
}
|
|
25598
|
+
const candidate = files.join(directory, FORMATTER_FILE_NAME);
|
|
25599
|
+
if (files.exists(candidate)) {
|
|
25600
|
+
return candidate;
|
|
25601
|
+
}
|
|
25602
|
+
const parent = files.parent(directory);
|
|
25603
|
+
if (parent === directory) {
|
|
25604
|
+
return null;
|
|
25605
|
+
}
|
|
25606
|
+
directory = parent;
|
|
25607
|
+
}
|
|
25608
|
+
}
|
|
25609
|
+
function readFormatterFile(files, path, root) {
|
|
25610
|
+
let source;
|
|
25611
|
+
try {
|
|
25612
|
+
source = files.read(path);
|
|
25613
|
+
} catch (error) {
|
|
25614
|
+
const message = `"${path}" could not be read: ${error instanceof Error ? error.message : String(error)}`;
|
|
25615
|
+
return { path, options: DEFAULT_FORMAT_OPTIONS, diagnostics: [formatterFileError(message)], valid: false };
|
|
25616
|
+
}
|
|
25617
|
+
const analysis = analyzeFormatterFile(source, root);
|
|
25618
|
+
return { path, options: analysis.options, diagnostics: analysis.diagnostics, valid: !hasErrors(analysis.diagnostics) };
|
|
25619
|
+
}
|
|
25620
|
+
function resolveFormatterOptions(files, start) {
|
|
25621
|
+
const path = findFormatterFile(files, start);
|
|
25622
|
+
return path === null ? DEFAULT_FORMATTER_OPTIONS : readFormatterFile(files, path, files.parent(path));
|
|
25623
|
+
}
|
|
25624
|
+
|
|
25625
|
+
// src/commands/format-command.ts
|
|
25626
|
+
var UNPARSEABLE_SOURCE = "format-source-unparseable";
|
|
25627
|
+
var UNREADABLE_SOURCE2 = "format-source-unreadable";
|
|
25628
|
+
var UNWRITABLE_SOURCE = "format-source-unwritable";
|
|
25629
|
+
function describe2(error) {
|
|
25630
|
+
return error instanceof Error ? error.message : String(error);
|
|
25631
|
+
}
|
|
25632
|
+
function select(context, options) {
|
|
25633
|
+
if (options.paths.length > 0) {
|
|
25634
|
+
return selectPathFiles(context.root, options.paths);
|
|
25635
|
+
}
|
|
25636
|
+
if (context.config === null) {
|
|
25637
|
+
return { files: [], diagnostics: [] };
|
|
25638
|
+
}
|
|
25639
|
+
return selectProjectFiles(context.root, context.config);
|
|
25640
|
+
}
|
|
25641
|
+
function formatFile(context, path, check2, style, diagnostics) {
|
|
25642
|
+
const absolute = resolve19(context.root, path);
|
|
25643
|
+
let source;
|
|
25644
|
+
try {
|
|
25645
|
+
source = readFileSync12(absolute, "utf8");
|
|
25646
|
+
} catch (error) {
|
|
25647
|
+
diagnostics.push(cliError(UNREADABLE_SOURCE2, `The source file "${path}" could not be read: ${describe2(error)}`));
|
|
25648
|
+
return false;
|
|
25649
|
+
}
|
|
25650
|
+
const formatted = formatSource(source, style);
|
|
25651
|
+
if (formatted === null) {
|
|
25652
|
+
diagnostics.push(cliWarning(UNPARSEABLE_SOURCE, `"${path}" could not be parsed and was left unchanged. Run "luam check" to see why.`));
|
|
25653
|
+
return false;
|
|
25654
|
+
}
|
|
25655
|
+
if (formatted === source) {
|
|
25656
|
+
return false;
|
|
25657
|
+
}
|
|
25658
|
+
if (check2) {
|
|
25659
|
+
return true;
|
|
25660
|
+
}
|
|
25661
|
+
try {
|
|
25662
|
+
writeFileSync7(absolute, formatted, "utf8");
|
|
25663
|
+
} catch (error) {
|
|
25664
|
+
diagnostics.push(cliError(UNWRITABLE_SOURCE, `The source file "${path}" could not be written: ${describe2(error)}`));
|
|
25665
|
+
return false;
|
|
25666
|
+
}
|
|
25667
|
+
return true;
|
|
25668
|
+
}
|
|
25669
|
+
function runFormatCommand(context, options) {
|
|
25670
|
+
const reporter = context.reporter ?? createReporter(context.logger);
|
|
25671
|
+
const started = Date.now();
|
|
25672
|
+
const style = resolveFormatterOptions(NODE_FORMATTER_FILES, context.root);
|
|
25673
|
+
if (!style.valid) {
|
|
25674
|
+
reportManifestDiagnostics(reporter, style.path ?? "", "", style.diagnostics);
|
|
25675
|
+
reporter.error(`The formatter configuration "${style.path ?? ""}" is invalid. Nothing was formatted.`);
|
|
25676
|
+
return EXIT_USAGE;
|
|
25677
|
+
}
|
|
25678
|
+
const selection = select(context, options);
|
|
25679
|
+
const diagnostics = [...selection.diagnostics];
|
|
25680
|
+
const touched = [];
|
|
25681
|
+
for (const path of selection.files) {
|
|
25682
|
+
if (formatFile(context, path, options.check, style.options, diagnostics)) {
|
|
25683
|
+
touched.push(path);
|
|
25684
|
+
}
|
|
25685
|
+
}
|
|
25686
|
+
if (options.check) {
|
|
25687
|
+
for (const path of touched) {
|
|
25688
|
+
reporter.raw(path);
|
|
25689
|
+
}
|
|
25690
|
+
}
|
|
25691
|
+
reportCliDiagnostics(reporter, diagnostics);
|
|
25692
|
+
const failed3 = hasCliErrors(diagnostics) || options.check && touched.length > 0;
|
|
25693
|
+
const label2 = options.check ? "differing" : "reformatted";
|
|
25694
|
+
const summary = `${pluralize(selection.files.length, "file")} scanned, ${touched.length} ${label2} in ${formatDuration(Date.now() - started)}.`;
|
|
25695
|
+
if (failed3) {
|
|
25696
|
+
reporter.error(`Format failed: ${summary}`);
|
|
25697
|
+
return EXIT_DIAGNOSTICS;
|
|
25698
|
+
}
|
|
25699
|
+
reporter.success(`Format passed: ${summary}`);
|
|
25700
|
+
return EXIT_OK;
|
|
25701
|
+
}
|
|
25702
|
+
|
|
25703
|
+
// src/cli/registry/format-registration.ts
|
|
25704
|
+
function registerFormatCommand(program2, runtime) {
|
|
25705
|
+
const command = program2.command("format").description("Rewrite the project sources in the recorded formatting style.");
|
|
25706
|
+
command.argument("[paths...]", "Files or directories to format instead of the manifest sources.");
|
|
25707
|
+
addProjectOptions(command).addOption(new Option("--check", "Write nothing and report the files that differ."));
|
|
25708
|
+
command.action((paths, options) => {
|
|
25709
|
+
const check2 = options.check === true;
|
|
25710
|
+
if (paths.length > 0) {
|
|
25711
|
+
runtime.exitCode = runFormatCommand(
|
|
25712
|
+
{ root: commandRoot(runtime, options), config: null, logger: runtime.logger, reporter: runtime.reporter },
|
|
25713
|
+
{ check: check2, paths }
|
|
25714
|
+
);
|
|
25715
|
+
return;
|
|
25716
|
+
}
|
|
25717
|
+
const project = createProjectContext(runtime, "format", options);
|
|
25718
|
+
runtime.exitCode = project.context === null ? project.error : runFormatCommand({ ...project.context, config: project.context.config }, { check: check2, paths: [] });
|
|
25719
|
+
});
|
|
25720
|
+
}
|
|
25721
|
+
|
|
24536
25722
|
// src/cli/registry/init-registration.ts
|
|
24537
|
-
import { resolve as
|
|
25723
|
+
import { resolve as resolve21 } from "node:path";
|
|
24538
25724
|
|
|
24539
25725
|
// src/commands/init-command.ts
|
|
24540
25726
|
import { basename as basename2 } from "node:path";
|
|
@@ -24596,7 +25782,7 @@ function renderManifest(source, details) {
|
|
|
24596
25782
|
}
|
|
24597
25783
|
|
|
24598
25784
|
// src/scaffold/template-files.ts
|
|
24599
|
-
import { existsSync as
|
|
25785
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13 } from "node:fs";
|
|
24600
25786
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
24601
25787
|
|
|
24602
25788
|
// ../template/src/template.ts
|
|
@@ -24612,10 +25798,10 @@ function bundledTemplatePath(source) {
|
|
|
24612
25798
|
}
|
|
24613
25799
|
function resolveTemplatePath(source) {
|
|
24614
25800
|
const packaged = fileURLToPath2(resolveTemplateUrl(source));
|
|
24615
|
-
return
|
|
25801
|
+
return existsSync14(packaged) ? packaged : bundledTemplatePath(source);
|
|
24616
25802
|
}
|
|
24617
25803
|
function readTemplateSource(source) {
|
|
24618
|
-
return
|
|
25804
|
+
return readFileSync13(resolveTemplatePath(source), "utf8");
|
|
24619
25805
|
}
|
|
24620
25806
|
|
|
24621
25807
|
// src/scaffold/scaffold-plan.ts
|
|
@@ -24631,19 +25817,19 @@ function buildScaffoldPlan(details) {
|
|
|
24631
25817
|
}
|
|
24632
25818
|
|
|
24633
25819
|
// src/scaffold/scaffold-writer.ts
|
|
24634
|
-
import { existsSync as
|
|
24635
|
-
import { dirname as
|
|
25820
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync6, writeFileSync as writeFileSync8 } from "node:fs";
|
|
25821
|
+
import { dirname as dirname7, resolve as resolve20 } from "node:path";
|
|
24636
25822
|
function writeScaffold(targetDir, plan, force) {
|
|
24637
25823
|
const written = [];
|
|
24638
25824
|
const skipped = [];
|
|
24639
25825
|
for (const file of plan.files) {
|
|
24640
|
-
const absolute =
|
|
24641
|
-
if (!force &&
|
|
25826
|
+
const absolute = resolve20(targetDir, file.path);
|
|
25827
|
+
if (!force && existsSync15(absolute)) {
|
|
24642
25828
|
skipped.push(file.path);
|
|
24643
25829
|
continue;
|
|
24644
25830
|
}
|
|
24645
|
-
mkdirSync6(
|
|
24646
|
-
|
|
25831
|
+
mkdirSync6(dirname7(absolute), { recursive: true });
|
|
25832
|
+
writeFileSync8(absolute, file.content, "utf8");
|
|
24647
25833
|
written.push(file.path);
|
|
24648
25834
|
}
|
|
24649
25835
|
return { written: written.sort((left, right) => left.localeCompare(right)), skipped: skipped.sort((left, right) => left.localeCompare(right)) };
|
|
@@ -24693,7 +25879,7 @@ function registerInitCommand(program2, runtime) {
|
|
|
24693
25879
|
command.addOption(cwdOption()).addOption(valueOption("--name <name>", "Resource name. Defaults to the destination directory name.")).addOption(new Option("--force", "Overwrite files that already exist.")).addOption(new Option("-y, --yes", "Accept the defaults without prompting.")).addOption(colorOption());
|
|
24694
25880
|
command.action(async (path, options) => {
|
|
24695
25881
|
const root = commandRoot(runtime, options);
|
|
24696
|
-
const target = path === void 0 ? root :
|
|
25882
|
+
const target = path === void 0 ? root : resolve21(root, path);
|
|
24697
25883
|
runtime.exitCode = await runInitCommand(target, runtime.logger, {
|
|
24698
25884
|
name: options.name ?? null,
|
|
24699
25885
|
force: options.force === true,
|
|
@@ -24817,13 +26003,13 @@ function registerServerCommand(program2, runtime) {
|
|
|
24817
26003
|
}
|
|
24818
26004
|
|
|
24819
26005
|
// src/testing/test-report.ts
|
|
24820
|
-
import { readFileSync as
|
|
24821
|
-
import { resolve as
|
|
26006
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
26007
|
+
import { resolve as resolve22 } from "node:path";
|
|
24822
26008
|
function sourceLine(root, path, line2, cache3) {
|
|
24823
26009
|
let lines = cache3.get(path);
|
|
24824
26010
|
if (lines === void 0) {
|
|
24825
26011
|
try {
|
|
24826
|
-
lines =
|
|
26012
|
+
lines = readFileSync14(resolve22(root, path), "utf8").split(/\r?\n/);
|
|
24827
26013
|
} catch {
|
|
24828
26014
|
lines = [];
|
|
24829
26015
|
}
|
|
@@ -24896,14 +26082,14 @@ function reportTestResults(reporter, runs, root, map, durationMs) {
|
|
|
24896
26082
|
}
|
|
24897
26083
|
|
|
24898
26084
|
// src/testing/test-discovery.ts
|
|
24899
|
-
import { readFileSync as
|
|
24900
|
-
import { resolve as
|
|
26085
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
26086
|
+
import { resolve as resolve23 } from "node:path";
|
|
24901
26087
|
var DEFAULT_TEST_ENVIRONMENT = "shared";
|
|
24902
26088
|
var SIDE_CONFLICT2 = "test-source-side-conflict";
|
|
24903
26089
|
var UNREADABLE_TEST = "test-source-unreadable";
|
|
24904
26090
|
function readTest(root, path, diagnostics) {
|
|
24905
26091
|
try {
|
|
24906
|
-
return
|
|
26092
|
+
return readFileSync15(resolve23(root, path), "utf8");
|
|
24907
26093
|
} catch (error) {
|
|
24908
26094
|
diagnostics.push(cliError(UNREADABLE_TEST, `The test file "${path}" could not be read: ${error instanceof Error ? error.message : String(error)}`));
|
|
24909
26095
|
return null;
|
|
@@ -24930,9 +26116,9 @@ function discoverTests(root, sources, excluded = []) {
|
|
|
24930
26116
|
|
|
24931
26117
|
// src/testing/test-runner.ts
|
|
24932
26118
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
24933
|
-
import { mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as
|
|
26119
|
+
import { mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync9 } from "node:fs";
|
|
24934
26120
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
24935
|
-
import { dirname as
|
|
26121
|
+
import { dirname as dirname8, join as join7 } from "node:path";
|
|
24936
26122
|
|
|
24937
26123
|
// src/testing/harness-assertions.ts
|
|
24938
26124
|
var ASSERTIONS_SOURCE = String.raw`local SENTINEL = '##luam:test'
|
|
@@ -25347,11 +26533,11 @@ function parseRunOutput(environment, stdout) {
|
|
|
25347
26533
|
return { results, output };
|
|
25348
26534
|
}
|
|
25349
26535
|
function writeWorkspace(directory, scripts) {
|
|
25350
|
-
|
|
26536
|
+
writeFileSync9(join7(directory, HARNESS_FILE), HARNESS_SOURCE, "utf8");
|
|
25351
26537
|
for (const script of scripts) {
|
|
25352
|
-
const target =
|
|
25353
|
-
mkdirSync7(
|
|
25354
|
-
|
|
26538
|
+
const target = join7(directory, script.path);
|
|
26539
|
+
mkdirSync7(dirname8(target), { recursive: true });
|
|
26540
|
+
writeFileSync9(target, script.content, "utf8");
|
|
25355
26541
|
}
|
|
25356
26542
|
}
|
|
25357
26543
|
function loadOrder(available, environment) {
|
|
@@ -25365,14 +26551,14 @@ function loadOrder(available, environment) {
|
|
|
25365
26551
|
}
|
|
25366
26552
|
function runTests(request) {
|
|
25367
26553
|
const spawn2 = request.spawn ?? runLua;
|
|
25368
|
-
const directory = mkdtempSync2(
|
|
26554
|
+
const directory = mkdtempSync2(join7(tmpdir2(), "luam-test-"));
|
|
25369
26555
|
const available = new Set(request.scripts.map((script) => script.path));
|
|
25370
26556
|
try {
|
|
25371
26557
|
writeWorkspace(directory, request.scripts);
|
|
25372
26558
|
return ALL_ENVIRONMENTS.filter((environment) => request.environments.includes(environment)).map((environment) => {
|
|
25373
26559
|
const { preload, target } = loadOrder(available, environment);
|
|
25374
26560
|
const entry = entryFile(environment);
|
|
25375
|
-
|
|
26561
|
+
writeFileSync9(join7(directory, entry), entrySource(environment, preload, target), "utf8");
|
|
25376
26562
|
const execution = spawn2(request.executable, [entry], directory);
|
|
25377
26563
|
const parsed = parseRunOutput(environment, execution.stdout);
|
|
25378
26564
|
const failure3 = execution.failure ?? (parsed.results.length === 0 && execution.stderr.length > 0 ? execution.stderr.trim() : null);
|
|
@@ -25444,12 +26630,12 @@ function registerTestCommand(program2, runtime) {
|
|
|
25444
26630
|
}
|
|
25445
26631
|
|
|
25446
26632
|
// src/commands/trace-command.ts
|
|
25447
|
-
import { existsSync as
|
|
26633
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16 } from "node:fs";
|
|
25448
26634
|
function defaultMapPath(root, options, reporter) {
|
|
25449
26635
|
const loaded = loadManifest(root, { path: options.manifestPath, mode: manifestMode("trace"), env: options.env });
|
|
25450
26636
|
if (loaded.config !== null) {
|
|
25451
26637
|
const configured = resourceMapPath(root, loaded.config);
|
|
25452
|
-
if (
|
|
26638
|
+
if (existsSync16(configured)) {
|
|
25453
26639
|
return configured;
|
|
25454
26640
|
}
|
|
25455
26641
|
}
|
|
@@ -25469,7 +26655,7 @@ function readStandardInput() {
|
|
|
25469
26655
|
return "";
|
|
25470
26656
|
}
|
|
25471
26657
|
try {
|
|
25472
|
-
return
|
|
26658
|
+
return readFileSync16(0, "utf8");
|
|
25473
26659
|
} catch {
|
|
25474
26660
|
return "";
|
|
25475
26661
|
}
|
|
@@ -25551,6 +26737,7 @@ var COMMAND_REGISTRARS = [
|
|
|
25551
26737
|
registerDevCommand,
|
|
25552
26738
|
registerDoctorCommand,
|
|
25553
26739
|
registerEnsureCommand,
|
|
26740
|
+
registerFormatCommand,
|
|
25554
26741
|
registerInitCommand,
|
|
25555
26742
|
registerServerCommand,
|
|
25556
26743
|
registerSetupCommand,
|