@thigasdevelopment/luam 0.19.5 → 0.19.8
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 +1968 -617
- 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
|
}
|
|
@@ -4008,6 +4019,188 @@ function parseNamedAnnotation(stream, declaration) {
|
|
|
4008
4019
|
return { kind: "type-optional", element, position: optional.position };
|
|
4009
4020
|
}
|
|
4010
4021
|
|
|
4022
|
+
// ../compiler/src/parser/token-stream.ts
|
|
4023
|
+
var ParserError = class extends Error {
|
|
4024
|
+
diagnostic;
|
|
4025
|
+
constructor(diagnostic) {
|
|
4026
|
+
super(diagnostic.message);
|
|
4027
|
+
this.name = "ParserError";
|
|
4028
|
+
this.diagnostic = diagnostic;
|
|
4029
|
+
}
|
|
4030
|
+
};
|
|
4031
|
+
var TokenStream = class {
|
|
4032
|
+
diagnostics = [];
|
|
4033
|
+
tokens;
|
|
4034
|
+
index = 0;
|
|
4035
|
+
erased = [];
|
|
4036
|
+
spans = /* @__PURE__ */ new Map();
|
|
4037
|
+
constructor(tokens) {
|
|
4038
|
+
this.tokens = tokens;
|
|
4039
|
+
}
|
|
4040
|
+
peek(offset = 0) {
|
|
4041
|
+
const token = this.tokens[Math.min(this.index + offset, this.tokens.length - 1)];
|
|
4042
|
+
return token;
|
|
4043
|
+
}
|
|
4044
|
+
current() {
|
|
4045
|
+
return this.peek();
|
|
4046
|
+
}
|
|
4047
|
+
isEof() {
|
|
4048
|
+
return this.current().kind === "eof";
|
|
4049
|
+
}
|
|
4050
|
+
next() {
|
|
4051
|
+
const token = this.current();
|
|
4052
|
+
if (!this.isEof()) {
|
|
4053
|
+
this.index += 1;
|
|
4054
|
+
}
|
|
4055
|
+
return token;
|
|
4056
|
+
}
|
|
4057
|
+
checkpoint() {
|
|
4058
|
+
return this.index;
|
|
4059
|
+
}
|
|
4060
|
+
speculate() {
|
|
4061
|
+
return { index: this.index, erasures: this.erased.length, diagnostics: this.diagnostics.length };
|
|
4062
|
+
}
|
|
4063
|
+
rewind(point) {
|
|
4064
|
+
this.index = point.index;
|
|
4065
|
+
this.erased.length = point.erasures;
|
|
4066
|
+
this.diagnostics.length = point.diagnostics;
|
|
4067
|
+
}
|
|
4068
|
+
eraseFrom(checkpoint, kind = "annotation") {
|
|
4069
|
+
const first = this.tokens[checkpoint];
|
|
4070
|
+
const last = this.tokens[this.index - 1];
|
|
4071
|
+
if (first !== void 0 && last !== void 0 && first.kind !== "eof") {
|
|
4072
|
+
this.erased.push({ start: first.position.offset, end: last.end.offset, kind });
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
eraseToCurrent(checkpoint) {
|
|
4076
|
+
const first = this.tokens[checkpoint];
|
|
4077
|
+
if (first !== void 0 && first.kind !== "eof") {
|
|
4078
|
+
this.erased.push({ start: first.position.offset, end: this.current().position.offset, kind: "annotation" });
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
extendDeclarationErasure(end) {
|
|
4082
|
+
const last = this.erased[this.erased.length - 1];
|
|
4083
|
+
if (last !== void 0 && last.kind === "declaration" && last.end <= end) {
|
|
4084
|
+
last.end = end;
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
erasures() {
|
|
4088
|
+
return [...this.erased];
|
|
4089
|
+
}
|
|
4090
|
+
recordSpan(node, checkpoint) {
|
|
4091
|
+
const span = this.sourceSpanFrom(checkpoint);
|
|
4092
|
+
if (span !== null) {
|
|
4093
|
+
this.spans.set(node, span);
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
nodeSpans() {
|
|
4097
|
+
return this.spans;
|
|
4098
|
+
}
|
|
4099
|
+
sourceSpanFrom(checkpoint) {
|
|
4100
|
+
const first = this.tokens[checkpoint];
|
|
4101
|
+
const last = this.tokens[this.index - 1];
|
|
4102
|
+
return first === void 0 || last === void 0 || first.kind === "eof" ? null : { start: first.position.offset, end: last.end.offset };
|
|
4103
|
+
}
|
|
4104
|
+
check(kind, value) {
|
|
4105
|
+
const token = this.current();
|
|
4106
|
+
return token.kind === kind && (value === void 0 || token.value === value);
|
|
4107
|
+
}
|
|
4108
|
+
checkAhead(offset, kind, value) {
|
|
4109
|
+
const token = this.peek(offset);
|
|
4110
|
+
return token.kind === kind && (value === void 0 || token.value === value);
|
|
4111
|
+
}
|
|
4112
|
+
match(kind, value) {
|
|
4113
|
+
if (!this.check(kind, value)) {
|
|
4114
|
+
return false;
|
|
4115
|
+
}
|
|
4116
|
+
this.next();
|
|
4117
|
+
return true;
|
|
4118
|
+
}
|
|
4119
|
+
expect(kind, value) {
|
|
4120
|
+
if (this.check(kind, value)) {
|
|
4121
|
+
return this.next();
|
|
4122
|
+
}
|
|
4123
|
+
const expected = value === void 0 ? kind : `"${value}"`;
|
|
4124
|
+
throw this.error(`Expected ${expected} but found "${this.describeCurrent()}".`, "parse-unexpected-token");
|
|
4125
|
+
}
|
|
4126
|
+
checkName(offset = 0) {
|
|
4127
|
+
const token = this.peek(offset);
|
|
4128
|
+
return token.kind === "identifier" || token.kind === "keyword" && isLuamKeyword(token.value);
|
|
4129
|
+
}
|
|
4130
|
+
expectName() {
|
|
4131
|
+
if (this.checkName()) {
|
|
4132
|
+
return this.next();
|
|
4133
|
+
}
|
|
4134
|
+
throw this.error(`Expected a name but found "${this.describeCurrent()}".`, "parse-unexpected-token");
|
|
4135
|
+
}
|
|
4136
|
+
describeCurrent() {
|
|
4137
|
+
const token = this.current();
|
|
4138
|
+
return token.kind === "eof" ? "<end of file>" : token.value;
|
|
4139
|
+
}
|
|
4140
|
+
error(message, code = "parse-error") {
|
|
4141
|
+
const token = this.current();
|
|
4142
|
+
return new ParserError(createDiagnostic("parser", code, message, token.position, "error", token.end));
|
|
4143
|
+
}
|
|
4144
|
+
errorAt(message, code, position2, end) {
|
|
4145
|
+
return new ParserError(createDiagnostic("parser", code, message, position2, "error", end));
|
|
4146
|
+
}
|
|
4147
|
+
report(code, message, position2) {
|
|
4148
|
+
this.diagnostics.push(createDiagnostic("parser", code, message, position2));
|
|
4149
|
+
}
|
|
4150
|
+
};
|
|
4151
|
+
|
|
4152
|
+
// ../compiler/src/parser/type-parameters.ts
|
|
4153
|
+
function emptyTypeParameters() {
|
|
4154
|
+
return { names: [], constraints: [] };
|
|
4155
|
+
}
|
|
4156
|
+
function parseTypeParameters(stream) {
|
|
4157
|
+
const list = emptyTypeParameters();
|
|
4158
|
+
if (!stream.check("operator", "<")) {
|
|
4159
|
+
return list;
|
|
4160
|
+
}
|
|
4161
|
+
const checkpoint = stream.checkpoint();
|
|
4162
|
+
stream.next();
|
|
4163
|
+
do {
|
|
4164
|
+
list.names.push(stream.expect("identifier").value);
|
|
4165
|
+
list.constraints.push(stream.match("keyword", "extends") ? parseTypeAnnotation(stream) : null);
|
|
4166
|
+
} while (stream.match("punctuation", ","));
|
|
4167
|
+
stream.expect("operator", ">");
|
|
4168
|
+
stream.eraseFrom(checkpoint);
|
|
4169
|
+
return list;
|
|
4170
|
+
}
|
|
4171
|
+
function parseTypeArguments(stream) {
|
|
4172
|
+
const args = [];
|
|
4173
|
+
if (!stream.check("operator", "<")) {
|
|
4174
|
+
return args;
|
|
4175
|
+
}
|
|
4176
|
+
const checkpoint = stream.checkpoint();
|
|
4177
|
+
stream.next();
|
|
4178
|
+
do {
|
|
4179
|
+
args.push(parseTypeAnnotation(stream));
|
|
4180
|
+
} while (stream.match("punctuation", ","));
|
|
4181
|
+
stream.expect("operator", ">");
|
|
4182
|
+
stream.eraseFrom(checkpoint);
|
|
4183
|
+
return args;
|
|
4184
|
+
}
|
|
4185
|
+
function parseCallTypeArguments(stream) {
|
|
4186
|
+
if (!stream.check("operator", "<")) {
|
|
4187
|
+
return [];
|
|
4188
|
+
}
|
|
4189
|
+
const point = stream.speculate();
|
|
4190
|
+
try {
|
|
4191
|
+
const args = parseTypeArguments(stream);
|
|
4192
|
+
if (args.length > 0 && stream.check("punctuation", "(")) {
|
|
4193
|
+
return args;
|
|
4194
|
+
}
|
|
4195
|
+
} catch (error) {
|
|
4196
|
+
if (!(error instanceof ParserError)) {
|
|
4197
|
+
throw error;
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
stream.rewind(point);
|
|
4201
|
+
return [];
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4011
4204
|
// ../compiler/src/parser/function-expression.ts
|
|
4012
4205
|
function parseParameter(stream) {
|
|
4013
4206
|
const token = stream.current();
|
|
@@ -4038,11 +4231,20 @@ function parseParameters(stream) {
|
|
|
4038
4231
|
}
|
|
4039
4232
|
function parseFunctionExpression(stream) {
|
|
4040
4233
|
const position2 = stream.expect("keyword", "function").position;
|
|
4234
|
+
const typeParameters = parseTypeParameters(stream);
|
|
4041
4235
|
const parameters = parseParameters(stream);
|
|
4042
4236
|
const returnAnnotation = parseOptionalAnnotation(stream);
|
|
4043
4237
|
const body = parseBlock(stream, ["end"]);
|
|
4044
4238
|
stream.expect("keyword", "end");
|
|
4045
|
-
return {
|
|
4239
|
+
return {
|
|
4240
|
+
kind: "function-expression",
|
|
4241
|
+
typeParameters: typeParameters.names,
|
|
4242
|
+
typeConstraints: typeParameters.constraints,
|
|
4243
|
+
parameters,
|
|
4244
|
+
returnAnnotation,
|
|
4245
|
+
body,
|
|
4246
|
+
position: position2
|
|
4247
|
+
};
|
|
4046
4248
|
}
|
|
4047
4249
|
function parseFunctionName(stream) {
|
|
4048
4250
|
const token = stream.expect("identifier");
|
|
@@ -4060,11 +4262,25 @@ function parseFunctionName(stream) {
|
|
|
4060
4262
|
function parseFunctionDeclaration(stream, isLocal, isExported = false, isHttpExport = false) {
|
|
4061
4263
|
const position2 = stream.expect("keyword", "function").position;
|
|
4062
4264
|
const { name, isMethod } = parseFunctionName(stream);
|
|
4265
|
+
const typeParameters = parseTypeParameters(stream);
|
|
4063
4266
|
const parameters = parseParameters(stream);
|
|
4064
4267
|
const returnAnnotation = parseOptionalAnnotation(stream);
|
|
4065
4268
|
const body = parseBlock(stream, ["end"]);
|
|
4066
4269
|
stream.expect("keyword", "end");
|
|
4067
|
-
return {
|
|
4270
|
+
return {
|
|
4271
|
+
kind: "function-declaration",
|
|
4272
|
+
name,
|
|
4273
|
+
isLocal,
|
|
4274
|
+
isExported,
|
|
4275
|
+
isHttpExport,
|
|
4276
|
+
isMethod,
|
|
4277
|
+
typeParameters: typeParameters.names,
|
|
4278
|
+
typeConstraints: typeParameters.constraints,
|
|
4279
|
+
parameters,
|
|
4280
|
+
returnAnnotation,
|
|
4281
|
+
body,
|
|
4282
|
+
position: position2
|
|
4283
|
+
};
|
|
4068
4284
|
}
|
|
4069
4285
|
|
|
4070
4286
|
// ../compiler/src/parser/precedence.ts
|
|
@@ -4159,7 +4375,7 @@ function parsePrimary(stream) {
|
|
|
4159
4375
|
if (token.kind === "keyword" && token.value === "new" && stream.checkAhead(1, "identifier")) {
|
|
4160
4376
|
stream.next();
|
|
4161
4377
|
const className = stream.next().value;
|
|
4162
|
-
const typeArguments =
|
|
4378
|
+
const typeArguments = parseTypeArguments(stream);
|
|
4163
4379
|
return { kind: "new-expression", className, typeArguments, args: parseArguments(stream), position: token.position };
|
|
4164
4380
|
}
|
|
4165
4381
|
if (token.kind === "keyword" && CALLABLE_KEYWORDS.has(token.value) && stream.checkAhead(1, "punctuation", "(")) {
|
|
@@ -4192,20 +4408,6 @@ function parsePrimary(stream) {
|
|
|
4192
4408
|
}
|
|
4193
4409
|
throw stream.error(`Unexpected "${stream.describeCurrent()}" in expression.`, "parse-unexpected-token");
|
|
4194
4410
|
}
|
|
4195
|
-
function parseNewTypeArguments(stream) {
|
|
4196
|
-
const args = [];
|
|
4197
|
-
if (!stream.check("operator", "<")) {
|
|
4198
|
-
return args;
|
|
4199
|
-
}
|
|
4200
|
-
const checkpoint = stream.checkpoint();
|
|
4201
|
-
stream.next();
|
|
4202
|
-
do {
|
|
4203
|
-
args.push(parseTypeAnnotation(stream));
|
|
4204
|
-
} while (stream.match("punctuation", ","));
|
|
4205
|
-
stream.expect("operator", ">");
|
|
4206
|
-
stream.eraseFrom(checkpoint);
|
|
4207
|
-
return args;
|
|
4208
|
-
}
|
|
4209
4411
|
function parseArguments(stream) {
|
|
4210
4412
|
if (stream.check("string") || stream.check("template") || stream.check("punctuation", "{")) {
|
|
4211
4413
|
return [parsePrimary(stream)];
|
|
@@ -4244,11 +4446,13 @@ function parseSuffixed(stream) {
|
|
|
4244
4446
|
if (token.kind === "punctuation" && token.value === ":" && stream.checkName(1)) {
|
|
4245
4447
|
stream.next();
|
|
4246
4448
|
const method = stream.next().value;
|
|
4247
|
-
|
|
4449
|
+
const typeArguments2 = parseCallTypeArguments(stream);
|
|
4450
|
+
expression = { kind: "call-expression", callee: expression, method, typeArguments: typeArguments2, args: parseArguments(stream), position: token.position };
|
|
4248
4451
|
continue;
|
|
4249
4452
|
}
|
|
4250
|
-
|
|
4251
|
-
|
|
4453
|
+
const typeArguments = parseCallTypeArguments(stream);
|
|
4454
|
+
if (typeArguments.length > 0 || isCallStart(stream)) {
|
|
4455
|
+
expression = { kind: "call-expression", callee: expression, method: null, typeArguments, args: parseArguments(stream), position: token.position };
|
|
4252
4456
|
continue;
|
|
4253
4457
|
}
|
|
4254
4458
|
return expression;
|
|
@@ -4256,8 +4460,8 @@ function parseSuffixed(stream) {
|
|
|
4256
4460
|
}
|
|
4257
4461
|
function parseUnary(stream) {
|
|
4258
4462
|
const token = stream.current();
|
|
4259
|
-
const
|
|
4260
|
-
if (!
|
|
4463
|
+
const isUnary2 = (token.kind === "operator" || token.kind === "keyword") && UNARY_OPERATORS.has(token.value);
|
|
4464
|
+
if (!isUnary2) {
|
|
4261
4465
|
return parseSuffixed(stream);
|
|
4262
4466
|
}
|
|
4263
4467
|
stream.next();
|
|
@@ -4367,166 +4571,44 @@ function recoverInBlock(stream, error, terminators = BRACE_TERMINATORS) {
|
|
|
4367
4571
|
}
|
|
4368
4572
|
}
|
|
4369
4573
|
|
|
4370
|
-
// ../compiler/src/parser/
|
|
4371
|
-
var
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
this.diagnostic = diagnostic;
|
|
4574
|
+
// ../compiler/src/parser/declarations.ts
|
|
4575
|
+
var DECLARATION_NAMES = /* @__PURE__ */ new Set(["class", "interface", "enum"]);
|
|
4576
|
+
var CLASS_MODIFIERS = /* @__PURE__ */ new Set(["extends", "implements"]);
|
|
4577
|
+
function skipTypeParameters(stream, offset) {
|
|
4578
|
+
if (!stream.checkAhead(offset, "operator", "<")) {
|
|
4579
|
+
return offset;
|
|
4377
4580
|
}
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4581
|
+
let depth = 0;
|
|
4582
|
+
let index = offset;
|
|
4583
|
+
do {
|
|
4584
|
+
const token = stream.peek(index);
|
|
4585
|
+
depth += token.kind === "operator" && token.value === "<" ? 1 : 0;
|
|
4586
|
+
depth -= token.kind === "operator" && token.value === ">" ? 1 : 0;
|
|
4587
|
+
index += 1;
|
|
4588
|
+
} while (depth > 0 && stream.peek(index).kind !== "eof");
|
|
4589
|
+
return index;
|
|
4590
|
+
}
|
|
4591
|
+
function isClassHeader(stream, offset = 0) {
|
|
4592
|
+
const after = skipTypeParameters(stream, offset + 2);
|
|
4593
|
+
return stream.checkAhead(after, "punctuation", "{") || stream.checkAhead(after, "keyword", "extends") || stream.checkAhead(after, "keyword", "implements");
|
|
4594
|
+
}
|
|
4595
|
+
function isDeclarationStart(stream) {
|
|
4596
|
+
let offset = 0;
|
|
4597
|
+
while (stream.checkAhead(offset, "punctuation", "@") && stream.checkAhead(offset + 1, "identifier")) {
|
|
4598
|
+
offset += 2;
|
|
4599
|
+
if (stream.checkAhead(offset, "punctuation", "(")) {
|
|
4600
|
+
let depth = 0;
|
|
4601
|
+
do {
|
|
4602
|
+
const token2 = stream.peek(offset);
|
|
4603
|
+
depth += token2.kind === "punctuation" && token2.value === "(" ? 1 : 0;
|
|
4604
|
+
depth -= token2.kind === "punctuation" && token2.value === ")" ? 1 : 0;
|
|
4605
|
+
offset += 1;
|
|
4606
|
+
} while (depth > 0 && stream.peek(offset).kind !== "eof");
|
|
4607
|
+
}
|
|
4387
4608
|
}
|
|
4388
|
-
peek(offset
|
|
4389
|
-
|
|
4390
|
-
return
|
|
4391
|
-
}
|
|
4392
|
-
current() {
|
|
4393
|
-
return this.peek();
|
|
4394
|
-
}
|
|
4395
|
-
isEof() {
|
|
4396
|
-
return this.current().kind === "eof";
|
|
4397
|
-
}
|
|
4398
|
-
next() {
|
|
4399
|
-
const token = this.current();
|
|
4400
|
-
if (!this.isEof()) {
|
|
4401
|
-
this.index += 1;
|
|
4402
|
-
}
|
|
4403
|
-
return token;
|
|
4404
|
-
}
|
|
4405
|
-
checkpoint() {
|
|
4406
|
-
return this.index;
|
|
4407
|
-
}
|
|
4408
|
-
eraseFrom(checkpoint, kind = "annotation") {
|
|
4409
|
-
const first = this.tokens[checkpoint];
|
|
4410
|
-
const last = this.tokens[this.index - 1];
|
|
4411
|
-
if (first !== void 0 && last !== void 0 && first.kind !== "eof") {
|
|
4412
|
-
this.erased.push({ start: first.position.offset, end: last.end.offset, kind });
|
|
4413
|
-
}
|
|
4414
|
-
}
|
|
4415
|
-
eraseToCurrent(checkpoint) {
|
|
4416
|
-
const first = this.tokens[checkpoint];
|
|
4417
|
-
if (first !== void 0 && first.kind !== "eof") {
|
|
4418
|
-
this.erased.push({ start: first.position.offset, end: this.current().position.offset, kind: "annotation" });
|
|
4419
|
-
}
|
|
4420
|
-
}
|
|
4421
|
-
extendDeclarationErasure(end) {
|
|
4422
|
-
const last = this.erased[this.erased.length - 1];
|
|
4423
|
-
if (last !== void 0 && last.kind === "declaration" && last.end <= end) {
|
|
4424
|
-
last.end = end;
|
|
4425
|
-
}
|
|
4426
|
-
}
|
|
4427
|
-
erasures() {
|
|
4428
|
-
return [...this.erased];
|
|
4429
|
-
}
|
|
4430
|
-
recordSpan(node, checkpoint) {
|
|
4431
|
-
const span = this.sourceSpanFrom(checkpoint);
|
|
4432
|
-
if (span !== null) {
|
|
4433
|
-
this.spans.set(node, span);
|
|
4434
|
-
}
|
|
4435
|
-
}
|
|
4436
|
-
nodeSpans() {
|
|
4437
|
-
return this.spans;
|
|
4438
|
-
}
|
|
4439
|
-
sourceSpanFrom(checkpoint) {
|
|
4440
|
-
const first = this.tokens[checkpoint];
|
|
4441
|
-
const last = this.tokens[this.index - 1];
|
|
4442
|
-
return first === void 0 || last === void 0 || first.kind === "eof" ? null : { start: first.position.offset, end: last.end.offset };
|
|
4443
|
-
}
|
|
4444
|
-
check(kind, value) {
|
|
4445
|
-
const token = this.current();
|
|
4446
|
-
return token.kind === kind && (value === void 0 || token.value === value);
|
|
4447
|
-
}
|
|
4448
|
-
checkAhead(offset, kind, value) {
|
|
4449
|
-
const token = this.peek(offset);
|
|
4450
|
-
return token.kind === kind && (value === void 0 || token.value === value);
|
|
4451
|
-
}
|
|
4452
|
-
match(kind, value) {
|
|
4453
|
-
if (!this.check(kind, value)) {
|
|
4454
|
-
return false;
|
|
4455
|
-
}
|
|
4456
|
-
this.next();
|
|
4457
|
-
return true;
|
|
4458
|
-
}
|
|
4459
|
-
expect(kind, value) {
|
|
4460
|
-
if (this.check(kind, value)) {
|
|
4461
|
-
return this.next();
|
|
4462
|
-
}
|
|
4463
|
-
const expected = value === void 0 ? kind : `"${value}"`;
|
|
4464
|
-
throw this.error(`Expected ${expected} but found "${this.describeCurrent()}".`, "parse-unexpected-token");
|
|
4465
|
-
}
|
|
4466
|
-
checkName(offset = 0) {
|
|
4467
|
-
const token = this.peek(offset);
|
|
4468
|
-
return token.kind === "identifier" || token.kind === "keyword" && isLuamKeyword(token.value);
|
|
4469
|
-
}
|
|
4470
|
-
expectName() {
|
|
4471
|
-
if (this.checkName()) {
|
|
4472
|
-
return this.next();
|
|
4473
|
-
}
|
|
4474
|
-
throw this.error(`Expected a name but found "${this.describeCurrent()}".`, "parse-unexpected-token");
|
|
4475
|
-
}
|
|
4476
|
-
describeCurrent() {
|
|
4477
|
-
const token = this.current();
|
|
4478
|
-
return token.kind === "eof" ? "<end of file>" : token.value;
|
|
4479
|
-
}
|
|
4480
|
-
error(message, code = "parse-error") {
|
|
4481
|
-
const token = this.current();
|
|
4482
|
-
return new ParserError(createDiagnostic("parser", code, message, token.position, "error", token.end));
|
|
4483
|
-
}
|
|
4484
|
-
errorAt(message, code, position2, end) {
|
|
4485
|
-
return new ParserError(createDiagnostic("parser", code, message, position2, "error", end));
|
|
4486
|
-
}
|
|
4487
|
-
report(code, message, position2) {
|
|
4488
|
-
this.diagnostics.push(createDiagnostic("parser", code, message, position2));
|
|
4489
|
-
}
|
|
4490
|
-
};
|
|
4491
|
-
|
|
4492
|
-
// ../compiler/src/parser/declarations.ts
|
|
4493
|
-
var DECLARATION_NAMES = /* @__PURE__ */ new Set(["class", "interface", "enum"]);
|
|
4494
|
-
var CLASS_MODIFIERS = /* @__PURE__ */ new Set(["extends", "implements"]);
|
|
4495
|
-
function skipTypeParameters(stream, offset) {
|
|
4496
|
-
if (!stream.checkAhead(offset, "operator", "<")) {
|
|
4497
|
-
return offset;
|
|
4498
|
-
}
|
|
4499
|
-
let depth = 0;
|
|
4500
|
-
let index = offset;
|
|
4501
|
-
do {
|
|
4502
|
-
const token = stream.peek(index);
|
|
4503
|
-
depth += token.kind === "operator" && token.value === "<" ? 1 : 0;
|
|
4504
|
-
depth -= token.kind === "operator" && token.value === ">" ? 1 : 0;
|
|
4505
|
-
index += 1;
|
|
4506
|
-
} while (depth > 0 && stream.peek(index).kind !== "eof");
|
|
4507
|
-
return index;
|
|
4508
|
-
}
|
|
4509
|
-
function isClassHeader(stream, offset = 0) {
|
|
4510
|
-
const after = skipTypeParameters(stream, offset + 2);
|
|
4511
|
-
return stream.checkAhead(after, "punctuation", "{") || stream.checkAhead(after, "keyword", "extends") || stream.checkAhead(after, "keyword", "implements");
|
|
4512
|
-
}
|
|
4513
|
-
function isDeclarationStart(stream) {
|
|
4514
|
-
let offset = 0;
|
|
4515
|
-
while (stream.checkAhead(offset, "punctuation", "@") && stream.checkAhead(offset + 1, "identifier")) {
|
|
4516
|
-
offset += 2;
|
|
4517
|
-
if (stream.checkAhead(offset, "punctuation", "(")) {
|
|
4518
|
-
let depth = 0;
|
|
4519
|
-
do {
|
|
4520
|
-
const token2 = stream.peek(offset);
|
|
4521
|
-
depth += token2.kind === "punctuation" && token2.value === "(" ? 1 : 0;
|
|
4522
|
-
depth -= token2.kind === "punctuation" && token2.value === ")" ? 1 : 0;
|
|
4523
|
-
offset += 1;
|
|
4524
|
-
} while (depth > 0 && stream.peek(offset).kind !== "eof");
|
|
4525
|
-
}
|
|
4526
|
-
}
|
|
4527
|
-
const token = stream.peek(offset);
|
|
4528
|
-
if (token.kind !== "keyword" || !DECLARATION_NAMES.has(token.value) || !stream.checkAhead(offset + 1, "identifier")) {
|
|
4529
|
-
return false;
|
|
4609
|
+
const token = stream.peek(offset);
|
|
4610
|
+
if (token.kind !== "keyword" || !DECLARATION_NAMES.has(token.value) || !stream.checkAhead(offset + 1, "identifier")) {
|
|
4611
|
+
return false;
|
|
4530
4612
|
}
|
|
4531
4613
|
if (offset > 0 && token.value !== "class") {
|
|
4532
4614
|
return false;
|
|
@@ -4573,6 +4655,8 @@ function parseClassMethod(stream, token, decorators, isStatic) {
|
|
|
4573
4655
|
isConstructor: token.value === "constructor",
|
|
4574
4656
|
isSynthetic: false,
|
|
4575
4657
|
isStatic,
|
|
4658
|
+
typeParameters: expression.typeParameters,
|
|
4659
|
+
typeConstraints: expression.typeConstraints,
|
|
4576
4660
|
parameters: expression.parameters,
|
|
4577
4661
|
returnAnnotation: expression.returnAnnotation,
|
|
4578
4662
|
body: expression.body,
|
|
@@ -4590,6 +4674,8 @@ function parseBraceClassMethod(stream, token, decorators, isStatic) {
|
|
|
4590
4674
|
isConstructor: token.value === "constructor",
|
|
4591
4675
|
isSynthetic: false,
|
|
4592
4676
|
isStatic,
|
|
4677
|
+
typeParameters: [],
|
|
4678
|
+
typeConstraints: [],
|
|
4593
4679
|
parameters,
|
|
4594
4680
|
returnAnnotation,
|
|
4595
4681
|
body,
|
|
@@ -4638,35 +4724,6 @@ function parseClassMember(stream) {
|
|
|
4638
4724
|
expectClassFieldBoundary(stream, token);
|
|
4639
4725
|
return { kind: "class-field", name: token.value, annotation, value, decorators, isStatic, position: token.position };
|
|
4640
4726
|
}
|
|
4641
|
-
function parseTypeParameters(stream) {
|
|
4642
|
-
const list = { names: [], constraints: [] };
|
|
4643
|
-
if (!stream.check("operator", "<")) {
|
|
4644
|
-
return list;
|
|
4645
|
-
}
|
|
4646
|
-
const checkpoint = stream.checkpoint();
|
|
4647
|
-
stream.next();
|
|
4648
|
-
do {
|
|
4649
|
-
list.names.push(stream.expect("identifier").value);
|
|
4650
|
-
list.constraints.push(stream.match("keyword", "extends") ? parseTypeAnnotation(stream) : null);
|
|
4651
|
-
} while (stream.match("punctuation", ","));
|
|
4652
|
-
stream.expect("operator", ">");
|
|
4653
|
-
stream.eraseFrom(checkpoint);
|
|
4654
|
-
return list;
|
|
4655
|
-
}
|
|
4656
|
-
function parseTypeArguments(stream) {
|
|
4657
|
-
const args = [];
|
|
4658
|
-
if (!stream.check("operator", "<")) {
|
|
4659
|
-
return args;
|
|
4660
|
-
}
|
|
4661
|
-
const checkpoint = stream.checkpoint();
|
|
4662
|
-
stream.next();
|
|
4663
|
-
do {
|
|
4664
|
-
args.push(parseTypeAnnotation(stream));
|
|
4665
|
-
} while (stream.match("punctuation", ","));
|
|
4666
|
-
stream.expect("operator", ">");
|
|
4667
|
-
stream.eraseFrom(checkpoint);
|
|
4668
|
-
return args;
|
|
4669
|
-
}
|
|
4670
4727
|
function parseClassModifiers(stream, declaration) {
|
|
4671
4728
|
while (stream.check("keyword") && CLASS_MODIFIERS.has(stream.current().value)) {
|
|
4672
4729
|
if (stream.next().value === "extends") {
|
|
@@ -5129,6 +5186,8 @@ var ESCAPING_PATH = "config-escaping-path";
|
|
|
5129
5186
|
var UNKNOWN_HELPER = "config-unknown-helper";
|
|
5130
5187
|
var INVALID_PATTERN = "config-invalid-pattern";
|
|
5131
5188
|
var INVALID_DEPENDENCY = "config-invalid-dependency";
|
|
5189
|
+
var INVALID_LIBRARY = "config-library-invalid";
|
|
5190
|
+
var DUPLICATE_LIBRARY = "config-library-duplicate";
|
|
5132
5191
|
var INVALID_ENGINE_VERSION = "config-invalid-engine-version";
|
|
5133
5192
|
var REMOVED_FIELD = "config-removed-field";
|
|
5134
5193
|
var ALLOWED_STATEMENTS = 'A manifest holds only "local" declarations and assignments to configuration fields.';
|
|
@@ -5305,10 +5364,12 @@ function typeToString(type) {
|
|
|
5305
5364
|
}
|
|
5306
5365
|
if (type.kind === "function") {
|
|
5307
5366
|
const parameters = type.parameters.map(typeToString);
|
|
5367
|
+
const names = type.typeParameters ?? [];
|
|
5308
5368
|
if (type.isVariadic) {
|
|
5309
5369
|
parameters.push(type.variadicType === void 0 ? "..." : `...: ${typeToString(type.variadicType)}`);
|
|
5310
5370
|
}
|
|
5311
|
-
|
|
5371
|
+
const generic = names.length === 0 ? "" : `<${names.join(", ")}>`;
|
|
5372
|
+
return `fun${generic}(${parameters.join(", ")}): ${typeToString(type.returnType)}`;
|
|
5312
5373
|
}
|
|
5313
5374
|
return type.kind;
|
|
5314
5375
|
}
|
|
@@ -5754,6 +5815,12 @@ var MANIFEST_FIELDS = [
|
|
|
5754
5815
|
owner: "dependencies",
|
|
5755
5816
|
allowEmpty: true
|
|
5756
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
|
+
}),
|
|
5757
5824
|
field("contracts", STRING_TYPE, "Directory the export contract is written to and dependency contracts are read from.", {
|
|
5758
5825
|
defaultValue: DEFAULT_CONTRACTS_DIR,
|
|
5759
5826
|
rule: "contained-path",
|
|
@@ -5918,8 +5985,8 @@ function isNumber(type) {
|
|
|
5918
5985
|
function isText(type) {
|
|
5919
5986
|
return type.kind === "string" || type.kind === "string-literal" || type.kind === "any";
|
|
5920
5987
|
}
|
|
5921
|
-
function fail(operator, expected, left, right,
|
|
5922
|
-
const culprit =
|
|
5988
|
+
function fail(operator, expected, left, right, describe3) {
|
|
5989
|
+
const culprit = describe3(isNumber(left) || isText(left) ? right : left);
|
|
5923
5990
|
return { evaluated: null, error: `"${operator}" expects ${expected} on both sides but received ${culprit}.` };
|
|
5924
5991
|
}
|
|
5925
5992
|
function arithmetic(operator, left, right) {
|
|
@@ -5958,22 +6025,22 @@ function applyOr(left, right) {
|
|
|
5958
6025
|
const value = isTruthy(left.value) ? left.value : right.value;
|
|
5959
6026
|
return { value, type: unionOf([left.truthy, right.type]), truthy: unionOf([left.truthy, right.truthy]), falsy: right.falsy };
|
|
5960
6027
|
}
|
|
5961
|
-
function applyOrdering(operator, left, right,
|
|
6028
|
+
function applyOrdering(operator, left, right, describe3) {
|
|
5962
6029
|
const numeric = isNumber(left.type) && isNumber(right.type);
|
|
5963
6030
|
const textual = isText(left.type) && isText(right.type);
|
|
5964
6031
|
if (!numeric && !textual) {
|
|
5965
|
-
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);
|
|
5966
6033
|
}
|
|
5967
6034
|
return { evaluated: booleanValue(compare(operator, left.value, right.value)), error: null };
|
|
5968
6035
|
}
|
|
5969
|
-
function applyConcat(left, right,
|
|
6036
|
+
function applyConcat(left, right, describe3) {
|
|
5970
6037
|
const usable = (type) => isText(type) || isNumber(type);
|
|
5971
6038
|
if (!usable(left.type) || !usable(right.type)) {
|
|
5972
|
-
return fail("..", "a string or a number", left.type, right.type,
|
|
6039
|
+
return fail("..", "a string or a number", left.type, right.type, describe3);
|
|
5973
6040
|
}
|
|
5974
6041
|
return { evaluated: stringValue(`${left.value}${right.value}`), error: null };
|
|
5975
6042
|
}
|
|
5976
|
-
function applyBinary(operator, left, right,
|
|
6043
|
+
function applyBinary(operator, left, right, describe3) {
|
|
5977
6044
|
if (operator === "and") {
|
|
5978
6045
|
return { evaluated: applyAnd(left, right), error: null };
|
|
5979
6046
|
}
|
|
@@ -5985,23 +6052,23 @@ function applyBinary(operator, left, right, describe2) {
|
|
|
5985
6052
|
return { evaluated: booleanValue(operator === "==" ? same : !same), error: null };
|
|
5986
6053
|
}
|
|
5987
6054
|
if (ORDERING.includes(operator)) {
|
|
5988
|
-
return applyOrdering(operator, left, right,
|
|
6055
|
+
return applyOrdering(operator, left, right, describe3);
|
|
5989
6056
|
}
|
|
5990
6057
|
if (operator === "..") {
|
|
5991
|
-
return applyConcat(left, right,
|
|
6058
|
+
return applyConcat(left, right, describe3);
|
|
5992
6059
|
}
|
|
5993
6060
|
if (!isNumber(left.type) || !isNumber(right.type)) {
|
|
5994
|
-
return fail(operator, "a number", left.type, right.type,
|
|
6061
|
+
return fail(operator, "a number", left.type, right.type, describe3);
|
|
5995
6062
|
}
|
|
5996
6063
|
return { evaluated: numberValue(arithmetic(operator, left.value, right.value)), error: null };
|
|
5997
6064
|
}
|
|
5998
|
-
function applyUnary(operator, operand,
|
|
6065
|
+
function applyUnary(operator, operand, describe3) {
|
|
5999
6066
|
if (operator === "not") {
|
|
6000
6067
|
return { evaluated: booleanValue(!isTruthy(operand.value)), error: null };
|
|
6001
6068
|
}
|
|
6002
6069
|
if (operator === "-") {
|
|
6003
6070
|
if (!isNumber(operand.type)) {
|
|
6004
|
-
return { evaluated: null, error: `"-" expects a number but received ${
|
|
6071
|
+
return { evaluated: null, error: `"-" expects a number but received ${describe3(operand.type)}.` };
|
|
6005
6072
|
}
|
|
6006
6073
|
return { evaluated: numberValue(-operand.value), error: null };
|
|
6007
6074
|
}
|
|
@@ -6337,6 +6404,130 @@ function watchRoots(patterns) {
|
|
|
6337
6404
|
return roots.filter((root) => !roots.some((other) => other.length < root.length && root.startsWith(`${other}/`)));
|
|
6338
6405
|
}
|
|
6339
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
|
+
|
|
6340
6531
|
// ../compiler/src/manifest/manifest-rules.ts
|
|
6341
6532
|
var START = createPosition(1, 1, 0);
|
|
6342
6533
|
var RESOURCE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
@@ -6429,6 +6620,9 @@ var RuleWalk = class {
|
|
|
6429
6620
|
if (entry.rule === "dependency-name" && !isValidResourceName(value)) {
|
|
6430
6621
|
this.report(INVALID_DEPENDENCY, `"${path}" must be a valid MTA resource name but received "${value}".`, key);
|
|
6431
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
|
+
}
|
|
6432
6626
|
}
|
|
6433
6627
|
version(entry, value, path, key) {
|
|
6434
6628
|
if (entry.rule !== "engine-version" || value === LATEST_ENGINE_VERSION || ENGINE_VERSION.test(value)) {
|
|
@@ -6465,6 +6659,7 @@ function normalizeManifest(value, positions) {
|
|
|
6465
6659
|
}
|
|
6466
6660
|
|
|
6467
6661
|
// ../compiler/src/manifest/manifest-analysis.ts
|
|
6662
|
+
var MANIFEST_SCHEMA = { fields: MANIFEST_FIELDS, removed: REMOVED_FIELDS, normalize: normalizeManifest };
|
|
6468
6663
|
var START2 = createPosition(1, 1, 0);
|
|
6469
6664
|
function statementError(kind) {
|
|
6470
6665
|
return `A manifest cannot contain ${kind}. ${ALLOWED_STATEMENTS}`;
|
|
@@ -6494,7 +6689,7 @@ function readLocal(pass, statement) {
|
|
|
6494
6689
|
pass.declareLocal(declaration.name, value === void 0 ? nilValue() : pass.evaluate(value, null), declaration.position);
|
|
6495
6690
|
}
|
|
6496
6691
|
}
|
|
6497
|
-
function readAssignment(pass, statement, assignments, value) {
|
|
6692
|
+
function readAssignment(pass, statement, assignments, value, schema) {
|
|
6498
6693
|
const [target] = statement.targets;
|
|
6499
6694
|
const [expression] = statement.values;
|
|
6500
6695
|
if (statement.operator !== "=" || statement.targets.length !== 1 || statement.values.length !== 1 || target === void 0 || expression === void 0) {
|
|
@@ -6505,11 +6700,11 @@ function readAssignment(pass, statement, assignments, value) {
|
|
|
6505
6700
|
pass.report(INVALID_STATEMENT, statementError("an assignment to anything but a configuration field"), target.position);
|
|
6506
6701
|
return;
|
|
6507
6702
|
}
|
|
6508
|
-
const field2 = findField(
|
|
6703
|
+
const field2 = findField(schema.fields, target.name);
|
|
6509
6704
|
if (field2 === null) {
|
|
6510
|
-
const replacement =
|
|
6705
|
+
const replacement = schema.removed[target.name];
|
|
6511
6706
|
if (replacement === void 0) {
|
|
6512
|
-
pass.report(UNKNOWN_FIELD, unknownNameMessage(target.name), target.position);
|
|
6707
|
+
pass.report(UNKNOWN_FIELD, (schema.unknownName ?? unknownNameMessage)(target.name), target.position);
|
|
6513
6708
|
} else {
|
|
6514
6709
|
pass.report(REMOVED_FIELD, `"${target.name}" is no longer a manifest field. ${replacement}`, target.position);
|
|
6515
6710
|
}
|
|
@@ -6518,25 +6713,25 @@ function readAssignment(pass, statement, assignments, value) {
|
|
|
6518
6713
|
assignments.push({ name: target.name, position: target.position, value: expression });
|
|
6519
6714
|
value[target.name] = pass.expression(expression, { field: field2, path: target.name, key: target.name }).value;
|
|
6520
6715
|
}
|
|
6521
|
-
function readStatement(pass, statement, assignments, value) {
|
|
6716
|
+
function readStatement(pass, statement, assignments, value, schema) {
|
|
6522
6717
|
if (statement.kind === "local-statement") {
|
|
6523
6718
|
readLocal(pass, statement);
|
|
6524
6719
|
return;
|
|
6525
6720
|
}
|
|
6526
6721
|
if (statement.kind === "assignment-statement") {
|
|
6527
|
-
readAssignment(pass, statement, assignments, value);
|
|
6722
|
+
readAssignment(pass, statement, assignments, value, schema);
|
|
6528
6723
|
return;
|
|
6529
6724
|
}
|
|
6530
6725
|
pass.report(INVALID_STATEMENT, statementError(STATEMENT_NAMES[statement.kind] ?? "this statement"), statement.position);
|
|
6531
6726
|
}
|
|
6532
|
-
function reportMissing(diagnostics, value) {
|
|
6533
|
-
for (const field2 of requiredFields(
|
|
6727
|
+
function reportMissing(diagnostics, value, schema) {
|
|
6728
|
+
for (const field2 of requiredFields(schema.fields)) {
|
|
6534
6729
|
if (value[field2.name] === void 0) {
|
|
6535
6730
|
diagnostics.push(manifestError(MISSING_FIELD, `The manifest requires a "${field2.name}" field. ${field2.summary}`, START2));
|
|
6536
6731
|
}
|
|
6537
6732
|
}
|
|
6538
6733
|
}
|
|
6539
|
-
function analyzeManifest(source, context) {
|
|
6734
|
+
function analyzeManifest(source, context, schema = MANIFEST_SCHEMA) {
|
|
6540
6735
|
const parsed = parse(source);
|
|
6541
6736
|
const pass = new ManifestPass(context);
|
|
6542
6737
|
const assignments = [];
|
|
@@ -6545,15 +6740,15 @@ function analyzeManifest(source, context) {
|
|
|
6545
6740
|
pass.report(INVALID_STATEMENT, statementError(`the "#!${directive}" directive`), START2);
|
|
6546
6741
|
}
|
|
6547
6742
|
for (const statement of parsed.program.body) {
|
|
6548
|
-
readStatement(pass, statement, assignments, raw);
|
|
6743
|
+
readStatement(pass, statement, assignments, raw, schema);
|
|
6549
6744
|
}
|
|
6550
|
-
reportMissing(pass.diagnostics, raw);
|
|
6745
|
+
reportMissing(pass.diagnostics, raw, schema);
|
|
6551
6746
|
pass.diagnostics.push(...pass.locals.unused());
|
|
6552
|
-
const normalized =
|
|
6747
|
+
const normalized = schema.normalize(raw, pass.positions);
|
|
6553
6748
|
return {
|
|
6554
6749
|
program: parsed.program,
|
|
6555
6750
|
tokens: parsed.tokens,
|
|
6556
|
-
diagnostics: sortDiagnostics([...parsed.diagnostics, ...pass.diagnostics, ...normalized.diagnostics]),
|
|
6751
|
+
diagnostics: sortDiagnostics([...parsed.diagnostics, ...pass.diagnostics, ...normalized.diagnostics]).map(schema.retag ?? ((entry) => entry)),
|
|
6557
6752
|
value: normalized.value,
|
|
6558
6753
|
raw,
|
|
6559
6754
|
positions: pass.positions,
|
|
@@ -6625,6 +6820,9 @@ function readAssetMappings(value) {
|
|
|
6625
6820
|
function readDependencies(value) {
|
|
6626
6821
|
return [...new Set(readStrings(value, "dependencies"))].sort();
|
|
6627
6822
|
}
|
|
6823
|
+
function readLibraries(value) {
|
|
6824
|
+
return readStrings(value, "libraries");
|
|
6825
|
+
}
|
|
6628
6826
|
function readEngine(value) {
|
|
6629
6827
|
const source = readTable(value, "engine") ?? EMPTY;
|
|
6630
6828
|
return { minVersion: readString(source, "minVersion") ?? DEFAULT_ENGINE.minVersion };
|
|
@@ -6684,10 +6882,20 @@ function checkDependencies(name, dependencies, context) {
|
|
|
6684
6882
|
}
|
|
6685
6883
|
}
|
|
6686
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
|
+
}
|
|
6687
6894
|
function validateConfig(value, positions) {
|
|
6688
6895
|
const context = new ValidationContext(positions);
|
|
6689
6896
|
const name = readString(value, "name") ?? "";
|
|
6690
6897
|
const dependencies = readDependencies(value);
|
|
6898
|
+
const libraries = readLibraries(value);
|
|
6691
6899
|
const config = {
|
|
6692
6900
|
name,
|
|
6693
6901
|
author: readString(value, "author"),
|
|
@@ -6697,6 +6905,7 @@ function validateConfig(value, positions) {
|
|
|
6697
6905
|
sources: readSourceMapping(value),
|
|
6698
6906
|
assets: readAssetMappings(value),
|
|
6699
6907
|
dependencies,
|
|
6908
|
+
libraries,
|
|
6700
6909
|
contracts: readString(value, "contracts") ?? "",
|
|
6701
6910
|
engine: readEngine(value),
|
|
6702
6911
|
environment: readEnvironmentFiles(value),
|
|
@@ -6709,6 +6918,7 @@ function validateConfig(value, positions) {
|
|
|
6709
6918
|
development: readDevelopment(readTable(value, "development"))
|
|
6710
6919
|
};
|
|
6711
6920
|
checkDependencies(name, dependencies, context);
|
|
6921
|
+
checkLibraries(libraries, context);
|
|
6712
6922
|
return { config, diagnostics: context.diagnostics };
|
|
6713
6923
|
}
|
|
6714
6924
|
|
|
@@ -6762,7 +6972,7 @@ import { tmpdir } from "node:os";
|
|
|
6762
6972
|
import { join as join2 } from "node:path";
|
|
6763
6973
|
|
|
6764
6974
|
// src/cli/version.ts
|
|
6765
|
-
var VERSION = true ? "0.19.
|
|
6975
|
+
var VERSION = true ? "0.19.8" : "0.0.0-dev";
|
|
6766
6976
|
var PROGRAM_NAME = "luam";
|
|
6767
6977
|
var PROGRAM_DESCRIPTION = "luam \u2014 the Luam compiler for Multi Theft Auto resources.";
|
|
6768
6978
|
|
|
@@ -7296,6 +7506,9 @@ function manifestOption() {
|
|
|
7296
7506
|
function colorOption() {
|
|
7297
7507
|
return new Option("--no-color", "Print plain output with no colour and no emoji.");
|
|
7298
7508
|
}
|
|
7509
|
+
function jsonOption() {
|
|
7510
|
+
return new Option("--json", "Write one machine-readable document to stdout instead of the human report.");
|
|
7511
|
+
}
|
|
7299
7512
|
function offlineOption() {
|
|
7300
7513
|
return new Option("--offline", "Skip the MTA release lookup and use the cached version, if there is one.");
|
|
7301
7514
|
}
|
|
@@ -7411,15 +7624,15 @@ function knowsResource(contracts, resource) {
|
|
|
7411
7624
|
}
|
|
7412
7625
|
function buildResourceAbi(resource, contributions) {
|
|
7413
7626
|
const exports = contributions.map((contribution) => {
|
|
7414
|
-
const
|
|
7627
|
+
const signature2 = contribution.signature;
|
|
7415
7628
|
return {
|
|
7416
7629
|
name: contribution.name,
|
|
7417
7630
|
side: contribution.side,
|
|
7418
7631
|
http: contribution.http,
|
|
7419
|
-
parameters:
|
|
7420
|
-
minimumArguments:
|
|
7421
|
-
variadic:
|
|
7422
|
-
returns:
|
|
7632
|
+
parameters: signature2?.parameters ?? [],
|
|
7633
|
+
minimumArguments: signature2?.minimumArguments ?? 0,
|
|
7634
|
+
variadic: signature2?.variadic ?? true,
|
|
7635
|
+
returns: signature2?.returns ?? "any"
|
|
7423
7636
|
};
|
|
7424
7637
|
});
|
|
7425
7638
|
return { abi: ABI_VERSION, resource, exports };
|
|
@@ -7476,78 +7689,9 @@ function readHelperSource(helper, file) {
|
|
|
7476
7689
|
return readFileSync4(resolveHelperPath(helper, file), "utf8");
|
|
7477
7690
|
}
|
|
7478
7691
|
|
|
7479
|
-
// src/build/
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
version: "Version",
|
|
7483
|
-
discovery: "Discovery",
|
|
7484
|
-
compile: "Compile",
|
|
7485
|
-
assembly: "Assembly",
|
|
7486
|
-
manifest: "Manifest",
|
|
7487
|
-
write: "Write",
|
|
7488
|
-
sync: "Sync",
|
|
7489
|
-
restart: "Restart"
|
|
7490
|
-
};
|
|
7491
|
-
var PHASE_UNITS = {
|
|
7492
|
-
version: "step",
|
|
7493
|
-
discovery: "file",
|
|
7494
|
-
compile: "file",
|
|
7495
|
-
assembly: "step",
|
|
7496
|
-
manifest: "step",
|
|
7497
|
-
write: "file",
|
|
7498
|
-
sync: "file",
|
|
7499
|
-
restart: "step"
|
|
7500
|
-
};
|
|
7501
|
-
function isCountedPhase(phase) {
|
|
7502
|
-
return COUNTED_PHASES.has(phase);
|
|
7503
|
-
}
|
|
7504
|
-
|
|
7505
|
-
// src/build/phase-tracker.ts
|
|
7506
|
-
function createPhaseTracker(listener = null) {
|
|
7507
|
-
const closed = [];
|
|
7508
|
-
let open = null;
|
|
7509
|
-
function emit3(phase, state, item, durationMs) {
|
|
7510
|
-
listener?.({ phase: phase.phase, state, completed: phase.completed, total: phase.total, item, durationMs });
|
|
7511
|
-
}
|
|
7512
|
-
function close(state) {
|
|
7513
|
-
if (open === null) {
|
|
7514
|
-
return;
|
|
7515
|
-
}
|
|
7516
|
-
const durationMs = performance.now() - open.startedAt;
|
|
7517
|
-
const completed = state === "done" && isCountedPhase(open.phase) ? open.total : open.completed;
|
|
7518
|
-
const finished = { ...open, completed };
|
|
7519
|
-
closed.push({ phase: open.phase, state, completed, total: open.total, durationMs });
|
|
7520
|
-
open = null;
|
|
7521
|
-
emit3(finished, state, null, durationMs);
|
|
7522
|
-
}
|
|
7523
|
-
return {
|
|
7524
|
-
begin: (phase, total = 0) => {
|
|
7525
|
-
close("done");
|
|
7526
|
-
open = { phase, startedAt: performance.now(), completed: 0, total };
|
|
7527
|
-
emit3(open, "active", null, 0);
|
|
7528
|
-
},
|
|
7529
|
-
advance: (item, completed, total) => {
|
|
7530
|
-
if (open === null) {
|
|
7531
|
-
return;
|
|
7532
|
-
}
|
|
7533
|
-
open.completed = completed;
|
|
7534
|
-
open.total = total;
|
|
7535
|
-
emit3(open, "active", item, performance.now() - open.startedAt);
|
|
7536
|
-
},
|
|
7537
|
-
end: (state = "done") => {
|
|
7538
|
-
close(state);
|
|
7539
|
-
},
|
|
7540
|
-
durations: () => [...closed]
|
|
7541
|
-
};
|
|
7542
|
-
}
|
|
7543
|
-
|
|
7544
|
-
// src/build/project-inputs.ts
|
|
7545
|
-
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
7546
|
-
import { resolve as resolve7 } from "node:path";
|
|
7547
|
-
|
|
7548
|
-
// src/build/asset-resolution.ts
|
|
7549
|
-
import { statSync as statSync3 } from "node:fs";
|
|
7550
|
-
import { resolve as resolve6 } from "node:path";
|
|
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";
|
|
7551
7695
|
|
|
7552
7696
|
// src/build/project-files.ts
|
|
7553
7697
|
import { readdirSync, statSync as statSync2 } from "node:fs";
|
|
@@ -7597,6 +7741,196 @@ function listProjectFiles(root, roots, excluded = []) {
|
|
|
7597
7741
|
return { files: [...new Set(tree.files)].sort(), errors: tree.errors };
|
|
7598
7742
|
}
|
|
7599
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
|
+
|
|
7861
|
+
// src/build/build-phase.ts
|
|
7862
|
+
var COUNTED_PHASES = /* @__PURE__ */ new Set(["compile", "write"]);
|
|
7863
|
+
var PHASE_LABELS = {
|
|
7864
|
+
version: "Version",
|
|
7865
|
+
discovery: "Discovery",
|
|
7866
|
+
compile: "Compile",
|
|
7867
|
+
assembly: "Assembly",
|
|
7868
|
+
manifest: "Manifest",
|
|
7869
|
+
write: "Write",
|
|
7870
|
+
sync: "Sync",
|
|
7871
|
+
restart: "Restart"
|
|
7872
|
+
};
|
|
7873
|
+
var PHASE_UNITS = {
|
|
7874
|
+
version: "step",
|
|
7875
|
+
discovery: "file",
|
|
7876
|
+
compile: "file",
|
|
7877
|
+
assembly: "step",
|
|
7878
|
+
manifest: "step",
|
|
7879
|
+
write: "file",
|
|
7880
|
+
sync: "file",
|
|
7881
|
+
restart: "step"
|
|
7882
|
+
};
|
|
7883
|
+
function isCountedPhase(phase) {
|
|
7884
|
+
return COUNTED_PHASES.has(phase);
|
|
7885
|
+
}
|
|
7886
|
+
|
|
7887
|
+
// src/build/phase-tracker.ts
|
|
7888
|
+
function createPhaseTracker(listener = null) {
|
|
7889
|
+
const closed = [];
|
|
7890
|
+
let open = null;
|
|
7891
|
+
function emit3(phase, state, item, durationMs) {
|
|
7892
|
+
listener?.({ phase: phase.phase, state, completed: phase.completed, total: phase.total, item, durationMs });
|
|
7893
|
+
}
|
|
7894
|
+
function close(state) {
|
|
7895
|
+
if (open === null) {
|
|
7896
|
+
return;
|
|
7897
|
+
}
|
|
7898
|
+
const durationMs = performance.now() - open.startedAt;
|
|
7899
|
+
const completed = state === "done" && isCountedPhase(open.phase) ? open.total : open.completed;
|
|
7900
|
+
const finished = { ...open, completed };
|
|
7901
|
+
closed.push({ phase: open.phase, state, completed, total: open.total, durationMs });
|
|
7902
|
+
open = null;
|
|
7903
|
+
emit3(finished, state, null, durationMs);
|
|
7904
|
+
}
|
|
7905
|
+
return {
|
|
7906
|
+
begin: (phase, total = 0) => {
|
|
7907
|
+
close("done");
|
|
7908
|
+
open = { phase, startedAt: performance.now(), completed: 0, total };
|
|
7909
|
+
emit3(open, "active", null, 0);
|
|
7910
|
+
},
|
|
7911
|
+
advance: (item, completed, total) => {
|
|
7912
|
+
if (open === null) {
|
|
7913
|
+
return;
|
|
7914
|
+
}
|
|
7915
|
+
open.completed = completed;
|
|
7916
|
+
open.total = total;
|
|
7917
|
+
emit3(open, "active", item, performance.now() - open.startedAt);
|
|
7918
|
+
},
|
|
7919
|
+
end: (state = "done") => {
|
|
7920
|
+
close(state);
|
|
7921
|
+
},
|
|
7922
|
+
durations: () => [...closed]
|
|
7923
|
+
};
|
|
7924
|
+
}
|
|
7925
|
+
|
|
7926
|
+
// src/build/project-inputs.ts
|
|
7927
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
|
|
7928
|
+
import { resolve as resolve8 } from "node:path";
|
|
7929
|
+
|
|
7930
|
+
// src/build/asset-resolution.ts
|
|
7931
|
+
import { statSync as statSync3 } from "node:fs";
|
|
7932
|
+
import { resolve as resolve7 } from "node:path";
|
|
7933
|
+
|
|
7600
7934
|
// ../compiler/src/project/resource-map.ts
|
|
7601
7935
|
var RESOURCE_MAP_VERSION = 1;
|
|
7602
7936
|
function findSegment(segments, line2) {
|
|
@@ -7669,11 +8003,12 @@ var ENVIRONMENTS2 = ["shared", "server", "client"];
|
|
|
7669
8003
|
function bundlePath(environment) {
|
|
7670
8004
|
return `${BUNDLE_DIRECTORY}/${environment}.lua`;
|
|
7671
8005
|
}
|
|
7672
|
-
function collectBundles(helpers, scripts, pinned) {
|
|
8006
|
+
function collectBundles(helpers, scripts, pinned, libraries = []) {
|
|
7673
8007
|
const pinnedPaths = new Set(pinned.map((script) => script.path));
|
|
7674
8008
|
return ENVIRONMENTS2.flatMap((environment) => {
|
|
7675
8009
|
const environmentHelpers = helpers.filter((helper) => helper.environment === environment).map((helper) => ({ kind: "helper", helper }));
|
|
7676
8010
|
const orderedModules = [
|
|
8011
|
+
...libraries.filter((script) => script.environment === environment),
|
|
7677
8012
|
...pinned.filter((script) => script.environment === environment),
|
|
7678
8013
|
...scripts.filter((script) => script.environment === environment && !pinnedPaths.has(script.path))
|
|
7679
8014
|
].map((module) => ({ kind: "module", module }));
|
|
@@ -7731,6 +8066,9 @@ var OCCUPIED_SIDES = {
|
|
|
7731
8066
|
function occupiedSides(contribution) {
|
|
7732
8067
|
return OCCUPIED_SIDES[contribution.side];
|
|
7733
8068
|
}
|
|
8069
|
+
function sidesOf(environment) {
|
|
8070
|
+
return OCCUPIED_SIDES[environment];
|
|
8071
|
+
}
|
|
7734
8072
|
function exportSignature(type) {
|
|
7735
8073
|
if (type === void 0 || type.kind !== "function") {
|
|
7736
8074
|
return null;
|
|
@@ -7753,10 +8091,11 @@ function toContributions(directives, environment, globals) {
|
|
|
7753
8091
|
var INDENT = " ";
|
|
7754
8092
|
var RESOURCE_TYPE = "script";
|
|
7755
8093
|
var DEFAULT_SIDE = "server";
|
|
7756
|
-
var
|
|
7757
|
-
var SCRIPT_GROUPS = ["library", "configuration", "source"];
|
|
8094
|
+
var SIDE_ORDER2 = { shared: 0, server: 1, client: 2 };
|
|
8095
|
+
var SCRIPT_GROUPS = ["library", "libraries", "configuration", "source"];
|
|
7758
8096
|
var GROUP_COMMENTS = {
|
|
7759
8097
|
library: "Runtime library",
|
|
8098
|
+
libraries: "Libraries",
|
|
7760
8099
|
configuration: "Configuration",
|
|
7761
8100
|
source: "Source scripts"
|
|
7762
8101
|
};
|
|
@@ -7819,7 +8158,7 @@ function versionElement(version) {
|
|
|
7819
8158
|
return `${INDENT}<min_mta_version ${attribute("server", version)} ${attribute("client", version)} />`;
|
|
7820
8159
|
}
|
|
7821
8160
|
function exportElements(contributions) {
|
|
7822
|
-
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);
|
|
7823
8162
|
}
|
|
7824
8163
|
function scriptSections(scripts) {
|
|
7825
8164
|
return SCRIPT_GROUPS.flatMap((group) => section(GROUP_COMMENTS[group], scripts.filter((script) => script.group === group).map(scriptElement)));
|
|
@@ -7903,16 +8242,39 @@ function collectDevelopmentLogHelpers(options) {
|
|
|
7903
8242
|
replacements
|
|
7904
8243
|
}));
|
|
7905
8244
|
}
|
|
8245
|
+
function emitted(modules) {
|
|
8246
|
+
return modules.filter((module) => module.code !== null);
|
|
8247
|
+
}
|
|
7906
8248
|
function collectScripts(modules) {
|
|
7907
|
-
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);
|
|
7908
8265
|
}
|
|
7909
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.';
|
|
7910
8268
|
function missingEntry(entry) {
|
|
7911
8269
|
return { path: entry, diagnostic: createDiagnostic("project", "project-load-order-missing", `"${entry}" ${MISSING_LOAD_ORDER}`, FILE_START) };
|
|
7912
8270
|
}
|
|
7913
|
-
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 = []) {
|
|
7914
8275
|
const byScript = new Map(scripts.map((script) => [normalizePath(script.source), script]));
|
|
7915
8276
|
const byAsset = new Map(assets.map((asset) => [normalizePath(asset.source), asset]));
|
|
8277
|
+
const byLibrary = new Set(libraries.map((script) => normalizePath(script.source)));
|
|
7916
8278
|
const resolved2 = { scripts: [], assets: [], diagnostics: [] };
|
|
7917
8279
|
const seen = /* @__PURE__ */ new Set();
|
|
7918
8280
|
for (const entry of entries3) {
|
|
@@ -7924,7 +8286,7 @@ function resolveLoadOrder(entries3, scripts, assets) {
|
|
|
7924
8286
|
}
|
|
7925
8287
|
seen.add(path);
|
|
7926
8288
|
if (script === void 0 && asset === void 0) {
|
|
7927
|
-
resolved2.diagnostics.push(missingEntry(entry));
|
|
8289
|
+
resolved2.diagnostics.push(byLibrary.has(path) ? libraryEntry(entry) : missingEntry(entry));
|
|
7928
8290
|
continue;
|
|
7929
8291
|
}
|
|
7930
8292
|
if (script !== void 0) {
|
|
@@ -8085,9 +8447,9 @@ function withEnvironmentFile(helpers, file) {
|
|
|
8085
8447
|
function helperEntry(helper) {
|
|
8086
8448
|
return { src: helper.path, environment: helper.environment, group: "library" };
|
|
8087
8449
|
}
|
|
8088
|
-
function manifestScripts(helpers, configuration, sources) {
|
|
8450
|
+
function manifestScripts(helpers, libraries, configuration, sources) {
|
|
8089
8451
|
const settings = configuration === null ? [] : [{ src: configuration.path, environment: "shared", group: "configuration" }];
|
|
8090
|
-
return [...helpers.map(helperEntry), ...settings, ...sources];
|
|
8452
|
+
return [...helpers.map(helperEntry), ...libraries, ...settings, ...sources];
|
|
8091
8453
|
}
|
|
8092
8454
|
function collectContributions(project) {
|
|
8093
8455
|
return project.modules.flatMap((module) => module.contributions);
|
|
@@ -8160,32 +8522,35 @@ function assembleResource(project, options, onStep) {
|
|
|
8160
8522
|
const collected = [...collectHelpers(project.modules, options.helpers ?? []), ...collectDevelopmentLogHelpers(options.developmentLogs)];
|
|
8161
8523
|
const helpers = withEnvironmentFile(collected, options.environmentFile);
|
|
8162
8524
|
const scripts = collectScripts(project.modules);
|
|
8525
|
+
const libraries = collectLibraryScripts(project.modules, options.libraryFiles ?? []);
|
|
8163
8526
|
const configuration = configurationScript(options.configuration);
|
|
8164
8527
|
const deployment = configuration === null ? [] : [configuration];
|
|
8165
|
-
const
|
|
8166
|
-
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);
|
|
8167
8530
|
const layout = options.layout ?? "tree";
|
|
8168
|
-
const bundles = layout === "bundle" ? collectBundles(helpers, scripts, order.scripts) : [];
|
|
8169
|
-
const duplicates = layout === "tree" ? findDuplicateOutputs([...scripts, ...deployment],
|
|
8170
|
-
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) : [];
|
|
8171
8534
|
const diagnostics = sortFileDiagnostics([...project.diagnostics, ...duplicates, ...collisions, ...order.diagnostics]);
|
|
8172
8535
|
if (duplicates.length > 0 || collisions.length > 0 || order.diagnostics.length > 0) {
|
|
8173
8536
|
return { build: null, diagnostics };
|
|
8174
8537
|
}
|
|
8175
8538
|
onStep?.("assembly");
|
|
8176
|
-
const assets = orderAssets(
|
|
8539
|
+
const assets = orderAssets(sorted2, order.assets);
|
|
8177
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" }));
|
|
8178
8541
|
const manifestHelpers = layout === "tree" ? helpers : [];
|
|
8542
|
+
const vendored = layout === "tree" ? libraries.map((script) => ({ src: script.path, environment: script.environment, group: "libraries" })) : [];
|
|
8179
8543
|
const manifest = generateManifest(
|
|
8180
8544
|
manifestInfo(options),
|
|
8181
|
-
manifestScripts(manifestHelpers, configuration, sources),
|
|
8545
|
+
manifestScripts(manifestHelpers, vendored, configuration, sources),
|
|
8182
8546
|
manifestFiles(assets),
|
|
8183
8547
|
collectContributions(project),
|
|
8184
8548
|
{ oop: options.oop === true, minMtaVersion: options.minMtaVersion ?? null, dependencies: options.dependencies ?? [] }
|
|
8185
8549
|
);
|
|
8186
8550
|
onStep?.("manifest");
|
|
8187
|
-
const
|
|
8188
|
-
|
|
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 };
|
|
8189
8554
|
}
|
|
8190
8555
|
|
|
8191
8556
|
// src/build/asset-resolution.ts
|
|
@@ -8195,14 +8560,14 @@ var MANIFEST_OUTPUT = "meta.xml";
|
|
|
8195
8560
|
var HERE = ".";
|
|
8196
8561
|
function isDirectory2(root, path) {
|
|
8197
8562
|
try {
|
|
8198
|
-
return statSync3(
|
|
8563
|
+
return statSync3(resolve7(root, path)).isDirectory();
|
|
8199
8564
|
} catch {
|
|
8200
8565
|
return false;
|
|
8201
8566
|
}
|
|
8202
8567
|
}
|
|
8203
8568
|
function exists(root, path) {
|
|
8204
8569
|
try {
|
|
8205
|
-
statSync3(
|
|
8570
|
+
statSync3(resolve7(root, path));
|
|
8206
8571
|
return true;
|
|
8207
8572
|
} catch {
|
|
8208
8573
|
return false;
|
|
@@ -8270,10 +8635,10 @@ var CONFIGURATION_FILE = "config.lua";
|
|
|
8270
8635
|
var MALFORMED_ENV = "build-env-malformed";
|
|
8271
8636
|
var MISSING_ENV = "config-missing-env-file";
|
|
8272
8637
|
function readTextFile(path) {
|
|
8273
|
-
return
|
|
8638
|
+
return existsSync5(path) ? readFileSync6(path, "utf8") : null;
|
|
8274
8639
|
}
|
|
8275
8640
|
function readEnvironment(root, file, required, diagnostics) {
|
|
8276
|
-
const source = readTextFile(
|
|
8641
|
+
const source = readTextFile(resolve8(root, file));
|
|
8277
8642
|
if (source === null) {
|
|
8278
8643
|
if (required) {
|
|
8279
8644
|
diagnostics.push(cliError(MISSING_ENV, `"${file}" is configured under "environment" but does not exist. Create it or remove the setting.`));
|
|
@@ -8287,7 +8652,7 @@ function readEnvironment(root, file, required, diagnostics) {
|
|
|
8287
8652
|
return parsed;
|
|
8288
8653
|
}
|
|
8289
8654
|
function readConfiguration(root, diagnostics) {
|
|
8290
|
-
const content = readTextFile(
|
|
8655
|
+
const content = readTextFile(resolve8(root, CONFIGURATION_FILE));
|
|
8291
8656
|
if (content === null) {
|
|
8292
8657
|
return null;
|
|
8293
8658
|
}
|
|
@@ -8306,14 +8671,14 @@ function readProjectInputs(root, options) {
|
|
|
8306
8671
|
}
|
|
8307
8672
|
|
|
8308
8673
|
// src/build/source-discovery.ts
|
|
8309
|
-
import { readFileSync as
|
|
8310
|
-
import { resolve as
|
|
8674
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
8675
|
+
import { resolve as resolve9 } from "node:path";
|
|
8311
8676
|
|
|
8312
8677
|
// ../compiler/src/project/source-mapping.ts
|
|
8313
8678
|
function createSourceResolver(mapping) {
|
|
8314
8679
|
const matchers = new Map(SOURCE_SIDES.map((environment) => [environment, createPatternMatcher(mapping[environment])]));
|
|
8315
8680
|
const patterns = SOURCE_SIDES.flatMap((environment) => [...matchers.get(environment)?.patterns ?? []]);
|
|
8316
|
-
function
|
|
8681
|
+
function resolve24(path) {
|
|
8317
8682
|
const normalized = normalizePattern(path);
|
|
8318
8683
|
const matches = [];
|
|
8319
8684
|
for (const environment of SOURCE_SIDES) {
|
|
@@ -8327,25 +8692,14 @@ function createSourceResolver(mapping) {
|
|
|
8327
8692
|
return {
|
|
8328
8693
|
patterns,
|
|
8329
8694
|
roots: watchRoots(patterns),
|
|
8330
|
-
resolve:
|
|
8331
|
-
side: (path) =>
|
|
8695
|
+
resolve: resolve24,
|
|
8696
|
+
side: (path) => resolve24(path).environment
|
|
8332
8697
|
};
|
|
8333
8698
|
}
|
|
8334
8699
|
function describeMatches(matches) {
|
|
8335
8700
|
return matches.map((match) => `"${match.environment}" through "${match.pattern}"`).join(" and ");
|
|
8336
8701
|
}
|
|
8337
8702
|
|
|
8338
|
-
// ../compiler/src/project/source-kind.ts
|
|
8339
|
-
var SOURCE_EXTENSION = ".luam";
|
|
8340
|
-
var DECLARATION_EXTENSION = ".d.luam";
|
|
8341
|
-
var TEST_EXTENSION = ".test.luam";
|
|
8342
|
-
function isDeclarationPath(path) {
|
|
8343
|
-
return normalizePath(path).endsWith(DECLARATION_EXTENSION);
|
|
8344
|
-
}
|
|
8345
|
-
function isTestPath(path) {
|
|
8346
|
-
return normalizePath(path).endsWith(TEST_EXTENSION);
|
|
8347
|
-
}
|
|
8348
|
-
|
|
8349
8703
|
// src/build/source-discovery.ts
|
|
8350
8704
|
var MISSING_SOURCE = "config-missing-source";
|
|
8351
8705
|
var NO_SOURCES = "config-no-sources";
|
|
@@ -8371,7 +8725,7 @@ function checkLiterals(root, resolver, found, diagnostics) {
|
|
|
8371
8725
|
}
|
|
8372
8726
|
function readSource(root, path, diagnostics) {
|
|
8373
8727
|
try {
|
|
8374
|
-
return
|
|
8728
|
+
return readFileSync7(resolve9(root, path), "utf8");
|
|
8375
8729
|
} catch (error) {
|
|
8376
8730
|
diagnostics.push(cliError(UNREADABLE_SOURCE, `The source file "${path}" could not be read: ${error instanceof Error ? error.message : String(error)}`));
|
|
8377
8731
|
return null;
|
|
@@ -8780,6 +9134,13 @@ function assignmentFact(narrowed, declared) {
|
|
|
8780
9134
|
}
|
|
8781
9135
|
|
|
8782
9136
|
// ../compiler/src/checker/type-substitution.ts
|
|
9137
|
+
function shadowed(substitutions, names) {
|
|
9138
|
+
const remaining = new Map(substitutions);
|
|
9139
|
+
for (const name of names) {
|
|
9140
|
+
remaining.delete(name);
|
|
9141
|
+
}
|
|
9142
|
+
return remaining;
|
|
9143
|
+
}
|
|
8783
9144
|
function substituteType(type, substitutions) {
|
|
8784
9145
|
if (type.kind === "named") {
|
|
8785
9146
|
const args = type.typeArguments ?? [];
|
|
@@ -8801,10 +9162,17 @@ function substituteType(type, substitutions) {
|
|
|
8801
9162
|
return createUnion(type.options.map((option) => substituteType(option, substitutions)));
|
|
8802
9163
|
}
|
|
8803
9164
|
if (type.kind === "function") {
|
|
8804
|
-
const
|
|
8805
|
-
const
|
|
8806
|
-
const
|
|
8807
|
-
|
|
9165
|
+
const own = type.typeParameters ?? [];
|
|
9166
|
+
const outer = own.length === 0 ? substitutions : shadowed(substitutions, own);
|
|
9167
|
+
const parameters = type.parameters.map((parameter) => substituteType(parameter, outer));
|
|
9168
|
+
const returnType = substituteType(type.returnType, outer);
|
|
9169
|
+
const variadicType = type.variadicType === void 0 ? void 0 : substituteType(type.variadicType, outer);
|
|
9170
|
+
const substituted = createFunction(parameters, returnType, type.minimumArguments, type.isVariadic, type.parameterNames, variadicType);
|
|
9171
|
+
if (own.length > 0) {
|
|
9172
|
+
substituted.typeParameters = [...own];
|
|
9173
|
+
substituted.typeConstraints = (type.typeConstraints ?? []).map((constraint) => constraint === null ? null : substituteType(constraint, outer));
|
|
9174
|
+
}
|
|
9175
|
+
return substituted;
|
|
8808
9176
|
}
|
|
8809
9177
|
if (type.kind === "tuple") {
|
|
8810
9178
|
return createTuple(type.elements.map((element) => substituteType(element, substitutions)));
|
|
@@ -8921,21 +9289,24 @@ function satisfies(context, argument, constraint) {
|
|
|
8921
9289
|
}
|
|
8922
9290
|
return isAssignable(argument, constraint, { allowNil: false });
|
|
8923
9291
|
}
|
|
8924
|
-
function
|
|
8925
|
-
|
|
8926
|
-
if (info === null) {
|
|
8927
|
-
return;
|
|
8928
|
-
}
|
|
8929
|
-
info.typeConstraints.forEach((constraint, index) => {
|
|
9292
|
+
function reportConstraintViolations(context, owner, typeParameters, typeConstraints, typeArguments, position2) {
|
|
9293
|
+
typeConstraints.forEach((constraint, index) => {
|
|
8930
9294
|
const argument = typeArguments[index];
|
|
8931
9295
|
if (constraint === null || argument === void 0 || argument.kind === "any" || satisfies(context, argument, constraint)) {
|
|
8932
9296
|
return;
|
|
8933
9297
|
}
|
|
8934
|
-
const parameter =
|
|
8935
|
-
const message = `Type argument "${typeToString(argument)}" does not satisfy "${parameter} extends ${typeToString(constraint)}" on
|
|
9298
|
+
const parameter = typeParameters[index] ?? "T";
|
|
9299
|
+
const message = `Type argument "${typeToString(argument)}" does not satisfy "${parameter} extends ${typeToString(constraint)}" on ${owner}.`;
|
|
8936
9300
|
context.report("check-generic-constraint", message, position2);
|
|
8937
9301
|
});
|
|
8938
9302
|
}
|
|
9303
|
+
function checkTypeConstraints(context, name, typeArguments, position2) {
|
|
9304
|
+
const info = context.declarations.lookupClass(name);
|
|
9305
|
+
if (info === null) {
|
|
9306
|
+
return;
|
|
9307
|
+
}
|
|
9308
|
+
reportConstraintViolations(context, `class "${name}"`, info.typeParameters, info.typeConstraints, typeArguments, position2);
|
|
9309
|
+
}
|
|
8939
9310
|
|
|
8940
9311
|
// ../mta-types/src/lua-standard.ts
|
|
8941
9312
|
var LUA_GLOBALS = {
|
|
@@ -14925,12 +15296,12 @@ function failed(type) {
|
|
|
14925
15296
|
function entries2(parts) {
|
|
14926
15297
|
return `{ ${parts.join(", ")} }`;
|
|
14927
15298
|
}
|
|
14928
|
-
function combine(parts,
|
|
15299
|
+
function combine(parts, render3) {
|
|
14929
15300
|
const broken = parts.find((part) => part.lua === null);
|
|
14930
15301
|
if (broken !== void 0) {
|
|
14931
15302
|
return broken;
|
|
14932
15303
|
}
|
|
14933
|
-
return { lua:
|
|
15304
|
+
return { lua: render3(parts.map((part) => part.lua)), unreifiable: null };
|
|
14934
15305
|
}
|
|
14935
15306
|
function namedDescriptor(context, type, name, seen) {
|
|
14936
15307
|
if (context.declarations.lookupClass(name) !== null) {
|
|
@@ -15027,6 +15398,8 @@ function accessorMethod(field2, decorator, name) {
|
|
|
15027
15398
|
isConstructor: false,
|
|
15028
15399
|
isSynthetic: true,
|
|
15029
15400
|
isStatic: false,
|
|
15401
|
+
typeParameters: [],
|
|
15402
|
+
typeConstraints: [],
|
|
15030
15403
|
parameters: decorator === "Getter" ? [] : [value],
|
|
15031
15404
|
returnAnnotation: decorator === "Getter" ? field2.annotation : voidAnnotation,
|
|
15032
15405
|
body,
|
|
@@ -15035,7 +15408,7 @@ function accessorMethod(field2, decorator, name) {
|
|
|
15035
15408
|
};
|
|
15036
15409
|
}
|
|
15037
15410
|
function generatedMethod(field2, name, parameters, returnAnnotation, kind, fields) {
|
|
15038
|
-
return { kind: "class-method", name, isConstructor: false, isSynthetic: true, isStatic: false, parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
|
|
15411
|
+
return { kind: "class-method", name, isConstructor: false, isSynthetic: true, isStatic: false, typeParameters: [], typeConstraints: [], parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
|
|
15039
15412
|
}
|
|
15040
15413
|
function typeName(name, node) {
|
|
15041
15414
|
return { kind: "type-name", name, typeArguments: [], position: node.position };
|
|
@@ -15073,6 +15446,8 @@ function staticMethod(statement, name, returnAnnotation, kind, descriptor) {
|
|
|
15073
15446
|
isConstructor: false,
|
|
15074
15447
|
isSynthetic: true,
|
|
15075
15448
|
isStatic: true,
|
|
15449
|
+
typeParameters: [],
|
|
15450
|
+
typeConstraints: [],
|
|
15076
15451
|
parameters: [value],
|
|
15077
15452
|
returnAnnotation,
|
|
15078
15453
|
body: [],
|
|
@@ -18541,33 +18916,60 @@ function selectCandidate(context, expression, forms) {
|
|
|
18541
18916
|
});
|
|
18542
18917
|
return found[0] ?? null;
|
|
18543
18918
|
}
|
|
18544
|
-
function specialize(
|
|
18919
|
+
function specialize(signature2, candidate) {
|
|
18545
18920
|
const callback = candidate.form.callbackArgument;
|
|
18546
18921
|
if (callback !== void 0) {
|
|
18547
|
-
const parameters = [...
|
|
18922
|
+
const parameters = [...signature2.parameters];
|
|
18548
18923
|
parameters[callback] = candidate.handler;
|
|
18549
|
-
return { ...
|
|
18924
|
+
return { ...signature2, parameters };
|
|
18550
18925
|
}
|
|
18551
18926
|
const payload = candidate.form.payloadArgument;
|
|
18552
18927
|
if (payload === void 0) {
|
|
18553
18928
|
return null;
|
|
18554
18929
|
}
|
|
18555
18930
|
return createFunction(
|
|
18556
|
-
[...
|
|
18557
|
-
|
|
18931
|
+
[...signature2.parameters.slice(0, payload), ...candidate.handler.parameters],
|
|
18932
|
+
signature2.returnType,
|
|
18558
18933
|
payload + candidate.handler.minimumArguments,
|
|
18559
18934
|
candidate.handler.isVariadic,
|
|
18560
18935
|
void 0,
|
|
18561
18936
|
candidate.handler.variadicType
|
|
18562
18937
|
);
|
|
18563
18938
|
}
|
|
18564
|
-
function specializeEventCall(context, expression,
|
|
18565
|
-
if (
|
|
18939
|
+
function specializeEventCall(context, expression, signature2) {
|
|
18940
|
+
if (signature2.kind !== "function" || expression.method !== null || expression.callee.kind !== "identifier") {
|
|
18566
18941
|
return null;
|
|
18567
18942
|
}
|
|
18568
18943
|
const forms = eventCallForms(expression.callee.name);
|
|
18569
18944
|
const candidate = selectCandidate(context, expression, forms);
|
|
18570
|
-
return candidate === null ? null : specialize(
|
|
18945
|
+
return candidate === null ? null : specialize(signature2, candidate);
|
|
18946
|
+
}
|
|
18947
|
+
|
|
18948
|
+
// ../compiler/src/checker/generic-call.ts
|
|
18949
|
+
function countArguments(total) {
|
|
18950
|
+
return total === 1 ? "1 type argument" : `${total} type arguments`;
|
|
18951
|
+
}
|
|
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);
|
|
18957
|
+
}
|
|
18958
|
+
function specializeCall(context, owner, signature2, argumentTypes, typeArguments, position2) {
|
|
18959
|
+
const names = signature2.typeParameters ?? [];
|
|
18960
|
+
if (names.length === 0) {
|
|
18961
|
+
if (typeArguments.length > 0) {
|
|
18962
|
+
context.report("check-generic-arity", `${owner} does not accept type arguments.`, position2);
|
|
18963
|
+
}
|
|
18964
|
+
return signature2;
|
|
18965
|
+
}
|
|
18966
|
+
const explicit = typeArguments.map((argument) => context.resolveAnnotation(argument));
|
|
18967
|
+
if (typeArguments.length > 0 && explicit.length !== names.length) {
|
|
18968
|
+
context.report("check-generic-arity", `${owner} expects ${countArguments(names.length)} but received ${explicit.length}.`, position2);
|
|
18969
|
+
}
|
|
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])));
|
|
18571
18973
|
}
|
|
18572
18974
|
|
|
18573
18975
|
// ../compiler/src/checker/method-receiver.ts
|
|
@@ -18579,13 +18981,13 @@ function resolveNonNominalMethod(receiver, method) {
|
|
|
18579
18981
|
const member = receiver.members.get(method);
|
|
18580
18982
|
return member !== void 0 && member.kind === "function" ? member : null;
|
|
18581
18983
|
}
|
|
18582
|
-
function withoutSelfParameter(
|
|
18583
|
-
const names =
|
|
18984
|
+
function withoutSelfParameter(signature2) {
|
|
18985
|
+
const names = signature2.parameterNames;
|
|
18584
18986
|
if (names === void 0 || names[0] !== SELF_PARAMETER) {
|
|
18585
|
-
return
|
|
18987
|
+
return signature2;
|
|
18586
18988
|
}
|
|
18587
|
-
const minimum = Math.max(0,
|
|
18588
|
-
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);
|
|
18589
18991
|
}
|
|
18590
18992
|
|
|
18591
18993
|
// ../compiler/src/checker/resource-exports.ts
|
|
@@ -18883,6 +19285,7 @@ function resolveMtaMember(context, className, name, position2) {
|
|
|
18883
19285
|
}
|
|
18884
19286
|
|
|
18885
19287
|
// ../compiler/src/checker/members.ts
|
|
19288
|
+
var SELF_RECEIVER = "self";
|
|
18886
19289
|
function checkEnumMember(context, name, members, expression) {
|
|
18887
19290
|
if (members.includes(expression.property)) {
|
|
18888
19291
|
return NUMBER_TYPE;
|
|
@@ -18943,6 +19346,35 @@ function resolveStaticMember(context, className, expression) {
|
|
|
18943
19346
|
context.report("check-unknown-member", `Class "${className}" has no static member "${expression.property}".${hint}`, expression.position);
|
|
18944
19347
|
return ANY_TYPE;
|
|
18945
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
|
+
}
|
|
18946
19378
|
function resolveNamedMember(context, receiver, expression) {
|
|
18947
19379
|
const name = receiver.name;
|
|
18948
19380
|
const enumeration = context.declarations.lookupEnum(name);
|
|
@@ -18968,13 +19400,39 @@ function resolveNamedMember(context, receiver, expression) {
|
|
|
18968
19400
|
if (context.awaitsDeclaration(name)) {
|
|
18969
19401
|
return ANY_TYPE;
|
|
18970
19402
|
}
|
|
18971
|
-
|
|
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);
|
|
18972
19407
|
if (contract === null) {
|
|
18973
19408
|
return null;
|
|
18974
19409
|
}
|
|
18975
19410
|
const members = new Map(context.declarations.collectMembers(name).map((member2) => [member2.name, member2]));
|
|
18976
19411
|
return checkInterfaceMember(context, name, members, expression);
|
|
18977
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
|
+
}
|
|
18978
19436
|
var NATIVE_CONSTRUCTOR = "new";
|
|
18979
19437
|
function nativeConstructor(context, name) {
|
|
18980
19438
|
const symbol = context.binder.lookup(name);
|
|
@@ -19031,9 +19489,9 @@ function checkNewExpression(context, expression) {
|
|
|
19031
19489
|
const constructor = context.declarations.lookupMember(expression.className, "constructor");
|
|
19032
19490
|
if (constructor !== null && constructor.type.kind === "function") {
|
|
19033
19491
|
const substitutions = info === null ? /* @__PURE__ */ new Map() : classSubstitutions(info, typeArguments);
|
|
19034
|
-
const
|
|
19035
|
-
if (
|
|
19036
|
-
checkSignature(context, expression.args,
|
|
19492
|
+
const signature2 = substituteType(constructor.type, substitutions);
|
|
19493
|
+
if (signature2.kind === "function") {
|
|
19494
|
+
checkSignature(context, expression.args, signature2, expression.position);
|
|
19037
19495
|
}
|
|
19038
19496
|
} else {
|
|
19039
19497
|
expression.args.forEach((argument) => checkExpression(context, argument));
|
|
@@ -19383,15 +19841,48 @@ function checkLoopBody(context, body, facts) {
|
|
|
19383
19841
|
checkBlock(context, body);
|
|
19384
19842
|
context.setFlow(entry);
|
|
19385
19843
|
}
|
|
19386
|
-
function
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19844
|
+
function isTruthyLiteral(condition) {
|
|
19845
|
+
if (condition.kind === "group-expression") {
|
|
19846
|
+
return isTruthyLiteral(condition.expression);
|
|
19847
|
+
}
|
|
19848
|
+
const literal2 = condition.kind === "number-literal" || condition.kind === "string-literal" || condition.kind === "template-literal";
|
|
19849
|
+
return literal2 || condition.kind === "boolean-literal" && condition.value;
|
|
19391
19850
|
}
|
|
19392
|
-
function
|
|
19393
|
-
|
|
19394
|
-
|
|
19851
|
+
function isFalsyLiteral(condition) {
|
|
19852
|
+
if (condition.kind === "group-expression") {
|
|
19853
|
+
return isFalsyLiteral(condition.expression);
|
|
19854
|
+
}
|
|
19855
|
+
return condition.kind === "nil-literal" || condition.kind === "boolean-literal" && !condition.value;
|
|
19856
|
+
}
|
|
19857
|
+
function hasBreak(body) {
|
|
19858
|
+
return body.some((statement) => {
|
|
19859
|
+
if (statement.kind === "break-statement") {
|
|
19860
|
+
return true;
|
|
19861
|
+
}
|
|
19862
|
+
if (statement.kind === "do-statement") {
|
|
19863
|
+
return hasBreak(statement.body);
|
|
19864
|
+
}
|
|
19865
|
+
if (statement.kind === "if-statement") {
|
|
19866
|
+
return statement.clauses.some((clause) => hasBreak(clause.body)) || statement.alternate !== null && hasBreak(statement.alternate);
|
|
19867
|
+
}
|
|
19868
|
+
return false;
|
|
19869
|
+
});
|
|
19870
|
+
}
|
|
19871
|
+
function checkWhile(context, statement) {
|
|
19872
|
+
forgetAssignedPaths(context, statement.body);
|
|
19873
|
+
checkExpression(context, statement.condition);
|
|
19874
|
+
checkLoopBody(context, statement.body, conditionFacts(context, statement.condition));
|
|
19875
|
+
context.applyFlowFacts(negatedFacts(context, statement.condition));
|
|
19876
|
+
if (isTruthyLiteral(statement.condition) && !hasBreak(statement.body)) {
|
|
19877
|
+
context.markUnreachable();
|
|
19878
|
+
}
|
|
19879
|
+
}
|
|
19880
|
+
function checkRepeat(context, statement) {
|
|
19881
|
+
checkLoopBody(context, statement.body, /* @__PURE__ */ new Map());
|
|
19882
|
+
checkExpression(context, statement.condition);
|
|
19883
|
+
if (isFalsyLiteral(statement.condition) && !hasBreak(statement.body)) {
|
|
19884
|
+
context.markUnreachable();
|
|
19885
|
+
}
|
|
19395
19886
|
}
|
|
19396
19887
|
function checkNumericFor(context, statement) {
|
|
19397
19888
|
const bounds = [statement.start, statement.limit, statement.step].filter((value) => value !== null);
|
|
@@ -19505,7 +19996,31 @@ function buildFunctionType(context, parameters, returnAnnotation, contextual = n
|
|
|
19505
19996
|
const names = named2.map((parameter) => parameter.name);
|
|
19506
19997
|
return createFunction(types, context.resolveAnnotation(returnAnnotation), minimumArguments(context, parameters), isVariadic, names);
|
|
19507
19998
|
}
|
|
19508
|
-
function
|
|
19999
|
+
function applyTypeParameters(context, type, names, constraints) {
|
|
20000
|
+
if (names.length === 0) {
|
|
20001
|
+
return type;
|
|
20002
|
+
}
|
|
20003
|
+
context.noteTypeParameters(names);
|
|
20004
|
+
type.typeParameters = [...names];
|
|
20005
|
+
type.typeConstraints = names.map((unused, index) => {
|
|
20006
|
+
const constraint = constraints[index];
|
|
20007
|
+
return constraint === void 0 || constraint === null ? null : context.resolveAnnotation(constraint);
|
|
20008
|
+
});
|
|
20009
|
+
return type;
|
|
20010
|
+
}
|
|
20011
|
+
var FALLTHROUGH_KINDS = /* @__PURE__ */ new Set(["any", "void", "nil", "optional", "unknown"]);
|
|
20012
|
+
function toleratesFallthrough(declared) {
|
|
20013
|
+
if (FALLTHROUGH_KINDS.has(declared.kind)) {
|
|
20014
|
+
return true;
|
|
20015
|
+
}
|
|
20016
|
+
return declared.kind === "union" && declared.options.some((option) => option.kind === "nil");
|
|
20017
|
+
}
|
|
20018
|
+
function reportMissingReturn(context, declared, position2) {
|
|
20019
|
+
const name = typeToString(declared);
|
|
20020
|
+
const repair = declared.kind === "tuple" ? "Add a return on every path." : `Add a return on every path, or declare "${name}?".`;
|
|
20021
|
+
context.report("check-missing-return", `This function declares "${name}" but can end without returning a value. ${repair}`, position2);
|
|
20022
|
+
}
|
|
20023
|
+
function checkFunctionBody(context, parameters, returnAnnotation, body, signature2, selfType2, position2 = ORIGIN) {
|
|
19509
20024
|
forgetAssignedPaths(context, body);
|
|
19510
20025
|
const entry = context.flowState;
|
|
19511
20026
|
context.setFlow(cloneFlow(entry));
|
|
@@ -19516,16 +20031,20 @@ function checkFunctionBody(context, parameters, returnAnnotation, body, signatur
|
|
|
19516
20031
|
}
|
|
19517
20032
|
let parameterIndex = 0;
|
|
19518
20033
|
for (const parameter of parameters) {
|
|
19519
|
-
const type = parameter.isVararg ? ANY_TYPE :
|
|
20034
|
+
const type = parameter.isVararg ? ANY_TYPE : signature2.parameters[parameterIndex] ?? ANY_TYPE;
|
|
19520
20035
|
context.binder.declare({ name: parameter.name, type, isLocal: true, position: parameter.position, origin: "parameter" });
|
|
19521
20036
|
if (!parameter.isVararg) {
|
|
19522
20037
|
parameterIndex += 1;
|
|
19523
20038
|
}
|
|
19524
20039
|
}
|
|
19525
20040
|
checkStatements(context, body);
|
|
20041
|
+
const declared = context.currentReturnType();
|
|
20042
|
+
if (declared !== null && context.flowState.reachable && !toleratesFallthrough(declared)) {
|
|
20043
|
+
reportMissingReturn(context, declared, position2);
|
|
20044
|
+
}
|
|
19526
20045
|
const inferred = context.popReturnType();
|
|
19527
20046
|
if (returnAnnotation === null) {
|
|
19528
|
-
|
|
20047
|
+
signature2.returnType = inferred;
|
|
19529
20048
|
}
|
|
19530
20049
|
context.binder.popScope();
|
|
19531
20050
|
context.setFlow(entry);
|
|
@@ -19616,7 +20135,8 @@ function checkAssignment(context, statement) {
|
|
|
19616
20135
|
});
|
|
19617
20136
|
}
|
|
19618
20137
|
function checkFunctionDeclaration(context, statement) {
|
|
19619
|
-
const
|
|
20138
|
+
const built = buildFunctionType(context, statement.parameters, statement.returnAnnotation);
|
|
20139
|
+
const type = applyTypeParameters(context, built, statement.typeParameters, statement.typeConstraints);
|
|
19620
20140
|
if (statement.name.kind === "identifier") {
|
|
19621
20141
|
const symbol = { name: statement.name.name, type, isLocal: statement.isLocal, position: statement.position };
|
|
19622
20142
|
if (statement.isLocal) {
|
|
@@ -19626,7 +20146,7 @@ function checkFunctionDeclaration(context, statement) {
|
|
|
19626
20146
|
}
|
|
19627
20147
|
}
|
|
19628
20148
|
context.record(statement.name, type);
|
|
19629
|
-
checkFunctionBody(context, statement.parameters, statement.returnAnnotation, statement.body, type, statement.isMethod ? ANY_TYPE : null);
|
|
20149
|
+
checkFunctionBody(context, statement.parameters, statement.returnAnnotation, statement.body, type, statement.isMethod ? ANY_TYPE : null, statement.position);
|
|
19630
20150
|
}
|
|
19631
20151
|
function checkReturn(context, statement) {
|
|
19632
20152
|
const valueTypes = checkValueList(context, statement.values);
|
|
@@ -19819,36 +20339,41 @@ function checkMember(context, expression) {
|
|
|
19819
20339
|
}
|
|
19820
20340
|
return context.record(expression, extension === null ? ANY_TYPE : EXTENSION_RESULTS[extension.result]);
|
|
19821
20341
|
}
|
|
19822
|
-
function
|
|
20342
|
+
function countArguments2(total) {
|
|
19823
20343
|
return total === 1 ? "1 argument" : `${total} arguments`;
|
|
19824
20344
|
}
|
|
19825
|
-
function checkSignature(context, args,
|
|
19826
|
-
const argumentTypes = checkValueList(context, args,
|
|
19827
|
-
|
|
19828
|
-
|
|
20345
|
+
function checkSignature(context, args, declared, position2, owner = "This call", typeArguments = []) {
|
|
20346
|
+
const argumentTypes = checkValueList(context, args, declared.parameters);
|
|
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}.`;
|
|
19829
20350
|
context.report("check-argument-count", message, position2);
|
|
19830
20351
|
}
|
|
19831
|
-
if (!
|
|
19832
|
-
const message = `This call expects at most ${
|
|
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}.`;
|
|
19833
20354
|
context.report("check-argument-count", message, position2);
|
|
19834
20355
|
}
|
|
19835
|
-
|
|
20356
|
+
signature2.parameters.forEach((parameter, index) => {
|
|
19836
20357
|
const argumentType = argumentTypes[index];
|
|
19837
20358
|
const argument = args[index];
|
|
19838
20359
|
if (argumentType !== void 0 && argument !== void 0) {
|
|
19839
20360
|
context.expectAssignable(argumentType, parameter, argument.position, `Argument ${index + 1}`);
|
|
19840
20361
|
}
|
|
19841
20362
|
});
|
|
19842
|
-
if (
|
|
19843
|
-
for (let index =
|
|
20363
|
+
if (signature2.isVariadic && signature2.variadicType !== void 0) {
|
|
20364
|
+
for (let index = signature2.parameters.length; index < argumentTypes.length; index += 1) {
|
|
19844
20365
|
const argumentType = argumentTypes[index];
|
|
19845
20366
|
const argument = args[Math.min(index, args.length - 1)];
|
|
19846
20367
|
if (argumentType !== void 0 && argument !== void 0) {
|
|
19847
|
-
context.expectAssignable(argumentType,
|
|
20368
|
+
context.expectAssignable(argumentType, signature2.variadicType, argument.position, `Argument ${index + 1}`);
|
|
19848
20369
|
}
|
|
19849
20370
|
}
|
|
19850
20371
|
}
|
|
19851
|
-
return
|
|
20372
|
+
return signature2.returnType;
|
|
20373
|
+
}
|
|
20374
|
+
function callOwner(expression) {
|
|
20375
|
+
const name = expression.method ?? (expression.callee.kind === "identifier" ? expression.callee.name : null);
|
|
20376
|
+
return name === null ? "This call" : `Function "${name}"`;
|
|
19852
20377
|
}
|
|
19853
20378
|
function checkArguments(context, expression, calleeType) {
|
|
19854
20379
|
if (calleeType.kind !== "function") {
|
|
@@ -19856,7 +20381,7 @@ function checkArguments(context, expression, calleeType) {
|
|
|
19856
20381
|
reportNotCallable(context, expression, calleeType);
|
|
19857
20382
|
return ANY_TYPE;
|
|
19858
20383
|
}
|
|
19859
|
-
return checkSignature(context, expression.args, calleeType, expression.position);
|
|
20384
|
+
return checkSignature(context, expression.args, calleeType, expression.position, callOwner(expression), expression.typeArguments);
|
|
19860
20385
|
}
|
|
19861
20386
|
function isSuperCall(expression) {
|
|
19862
20387
|
return expression.method === null && expression.callee.kind === "identifier" && expression.callee.name === "super";
|
|
@@ -19866,21 +20391,24 @@ function isLegacySuperCall(expression) {
|
|
|
19866
20391
|
}
|
|
19867
20392
|
function checkMethodCall(context, expression, method, receiver) {
|
|
19868
20393
|
if (receiver.kind !== "named") {
|
|
19869
|
-
const
|
|
19870
|
-
if (
|
|
20394
|
+
const signature2 = resolveNonNominalMethod(receiver, method);
|
|
20395
|
+
if (signature2 === null) {
|
|
19871
20396
|
checkValueList(context, expression.args);
|
|
19872
20397
|
return ANY_TYPE;
|
|
19873
20398
|
}
|
|
19874
|
-
return checkSignature(context, expression.args, withoutSelfParameter(
|
|
20399
|
+
return checkSignature(context, expression.args, withoutSelfParameter(signature2), expression.position, callOwner(expression), expression.typeArguments);
|
|
19875
20400
|
}
|
|
19876
20401
|
const declared = memberOf(context, receiver, method);
|
|
19877
20402
|
if (declared?.type.kind === "function") {
|
|
19878
20403
|
if (declared.deprecated === true) {
|
|
19879
20404
|
context.warn("check-deprecated-use", `Member "${method}" is deprecated.`, expression.position);
|
|
19880
20405
|
}
|
|
19881
|
-
return checkSignature(context, expression.args, declared.type, expression.position);
|
|
20406
|
+
return checkSignature(context, expression.args, declared.type, expression.position, callOwner(expression), expression.typeArguments);
|
|
19882
20407
|
}
|
|
19883
20408
|
if (!isMtaElement(context, receiver.name)) {
|
|
20409
|
+
if (declared === null) {
|
|
20410
|
+
reportUnknownMethod(context, receiver, expression.callee, method, expression.position);
|
|
20411
|
+
}
|
|
19884
20412
|
checkValueList(context, expression.args);
|
|
19885
20413
|
return ANY_TYPE;
|
|
19886
20414
|
}
|
|
@@ -19941,8 +20469,8 @@ function checkTable(context, expression) {
|
|
|
19941
20469
|
}
|
|
19942
20470
|
return checkExpression(context, field2.value);
|
|
19943
20471
|
});
|
|
19944
|
-
const
|
|
19945
|
-
if (
|
|
20472
|
+
const isRecord2 = expression.fields.every((field2) => field2.name !== null);
|
|
20473
|
+
if (isRecord2) {
|
|
19946
20474
|
const members = /* @__PURE__ */ new Map();
|
|
19947
20475
|
expression.fields.forEach((field2, index) => {
|
|
19948
20476
|
if (field2.name !== null) {
|
|
@@ -20019,8 +20547,9 @@ function checkMultiValueExpression(context, expression, expected = null) {
|
|
|
20019
20547
|
case "table-expression":
|
|
20020
20548
|
return checkTable(context, expression);
|
|
20021
20549
|
case "function-expression": {
|
|
20022
|
-
const
|
|
20023
|
-
|
|
20550
|
+
const built = buildFunctionType(context, expression.parameters, expression.returnAnnotation, contextualFunction(expected));
|
|
20551
|
+
const type = applyTypeParameters(context, built, expression.typeParameters, expression.typeConstraints);
|
|
20552
|
+
checkFunctionBody(context, expression.parameters, expression.returnAnnotation, expression.body, type, null, expression.position);
|
|
20024
20553
|
return context.record(expression, type);
|
|
20025
20554
|
}
|
|
20026
20555
|
case "binary-expression": {
|
|
@@ -20109,7 +20638,7 @@ function registerMembers(context, info, statement) {
|
|
|
20109
20638
|
}
|
|
20110
20639
|
const generated = expandClassDecorators(context, statement, fieldTypes);
|
|
20111
20640
|
for (const member of [...statement.members, ...generated]) {
|
|
20112
|
-
const type = member.kind === "class-field" ? fieldTypes.get(member) ?? ANY_TYPE : member.isSynthetic ? syntheticMethodType(context, member, fieldTypes) : buildFunctionType(context, member.parameters, member.returnAnnotation);
|
|
20641
|
+
const type = member.kind === "class-field" ? fieldTypes.get(member) ?? ANY_TYPE : member.isSynthetic ? syntheticMethodType(context, member, fieldTypes) : applyTypeParameters(context, buildFunctionType(context, member.parameters, member.returnAnnotation), member.typeParameters, member.typeConstraints);
|
|
20113
20642
|
const decorators = member.decorators.map((decorator) => decorator.name);
|
|
20114
20643
|
if (member.kind === "class-method" && isMetamethodMember(member)) {
|
|
20115
20644
|
checkMetamethod(context, info.name, member, type);
|
|
@@ -20164,18 +20693,22 @@ function checkMethodBody(context, info, member) {
|
|
|
20164
20693
|
if (explicitSelf !== void 0) {
|
|
20165
20694
|
context.report("check-explicit-self-parameter", 'Class methods receive "self" automatically; remove it from the parameter list.', explicitSelf.position);
|
|
20166
20695
|
}
|
|
20167
|
-
const
|
|
20168
|
-
if (
|
|
20696
|
+
const signature2 = (member.isStatic ? info.statics : info.members).get(member.name)?.type;
|
|
20697
|
+
if (signature2?.kind !== "function") {
|
|
20169
20698
|
return;
|
|
20170
20699
|
}
|
|
20171
20700
|
if (member.isStatic) {
|
|
20172
|
-
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body,
|
|
20701
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, null, member.position);
|
|
20173
20702
|
return;
|
|
20174
20703
|
}
|
|
20175
20704
|
context.pushClassMethod({ className: info.name, methodName: member.name });
|
|
20176
|
-
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body,
|
|
20705
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, selfType(info), member.position);
|
|
20177
20706
|
context.popClassMethod();
|
|
20178
20707
|
}
|
|
20708
|
+
function assignSuperClass(context, info, statement) {
|
|
20709
|
+
info.superClass = resolveSuperClass(context, statement);
|
|
20710
|
+
info.hasUnresolvedParent = statement.superClass !== null && info.superClass === null;
|
|
20711
|
+
}
|
|
20179
20712
|
function resolveSuperClass(context, statement) {
|
|
20180
20713
|
if (statement.superClass === null) {
|
|
20181
20714
|
return null;
|
|
@@ -20230,7 +20763,7 @@ function declareLocalClass(context, statement) {
|
|
|
20230
20763
|
if (info === null) {
|
|
20231
20764
|
return null;
|
|
20232
20765
|
}
|
|
20233
|
-
|
|
20766
|
+
assignSuperClass(context, info, statement);
|
|
20234
20767
|
resolveClassHeader(context, info, statement);
|
|
20235
20768
|
return info;
|
|
20236
20769
|
}
|
|
@@ -20344,7 +20877,7 @@ function breakCycle(context, info) {
|
|
|
20344
20877
|
function predeclareModule(context, body) {
|
|
20345
20878
|
const declared = declareHeaders(context, body);
|
|
20346
20879
|
for (const entry of declared) {
|
|
20347
|
-
entry.info
|
|
20880
|
+
assignSuperClass(context, entry.info, entry.statement);
|
|
20348
20881
|
resolveClassHeader(context, entry.info, entry.statement);
|
|
20349
20882
|
}
|
|
20350
20883
|
for (const entry of declared) {
|
|
@@ -20521,9 +21054,9 @@ function finalizeEmission(code, markers, sourceLineOffset = 0) {
|
|
|
20521
21054
|
continue;
|
|
20522
21055
|
}
|
|
20523
21056
|
const marker = markers[Number(match[1])];
|
|
20524
|
-
const
|
|
21057
|
+
const emitted2 = line2.replace(pattern, "");
|
|
20525
21058
|
if (marker === void 0) {
|
|
20526
|
-
output.push(
|
|
21059
|
+
output.push(emitted2);
|
|
20527
21060
|
continue;
|
|
20528
21061
|
}
|
|
20529
21062
|
while (output.length + 1 < marker.sourceLine - sourceLineOffset) {
|
|
@@ -20533,7 +21066,7 @@ function finalizeEmission(code, markers, sourceLineOffset = 0) {
|
|
|
20533
21066
|
if (marker.symbol !== void 0) {
|
|
20534
21067
|
mapping.symbol = marker.symbol;
|
|
20535
21068
|
}
|
|
20536
|
-
output.push(
|
|
21069
|
+
output.push(emitted2);
|
|
20537
21070
|
const sameSegment = previous !== null && previous.symbol === mapping.symbol && previous.sourceLine - previous.generatedLine === mapping.sourceLine - mapping.generatedLine;
|
|
20538
21071
|
if (!sameSegment) {
|
|
20539
21072
|
mappings.push(mapping);
|
|
@@ -20674,10 +21207,10 @@ function emitFunctionBody(state, parameters, body, header) {
|
|
|
20674
21207
|
const lines = emitBlock(state, body);
|
|
20675
21208
|
state.loopWrap = previous;
|
|
20676
21209
|
state.indent -= 1;
|
|
20677
|
-
const
|
|
21210
|
+
const signature2 = `${header}(${emitParameters(parameters)})`;
|
|
20678
21211
|
const closing = indentLine(state, "end");
|
|
20679
|
-
return lines.length === 0 ? `${
|
|
20680
|
-
${closing}` : `${
|
|
21212
|
+
return lines.length === 0 ? `${signature2}
|
|
21213
|
+
${closing}` : `${signature2}
|
|
20681
21214
|
${lines.join("\n")}
|
|
20682
21215
|
${closing}`;
|
|
20683
21216
|
}
|
|
@@ -21371,8 +21904,8 @@ function erasedEdit(source, span) {
|
|
|
21371
21904
|
}
|
|
21372
21905
|
function canonicalEdit(input, statement, span) {
|
|
21373
21906
|
const { source } = input;
|
|
21374
|
-
const
|
|
21375
|
-
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;
|
|
21376
21909
|
if (trimmed.length === 0) {
|
|
21377
21910
|
return erasedEdit(source, span);
|
|
21378
21911
|
}
|
|
@@ -21383,7 +21916,7 @@ function canonicalEdit(input, statement, span) {
|
|
|
21383
21916
|
return null;
|
|
21384
21917
|
}
|
|
21385
21918
|
const padded = missing2 > 0 && source.slice(span.end).trim().length > 0 ? `${replacement}${"\n".repeat(missing2)}` : replacement;
|
|
21386
|
-
return { start: span.start, end: span.end, replacement: padded, lines:
|
|
21919
|
+
return { start: span.start, end: span.end, replacement: padded, lines: emitted2.lines };
|
|
21387
21920
|
}
|
|
21388
21921
|
|
|
21389
21922
|
// ../compiler/src/emitter/preserve-decorators.ts
|
|
@@ -21856,7 +22389,7 @@ function compile(source, options = {}) {
|
|
|
21856
22389
|
const settings = options.compilerOptions ?? DEFAULT_COMPILER_OPTIONS;
|
|
21857
22390
|
const parsed = parse(source);
|
|
21858
22391
|
const mode = resolveStrictMode(parsed.directives, settings.strict);
|
|
21859
|
-
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);
|
|
21860
22393
|
const environment = resolved2.environment;
|
|
21861
22394
|
const isDeclarationFile = options.filePath !== void 0 && isDeclarationPath(options.filePath);
|
|
21862
22395
|
const checked = check(parsed.program, mode, environment, {
|
|
@@ -21886,7 +22419,7 @@ function compile(source, options = {}) {
|
|
|
21886
22419
|
return { ...shared, code: null, requiredHelpers: [], lines: [] };
|
|
21887
22420
|
}
|
|
21888
22421
|
const references = reachedNames(checked.references, options.projectReferences);
|
|
21889
|
-
const
|
|
22422
|
+
const emitted2 = emit2(parsed.program, checked.types, references, checked.generatedMembers, 0, checked.staticAccess);
|
|
21890
22423
|
const preserved = emitPreservingSource({
|
|
21891
22424
|
source,
|
|
21892
22425
|
program: parsed.program,
|
|
@@ -21899,7 +22432,7 @@ function compile(source, options = {}) {
|
|
|
21899
22432
|
staticAccess: checked.staticAccess,
|
|
21900
22433
|
development: options.development === true
|
|
21901
22434
|
});
|
|
21902
|
-
const required = new Set(
|
|
22435
|
+
const required = new Set(emitted2.requiredHelpers);
|
|
21903
22436
|
for (const name of checked.references) {
|
|
21904
22437
|
const helper = checked.declaredGlobals.has(name) ? null : helperForGlobal(name);
|
|
21905
22438
|
if (helper !== null) {
|
|
@@ -21908,9 +22441,9 @@ function compile(source, options = {}) {
|
|
|
21908
22441
|
}
|
|
21909
22442
|
return {
|
|
21910
22443
|
...shared,
|
|
21911
|
-
code: preserved?.code ??
|
|
22444
|
+
code: preserved?.code ?? emitted2.code,
|
|
21912
22445
|
requiredHelpers: expandHelpers(required).sort(),
|
|
21913
|
-
lines: preserved?.lines ??
|
|
22446
|
+
lines: preserved?.lines ?? emitted2.lines
|
|
21914
22447
|
};
|
|
21915
22448
|
}
|
|
21916
22449
|
|
|
@@ -22127,11 +22660,20 @@ function baseKey(context) {
|
|
|
22127
22660
|
const contracts = context.contracts.map((contract) => serializeAbi(contract)).join(";");
|
|
22128
22661
|
return `${optionsKey(context.options)}|${mode}|${JSON.stringify(context.project.globals)}|${[...context.references].sort().join(",")}|${hashString(contracts)}`;
|
|
22129
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];
|
|
22130
22670
|
function environmentKeys(collected) {
|
|
22131
|
-
const keys =
|
|
22671
|
+
const keys = /* @__PURE__ */ new Map();
|
|
22132
22672
|
for (const environment of ALL_ENVIRONMENTS) {
|
|
22133
|
-
const
|
|
22134
|
-
|
|
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
|
+
}
|
|
22135
22677
|
}
|
|
22136
22678
|
return keys;
|
|
22137
22679
|
}
|
|
@@ -22139,15 +22681,19 @@ function createResolver(collected) {
|
|
|
22139
22681
|
const visible = /* @__PURE__ */ new Map();
|
|
22140
22682
|
const merged = /* @__PURE__ */ new Map();
|
|
22141
22683
|
for (const environment of ALL_ENVIRONMENTS) {
|
|
22142
|
-
|
|
22143
|
-
|
|
22144
|
-
|
|
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
|
+
}
|
|
22145
22690
|
}
|
|
22146
22691
|
return (entry) => {
|
|
22692
|
+
const key = scopeKey(entry.environment, entry.isLibrary);
|
|
22147
22693
|
if (declaresNothing(entry.declarations)) {
|
|
22148
|
-
return merged.get(
|
|
22694
|
+
return merged.get(key) ?? EMPTY_AMBIENT;
|
|
22149
22695
|
}
|
|
22150
|
-
const entries3 = visible.get(
|
|
22696
|
+
const entries3 = visible.get(key) ?? [];
|
|
22151
22697
|
return mergeAmbient(entries3.filter((candidate) => candidate.path !== entry.path).map((candidate) => candidate.declarations));
|
|
22152
22698
|
};
|
|
22153
22699
|
}
|
|
@@ -22157,7 +22703,7 @@ function createAmbientScope(collected, context) {
|
|
|
22157
22703
|
const fallback = environmentKeys(collected);
|
|
22158
22704
|
return {
|
|
22159
22705
|
graph,
|
|
22160
|
-
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)) ?? ""}`),
|
|
22161
22707
|
resolve: createResolver(collected)
|
|
22162
22708
|
};
|
|
22163
22709
|
}
|
|
@@ -22202,13 +22748,96 @@ function validateContributions(modules) {
|
|
|
22202
22748
|
}
|
|
22203
22749
|
return diagnostics;
|
|
22204
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
|
+
}
|
|
22205
22826
|
function validateModuleReferences(modules) {
|
|
22206
22827
|
const symbols = buildSymbolTable(modules);
|
|
22828
|
+
const libraries = new Set(modules.filter((module) => module.origin !== null).map((module) => module.path));
|
|
22207
22829
|
const diagnostics = [];
|
|
22208
22830
|
for (const module of modules) {
|
|
22209
22831
|
for (const [name, position2] of module.externalReferences) {
|
|
22210
22832
|
const symbol = symbols.get(name);
|
|
22211
|
-
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)) {
|
|
22212
22841
|
continue;
|
|
22213
22842
|
}
|
|
22214
22843
|
diagnostics.push(referenceDiagnostic(module, symbol, position2));
|
|
@@ -22225,6 +22854,7 @@ function compileModule(file, ambient, context) {
|
|
|
22225
22854
|
const result = compile(file.source, {
|
|
22226
22855
|
filePath: file.path,
|
|
22227
22856
|
...file.environment === void 0 ? {} : { environment: file.environment },
|
|
22857
|
+
environmentLocked: file.origin !== void 0,
|
|
22228
22858
|
ambient,
|
|
22229
22859
|
contracts: context.contracts,
|
|
22230
22860
|
project: isTestPath(file.path) ? context.testProject : context.project,
|
|
@@ -22234,6 +22864,7 @@ function compileModule(file, ambient, context) {
|
|
|
22234
22864
|
});
|
|
22235
22865
|
return {
|
|
22236
22866
|
path: file.path,
|
|
22867
|
+
origin: file.origin ?? null,
|
|
22237
22868
|
environment: result.environment,
|
|
22238
22869
|
isDeclaration: isDeclarationPath(file.path),
|
|
22239
22870
|
code: result.code,
|
|
@@ -22263,7 +22894,7 @@ function createProjectCache() {
|
|
|
22263
22894
|
const declarationCache = /* @__PURE__ */ new Map();
|
|
22264
22895
|
const moduleCache = /* @__PURE__ */ new Map();
|
|
22265
22896
|
function declarationsFor(file, options, reused) {
|
|
22266
|
-
const hash = hashString(`${file.environment ?? ""}|${optionsKey(options)}|${file.source}`);
|
|
22897
|
+
const hash = hashString(`${file.environment ?? ""}|${file.origin?.root ?? ""}|${optionsKey(options)}|${file.source}`);
|
|
22267
22898
|
const cached = declarationCache.get(file.path);
|
|
22268
22899
|
if (cached !== void 0 && cached.hash === hash) {
|
|
22269
22900
|
reused.count += 1;
|
|
@@ -22272,11 +22903,13 @@ function createProjectCache() {
|
|
|
22272
22903
|
const result = compile(file.source, {
|
|
22273
22904
|
filePath: file.path,
|
|
22274
22905
|
...file.environment === void 0 ? {} : { environment: file.environment },
|
|
22906
|
+
environmentLocked: file.origin !== void 0,
|
|
22275
22907
|
compilerOptions: options,
|
|
22276
22908
|
emitCode: false
|
|
22277
22909
|
});
|
|
22278
22910
|
const entry = {
|
|
22279
22911
|
path: file.path,
|
|
22912
|
+
isLibrary: file.origin !== void 0,
|
|
22280
22913
|
hash,
|
|
22281
22914
|
environment: result.environment,
|
|
22282
22915
|
declarations: result.declarations,
|
|
@@ -22327,7 +22960,8 @@ function createProjectCache() {
|
|
|
22327
22960
|
});
|
|
22328
22961
|
const references = validateModuleReferences(modules);
|
|
22329
22962
|
const contributions = validateContributions(modules);
|
|
22330
|
-
const
|
|
22963
|
+
const libraries = [...validateLibraryGlobals(modules), ...validateLibraryApiShadowing(modules)];
|
|
22964
|
+
const collectedDiagnostics = sortFileDiagnostics([...flattenDiagnostics(modules), ...references, ...contributions, ...libraries]);
|
|
22331
22965
|
const diagnostics = compilerOptions.warningsAsErrors ? promoteWarnings(collectedDiagnostics) : collectedDiagnostics;
|
|
22332
22966
|
const paths = new Set(files.map((file) => file.path));
|
|
22333
22967
|
prune(declarationCache, paths);
|
|
@@ -22355,7 +22989,7 @@ function helperList(config, inputs) {
|
|
|
22355
22989
|
const helpers = [...config.helpers, "env"];
|
|
22356
22990
|
return helpers.sort();
|
|
22357
22991
|
}
|
|
22358
|
-
function resourceOptions(config, inputs, minMtaVersion, developmentLogs, layout) {
|
|
22992
|
+
function resourceOptions(config, inputs, minMtaVersion, developmentLogs, layout, libraryFiles) {
|
|
22359
22993
|
const options = {
|
|
22360
22994
|
oop: config.compilerOptions.oop,
|
|
22361
22995
|
dependencies: config.dependencies,
|
|
@@ -22364,6 +22998,7 @@ function resourceOptions(config, inputs, minMtaVersion, developmentLogs, layout)
|
|
|
22364
22998
|
configuration: inputs.configuration,
|
|
22365
22999
|
environmentFile: config.environment.file,
|
|
22366
23000
|
loadOrder: config.loadOrder,
|
|
23001
|
+
libraryFiles,
|
|
22367
23002
|
minMtaVersion,
|
|
22368
23003
|
developmentLogs,
|
|
22369
23004
|
layout,
|
|
@@ -22406,9 +23041,11 @@ function runCompile(root, config, options = {}) {
|
|
|
22406
23041
|
const excluded = [config.outDir, config.contracts];
|
|
22407
23042
|
const sources = discoverSources(root, config.sources, excluded);
|
|
22408
23043
|
const inputs = readProjectInputs(root, { assets: config.assets, environment: config.environment, excluded });
|
|
22409
|
-
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];
|
|
22410
23047
|
const contracts = readDependencyContracts(root, config);
|
|
22411
|
-
const diagnostics = [...sources.diagnostics, ...inputs.diagnostics, ...contracts.diagnostics];
|
|
23048
|
+
const diagnostics = [...sources.diagnostics, ...inputs.diagnostics, ...libraries.diagnostics, ...contracts.diagnostics];
|
|
22412
23049
|
if (hasCliErrors(diagnostics)) {
|
|
22413
23050
|
tracker.end("failed");
|
|
22414
23051
|
return {
|
|
@@ -22437,7 +23074,7 @@ function runCompile(root, config, options = {}) {
|
|
|
22437
23074
|
tracker.begin("assembly");
|
|
22438
23075
|
const assembly = assembleResource(
|
|
22439
23076
|
project,
|
|
22440
|
-
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),
|
|
22441
23078
|
(step) => {
|
|
22442
23079
|
if (step === "assembly") {
|
|
22443
23080
|
tracker.begin("manifest");
|
|
@@ -22462,8 +23099,8 @@ function runCompile(root, config, options = {}) {
|
|
|
22462
23099
|
}
|
|
22463
23100
|
|
|
22464
23101
|
// src/build/resource-map-file.ts
|
|
22465
|
-
import { existsSync as
|
|
22466
|
-
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";
|
|
22467
23104
|
var RESOURCE_MAP_SUFFIX = ".luam-map.json";
|
|
22468
23105
|
function isObject(value) {
|
|
22469
23106
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -22528,28 +23165,28 @@ function reason(error) {
|
|
|
22528
23165
|
return error instanceof Error ? error.message : String(error);
|
|
22529
23166
|
}
|
|
22530
23167
|
function resourceMapPath(root, config) {
|
|
22531
|
-
return
|
|
23168
|
+
return resolve10(root, config.outDir, `${config.name}${RESOURCE_MAP_SUFFIX}`);
|
|
22532
23169
|
}
|
|
22533
23170
|
function explicitResourceMapPath(root, path) {
|
|
22534
|
-
return isAbsolute3(path) ? path :
|
|
23171
|
+
return isAbsolute3(path) ? path : resolve10(root, path);
|
|
22535
23172
|
}
|
|
22536
23173
|
function writeResourceMap(root, config, map) {
|
|
22537
23174
|
const path = resourceMapPath(root, config);
|
|
22538
23175
|
if (map === null) {
|
|
22539
|
-
if (
|
|
23176
|
+
if (existsSync6(path)) {
|
|
22540
23177
|
unlinkSync(path);
|
|
22541
23178
|
}
|
|
22542
23179
|
return;
|
|
22543
23180
|
}
|
|
22544
23181
|
mkdirSync3(dirname3(path), { recursive: true });
|
|
22545
23182
|
const content = serializeResourceMap(map);
|
|
22546
|
-
if (!
|
|
23183
|
+
if (!existsSync6(path) || readFileSync8(path, "utf8") !== content) {
|
|
22547
23184
|
writeFileSync4(path, content, "utf8");
|
|
22548
23185
|
}
|
|
22549
23186
|
}
|
|
22550
23187
|
function readResourceMap(path) {
|
|
22551
23188
|
try {
|
|
22552
|
-
const value = JSON.parse(
|
|
23189
|
+
const value = JSON.parse(readFileSync8(path, "utf8"));
|
|
22553
23190
|
if (isObject(value) && Number.isInteger(value.version) && value.version !== RESOURCE_MAP_VERSION) {
|
|
22554
23191
|
return { map: null, error: `Resource map version ${String(value.version)} is not supported.` };
|
|
22555
23192
|
}
|
|
@@ -22583,7 +23220,7 @@ function collectResourceMaps(directory, found) {
|
|
|
22583
23220
|
}
|
|
22584
23221
|
}
|
|
22585
23222
|
function discoverResourceMap(root) {
|
|
22586
|
-
if (!
|
|
23223
|
+
if (!existsSync6(root)) {
|
|
22587
23224
|
return { path: null, candidates: [] };
|
|
22588
23225
|
}
|
|
22589
23226
|
const found = [];
|
|
@@ -22593,8 +23230,8 @@ function discoverResourceMap(root) {
|
|
|
22593
23230
|
}
|
|
22594
23231
|
|
|
22595
23232
|
// src/build/resource-writer.ts
|
|
22596
|
-
import { existsSync as
|
|
22597
|
-
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";
|
|
22598
23235
|
|
|
22599
23236
|
// src/build/lua-tokens.ts
|
|
22600
23237
|
var WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\r", "\v", "\f"]);
|
|
@@ -22797,8 +23434,8 @@ function minifyLuaFiles(files) {
|
|
|
22797
23434
|
}
|
|
22798
23435
|
|
|
22799
23436
|
// src/build/resource-prune.ts
|
|
22800
|
-
import { existsSync as
|
|
22801
|
-
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";
|
|
22802
23439
|
var GENERATED_MANIFEST = "meta.xml";
|
|
22803
23440
|
var GENERATED_EXTENSION = ".lua";
|
|
22804
23441
|
var PROTECTED = /* @__PURE__ */ new Set([ENVIRONMENT_FILE, ".env.local"]);
|
|
@@ -22815,17 +23452,17 @@ function isGenerated(relativePath2, options) {
|
|
|
22815
23452
|
return options.generatedRoots.some((root) => isUnderRoot(relativePath2, root));
|
|
22816
23453
|
}
|
|
22817
23454
|
function removeEmptyDirectories(targetDir, directory) {
|
|
22818
|
-
if (
|
|
23455
|
+
if (resolve11(directory) === resolve11(targetDir)) {
|
|
22819
23456
|
return;
|
|
22820
23457
|
}
|
|
22821
23458
|
if (readdirSync3(directory).length > 0) {
|
|
22822
23459
|
return;
|
|
22823
23460
|
}
|
|
22824
23461
|
rmdirSync(directory);
|
|
22825
|
-
removeEmptyDirectories(targetDir,
|
|
23462
|
+
removeEmptyDirectories(targetDir, resolve11(directory, ".."));
|
|
22826
23463
|
}
|
|
22827
23464
|
function pruneResource(targetDir, keep, options) {
|
|
22828
|
-
if (!
|
|
23465
|
+
if (!existsSync7(targetDir)) {
|
|
22829
23466
|
return [];
|
|
22830
23467
|
}
|
|
22831
23468
|
const removed = [];
|
|
@@ -22875,7 +23512,7 @@ function resourceFiles(build) {
|
|
|
22875
23512
|
return files;
|
|
22876
23513
|
}
|
|
22877
23514
|
function resolveInside(targetDir, path) {
|
|
22878
|
-
const absolute =
|
|
23515
|
+
const absolute = resolve12(targetDir, path);
|
|
22879
23516
|
const inside = relative4(targetDir, absolute);
|
|
22880
23517
|
if (inside.startsWith("..") || isAbsolute4(inside)) {
|
|
22881
23518
|
throw new Error(`The generated file "${path}" resolves outside the resource directory "${targetDir}".`);
|
|
@@ -22883,7 +23520,7 @@ function resolveInside(targetDir, path) {
|
|
|
22883
23520
|
return absolute;
|
|
22884
23521
|
}
|
|
22885
23522
|
function writeIfChanged(absolute, content) {
|
|
22886
|
-
if (
|
|
23523
|
+
if (existsSync8(absolute) && readFileSync9(absolute).equals(content)) {
|
|
22887
23524
|
return false;
|
|
22888
23525
|
}
|
|
22889
23526
|
mkdirSync4(dirname4(absolute), { recursive: true });
|
|
@@ -22895,7 +23532,7 @@ function writeEnvironmentFile(targetDir, template) {
|
|
|
22895
23532
|
return false;
|
|
22896
23533
|
}
|
|
22897
23534
|
const absolute = resolveInside(targetDir, ENVIRONMENT_FILE);
|
|
22898
|
-
if (
|
|
23535
|
+
if (existsSync8(absolute)) {
|
|
22899
23536
|
return false;
|
|
22900
23537
|
}
|
|
22901
23538
|
mkdirSync4(dirname4(absolute), { recursive: true });
|
|
@@ -22923,7 +23560,7 @@ function writeResource(targetDir, build, options) {
|
|
|
22923
23560
|
advance(path);
|
|
22924
23561
|
}
|
|
22925
23562
|
for (const asset of build.assets) {
|
|
22926
|
-
if (writeIfChanged(resolveInside(targetDir, asset.path),
|
|
23563
|
+
if (writeIfChanged(resolveInside(targetDir, asset.path), readFileSync9(resolve12(options.root, asset.source)))) {
|
|
22927
23564
|
written.push(asset.path);
|
|
22928
23565
|
advance(asset.path);
|
|
22929
23566
|
continue;
|
|
@@ -22953,7 +23590,7 @@ function destinationRoot(mapping) {
|
|
|
22953
23590
|
}
|
|
22954
23591
|
function generatedRoots(config) {
|
|
22955
23592
|
const roots = config.assets.map(destinationRoot).filter((root) => root.length > 0);
|
|
22956
|
-
return [.../* @__PURE__ */ new Set([...roots, LIBRARY_DIRECTORY])];
|
|
23593
|
+
return [.../* @__PURE__ */ new Set([...roots, LIBRARY_DIRECTORY, LIBRARIES_DIRECTORY])];
|
|
22957
23594
|
}
|
|
22958
23595
|
function trackedWriteOptions(root, config, environmentTemplate, tracker) {
|
|
22959
23596
|
return {
|
|
@@ -23040,16 +23677,16 @@ function reportBuildOutcome(context, outcome, action) {
|
|
|
23040
23677
|
}
|
|
23041
23678
|
|
|
23042
23679
|
// src/commands/resource-targets.ts
|
|
23043
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
23680
|
+
import { isAbsolute as isAbsolute5, resolve as resolve13 } from "node:path";
|
|
23044
23681
|
function resolveBuildTarget(root, config) {
|
|
23045
|
-
return
|
|
23682
|
+
return resolve13(root, config.outDir, config.name);
|
|
23046
23683
|
}
|
|
23047
23684
|
function resolveServerTarget(root, config) {
|
|
23048
23685
|
if (config.serverPath === null) {
|
|
23049
23686
|
return null;
|
|
23050
23687
|
}
|
|
23051
|
-
const serverRoot = isAbsolute5(config.serverPath) ? config.serverPath :
|
|
23052
|
-
return
|
|
23688
|
+
const serverRoot = isAbsolute5(config.serverPath) ? config.serverPath : resolve13(root, config.serverPath);
|
|
23689
|
+
return resolve13(serverRoot, config.resourcesDir, config.name);
|
|
23053
23690
|
}
|
|
23054
23691
|
|
|
23055
23692
|
// src/reporting/progress-renderer.ts
|
|
@@ -23094,7 +23731,7 @@ function createProgressRenderer(reporter, options = {}) {
|
|
|
23094
23731
|
paint(reporter.style.eraseLine());
|
|
23095
23732
|
dirty = false;
|
|
23096
23733
|
}
|
|
23097
|
-
function
|
|
23734
|
+
function render3(event) {
|
|
23098
23735
|
const columns = Math.max(20, reporter.capability.columns - 1);
|
|
23099
23736
|
const line2 = activeLine(reporter, event);
|
|
23100
23737
|
paint(`${reporter.style.eraseLine()}${line2.slice(0, columns)}`);
|
|
@@ -23114,7 +23751,7 @@ function createProgressRenderer(reporter, options = {}) {
|
|
|
23114
23751
|
if (frames > 0 && now() - lastPaintAt < throttleMs) {
|
|
23115
23752
|
return;
|
|
23116
23753
|
}
|
|
23117
|
-
|
|
23754
|
+
render3(event);
|
|
23118
23755
|
}
|
|
23119
23756
|
return {
|
|
23120
23757
|
listen: (event) => {
|
|
@@ -23157,6 +23794,7 @@ async function runBuildCommand(context, options = {}) {
|
|
|
23157
23794
|
if (outcome.build === null) {
|
|
23158
23795
|
reportBuildOutcome(context, outcome, "Build");
|
|
23159
23796
|
reportPhaseTimings(reporter, tracker.durations(), totalDuration(tracker.durations()));
|
|
23797
|
+
options.onOutcome?.(outcome);
|
|
23160
23798
|
return EXIT_DIAGNOSTICS;
|
|
23161
23799
|
}
|
|
23162
23800
|
const target = resolveBuildTarget(context.root, context.config);
|
|
@@ -23169,6 +23807,7 @@ async function runBuildCommand(context, options = {}) {
|
|
|
23169
23807
|
tracker.end("failed");
|
|
23170
23808
|
renderer.clear();
|
|
23171
23809
|
reporter.error(`Build wrote nothing to "${target}". ${error instanceof Error ? error.message : String(error)}`);
|
|
23810
|
+
options.onOutcome?.(outcome);
|
|
23172
23811
|
return EXIT_DIAGNOSTICS;
|
|
23173
23812
|
}
|
|
23174
23813
|
writeResourceMap(context.root, context.config, writtenMap(outcome.map, minify));
|
|
@@ -23181,13 +23820,93 @@ async function runBuildCommand(context, options = {}) {
|
|
|
23181
23820
|
const counts = `${result.unchanged} unchanged, ${result.removed.length} removed`;
|
|
23182
23821
|
reporter.info(`Wrote ${pluralize(result.written.length, "file")} to "${target}" (${counts}).`);
|
|
23183
23822
|
reportPhaseTimings(reporter, tracker.durations(), totalDuration(tracker.durations()));
|
|
23823
|
+
options.onOutcome?.(outcome);
|
|
23184
23824
|
return EXIT_OK;
|
|
23185
23825
|
}
|
|
23186
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
|
+
|
|
23187
23906
|
// src/cli/registry/build-registration.ts
|
|
23188
23907
|
function registerBuildCommand(program2, runtime) {
|
|
23189
23908
|
const command = program2.command("build").description("Compile the project and write the resource to the output directory.");
|
|
23190
|
-
addMinifyOptions(addLayoutOptions(addProjectOptions(command))).addOption(noMapOption()).addOption(offlineOption());
|
|
23909
|
+
addMinifyOptions(addLayoutOptions(addProjectOptions(command))).addOption(noMapOption()).addOption(offlineOption()).addOption(jsonOption());
|
|
23191
23910
|
command.action(async (options) => {
|
|
23192
23911
|
const project = createProjectContext(runtime, "build", options);
|
|
23193
23912
|
if (project.context === null) {
|
|
@@ -23195,39 +23914,236 @@ function registerBuildCommand(program2, runtime) {
|
|
|
23195
23914
|
return;
|
|
23196
23915
|
}
|
|
23197
23916
|
const bundled = options.bundle ?? project.context.config.output.bundle;
|
|
23198
|
-
|
|
23917
|
+
const build = {
|
|
23199
23918
|
layout: bundled ? "bundle" : "tree",
|
|
23200
23919
|
map: options.map && project.context.config.output.map,
|
|
23201
23920
|
minify: options.minify ?? project.context.config.output.minify
|
|
23202
|
-
}
|
|
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 }));
|
|
23203
23928
|
});
|
|
23204
23929
|
}
|
|
23205
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);
|
|
23958
|
+
});
|
|
23959
|
+
}
|
|
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
|
+
|
|
23206
24041
|
// src/commands/check-command.ts
|
|
23207
|
-
function runCheckCommand(context) {
|
|
24042
|
+
function runCheckCommand(context, options = {}) {
|
|
23208
24043
|
const reporter = commandReporter(context);
|
|
23209
24044
|
const renderer = createProgressRenderer(reporter);
|
|
23210
24045
|
const tracker = createPhaseTracker(renderer.listen);
|
|
23211
|
-
const
|
|
24046
|
+
const cache3 = options.cache;
|
|
24047
|
+
const outcome = runCompile(context.root, context.config, cache3 === void 0 ? { tracker } : { tracker, cache: cache3 });
|
|
23212
24048
|
renderer.clear();
|
|
23213
24049
|
const passed = reportBuildOutcome(context, outcome, "Check");
|
|
23214
24050
|
reportPhaseTimings(reporter, tracker.durations(), totalDuration(tracker.durations()));
|
|
24051
|
+
options.onOutcome?.(outcome);
|
|
23215
24052
|
return passed ? EXIT_OK : EXIT_DIAGNOSTICS;
|
|
23216
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
|
+
}
|
|
23217
24105
|
|
|
23218
24106
|
// src/cli/registry/check-registration.ts
|
|
23219
24107
|
function registerCheckCommand(program2, runtime) {
|
|
23220
24108
|
const command = program2.command("check").description("Compile the project and report diagnostics without writing files.");
|
|
23221
|
-
addProjectOptions(command);
|
|
23222
|
-
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
|
+
}
|
|
23223
24116
|
const project = createProjectContext(runtime, "check", options);
|
|
23224
|
-
|
|
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 });
|
|
23225
24141
|
});
|
|
23226
24142
|
}
|
|
23227
24143
|
|
|
23228
24144
|
// src/commands/config-command.ts
|
|
23229
|
-
import { existsSync as
|
|
23230
|
-
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";
|
|
23231
24147
|
|
|
23232
24148
|
// ../compiler/src/project/config-reader.ts
|
|
23233
24149
|
var Reader = class {
|
|
@@ -23441,33 +24357,33 @@ function isGeneratedDeclaration(text) {
|
|
|
23441
24357
|
var DEFAULT_CONFIG_SOURCE = "config.lua";
|
|
23442
24358
|
var DEFAULT_CONFIG_OUTPUT = "config.d.luam";
|
|
23443
24359
|
function escapes(root, path) {
|
|
23444
|
-
const inside =
|
|
23445
|
-
return inside.startsWith("..") ||
|
|
24360
|
+
const inside = relative6(root, path);
|
|
24361
|
+
return inside.startsWith("..") || resolve15(root, inside) !== path;
|
|
23446
24362
|
}
|
|
23447
24363
|
function readSource2(root, source, reporter) {
|
|
23448
|
-
const path =
|
|
24364
|
+
const path = resolve15(root, source);
|
|
23449
24365
|
if (escapes(root, path)) {
|
|
23450
24366
|
reporter.error(`Config declarations read only inside the project, but "${source}" points outside it.`);
|
|
23451
24367
|
return null;
|
|
23452
24368
|
}
|
|
23453
|
-
if (!
|
|
24369
|
+
if (!existsSync11(path)) {
|
|
23454
24370
|
reporter.error(`Config declarations found no file at "${source}".`);
|
|
23455
24371
|
return null;
|
|
23456
24372
|
}
|
|
23457
24373
|
try {
|
|
23458
|
-
return
|
|
24374
|
+
return readFileSync10(path, "utf8");
|
|
23459
24375
|
} catch {
|
|
23460
24376
|
reporter.error(`Config declarations could not read "${source}".`);
|
|
23461
24377
|
return null;
|
|
23462
24378
|
}
|
|
23463
24379
|
}
|
|
23464
24380
|
function writable(root, out, reporter) {
|
|
23465
|
-
const path =
|
|
24381
|
+
const path = resolve15(root, out);
|
|
23466
24382
|
if (escapes(root, path)) {
|
|
23467
24383
|
reporter.error(`Config declarations write only inside the project, but "${out}" points outside it.`);
|
|
23468
24384
|
return null;
|
|
23469
24385
|
}
|
|
23470
|
-
if (
|
|
24386
|
+
if (existsSync11(path) && !isGeneratedDeclaration(readFileSync10(path, "utf8"))) {
|
|
23471
24387
|
reporter.error(`"${out}" was not generated by this command and was left alone. Choose another path with --out.`);
|
|
23472
24388
|
return null;
|
|
23473
24389
|
}
|
|
@@ -23600,85 +24516,7 @@ function createEnsureRunner(context, options = {}) {
|
|
|
23600
24516
|
};
|
|
23601
24517
|
}
|
|
23602
24518
|
|
|
23603
|
-
// src/reporting/rebuild-separator.ts
|
|
23604
|
-
var RULE_WIDTH = 40;
|
|
23605
|
-
function formatTimestamp(at) {
|
|
23606
|
-
return at.toISOString().slice(11, 19);
|
|
23607
|
-
}
|
|
23608
|
-
function reportRebuildSeparator(reporter, at = /* @__PURE__ */ new Date()) {
|
|
23609
|
-
const rule = (reporter.capability.unicode ? "\u2500" : "-").repeat(RULE_WIDTH);
|
|
23610
|
-
reporter.raw("");
|
|
23611
|
-
reporter.detail(`${rule} rebuild at ${formatTimestamp(at)}`);
|
|
23612
|
-
}
|
|
23613
|
-
|
|
23614
|
-
// src/watch/source-watcher.ts
|
|
23615
|
-
import { existsSync as existsSync9, watch } from "node:fs";
|
|
23616
|
-
import { relative as relative6, resolve as resolve14 } from "node:path";
|
|
23617
|
-
var DEFAULT_DEBOUNCE_MS = 120;
|
|
23618
|
-
function watchSources(root, sources, onChange, debounceMs = DEFAULT_DEBOUNCE_MS) {
|
|
23619
|
-
const resolver = createSourceResolver(sources);
|
|
23620
|
-
const watchers = [];
|
|
23621
|
-
let timer = null;
|
|
23622
|
-
const schedule = () => {
|
|
23623
|
-
if (timer !== null) {
|
|
23624
|
-
clearTimeout(timer);
|
|
23625
|
-
}
|
|
23626
|
-
timer = setTimeout(() => {
|
|
23627
|
-
timer = null;
|
|
23628
|
-
onChange();
|
|
23629
|
-
}, debounceMs);
|
|
23630
|
-
};
|
|
23631
|
-
const isWatched = (directory, filename) => {
|
|
23632
|
-
const path = normalizePattern(relative6(root, resolve14(directory, filename)));
|
|
23633
|
-
return path.endsWith(SOURCE_EXTENSION) && resolver.resolve(path).matches.length > 0;
|
|
23634
|
-
};
|
|
23635
|
-
for (const entry of resolver.roots) {
|
|
23636
|
-
const absolute = resolve14(root, entry);
|
|
23637
|
-
if (!existsSync9(absolute)) {
|
|
23638
|
-
continue;
|
|
23639
|
-
}
|
|
23640
|
-
watchers.push(
|
|
23641
|
-
watch(absolute, { recursive: true }, (_event, filename) => {
|
|
23642
|
-
if (filename !== null && isWatched(absolute, filename.toString())) {
|
|
23643
|
-
schedule();
|
|
23644
|
-
}
|
|
23645
|
-
})
|
|
23646
|
-
);
|
|
23647
|
-
}
|
|
23648
|
-
return {
|
|
23649
|
-
close: () => {
|
|
23650
|
-
if (timer !== null) {
|
|
23651
|
-
clearTimeout(timer);
|
|
23652
|
-
timer = null;
|
|
23653
|
-
}
|
|
23654
|
-
for (const watcher of watchers) {
|
|
23655
|
-
watcher.close();
|
|
23656
|
-
}
|
|
23657
|
-
}
|
|
23658
|
-
};
|
|
23659
|
-
}
|
|
23660
|
-
function watchedRoots(sources) {
|
|
23661
|
-
return createSourceResolver(sources).roots;
|
|
23662
|
-
}
|
|
23663
|
-
|
|
23664
24519
|
// src/commands/ensure-command.ts
|
|
23665
|
-
function untilAborted(signal) {
|
|
23666
|
-
return new Promise((resolveLoop) => {
|
|
23667
|
-
if (signal?.aborted === true) {
|
|
23668
|
-
resolveLoop();
|
|
23669
|
-
return;
|
|
23670
|
-
}
|
|
23671
|
-
const stop = () => {
|
|
23672
|
-
process.off("SIGINT", stop);
|
|
23673
|
-
signal?.removeEventListener("abort", stop);
|
|
23674
|
-
resolveLoop();
|
|
23675
|
-
};
|
|
23676
|
-
if (signal !== null) {
|
|
23677
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
23678
|
-
}
|
|
23679
|
-
process.on("SIGINT", stop);
|
|
23680
|
-
});
|
|
23681
|
-
}
|
|
23682
24520
|
async function watchLoop(context, runner, options) {
|
|
23683
24521
|
const reporter = commandReporter(context);
|
|
23684
24522
|
let running = false;
|
|
@@ -23841,12 +24679,12 @@ function parseMtaLogLine(line2, activeResource, fallback = /* @__PURE__ */ new D
|
|
|
23841
24679
|
}
|
|
23842
24680
|
|
|
23843
24681
|
// src/logging/server-log-follower.ts
|
|
23844
|
-
import { closeSync, existsSync as
|
|
23845
|
-
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";
|
|
23846
24684
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
23847
24685
|
function resolveServerLogPath(root, serverPath) {
|
|
23848
|
-
const server = isAbsolute6(serverPath) ? serverPath :
|
|
23849
|
-
return
|
|
24686
|
+
const server = isAbsolute6(serverPath) ? serverPath : resolve16(root, serverPath);
|
|
24687
|
+
return resolve16(server, "mods/deathmatch/logs/server.log");
|
|
23850
24688
|
}
|
|
23851
24689
|
function identity(path) {
|
|
23852
24690
|
const stats = statSync4(path);
|
|
@@ -23871,7 +24709,7 @@ function followServerLog(path, onLine, options = {}) {
|
|
|
23871
24709
|
let initialized = false;
|
|
23872
24710
|
let closed = false;
|
|
23873
24711
|
const poll = () => {
|
|
23874
|
-
if (closed || !
|
|
24712
|
+
if (closed || !existsSync12(path)) {
|
|
23875
24713
|
return;
|
|
23876
24714
|
}
|
|
23877
24715
|
try {
|
|
@@ -23987,7 +24825,7 @@ function connectServerConsoleInput(input, output, interrupt) {
|
|
|
23987
24825
|
|
|
23988
24826
|
// src/server/server-executable-resolver.ts
|
|
23989
24827
|
import { realpathSync, statSync as statSync5 } from "node:fs";
|
|
23990
|
-
import { isAbsolute as isAbsolute7, relative as relative7, resolve as
|
|
24828
|
+
import { isAbsolute as isAbsolute7, relative as relative7, resolve as resolve17 } from "node:path";
|
|
23991
24829
|
function isInside(root, path) {
|
|
23992
24830
|
const pathFromRoot = relative7(root, path);
|
|
23993
24831
|
return pathFromRoot.length === 0 || !pathFromRoot.startsWith("..") && !isAbsolute7(pathFromRoot);
|
|
@@ -24002,14 +24840,14 @@ function candidates2(platform) {
|
|
|
24002
24840
|
throw new Error(`Local MTA server startup is not supported on platform "${platform}". Use Windows or Linux.`);
|
|
24003
24841
|
}
|
|
24004
24842
|
function resolveServerExecutable(options) {
|
|
24005
|
-
const serverRoot =
|
|
24843
|
+
const serverRoot = resolve17(options.root, options.serverPath);
|
|
24006
24844
|
const names = options.configured === null ? candidates2(options.platform ?? process.platform) : [options.configured];
|
|
24007
24845
|
const attempted = [];
|
|
24008
|
-
if (options.configured !== null && (isAbsolute7(options.configured) || !isInside(serverRoot,
|
|
24846
|
+
if (options.configured !== null && (isAbsolute7(options.configured) || !isInside(serverRoot, resolve17(serverRoot, options.configured)))) {
|
|
24009
24847
|
throw new Error(`Configured development.server.executable must stay inside serverPath but received "${options.configured}".`);
|
|
24010
24848
|
}
|
|
24011
24849
|
for (const name of names) {
|
|
24012
|
-
const path =
|
|
24850
|
+
const path = resolve17(serverRoot, name);
|
|
24013
24851
|
attempted.push(path);
|
|
24014
24852
|
try {
|
|
24015
24853
|
if (!statSync5(path).isFile()) {
|
|
@@ -24369,8 +25207,520 @@ function registerEnsureCommand(program2, runtime) {
|
|
|
24369
25207
|
});
|
|
24370
25208
|
}
|
|
24371
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
|
+
|
|
24372
25722
|
// src/cli/registry/init-registration.ts
|
|
24373
|
-
import { resolve as
|
|
25723
|
+
import { resolve as resolve21 } from "node:path";
|
|
24374
25724
|
|
|
24375
25725
|
// src/commands/init-command.ts
|
|
24376
25726
|
import { basename as basename2 } from "node:path";
|
|
@@ -24432,7 +25782,7 @@ function renderManifest(source, details) {
|
|
|
24432
25782
|
}
|
|
24433
25783
|
|
|
24434
25784
|
// src/scaffold/template-files.ts
|
|
24435
|
-
import { existsSync as
|
|
25785
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13 } from "node:fs";
|
|
24436
25786
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
24437
25787
|
|
|
24438
25788
|
// ../template/src/template.ts
|
|
@@ -24448,10 +25798,10 @@ function bundledTemplatePath(source) {
|
|
|
24448
25798
|
}
|
|
24449
25799
|
function resolveTemplatePath(source) {
|
|
24450
25800
|
const packaged = fileURLToPath2(resolveTemplateUrl(source));
|
|
24451
|
-
return
|
|
25801
|
+
return existsSync14(packaged) ? packaged : bundledTemplatePath(source);
|
|
24452
25802
|
}
|
|
24453
25803
|
function readTemplateSource(source) {
|
|
24454
|
-
return
|
|
25804
|
+
return readFileSync13(resolveTemplatePath(source), "utf8");
|
|
24455
25805
|
}
|
|
24456
25806
|
|
|
24457
25807
|
// src/scaffold/scaffold-plan.ts
|
|
@@ -24467,19 +25817,19 @@ function buildScaffoldPlan(details) {
|
|
|
24467
25817
|
}
|
|
24468
25818
|
|
|
24469
25819
|
// src/scaffold/scaffold-writer.ts
|
|
24470
|
-
import { existsSync as
|
|
24471
|
-
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";
|
|
24472
25822
|
function writeScaffold(targetDir, plan, force) {
|
|
24473
25823
|
const written = [];
|
|
24474
25824
|
const skipped = [];
|
|
24475
25825
|
for (const file of plan.files) {
|
|
24476
|
-
const absolute =
|
|
24477
|
-
if (!force &&
|
|
25826
|
+
const absolute = resolve20(targetDir, file.path);
|
|
25827
|
+
if (!force && existsSync15(absolute)) {
|
|
24478
25828
|
skipped.push(file.path);
|
|
24479
25829
|
continue;
|
|
24480
25830
|
}
|
|
24481
|
-
mkdirSync6(
|
|
24482
|
-
|
|
25831
|
+
mkdirSync6(dirname7(absolute), { recursive: true });
|
|
25832
|
+
writeFileSync8(absolute, file.content, "utf8");
|
|
24483
25833
|
written.push(file.path);
|
|
24484
25834
|
}
|
|
24485
25835
|
return { written: written.sort((left, right) => left.localeCompare(right)), skipped: skipped.sort((left, right) => left.localeCompare(right)) };
|
|
@@ -24529,7 +25879,7 @@ function registerInitCommand(program2, runtime) {
|
|
|
24529
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());
|
|
24530
25880
|
command.action(async (path, options) => {
|
|
24531
25881
|
const root = commandRoot(runtime, options);
|
|
24532
|
-
const target = path === void 0 ? root :
|
|
25882
|
+
const target = path === void 0 ? root : resolve21(root, path);
|
|
24533
25883
|
runtime.exitCode = await runInitCommand(target, runtime.logger, {
|
|
24534
25884
|
name: options.name ?? null,
|
|
24535
25885
|
force: options.force === true,
|
|
@@ -24653,13 +26003,13 @@ function registerServerCommand(program2, runtime) {
|
|
|
24653
26003
|
}
|
|
24654
26004
|
|
|
24655
26005
|
// src/testing/test-report.ts
|
|
24656
|
-
import { readFileSync as
|
|
24657
|
-
import { resolve as
|
|
26006
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
26007
|
+
import { resolve as resolve22 } from "node:path";
|
|
24658
26008
|
function sourceLine(root, path, line2, cache3) {
|
|
24659
26009
|
let lines = cache3.get(path);
|
|
24660
26010
|
if (lines === void 0) {
|
|
24661
26011
|
try {
|
|
24662
|
-
lines =
|
|
26012
|
+
lines = readFileSync14(resolve22(root, path), "utf8").split(/\r?\n/);
|
|
24663
26013
|
} catch {
|
|
24664
26014
|
lines = [];
|
|
24665
26015
|
}
|
|
@@ -24732,14 +26082,14 @@ function reportTestResults(reporter, runs, root, map, durationMs) {
|
|
|
24732
26082
|
}
|
|
24733
26083
|
|
|
24734
26084
|
// src/testing/test-discovery.ts
|
|
24735
|
-
import { readFileSync as
|
|
24736
|
-
import { resolve as
|
|
26085
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
26086
|
+
import { resolve as resolve23 } from "node:path";
|
|
24737
26087
|
var DEFAULT_TEST_ENVIRONMENT = "shared";
|
|
24738
26088
|
var SIDE_CONFLICT2 = "test-source-side-conflict";
|
|
24739
26089
|
var UNREADABLE_TEST = "test-source-unreadable";
|
|
24740
26090
|
function readTest(root, path, diagnostics) {
|
|
24741
26091
|
try {
|
|
24742
|
-
return
|
|
26092
|
+
return readFileSync15(resolve23(root, path), "utf8");
|
|
24743
26093
|
} catch (error) {
|
|
24744
26094
|
diagnostics.push(cliError(UNREADABLE_TEST, `The test file "${path}" could not be read: ${error instanceof Error ? error.message : String(error)}`));
|
|
24745
26095
|
return null;
|
|
@@ -24766,9 +26116,9 @@ function discoverTests(root, sources, excluded = []) {
|
|
|
24766
26116
|
|
|
24767
26117
|
// src/testing/test-runner.ts
|
|
24768
26118
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
24769
|
-
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";
|
|
24770
26120
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
24771
|
-
import { dirname as
|
|
26121
|
+
import { dirname as dirname8, join as join7 } from "node:path";
|
|
24772
26122
|
|
|
24773
26123
|
// src/testing/harness-assertions.ts
|
|
24774
26124
|
var ASSERTIONS_SOURCE = String.raw`local SENTINEL = '##luam:test'
|
|
@@ -25183,11 +26533,11 @@ function parseRunOutput(environment, stdout) {
|
|
|
25183
26533
|
return { results, output };
|
|
25184
26534
|
}
|
|
25185
26535
|
function writeWorkspace(directory, scripts) {
|
|
25186
|
-
|
|
26536
|
+
writeFileSync9(join7(directory, HARNESS_FILE), HARNESS_SOURCE, "utf8");
|
|
25187
26537
|
for (const script of scripts) {
|
|
25188
|
-
const target =
|
|
25189
|
-
mkdirSync7(
|
|
25190
|
-
|
|
26538
|
+
const target = join7(directory, script.path);
|
|
26539
|
+
mkdirSync7(dirname8(target), { recursive: true });
|
|
26540
|
+
writeFileSync9(target, script.content, "utf8");
|
|
25191
26541
|
}
|
|
25192
26542
|
}
|
|
25193
26543
|
function loadOrder(available, environment) {
|
|
@@ -25201,14 +26551,14 @@ function loadOrder(available, environment) {
|
|
|
25201
26551
|
}
|
|
25202
26552
|
function runTests(request) {
|
|
25203
26553
|
const spawn2 = request.spawn ?? runLua;
|
|
25204
|
-
const directory = mkdtempSync2(
|
|
26554
|
+
const directory = mkdtempSync2(join7(tmpdir2(), "luam-test-"));
|
|
25205
26555
|
const available = new Set(request.scripts.map((script) => script.path));
|
|
25206
26556
|
try {
|
|
25207
26557
|
writeWorkspace(directory, request.scripts);
|
|
25208
26558
|
return ALL_ENVIRONMENTS.filter((environment) => request.environments.includes(environment)).map((environment) => {
|
|
25209
26559
|
const { preload, target } = loadOrder(available, environment);
|
|
25210
26560
|
const entry = entryFile(environment);
|
|
25211
|
-
|
|
26561
|
+
writeFileSync9(join7(directory, entry), entrySource(environment, preload, target), "utf8");
|
|
25212
26562
|
const execution = spawn2(request.executable, [entry], directory);
|
|
25213
26563
|
const parsed = parseRunOutput(environment, execution.stdout);
|
|
25214
26564
|
const failure3 = execution.failure ?? (parsed.results.length === 0 && execution.stderr.length > 0 ? execution.stderr.trim() : null);
|
|
@@ -25280,12 +26630,12 @@ function registerTestCommand(program2, runtime) {
|
|
|
25280
26630
|
}
|
|
25281
26631
|
|
|
25282
26632
|
// src/commands/trace-command.ts
|
|
25283
|
-
import { existsSync as
|
|
26633
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16 } from "node:fs";
|
|
25284
26634
|
function defaultMapPath(root, options, reporter) {
|
|
25285
26635
|
const loaded = loadManifest(root, { path: options.manifestPath, mode: manifestMode("trace"), env: options.env });
|
|
25286
26636
|
if (loaded.config !== null) {
|
|
25287
26637
|
const configured = resourceMapPath(root, loaded.config);
|
|
25288
|
-
if (
|
|
26638
|
+
if (existsSync16(configured)) {
|
|
25289
26639
|
return configured;
|
|
25290
26640
|
}
|
|
25291
26641
|
}
|
|
@@ -25305,7 +26655,7 @@ function readStandardInput() {
|
|
|
25305
26655
|
return "";
|
|
25306
26656
|
}
|
|
25307
26657
|
try {
|
|
25308
|
-
return
|
|
26658
|
+
return readFileSync16(0, "utf8");
|
|
25309
26659
|
} catch {
|
|
25310
26660
|
return "";
|
|
25311
26661
|
}
|
|
@@ -25387,6 +26737,7 @@ var COMMAND_REGISTRARS = [
|
|
|
25387
26737
|
registerDevCommand,
|
|
25388
26738
|
registerDoctorCommand,
|
|
25389
26739
|
registerEnsureCommand,
|
|
26740
|
+
registerFormatCommand,
|
|
25390
26741
|
registerInitCommand,
|
|
25391
26742
|
registerServerCommand,
|
|
25392
26743
|
registerSetupCommand,
|