@thigasdevelopment/luam 0.19.0 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/lua/class.lua +48 -10
- package/lua/validate.lua +239 -0
- package/luam.mjs +2062 -448
- package/package.json +1 -1
package/luam.mjs
CHANGED
|
@@ -1644,8 +1644,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1644
1644
|
* @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
|
|
1645
1645
|
* @return {Command} `this` command for chaining
|
|
1646
1646
|
*/
|
|
1647
|
-
combineFlagAndOptionalValue(
|
|
1648
|
-
this._combineFlagAndOptionalValue = !!
|
|
1647
|
+
combineFlagAndOptionalValue(combine2 = true) {
|
|
1648
|
+
this._combineFlagAndOptionalValue = !!combine2;
|
|
1649
1649
|
return this;
|
|
1650
1650
|
}
|
|
1651
1651
|
/**
|
|
@@ -3143,6 +3143,7 @@ var DEFAULT_ENVIRONMENT_FILE = ".env";
|
|
|
3143
3143
|
var DEFAULT_LOCAL_ENVIRONMENT_FILE = ".env.local";
|
|
3144
3144
|
var DEFAULT_ASSET_DESTINATION = ".";
|
|
3145
3145
|
var DEFAULT_OUT_DIR = "build";
|
|
3146
|
+
var DEFAULT_CONTRACTS_DIR = ".luam/contracts";
|
|
3146
3147
|
var DEFAULT_RESOURCES_DIR = "mods/deathmatch/resources";
|
|
3147
3148
|
var DEFAULT_COMPILER_OPTIONS = {
|
|
3148
3149
|
strict: true,
|
|
@@ -3492,14 +3493,14 @@ function readEscape(cursor) {
|
|
|
3492
3493
|
}
|
|
3493
3494
|
function scanQuotedString(cursor, diagnostics) {
|
|
3494
3495
|
const position2 = cursor.position();
|
|
3495
|
-
const
|
|
3496
|
+
const quote3 = cursor.peek();
|
|
3496
3497
|
cursor.advance();
|
|
3497
3498
|
let value = "";
|
|
3498
|
-
while (!cursor.isEof() && cursor.peek() !==
|
|
3499
|
+
while (!cursor.isEof() && cursor.peek() !== quote3 && !isLineBreak(cursor.peek())) {
|
|
3499
3500
|
value += cursor.peek() === "\\" ? readEscape(cursor) : cursor.advance();
|
|
3500
3501
|
}
|
|
3501
|
-
if (cursor.peek() !==
|
|
3502
|
-
const message = `Unterminated string. Close it with ${
|
|
3502
|
+
if (cursor.peek() !== quote3) {
|
|
3503
|
+
const message = `Unterminated string. Close it with ${quote3}.`;
|
|
3503
3504
|
diagnostics.push(createDiagnostic("lexer", "lex-unterminated-string", message, position2));
|
|
3504
3505
|
return value;
|
|
3505
3506
|
}
|
|
@@ -3827,19 +3828,21 @@ function parseTypeName(stream) {
|
|
|
3827
3828
|
return { kind: "type-name", name: token.value, typeArguments, position: token.position };
|
|
3828
3829
|
}
|
|
3829
3830
|
function parseParameterType(stream) {
|
|
3831
|
+
let name = null;
|
|
3830
3832
|
if (stream.check("identifier") && stream.checkAhead(1, "punctuation", ":")) {
|
|
3831
|
-
stream.next();
|
|
3833
|
+
name = stream.next().value;
|
|
3832
3834
|
stream.next();
|
|
3833
3835
|
}
|
|
3834
|
-
return parseTypeAnnotation(stream);
|
|
3836
|
+
return { name, annotation: parseTypeAnnotation(stream) };
|
|
3835
3837
|
}
|
|
3836
3838
|
function parseFunctionType(stream) {
|
|
3837
3839
|
const position2 = stream.expect("identifier", FUNCTION_TYPE).position;
|
|
3838
3840
|
if (!stream.check("punctuation", "(")) {
|
|
3839
|
-
return { kind: "type-function", parameters: [], isVariadic: true, returnType: null, position: position2 };
|
|
3841
|
+
return { kind: "type-function", parameters: [], parameterNames: [], isVariadic: true, returnType: null, position: position2 };
|
|
3840
3842
|
}
|
|
3841
3843
|
stream.next();
|
|
3842
3844
|
const parameters = [];
|
|
3845
|
+
const parameterNames = [];
|
|
3843
3846
|
let isVariadic = false;
|
|
3844
3847
|
while (!stream.check("punctuation", ")") && !stream.isEof()) {
|
|
3845
3848
|
if (stream.match("operator", "...")) {
|
|
@@ -3848,7 +3851,9 @@ function parseFunctionType(stream) {
|
|
|
3848
3851
|
parseTypeAnnotation(stream);
|
|
3849
3852
|
}
|
|
3850
3853
|
} else {
|
|
3851
|
-
|
|
3854
|
+
const parameter = parseParameterType(stream);
|
|
3855
|
+
parameters.push(parameter.annotation);
|
|
3856
|
+
parameterNames.push(parameter.name);
|
|
3852
3857
|
}
|
|
3853
3858
|
if (!stream.match("punctuation", ",")) {
|
|
3854
3859
|
break;
|
|
@@ -3856,7 +3861,7 @@ function parseFunctionType(stream) {
|
|
|
3856
3861
|
}
|
|
3857
3862
|
stream.expect("punctuation", ")");
|
|
3858
3863
|
const returnType = stream.match("punctuation", ":") ? parseTypeAnnotation(stream) : null;
|
|
3859
|
-
return { kind: "type-function", parameters, isVariadic, returnType, position: position2 };
|
|
3864
|
+
return { kind: "type-function", parameters, parameterNames, isVariadic, returnType, position: position2 };
|
|
3860
3865
|
}
|
|
3861
3866
|
function parseGroupedType(stream) {
|
|
3862
3867
|
const position2 = stream.expect("punctuation", "(").position;
|
|
@@ -3989,10 +3994,18 @@ function parseNamedAnnotation(stream, declaration) {
|
|
|
3989
3994
|
if (optional === null && annotation?.kind === "type-optional") {
|
|
3990
3995
|
stream.report("parse-optional-position", `Write optional ${label2} as "name?: Type", not "name: Type?".`, annotation.position);
|
|
3991
3996
|
}
|
|
3997
|
+
if (optional !== null && annotation?.kind === "type-optional") {
|
|
3998
|
+
const message = `The marker on the name already allows "nil". Remove the "?" after the type.`;
|
|
3999
|
+
stream.report("parse-redundant-optional", message, annotation.position);
|
|
4000
|
+
}
|
|
3992
4001
|
if (optional !== null && annotation !== null) {
|
|
3993
4002
|
stream.eraseFrom(checkpoint);
|
|
3994
4003
|
}
|
|
3995
|
-
|
|
4004
|
+
if (optional === null || annotation === null) {
|
|
4005
|
+
return annotation;
|
|
4006
|
+
}
|
|
4007
|
+
const element = annotation.kind === "type-optional" ? annotation.element : annotation;
|
|
4008
|
+
return { kind: "type-optional", element, position: optional.position };
|
|
3996
4009
|
}
|
|
3997
4010
|
|
|
3998
4011
|
// ../compiler/src/parser/function-expression.ts
|
|
@@ -4146,7 +4159,8 @@ function parsePrimary(stream) {
|
|
|
4146
4159
|
if (token.kind === "keyword" && token.value === "new" && stream.checkAhead(1, "identifier")) {
|
|
4147
4160
|
stream.next();
|
|
4148
4161
|
const className = stream.next().value;
|
|
4149
|
-
|
|
4162
|
+
const typeArguments = parseNewTypeArguments(stream);
|
|
4163
|
+
return { kind: "new-expression", className, typeArguments, args: parseArguments(stream), position: token.position };
|
|
4150
4164
|
}
|
|
4151
4165
|
if (token.kind === "keyword" && CALLABLE_KEYWORDS.has(token.value) && stream.checkAhead(1, "punctuation", "(")) {
|
|
4152
4166
|
stream.next();
|
|
@@ -4178,6 +4192,20 @@ function parsePrimary(stream) {
|
|
|
4178
4192
|
}
|
|
4179
4193
|
throw stream.error(`Unexpected "${stream.describeCurrent()}" in expression.`, "parse-unexpected-token");
|
|
4180
4194
|
}
|
|
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
|
+
}
|
|
4181
4209
|
function parseArguments(stream) {
|
|
4182
4210
|
if (stream.check("string") || stream.check("template") || stream.check("punctuation", "{")) {
|
|
4183
4211
|
return [parsePrimary(stream)];
|
|
@@ -4464,8 +4492,23 @@ var TokenStream = class {
|
|
|
4464
4492
|
// ../compiler/src/parser/declarations.ts
|
|
4465
4493
|
var DECLARATION_NAMES = /* @__PURE__ */ new Set(["class", "interface", "enum"]);
|
|
4466
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
|
+
}
|
|
4467
4509
|
function isClassHeader(stream, offset = 0) {
|
|
4468
|
-
|
|
4510
|
+
const after = skipTypeParameters(stream, offset + 2);
|
|
4511
|
+
return stream.checkAhead(after, "punctuation", "{") || stream.checkAhead(after, "keyword", "extends") || stream.checkAhead(after, "keyword", "implements");
|
|
4469
4512
|
}
|
|
4470
4513
|
function isDeclarationStart(stream) {
|
|
4471
4514
|
let offset = 0;
|
|
@@ -4521,7 +4564,7 @@ function parseDecorators(stream) {
|
|
|
4521
4564
|
}
|
|
4522
4565
|
return decorators;
|
|
4523
4566
|
}
|
|
4524
|
-
function parseClassMethod(stream, token, decorators) {
|
|
4567
|
+
function parseClassMethod(stream, token, decorators, isStatic) {
|
|
4525
4568
|
stream.expect("operator", "=");
|
|
4526
4569
|
const expression = parseFunctionExpression(stream);
|
|
4527
4570
|
return {
|
|
@@ -4529,6 +4572,7 @@ function parseClassMethod(stream, token, decorators) {
|
|
|
4529
4572
|
name: token.value,
|
|
4530
4573
|
isConstructor: token.value === "constructor",
|
|
4531
4574
|
isSynthetic: false,
|
|
4575
|
+
isStatic,
|
|
4532
4576
|
parameters: expression.parameters,
|
|
4533
4577
|
returnAnnotation: expression.returnAnnotation,
|
|
4534
4578
|
body: expression.body,
|
|
@@ -4536,7 +4580,7 @@ function parseClassMethod(stream, token, decorators) {
|
|
|
4536
4580
|
position: token.position
|
|
4537
4581
|
};
|
|
4538
4582
|
}
|
|
4539
|
-
function parseBraceClassMethod(stream, token, decorators) {
|
|
4583
|
+
function parseBraceClassMethod(stream, token, decorators, isStatic) {
|
|
4540
4584
|
const parameters = parseParameters(stream);
|
|
4541
4585
|
const returnAnnotation = parseOptionalAnnotation(stream);
|
|
4542
4586
|
const body = parseBraceBlock(stream);
|
|
@@ -4545,6 +4589,7 @@ function parseBraceClassMethod(stream, token, decorators) {
|
|
|
4545
4589
|
name: token.value,
|
|
4546
4590
|
isConstructor: token.value === "constructor",
|
|
4547
4591
|
isSynthetic: false,
|
|
4592
|
+
isStatic,
|
|
4548
4593
|
parameters,
|
|
4549
4594
|
returnAnnotation,
|
|
4550
4595
|
body,
|
|
@@ -4563,25 +4608,70 @@ function expectClassFieldBoundary(stream, token) {
|
|
|
4563
4608
|
}
|
|
4564
4609
|
throw stream.error(`Expected a line break or separator after class member "${token.value}".`, "parse-unexpected-token");
|
|
4565
4610
|
}
|
|
4611
|
+
var STATIC_MODIFIER = "static";
|
|
4612
|
+
function parseStaticModifier(stream) {
|
|
4613
|
+
if (!stream.check("identifier", STATIC_MODIFIER)) {
|
|
4614
|
+
return false;
|
|
4615
|
+
}
|
|
4616
|
+
const modifier = stream.current();
|
|
4617
|
+
if (!stream.checkName(1) || stream.peek(1).position.line !== modifier.position.line) {
|
|
4618
|
+
return false;
|
|
4619
|
+
}
|
|
4620
|
+
const checkpoint = stream.checkpoint();
|
|
4621
|
+
stream.next();
|
|
4622
|
+
stream.eraseToCurrent(checkpoint);
|
|
4623
|
+
return true;
|
|
4624
|
+
}
|
|
4566
4625
|
function parseClassMember(stream) {
|
|
4567
4626
|
const decorators = parseDecorators(stream);
|
|
4627
|
+
const isStatic = parseStaticModifier(stream);
|
|
4568
4628
|
const token = stream.expectName();
|
|
4569
4629
|
if (stream.check("punctuation", "(")) {
|
|
4570
4630
|
stream.report("parse-class-method-form", `Write class member "${token.value}" as "${token.value} = function (...) ... end".`, token.position);
|
|
4571
|
-
return parseBraceClassMethod(stream, token, decorators);
|
|
4631
|
+
return parseBraceClassMethod(stream, token, decorators, isStatic);
|
|
4572
4632
|
}
|
|
4573
4633
|
if (stream.check("operator", "=") && stream.checkAhead(1, "keyword", "function")) {
|
|
4574
|
-
return parseClassMethod(stream, token, decorators);
|
|
4634
|
+
return parseClassMethod(stream, token, decorators, isStatic);
|
|
4575
4635
|
}
|
|
4576
4636
|
const annotation = parseFieldAnnotation(stream);
|
|
4577
4637
|
const value = stream.match("operator", "=") ? parseExpression(stream) : null;
|
|
4578
4638
|
expectClassFieldBoundary(stream, token);
|
|
4579
|
-
return { kind: "class-field", name: token.value, annotation, value, decorators, position: token.position };
|
|
4639
|
+
return { kind: "class-field", name: token.value, annotation, value, decorators, isStatic, position: token.position };
|
|
4640
|
+
}
|
|
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;
|
|
4580
4669
|
}
|
|
4581
4670
|
function parseClassModifiers(stream, declaration) {
|
|
4582
4671
|
while (stream.check("keyword") && CLASS_MODIFIERS.has(stream.current().value)) {
|
|
4583
4672
|
if (stream.next().value === "extends") {
|
|
4584
4673
|
declaration.superClass = stream.expect("identifier").value;
|
|
4674
|
+
declaration.superClassArguments = parseTypeArguments(stream);
|
|
4585
4675
|
continue;
|
|
4586
4676
|
}
|
|
4587
4677
|
do {
|
|
@@ -4592,7 +4682,19 @@ function parseClassModifiers(stream, declaration) {
|
|
|
4592
4682
|
function parseClassDeclaration(stream, decorators) {
|
|
4593
4683
|
const position2 = stream.next().position;
|
|
4594
4684
|
const name = stream.expect("identifier").value;
|
|
4595
|
-
const
|
|
4685
|
+
const typeParameters = parseTypeParameters(stream);
|
|
4686
|
+
const declaration = {
|
|
4687
|
+
kind: "class-declaration",
|
|
4688
|
+
name,
|
|
4689
|
+
typeParameters: typeParameters.names,
|
|
4690
|
+
typeConstraints: typeParameters.constraints,
|
|
4691
|
+
superClass: null,
|
|
4692
|
+
superClassArguments: [],
|
|
4693
|
+
interfaces: [],
|
|
4694
|
+
members: [],
|
|
4695
|
+
decorators,
|
|
4696
|
+
position: position2
|
|
4697
|
+
};
|
|
4596
4698
|
parseClassModifiers(stream, declaration);
|
|
4597
4699
|
stream.expect("punctuation", "{");
|
|
4598
4700
|
while (!stream.check("punctuation", "}") && !stream.isEof()) {
|
|
@@ -5052,8 +5154,8 @@ var TABLE_TYPE = { kind: "table" };
|
|
|
5052
5154
|
function createArray(element) {
|
|
5053
5155
|
return { kind: "array", element };
|
|
5054
5156
|
}
|
|
5055
|
-
function createNamed(name) {
|
|
5056
|
-
return { kind: "named", name };
|
|
5157
|
+
function createNamed(name, typeArguments = []) {
|
|
5158
|
+
return typeArguments.length === 0 ? { kind: "named", name } : { kind: "named", name, typeArguments };
|
|
5057
5159
|
}
|
|
5058
5160
|
function createMap(key, value) {
|
|
5059
5161
|
return { kind: "map", key, value };
|
|
@@ -5166,6 +5268,12 @@ function createUnion(options) {
|
|
|
5166
5268
|
}
|
|
5167
5269
|
return { kind: "union", options: flattened };
|
|
5168
5270
|
}
|
|
5271
|
+
function namedNesting(type) {
|
|
5272
|
+
if (type.kind !== "named") {
|
|
5273
|
+
return 0;
|
|
5274
|
+
}
|
|
5275
|
+
return 1 + Math.max(0, ...(type.typeArguments ?? []).map(namedNesting));
|
|
5276
|
+
}
|
|
5169
5277
|
function typeToString(type) {
|
|
5170
5278
|
if (type.kind === "array") {
|
|
5171
5279
|
return `${typeToString(type.element)}[]`;
|
|
@@ -5185,7 +5293,11 @@ function typeToString(type) {
|
|
|
5185
5293
|
if (type.kind === "boolean-literal" || type.kind === "number-literal") {
|
|
5186
5294
|
return String(type.value);
|
|
5187
5295
|
}
|
|
5188
|
-
if (type.kind === "named"
|
|
5296
|
+
if (type.kind === "named") {
|
|
5297
|
+
const args = type.typeArguments ?? [];
|
|
5298
|
+
return args.length === 0 ? type.name : `${type.name}<${args.map(typeToString).join(", ")}>`;
|
|
5299
|
+
}
|
|
5300
|
+
if (type.kind === "record") {
|
|
5189
5301
|
return type.name;
|
|
5190
5302
|
}
|
|
5191
5303
|
if (type.kind === "tuple") {
|
|
@@ -5275,6 +5387,59 @@ function isRecordAssignable(source, target, options) {
|
|
|
5275
5387
|
}
|
|
5276
5388
|
return true;
|
|
5277
5389
|
}
|
|
5390
|
+
function isNamedAssignable(source, target, options) {
|
|
5391
|
+
const sourceArguments = source.typeArguments ?? [];
|
|
5392
|
+
const targetArguments = target.typeArguments ?? [];
|
|
5393
|
+
if (source.name !== target.name || sourceArguments.length === 0 || targetArguments.length !== sourceArguments.length) {
|
|
5394
|
+
return true;
|
|
5395
|
+
}
|
|
5396
|
+
return sourceArguments.every((argument, index) => isAssignable(argument, targetArguments[index] ?? ANY_TYPE, options));
|
|
5397
|
+
}
|
|
5398
|
+
function asRecord(name, members) {
|
|
5399
|
+
return { kind: "record", name, origin: null, members };
|
|
5400
|
+
}
|
|
5401
|
+
function shapeOf(name, options) {
|
|
5402
|
+
return options.resolveNominal?.(name) ?? null;
|
|
5403
|
+
}
|
|
5404
|
+
function withVisit(options, pair) {
|
|
5405
|
+
return { ...options, visited: /* @__PURE__ */ new Set([...options.visited ?? [], pair]) };
|
|
5406
|
+
}
|
|
5407
|
+
function isNominalAssignable(source, target, options) {
|
|
5408
|
+
const pair = `${source.name}>${target.name}`;
|
|
5409
|
+
if (options.visited?.has(pair) === true) {
|
|
5410
|
+
return true;
|
|
5411
|
+
}
|
|
5412
|
+
const declared = shapeOf(target.name, options);
|
|
5413
|
+
const actual = shapeOf(source.name, options);
|
|
5414
|
+
if (declared === null || actual === null) {
|
|
5415
|
+
return true;
|
|
5416
|
+
}
|
|
5417
|
+
if (declared.kind === "class" || actual.kind === "class") {
|
|
5418
|
+
return actual.kind === "class" && actual.ancestors.has(target.name);
|
|
5419
|
+
}
|
|
5420
|
+
return isRecordAssignable(asRecord(source.name, actual.members), asRecord(target.name, declared.members), withVisit(options, pair));
|
|
5421
|
+
}
|
|
5422
|
+
var SCALAR_KINDS = /* @__PURE__ */ new Set(["string", "number", "boolean", "thread", "userdata", "void", "nil", "function"]);
|
|
5423
|
+
function isNamedSourceAssignable(source, target, options) {
|
|
5424
|
+
const actual = shapeOf(source.name, options);
|
|
5425
|
+
if (actual === null) {
|
|
5426
|
+
return true;
|
|
5427
|
+
}
|
|
5428
|
+
if (actual.kind === "class") {
|
|
5429
|
+
return !SCALAR_KINDS.has(target.kind) && !isLiteralType(target);
|
|
5430
|
+
}
|
|
5431
|
+
return isAssignable(asRecord(source.name, actual.members), target, options);
|
|
5432
|
+
}
|
|
5433
|
+
function isNamedTargetAssignable(source, target, options) {
|
|
5434
|
+
const declared = shapeOf(target.name, options);
|
|
5435
|
+
if (declared === null) {
|
|
5436
|
+
return true;
|
|
5437
|
+
}
|
|
5438
|
+
if (declared.kind === "class") {
|
|
5439
|
+
return false;
|
|
5440
|
+
}
|
|
5441
|
+
return isAssignable(source, asRecord(target.name, declared.members), options);
|
|
5442
|
+
}
|
|
5278
5443
|
function isAssignable(source, target, options = { allowNil: false }) {
|
|
5279
5444
|
if (source.kind === "any" || target.kind === "any" || target.kind === "unknown") {
|
|
5280
5445
|
return true;
|
|
@@ -5282,9 +5447,6 @@ function isAssignable(source, target, options = { allowNil: false }) {
|
|
|
5282
5447
|
if (source.kind === "tuple" || target.kind === "tuple") {
|
|
5283
5448
|
return isAssignable(firstValueOf(source), firstValueOf(target), options);
|
|
5284
5449
|
}
|
|
5285
|
-
if (source.kind === "named" || target.kind === "named") {
|
|
5286
|
-
return true;
|
|
5287
|
-
}
|
|
5288
5450
|
if (source.kind === "nil" && (options.allowNil || target.kind === "optional" || target.kind === "nil")) {
|
|
5289
5451
|
return true;
|
|
5290
5452
|
}
|
|
@@ -5303,6 +5465,15 @@ function isAssignable(source, target, options = { allowNil: false }) {
|
|
|
5303
5465
|
if (target.kind === "optional") {
|
|
5304
5466
|
return isAssignable(source, target.element, options);
|
|
5305
5467
|
}
|
|
5468
|
+
if (source.kind === "named" && target.kind === "named") {
|
|
5469
|
+
return source.name === target.name ? isNamedAssignable(source, target, options) : isNominalAssignable(source, target, options);
|
|
5470
|
+
}
|
|
5471
|
+
if (source.kind === "named") {
|
|
5472
|
+
return isNamedSourceAssignable(source, target, options);
|
|
5473
|
+
}
|
|
5474
|
+
if (target.kind === "named") {
|
|
5475
|
+
return isNamedTargetAssignable(source, target, options);
|
|
5476
|
+
}
|
|
5306
5477
|
if (target.kind === "table") {
|
|
5307
5478
|
return isTableLike(source) || source.kind === "record";
|
|
5308
5479
|
}
|
|
@@ -5441,7 +5612,8 @@ var RUNTIME_HELPERS = {
|
|
|
5441
5612
|
math: { name: "math", file: "math.lua", injection: "automatic", features: ["number-extension"] },
|
|
5442
5613
|
string: { name: "string", file: "string.lua", injection: "automatic", features: ["string-extension", "template-string"] },
|
|
5443
5614
|
table: { name: "table", file: "table.lua", injection: "automatic", features: ["table-extension"] },
|
|
5444
|
-
threads: { name: "threads", file: "threads.lua", injection: "reference", features: ["thread"], globals: ["sleep", "Threads"] }
|
|
5615
|
+
threads: { name: "threads", file: "threads.lua", injection: "reference", features: ["thread"], globals: ["sleep", "Threads"] },
|
|
5616
|
+
validate: { name: "validate", file: "validate.lua", injection: "automatic", features: ["boundary-validation"] }
|
|
5445
5617
|
};
|
|
5446
5618
|
var DEVELOPMENT_RUNTIME_HELPERS = {
|
|
5447
5619
|
"development-logs-client": {
|
|
@@ -5582,6 +5754,11 @@ var MANIFEST_FIELDS = [
|
|
|
5582
5754
|
owner: "dependencies",
|
|
5583
5755
|
allowEmpty: true
|
|
5584
5756
|
}),
|
|
5757
|
+
field("contracts", STRING_TYPE, "Directory the export contract is written to and dependency contracts are read from.", {
|
|
5758
|
+
defaultValue: DEFAULT_CONTRACTS_DIR,
|
|
5759
|
+
rule: "contained-path",
|
|
5760
|
+
owner: "dependencies"
|
|
5761
|
+
}),
|
|
5585
5762
|
table("engine", "Requirements the MTA server and client must meet.", ENGINE_FIELDS, { defaultValue: {}, owner: "engine" }),
|
|
5586
5763
|
table("environment", "Files that declare and override the project environment.", ENVIRONMENT_FIELDS, { defaultValue: {}, owner: "environment" }),
|
|
5587
5764
|
field("outDir", STRING_TYPE, "Directory the built resource is written to.", { defaultValue: DEFAULT_OUT_DIR, rule: "static-path", owner: "output" }),
|
|
@@ -5741,8 +5918,8 @@ function isNumber(type) {
|
|
|
5741
5918
|
function isText(type) {
|
|
5742
5919
|
return type.kind === "string" || type.kind === "string-literal" || type.kind === "any";
|
|
5743
5920
|
}
|
|
5744
|
-
function fail(operator, expected, left, right,
|
|
5745
|
-
const culprit =
|
|
5921
|
+
function fail(operator, expected, left, right, describe2) {
|
|
5922
|
+
const culprit = describe2(isNumber(left) || isText(left) ? right : left);
|
|
5746
5923
|
return { evaluated: null, error: `"${operator}" expects ${expected} on both sides but received ${culprit}.` };
|
|
5747
5924
|
}
|
|
5748
5925
|
function arithmetic(operator, left, right) {
|
|
@@ -5781,22 +5958,22 @@ function applyOr(left, right) {
|
|
|
5781
5958
|
const value = isTruthy(left.value) ? left.value : right.value;
|
|
5782
5959
|
return { value, type: unionOf([left.truthy, right.type]), truthy: unionOf([left.truthy, right.truthy]), falsy: right.falsy };
|
|
5783
5960
|
}
|
|
5784
|
-
function applyOrdering(operator, left, right,
|
|
5961
|
+
function applyOrdering(operator, left, right, describe2) {
|
|
5785
5962
|
const numeric = isNumber(left.type) && isNumber(right.type);
|
|
5786
5963
|
const textual = isText(left.type) && isText(right.type);
|
|
5787
5964
|
if (!numeric && !textual) {
|
|
5788
|
-
return fail(operator, "two numbers or two strings", left.type, right.type,
|
|
5965
|
+
return fail(operator, "two numbers or two strings", left.type, right.type, describe2);
|
|
5789
5966
|
}
|
|
5790
5967
|
return { evaluated: booleanValue(compare(operator, left.value, right.value)), error: null };
|
|
5791
5968
|
}
|
|
5792
|
-
function applyConcat(left, right,
|
|
5969
|
+
function applyConcat(left, right, describe2) {
|
|
5793
5970
|
const usable = (type) => isText(type) || isNumber(type);
|
|
5794
5971
|
if (!usable(left.type) || !usable(right.type)) {
|
|
5795
|
-
return fail("..", "a string or a number", left.type, right.type,
|
|
5972
|
+
return fail("..", "a string or a number", left.type, right.type, describe2);
|
|
5796
5973
|
}
|
|
5797
5974
|
return { evaluated: stringValue(`${left.value}${right.value}`), error: null };
|
|
5798
5975
|
}
|
|
5799
|
-
function applyBinary(operator, left, right,
|
|
5976
|
+
function applyBinary(operator, left, right, describe2) {
|
|
5800
5977
|
if (operator === "and") {
|
|
5801
5978
|
return { evaluated: applyAnd(left, right), error: null };
|
|
5802
5979
|
}
|
|
@@ -5808,23 +5985,23 @@ function applyBinary(operator, left, right, describe) {
|
|
|
5808
5985
|
return { evaluated: booleanValue(operator === "==" ? same : !same), error: null };
|
|
5809
5986
|
}
|
|
5810
5987
|
if (ORDERING.includes(operator)) {
|
|
5811
|
-
return applyOrdering(operator, left, right,
|
|
5988
|
+
return applyOrdering(operator, left, right, describe2);
|
|
5812
5989
|
}
|
|
5813
5990
|
if (operator === "..") {
|
|
5814
|
-
return applyConcat(left, right,
|
|
5991
|
+
return applyConcat(left, right, describe2);
|
|
5815
5992
|
}
|
|
5816
5993
|
if (!isNumber(left.type) || !isNumber(right.type)) {
|
|
5817
|
-
return fail(operator, "a number", left.type, right.type,
|
|
5994
|
+
return fail(operator, "a number", left.type, right.type, describe2);
|
|
5818
5995
|
}
|
|
5819
5996
|
return { evaluated: numberValue(arithmetic(operator, left.value, right.value)), error: null };
|
|
5820
5997
|
}
|
|
5821
|
-
function applyUnary(operator, operand,
|
|
5998
|
+
function applyUnary(operator, operand, describe2) {
|
|
5822
5999
|
if (operator === "not") {
|
|
5823
6000
|
return { evaluated: booleanValue(!isTruthy(operand.value)), error: null };
|
|
5824
6001
|
}
|
|
5825
6002
|
if (operator === "-") {
|
|
5826
6003
|
if (!isNumber(operand.type)) {
|
|
5827
|
-
return { evaluated: null, error: `"-" expects a number but received ${
|
|
6004
|
+
return { evaluated: null, error: `"-" expects a number but received ${describe2(operand.type)}.` };
|
|
5828
6005
|
}
|
|
5829
6006
|
return { evaluated: numberValue(-operand.value), error: null };
|
|
5830
6007
|
}
|
|
@@ -6283,8 +6460,8 @@ var RuleWalk = class {
|
|
|
6283
6460
|
}
|
|
6284
6461
|
};
|
|
6285
6462
|
function normalizeManifest(value, positions) {
|
|
6286
|
-
const
|
|
6287
|
-
return { value:
|
|
6463
|
+
const walk4 = new RuleWalk(positions);
|
|
6464
|
+
return { value: walk4.fields(MANIFEST_FIELDS, value, "", ""), diagnostics: walk4.diagnostics };
|
|
6288
6465
|
}
|
|
6289
6466
|
|
|
6290
6467
|
// ../compiler/src/manifest/manifest-analysis.ts
|
|
@@ -6520,6 +6697,7 @@ function validateConfig(value, positions) {
|
|
|
6520
6697
|
sources: readSourceMapping(value),
|
|
6521
6698
|
assets: readAssetMappings(value),
|
|
6522
6699
|
dependencies,
|
|
6700
|
+
contracts: readString(value, "contracts") ?? "",
|
|
6523
6701
|
engine: readEngine(value),
|
|
6524
6702
|
environment: readEnvironmentFiles(value),
|
|
6525
6703
|
outDir: readString(value, "outDir") ?? "",
|
|
@@ -6584,7 +6762,7 @@ import { tmpdir } from "node:os";
|
|
|
6584
6762
|
import { join as join2 } from "node:path";
|
|
6585
6763
|
|
|
6586
6764
|
// src/cli/version.ts
|
|
6587
|
-
var VERSION = true ? "0.19.
|
|
6765
|
+
var VERSION = true ? "0.19.2" : "0.0.0-dev";
|
|
6588
6766
|
var PROGRAM_NAME = "luam";
|
|
6589
6767
|
var PROGRAM_DESCRIPTION = "luam \u2014 the Luam compiler for Multi Theft Auto resources.";
|
|
6590
6768
|
|
|
@@ -6769,9 +6947,9 @@ function pluralize(count, singular, plural = `${singular}s`) {
|
|
|
6769
6947
|
var MAX_ENTRIES_PER_FILE = 10;
|
|
6770
6948
|
var MAX_FILES = 10;
|
|
6771
6949
|
var GUTTER_WIDTH = 6;
|
|
6772
|
-
function groupByFile(
|
|
6950
|
+
function groupByFile(entries3) {
|
|
6773
6951
|
const groups = /* @__PURE__ */ new Map();
|
|
6774
|
-
for (const entry of
|
|
6952
|
+
for (const entry of entries3) {
|
|
6775
6953
|
const group = groups.get(entry.path);
|
|
6776
6954
|
if (group === void 0) {
|
|
6777
6955
|
groups.set(entry.path, [entry]);
|
|
@@ -6818,19 +6996,19 @@ function emit(reporter, entry, block) {
|
|
|
6818
6996
|
}
|
|
6819
6997
|
reporter.rawWarn(block);
|
|
6820
6998
|
}
|
|
6821
|
-
function reportGroup(reporter, path,
|
|
6999
|
+
function reportGroup(reporter, path, entries3, options) {
|
|
6822
7000
|
const limit = options.maxPerFile ?? MAX_ENTRIES_PER_FILE;
|
|
6823
7001
|
const source = options.sources.get(path);
|
|
6824
7002
|
reporter.raw(reporter.style.paint("strong", path));
|
|
6825
|
-
for (const entry of
|
|
7003
|
+
for (const entry of entries3.slice(0, limit)) {
|
|
6826
7004
|
emit(reporter, entry, entryBlock(reporter, entry, source));
|
|
6827
7005
|
}
|
|
6828
|
-
if (
|
|
6829
|
-
reporter.detail(` ... and ${pluralize(
|
|
7006
|
+
if (entries3.length > limit) {
|
|
7007
|
+
reporter.detail(` ... and ${pluralize(entries3.length - limit, "more diagnostic")} in this file.`);
|
|
6830
7008
|
}
|
|
6831
7009
|
}
|
|
6832
|
-
function reportGroupedDiagnostics(reporter,
|
|
6833
|
-
const groups = [...groupByFile(
|
|
7010
|
+
function reportGroupedDiagnostics(reporter, entries3, options) {
|
|
7011
|
+
const groups = [...groupByFile(entries3)];
|
|
6834
7012
|
const limit = options.maxFiles ?? MAX_FILES;
|
|
6835
7013
|
for (const [path, group] of groups.slice(0, limit)) {
|
|
6836
7014
|
reportGroup(reporter, path, group, options);
|
|
@@ -6846,9 +7024,9 @@ function formatFileDiagnostic(entry) {
|
|
|
6846
7024
|
const location = `${path}:${diagnostic.position.line}:${diagnostic.position.column}`;
|
|
6847
7025
|
return `${location} ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}`;
|
|
6848
7026
|
}
|
|
6849
|
-
function countFileDiagnostics(
|
|
6850
|
-
const errors =
|
|
6851
|
-
return { errors, warnings:
|
|
7027
|
+
function countFileDiagnostics(entries3) {
|
|
7028
|
+
const errors = entries3.filter((entry) => entry.diagnostic.severity === "error").length;
|
|
7029
|
+
return { errors, warnings: entries3.length - errors };
|
|
6852
7030
|
}
|
|
6853
7031
|
function countCliDiagnostics(diagnostics) {
|
|
6854
7032
|
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
|
|
@@ -6858,8 +7036,8 @@ function reportManifestDiagnostics(reporter, path, source, diagnostics) {
|
|
|
6858
7036
|
if (diagnostics.length === 0) {
|
|
6859
7037
|
return;
|
|
6860
7038
|
}
|
|
6861
|
-
const
|
|
6862
|
-
reportFileDiagnostics(reporter,
|
|
7039
|
+
const entries3 = diagnostics.map((diagnostic) => ({ path, diagnostic }));
|
|
7040
|
+
reportFileDiagnostics(reporter, entries3, /* @__PURE__ */ new Map([[path, source]]));
|
|
6863
7041
|
}
|
|
6864
7042
|
function reportCliDiagnostics(reporter, diagnostics) {
|
|
6865
7043
|
for (const diagnostic of diagnostics) {
|
|
@@ -6871,8 +7049,8 @@ function reportCliDiagnostics(reporter, diagnostics) {
|
|
|
6871
7049
|
reporter.warn(line2);
|
|
6872
7050
|
}
|
|
6873
7051
|
}
|
|
6874
|
-
function reportPlainFileDiagnostics(reporter,
|
|
6875
|
-
for (const entry of
|
|
7052
|
+
function reportPlainFileDiagnostics(reporter, entries3) {
|
|
7053
|
+
for (const entry of entries3) {
|
|
6876
7054
|
const line2 = formatFileDiagnostic(entry);
|
|
6877
7055
|
if (entry.diagnostic.severity === "error") {
|
|
6878
7056
|
reporter.rawError(line2);
|
|
@@ -6881,12 +7059,12 @@ function reportPlainFileDiagnostics(reporter, entries2) {
|
|
|
6881
7059
|
reporter.rawWarn(line2);
|
|
6882
7060
|
}
|
|
6883
7061
|
}
|
|
6884
|
-
function reportFileDiagnostics(reporter,
|
|
7062
|
+
function reportFileDiagnostics(reporter, entries3, sources) {
|
|
6885
7063
|
if (!reporter.capability.interactive) {
|
|
6886
|
-
reportPlainFileDiagnostics(reporter,
|
|
7064
|
+
reportPlainFileDiagnostics(reporter, entries3);
|
|
6887
7065
|
return;
|
|
6888
7066
|
}
|
|
6889
|
-
reportGroupedDiagnostics(reporter,
|
|
7067
|
+
reportGroupedDiagnostics(reporter, entries3, { sources });
|
|
6890
7068
|
}
|
|
6891
7069
|
function formatCounts(counts) {
|
|
6892
7070
|
return `${pluralize(counts.errors, "error")}, ${pluralize(counts.warnings, "warning")}`;
|
|
@@ -7137,8 +7315,153 @@ function addProjectOptions(command) {
|
|
|
7137
7315
|
return command.addOption(cwdOption()).addOption(manifestOption()).addOption(colorOption());
|
|
7138
7316
|
}
|
|
7139
7317
|
|
|
7318
|
+
// src/build/contract-files.ts
|
|
7319
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
7320
|
+
import { dirname as dirname2, resolve as resolve4 } from "node:path";
|
|
7321
|
+
|
|
7322
|
+
// ../compiler/src/project/export-abi.ts
|
|
7323
|
+
var ABI_VERSION = 1;
|
|
7324
|
+
var ABI_EXTENSION = ".abi.json";
|
|
7325
|
+
var MAX_ABI_BYTES = 262144;
|
|
7326
|
+
var MAX_EXPORTS = 512;
|
|
7327
|
+
var MAX_PARAMETERS = 32;
|
|
7328
|
+
var MAX_TYPE_LENGTH = 512;
|
|
7329
|
+
var NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7330
|
+
var RESOURCE_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
7331
|
+
var SIDES = /* @__PURE__ */ new Set(["server", "client", "shared"]);
|
|
7332
|
+
function serializeAbi(abi) {
|
|
7333
|
+
const exports = [...abi.exports].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
7334
|
+
return `${JSON.stringify({ abi: abi.abi, resource: abi.resource, exports }, null, 4)}
|
|
7335
|
+
`;
|
|
7336
|
+
}
|
|
7337
|
+
function readString2(value, limit) {
|
|
7338
|
+
return typeof value === "string" && value.length > 0 && value.length <= limit ? value : null;
|
|
7339
|
+
}
|
|
7340
|
+
function readParameter(value) {
|
|
7341
|
+
if (typeof value !== "object" || value === null) {
|
|
7342
|
+
return null;
|
|
7343
|
+
}
|
|
7344
|
+
const entry = value;
|
|
7345
|
+
const name = readString2(entry.name, 64);
|
|
7346
|
+
const type = readString2(entry.type, MAX_TYPE_LENGTH);
|
|
7347
|
+
return name === null || type === null || !NAME_PATTERN.test(name) ? null : { name, type };
|
|
7348
|
+
}
|
|
7349
|
+
function readExport(value) {
|
|
7350
|
+
if (typeof value !== "object" || value === null) {
|
|
7351
|
+
return null;
|
|
7352
|
+
}
|
|
7353
|
+
const entry = value;
|
|
7354
|
+
const name = readString2(entry.name, 128);
|
|
7355
|
+
const side2 = readString2(entry.side, 16);
|
|
7356
|
+
const returns = readString2(entry.returns, MAX_TYPE_LENGTH);
|
|
7357
|
+
const parameters = Array.isArray(entry.parameters) ? entry.parameters : null;
|
|
7358
|
+
if (name === null || !NAME_PATTERN.test(name) || side2 === null || !SIDES.has(side2) || returns === null || parameters === null) {
|
|
7359
|
+
return null;
|
|
7360
|
+
}
|
|
7361
|
+
if (parameters.length > MAX_PARAMETERS) {
|
|
7362
|
+
return null;
|
|
7363
|
+
}
|
|
7364
|
+
const read = parameters.map(readParameter);
|
|
7365
|
+
if (read.some((parameter) => parameter === null)) {
|
|
7366
|
+
return null;
|
|
7367
|
+
}
|
|
7368
|
+
return {
|
|
7369
|
+
name,
|
|
7370
|
+
side: side2,
|
|
7371
|
+
http: entry.http === true,
|
|
7372
|
+
parameters: read,
|
|
7373
|
+
minimumArguments: typeof entry.minimumArguments === "number" && Number.isInteger(entry.minimumArguments) ? entry.minimumArguments : 0,
|
|
7374
|
+
variadic: entry.variadic === true,
|
|
7375
|
+
returns
|
|
7376
|
+
};
|
|
7377
|
+
}
|
|
7378
|
+
function parseResourceAbi(text) {
|
|
7379
|
+
if (text.length > MAX_ABI_BYTES) {
|
|
7380
|
+
return null;
|
|
7381
|
+
}
|
|
7382
|
+
let parsed;
|
|
7383
|
+
try {
|
|
7384
|
+
parsed = JSON.parse(text);
|
|
7385
|
+
} catch {
|
|
7386
|
+
return null;
|
|
7387
|
+
}
|
|
7388
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
7389
|
+
return null;
|
|
7390
|
+
}
|
|
7391
|
+
const document = parsed;
|
|
7392
|
+
const resource = readString2(document.resource, 64);
|
|
7393
|
+
const entries3 = Array.isArray(document.exports) ? document.exports : null;
|
|
7394
|
+
if (document.abi !== ABI_VERSION || resource === null || !RESOURCE_PATTERN.test(resource) || entries3 === null || entries3.length > MAX_EXPORTS) {
|
|
7395
|
+
return null;
|
|
7396
|
+
}
|
|
7397
|
+
const read = entries3.map(readExport);
|
|
7398
|
+
if (read.some((entry) => entry === null)) {
|
|
7399
|
+
return null;
|
|
7400
|
+
}
|
|
7401
|
+
return { abi: ABI_VERSION, resource, exports: read };
|
|
7402
|
+
}
|
|
7403
|
+
function abiFileName(resource) {
|
|
7404
|
+
return `${resource}${ABI_EXTENSION}`;
|
|
7405
|
+
}
|
|
7406
|
+
function lookupAbiExport(contracts, resource, name) {
|
|
7407
|
+
return contracts.find((entry) => entry.resource === resource)?.exports.find((entry) => entry.name === name) ?? null;
|
|
7408
|
+
}
|
|
7409
|
+
function knowsResource(contracts, resource) {
|
|
7410
|
+
return contracts.some((entry) => entry.resource === resource);
|
|
7411
|
+
}
|
|
7412
|
+
function buildResourceAbi(resource, contributions) {
|
|
7413
|
+
const exports = contributions.map((contribution) => {
|
|
7414
|
+
const signature = contribution.signature;
|
|
7415
|
+
return {
|
|
7416
|
+
name: contribution.name,
|
|
7417
|
+
side: contribution.side,
|
|
7418
|
+
http: contribution.http,
|
|
7419
|
+
parameters: signature?.parameters ?? [],
|
|
7420
|
+
minimumArguments: signature?.minimumArguments ?? 0,
|
|
7421
|
+
variadic: signature?.variadic ?? true,
|
|
7422
|
+
returns: signature?.returns ?? "any"
|
|
7423
|
+
};
|
|
7424
|
+
});
|
|
7425
|
+
return { abi: ABI_VERSION, resource, exports };
|
|
7426
|
+
}
|
|
7427
|
+
|
|
7428
|
+
// src/build/contract-files.ts
|
|
7429
|
+
function contractPath(root, config, resource) {
|
|
7430
|
+
return resolve4(root, config.contracts, abiFileName(resource));
|
|
7431
|
+
}
|
|
7432
|
+
function readDependencyContracts(root, config) {
|
|
7433
|
+
const contracts = [];
|
|
7434
|
+
const diagnostics = [];
|
|
7435
|
+
for (const dependency of config.dependencies) {
|
|
7436
|
+
const path = contractPath(root, config, dependency);
|
|
7437
|
+
let text;
|
|
7438
|
+
try {
|
|
7439
|
+
text = readFileSync3(path, "utf8");
|
|
7440
|
+
} catch {
|
|
7441
|
+
continue;
|
|
7442
|
+
}
|
|
7443
|
+
const parsed = parseResourceAbi(text);
|
|
7444
|
+
if (parsed === null) {
|
|
7445
|
+
diagnostics.push(cliWarning("build-invalid-contract", `The export contract for "${dependency}" at "${path}" could not be read and was ignored.`));
|
|
7446
|
+
continue;
|
|
7447
|
+
}
|
|
7448
|
+
if (parsed.resource !== dependency) {
|
|
7449
|
+
diagnostics.push(cliWarning("build-invalid-contract", `The export contract at "${path}" names resource "${parsed.resource}" and was ignored.`));
|
|
7450
|
+
continue;
|
|
7451
|
+
}
|
|
7452
|
+
contracts.push(parsed);
|
|
7453
|
+
}
|
|
7454
|
+
return { contracts, diagnostics };
|
|
7455
|
+
}
|
|
7456
|
+
function writeResourceContract(root, config, contract) {
|
|
7457
|
+
const path = contractPath(root, config, config.name);
|
|
7458
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
7459
|
+
writeFileSync3(path, serializeAbi(contract), "utf8");
|
|
7460
|
+
return path;
|
|
7461
|
+
}
|
|
7462
|
+
|
|
7140
7463
|
// src/build/helper-files.ts
|
|
7141
|
-
import { existsSync as existsSync3, readFileSync as
|
|
7464
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
7142
7465
|
import { fileURLToPath } from "node:url";
|
|
7143
7466
|
function bundledHelperPath(file) {
|
|
7144
7467
|
return fileURLToPath(new URL(`./lua/${file}`, import.meta.url));
|
|
@@ -7150,7 +7473,7 @@ function resolveHelperPath(helper, file) {
|
|
|
7150
7473
|
return existsSync3(packaged) ? packaged : bundledHelperPath(file);
|
|
7151
7474
|
}
|
|
7152
7475
|
function readHelperSource(helper, file) {
|
|
7153
|
-
return
|
|
7476
|
+
return readFileSync4(resolveHelperPath(helper, file), "utf8");
|
|
7154
7477
|
}
|
|
7155
7478
|
|
|
7156
7479
|
// src/build/build-phase.ts
|
|
@@ -7219,16 +7542,16 @@ function createPhaseTracker(listener = null) {
|
|
|
7219
7542
|
}
|
|
7220
7543
|
|
|
7221
7544
|
// src/build/project-inputs.ts
|
|
7222
|
-
import { existsSync as existsSync4, readFileSync as
|
|
7223
|
-
import { resolve as
|
|
7545
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
7546
|
+
import { resolve as resolve7 } from "node:path";
|
|
7224
7547
|
|
|
7225
7548
|
// src/build/asset-resolution.ts
|
|
7226
7549
|
import { statSync as statSync3 } from "node:fs";
|
|
7227
|
-
import { resolve as
|
|
7550
|
+
import { resolve as resolve6 } from "node:path";
|
|
7228
7551
|
|
|
7229
7552
|
// src/build/project-files.ts
|
|
7230
7553
|
import { readdirSync, statSync as statSync2 } from "node:fs";
|
|
7231
|
-
import { join as join3, relative, resolve as
|
|
7554
|
+
import { join as join3, relative, resolve as resolve5 } from "node:path";
|
|
7232
7555
|
function isDirectory(path) {
|
|
7233
7556
|
try {
|
|
7234
7557
|
return statSync2(path).isDirectory();
|
|
@@ -7240,14 +7563,14 @@ function relativePath(root, absolute) {
|
|
|
7240
7563
|
return normalizePattern(relative(root, absolute));
|
|
7241
7564
|
}
|
|
7242
7565
|
function walk(root, directory, excluded, tree) {
|
|
7243
|
-
let
|
|
7566
|
+
let entries3;
|
|
7244
7567
|
try {
|
|
7245
|
-
|
|
7568
|
+
entries3 = readdirSync(directory, { withFileTypes: true });
|
|
7246
7569
|
} catch (error) {
|
|
7247
7570
|
tree.errors.push(`"${relativePath(root, directory)}" could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
7248
7571
|
return;
|
|
7249
7572
|
}
|
|
7250
|
-
for (const entry of
|
|
7573
|
+
for (const entry of entries3) {
|
|
7251
7574
|
const absolute = join3(directory, entry.name);
|
|
7252
7575
|
const path = relativePath(root, absolute);
|
|
7253
7576
|
if (path.length === 0 || isExcludedPath(path, excluded)) {
|
|
@@ -7264,7 +7587,7 @@ function listProjectFiles(root, roots, excluded = []) {
|
|
|
7264
7587
|
const tree = { files: [], errors: [] };
|
|
7265
7588
|
const seen = /* @__PURE__ */ new Set();
|
|
7266
7589
|
for (const start of [...new Set(roots)].sort()) {
|
|
7267
|
-
const absolute =
|
|
7590
|
+
const absolute = resolve5(root, start);
|
|
7268
7591
|
if (!isDirectory(absolute) || seen.has(absolute)) {
|
|
7269
7592
|
continue;
|
|
7270
7593
|
}
|
|
@@ -7408,9 +7731,23 @@ var OCCUPIED_SIDES = {
|
|
|
7408
7731
|
function occupiedSides(contribution) {
|
|
7409
7732
|
return OCCUPIED_SIDES[contribution.side];
|
|
7410
7733
|
}
|
|
7411
|
-
function
|
|
7734
|
+
function exportSignature(type) {
|
|
7735
|
+
if (type === void 0 || type.kind !== "function") {
|
|
7736
|
+
return null;
|
|
7737
|
+
}
|
|
7738
|
+
const parameters = type.parameters.map((parameter, index) => ({ name: type.parameterNames?.[index] ?? `arg${index + 1}`, type: typeToString(parameter) }));
|
|
7739
|
+
return { parameters, minimumArguments: type.minimumArguments, variadic: type.isVariadic, returns: typeToString(type.returnType) };
|
|
7740
|
+
}
|
|
7741
|
+
function toContributions(directives, environment, globals) {
|
|
7412
7742
|
return directives.exports.map(
|
|
7413
|
-
(entry) => ({
|
|
7743
|
+
(entry) => ({
|
|
7744
|
+
kind: "export",
|
|
7745
|
+
name: entry.name,
|
|
7746
|
+
http: entry.http,
|
|
7747
|
+
side: environment,
|
|
7748
|
+
signature: exportSignature(globals.get(entry.name)),
|
|
7749
|
+
position: entry.position
|
|
7750
|
+
})
|
|
7414
7751
|
);
|
|
7415
7752
|
}
|
|
7416
7753
|
var INDENT = " ";
|
|
@@ -7444,8 +7781,8 @@ function attribute(name, value) {
|
|
|
7444
7781
|
function textElement(name, value) {
|
|
7445
7782
|
return `${INDENT}<${name}>${escapeXml(value)}</${name}>`;
|
|
7446
7783
|
}
|
|
7447
|
-
function section(text,
|
|
7448
|
-
return
|
|
7784
|
+
function section(text, entries3) {
|
|
7785
|
+
return entries3.length === 0 ? [] : [`${INDENT}<!-- ${text} -->`, ...entries3];
|
|
7449
7786
|
}
|
|
7450
7787
|
function infoElement(info) {
|
|
7451
7788
|
const attributes = info.author === void 0 ? [] : [attribute("author", info.author)];
|
|
@@ -7573,12 +7910,12 @@ var MISSING_LOAD_ORDER = 'is listed in "loadOrder" but no source file or asset m
|
|
|
7573
7910
|
function missingEntry(entry) {
|
|
7574
7911
|
return { path: entry, diagnostic: createDiagnostic("project", "project-load-order-missing", `"${entry}" ${MISSING_LOAD_ORDER}`, FILE_START) };
|
|
7575
7912
|
}
|
|
7576
|
-
function resolveLoadOrder(
|
|
7913
|
+
function resolveLoadOrder(entries3, scripts, assets) {
|
|
7577
7914
|
const byScript = new Map(scripts.map((script) => [normalizePath(script.source), script]));
|
|
7578
7915
|
const byAsset = new Map(assets.map((asset) => [normalizePath(asset.source), asset]));
|
|
7579
7916
|
const resolved2 = { scripts: [], assets: [], diagnostics: [] };
|
|
7580
7917
|
const seen = /* @__PURE__ */ new Set();
|
|
7581
|
-
for (const entry of
|
|
7918
|
+
for (const entry of entries3) {
|
|
7582
7919
|
const path = normalizePath(entry).replace(/^\.\//, "");
|
|
7583
7920
|
const script = byScript.get(path);
|
|
7584
7921
|
const asset = byAsset.get(path);
|
|
@@ -7654,11 +7991,11 @@ var ENTRY = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;
|
|
|
7654
7991
|
var SENSITIVE = /(password|secret|token|key|credential|dsn|private)/i;
|
|
7655
7992
|
var EMPTY_ENV_FILE = { entries: [], errors: [] };
|
|
7656
7993
|
function unquote(raw) {
|
|
7657
|
-
const
|
|
7658
|
-
if (
|
|
7994
|
+
const quote3 = raw.slice(0, 1);
|
|
7995
|
+
if (quote3 !== '"' && quote3 !== "'") {
|
|
7659
7996
|
return null;
|
|
7660
7997
|
}
|
|
7661
|
-
const closing = raw.lastIndexOf(
|
|
7998
|
+
const closing = raw.lastIndexOf(quote3);
|
|
7662
7999
|
return closing > 0 ? raw.slice(1, closing) : null;
|
|
7663
8000
|
}
|
|
7664
8001
|
function stripComment(raw) {
|
|
@@ -7676,7 +8013,7 @@ function classify(raw) {
|
|
|
7676
8013
|
return { value, kind: value.length > 0 && Number.isFinite(Number(value)) ? "number" : "string" };
|
|
7677
8014
|
}
|
|
7678
8015
|
function parseEnvFile(source) {
|
|
7679
|
-
const
|
|
8016
|
+
const entries3 = [];
|
|
7680
8017
|
const errors = [];
|
|
7681
8018
|
source.split(/\r?\n/).forEach((raw, index) => {
|
|
7682
8019
|
const trimmed = raw.trim();
|
|
@@ -7690,9 +8027,9 @@ function parseEnvFile(source) {
|
|
|
7690
8027
|
return;
|
|
7691
8028
|
}
|
|
7692
8029
|
const { value, kind } = classify(match[2]);
|
|
7693
|
-
|
|
8030
|
+
entries3.push({ key: match[1], value, kind, line: line2 });
|
|
7694
8031
|
});
|
|
7695
|
-
return { entries:
|
|
8032
|
+
return { entries: entries3, errors };
|
|
7696
8033
|
}
|
|
7697
8034
|
function isSensitiveKey(key) {
|
|
7698
8035
|
return SENSITIVE.test(key);
|
|
@@ -7858,14 +8195,14 @@ var MANIFEST_OUTPUT = "meta.xml";
|
|
|
7858
8195
|
var HERE = ".";
|
|
7859
8196
|
function isDirectory2(root, path) {
|
|
7860
8197
|
try {
|
|
7861
|
-
return statSync3(
|
|
8198
|
+
return statSync3(resolve6(root, path)).isDirectory();
|
|
7862
8199
|
} catch {
|
|
7863
8200
|
return false;
|
|
7864
8201
|
}
|
|
7865
8202
|
}
|
|
7866
8203
|
function exists(root, path) {
|
|
7867
8204
|
try {
|
|
7868
|
-
statSync3(
|
|
8205
|
+
statSync3(resolve6(root, path));
|
|
7869
8206
|
return true;
|
|
7870
8207
|
} catch {
|
|
7871
8208
|
return false;
|
|
@@ -7933,10 +8270,10 @@ var CONFIGURATION_FILE = "config.lua";
|
|
|
7933
8270
|
var MALFORMED_ENV = "build-env-malformed";
|
|
7934
8271
|
var MISSING_ENV = "config-missing-env-file";
|
|
7935
8272
|
function readTextFile(path) {
|
|
7936
|
-
return existsSync4(path) ?
|
|
8273
|
+
return existsSync4(path) ? readFileSync5(path, "utf8") : null;
|
|
7937
8274
|
}
|
|
7938
8275
|
function readEnvironment(root, file, required, diagnostics) {
|
|
7939
|
-
const source = readTextFile(
|
|
8276
|
+
const source = readTextFile(resolve7(root, file));
|
|
7940
8277
|
if (source === null) {
|
|
7941
8278
|
if (required) {
|
|
7942
8279
|
diagnostics.push(cliError(MISSING_ENV, `"${file}" is configured under "environment" but does not exist. Create it or remove the setting.`));
|
|
@@ -7950,7 +8287,7 @@ function readEnvironment(root, file, required, diagnostics) {
|
|
|
7950
8287
|
return parsed;
|
|
7951
8288
|
}
|
|
7952
8289
|
function readConfiguration(root, diagnostics) {
|
|
7953
|
-
const content = readTextFile(
|
|
8290
|
+
const content = readTextFile(resolve7(root, CONFIGURATION_FILE));
|
|
7954
8291
|
if (content === null) {
|
|
7955
8292
|
return null;
|
|
7956
8293
|
}
|
|
@@ -7969,14 +8306,14 @@ function readProjectInputs(root, options) {
|
|
|
7969
8306
|
}
|
|
7970
8307
|
|
|
7971
8308
|
// src/build/source-discovery.ts
|
|
7972
|
-
import { readFileSync as
|
|
7973
|
-
import { resolve as
|
|
8309
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
8310
|
+
import { resolve as resolve8 } from "node:path";
|
|
7974
8311
|
|
|
7975
8312
|
// ../compiler/src/project/source-mapping.ts
|
|
7976
8313
|
function createSourceResolver(mapping) {
|
|
7977
8314
|
const matchers = new Map(SOURCE_SIDES.map((environment) => [environment, createPatternMatcher(mapping[environment])]));
|
|
7978
8315
|
const patterns = SOURCE_SIDES.flatMap((environment) => [...matchers.get(environment)?.patterns ?? []]);
|
|
7979
|
-
function
|
|
8316
|
+
function resolve19(path) {
|
|
7980
8317
|
const normalized = normalizePattern(path);
|
|
7981
8318
|
const matches = [];
|
|
7982
8319
|
for (const environment of SOURCE_SIDES) {
|
|
@@ -7990,8 +8327,8 @@ function createSourceResolver(mapping) {
|
|
|
7990
8327
|
return {
|
|
7991
8328
|
patterns,
|
|
7992
8329
|
roots: watchRoots(patterns),
|
|
7993
|
-
resolve:
|
|
7994
|
-
side: (path) =>
|
|
8330
|
+
resolve: resolve19,
|
|
8331
|
+
side: (path) => resolve19(path).environment
|
|
7995
8332
|
};
|
|
7996
8333
|
}
|
|
7997
8334
|
function describeMatches(matches) {
|
|
@@ -8023,7 +8360,7 @@ function checkLiterals(root, resolver, found, diagnostics) {
|
|
|
8023
8360
|
}
|
|
8024
8361
|
function readSource(root, path, diagnostics) {
|
|
8025
8362
|
try {
|
|
8026
|
-
return
|
|
8363
|
+
return readFileSync6(resolve8(root, path), "utf8");
|
|
8027
8364
|
} catch (error) {
|
|
8028
8365
|
diagnostics.push(cliError(UNREADABLE_SOURCE, `The source file "${path}" could not be read: ${error instanceof Error ? error.message : String(error)}`));
|
|
8029
8366
|
return null;
|
|
@@ -8103,25 +8440,26 @@ function fn(parameters, returnType, minimumArguments2, isVariadic = false, param
|
|
|
8103
8440
|
var EMPTY_PROJECT_DECLARATIONS = { globals: [] };
|
|
8104
8441
|
var ENV_GLOBAL = "env";
|
|
8105
8442
|
var VALUE_TYPES = { boolean: BOOLEAN, number: NUMBER, string: STRING };
|
|
8106
|
-
function envMembers(
|
|
8443
|
+
function envMembers(entries3) {
|
|
8107
8444
|
const members = /* @__PURE__ */ new Map();
|
|
8108
|
-
for (const entry of
|
|
8445
|
+
for (const entry of entries3) {
|
|
8109
8446
|
members.set(entry.key, { name: entry.key, type: VALUE_TYPES[entry.kind] });
|
|
8110
8447
|
}
|
|
8111
8448
|
return [...members.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
8112
8449
|
}
|
|
8113
|
-
function envDeclaration(
|
|
8114
|
-
const env = record(ENV_GLOBAL, envMembers(
|
|
8450
|
+
function envDeclaration(entries3, origin) {
|
|
8451
|
+
const env = record(ENV_GLOBAL, envMembers(entries3), origin);
|
|
8115
8452
|
return { name: ENV_GLOBAL, environment: "server", source: "project", type: env };
|
|
8116
8453
|
}
|
|
8117
|
-
function projectDeclarations(
|
|
8118
|
-
if (
|
|
8454
|
+
function projectDeclarations(entries3, origin) {
|
|
8455
|
+
if (entries3 === null) {
|
|
8119
8456
|
return EMPTY_PROJECT_DECLARATIONS;
|
|
8120
8457
|
}
|
|
8121
|
-
return { globals: [envDeclaration(
|
|
8458
|
+
return { globals: [envDeclaration(entries3, origin)] };
|
|
8122
8459
|
}
|
|
8123
8460
|
|
|
8124
8461
|
// ../compiler/src/checker/ambient.ts
|
|
8462
|
+
var EVENT_NAME_PREFIX = "event:";
|
|
8125
8463
|
var EMPTY_AMBIENT = { classes: [], interfaces: [], enums: [], globals: [], events: [] };
|
|
8126
8464
|
function ambientFromRegistry(registry) {
|
|
8127
8465
|
return {
|
|
@@ -8132,9 +8470,9 @@ function ambientFromRegistry(registry) {
|
|
|
8132
8470
|
events: registry.allEvents()
|
|
8133
8471
|
};
|
|
8134
8472
|
}
|
|
8135
|
-
function withoutNames(
|
|
8473
|
+
function withoutNames(entries3, excluded) {
|
|
8136
8474
|
const names = new Set(excluded.map((entry) => entry.name));
|
|
8137
|
-
return
|
|
8475
|
+
return entries3.filter((entry) => !names.has(entry.name));
|
|
8138
8476
|
}
|
|
8139
8477
|
function ownDeclarations(registry, ambient) {
|
|
8140
8478
|
const all = ambientFromRegistry(registry);
|
|
@@ -8311,6 +8649,9 @@ var Binder = class {
|
|
|
8311
8649
|
declaredSymbols() {
|
|
8312
8650
|
return [...this.discarded, ...this.scopes.flatMap((scope) => [...scope.values()])];
|
|
8313
8651
|
}
|
|
8652
|
+
currentScopeNames() {
|
|
8653
|
+
return [...this.scopes[this.scopes.length - 1]?.keys() ?? []];
|
|
8654
|
+
}
|
|
8314
8655
|
declare(symbol) {
|
|
8315
8656
|
const scope = this.scopes[this.scopes.length - 1];
|
|
8316
8657
|
scope?.set(symbol.name, symbol);
|
|
@@ -8349,6 +8690,211 @@ var Binder = class {
|
|
|
8349
8690
|
}
|
|
8350
8691
|
};
|
|
8351
8692
|
|
|
8693
|
+
// ../compiler/src/checker/flow.ts
|
|
8694
|
+
function createFlow() {
|
|
8695
|
+
return { facts: /* @__PURE__ */ new Map(), reachable: true };
|
|
8696
|
+
}
|
|
8697
|
+
function cloneFlow(state) {
|
|
8698
|
+
return { facts: new Map(state.facts), reachable: state.reachable };
|
|
8699
|
+
}
|
|
8700
|
+
function applyFacts(state, facts) {
|
|
8701
|
+
for (const [path, type] of facts) {
|
|
8702
|
+
state.facts.set(path, type);
|
|
8703
|
+
}
|
|
8704
|
+
}
|
|
8705
|
+
function forgetPath(state, path) {
|
|
8706
|
+
for (const key of [...state.facts.keys()]) {
|
|
8707
|
+
if (key === path || key.startsWith(`${path}.`) || path.startsWith(`${key}.`)) {
|
|
8708
|
+
state.facts.delete(key);
|
|
8709
|
+
}
|
|
8710
|
+
}
|
|
8711
|
+
}
|
|
8712
|
+
function joinFlows(states) {
|
|
8713
|
+
const live = states.filter((state) => state.reachable);
|
|
8714
|
+
const [first, ...rest] = live;
|
|
8715
|
+
if (first === void 0) {
|
|
8716
|
+
return { facts: /* @__PURE__ */ new Map(), reachable: false };
|
|
8717
|
+
}
|
|
8718
|
+
const facts = /* @__PURE__ */ new Map();
|
|
8719
|
+
for (const [path, type] of first.facts) {
|
|
8720
|
+
const others = rest.map((state) => state.facts.get(path));
|
|
8721
|
+
if (others.some((other) => other === void 0)) {
|
|
8722
|
+
continue;
|
|
8723
|
+
}
|
|
8724
|
+
facts.set(path, createUnion([type, ...others]));
|
|
8725
|
+
}
|
|
8726
|
+
return { facts, reachable: true };
|
|
8727
|
+
}
|
|
8728
|
+
function optionsOf(declared) {
|
|
8729
|
+
if (declared.kind === "union") {
|
|
8730
|
+
return declared.options;
|
|
8731
|
+
}
|
|
8732
|
+
return declared.kind === "optional" ? [declared.element, NIL_TYPE] : [];
|
|
8733
|
+
}
|
|
8734
|
+
function assignmentFact(narrowed, declared) {
|
|
8735
|
+
const matched = optionsOf(declared).filter((option) => isAssignable(narrowed, option));
|
|
8736
|
+
const [only] = matched;
|
|
8737
|
+
return matched.length === 1 && only !== void 0 ? only : null;
|
|
8738
|
+
}
|
|
8739
|
+
|
|
8740
|
+
// ../compiler/src/checker/type-substitution.ts
|
|
8741
|
+
function substituteType(type, substitutions) {
|
|
8742
|
+
if (type.kind === "named") {
|
|
8743
|
+
const args = type.typeArguments ?? [];
|
|
8744
|
+
if (args.length > 0) {
|
|
8745
|
+
return createNamed(type.name, args.map((argument) => substituteType(argument, substitutions)));
|
|
8746
|
+
}
|
|
8747
|
+
return substitutions.get(type.name) ?? type;
|
|
8748
|
+
}
|
|
8749
|
+
if (type.kind === "array") {
|
|
8750
|
+
return createArray(substituteType(type.element, substitutions));
|
|
8751
|
+
}
|
|
8752
|
+
if (type.kind === "map") {
|
|
8753
|
+
return createMap(substituteType(type.key, substitutions), substituteType(type.value, substitutions));
|
|
8754
|
+
}
|
|
8755
|
+
if (type.kind === "optional") {
|
|
8756
|
+
return createOptional(substituteType(type.element, substitutions));
|
|
8757
|
+
}
|
|
8758
|
+
if (type.kind === "union") {
|
|
8759
|
+
return createUnion(type.options.map((option) => substituteType(option, substitutions)));
|
|
8760
|
+
}
|
|
8761
|
+
if (type.kind === "function") {
|
|
8762
|
+
const parameters = type.parameters.map((parameter) => substituteType(parameter, substitutions));
|
|
8763
|
+
const returnType = substituteType(type.returnType, substitutions);
|
|
8764
|
+
const variadicType = type.variadicType === void 0 ? void 0 : substituteType(type.variadicType, substitutions);
|
|
8765
|
+
return createFunction(parameters, returnType, type.minimumArguments, type.isVariadic, type.parameterNames, variadicType);
|
|
8766
|
+
}
|
|
8767
|
+
if (type.kind === "tuple") {
|
|
8768
|
+
return createTuple(type.elements.map((element) => substituteType(element, substitutions)));
|
|
8769
|
+
}
|
|
8770
|
+
if (type.kind === "record") {
|
|
8771
|
+
const members = new Map([...type.members].map(([name, member]) => [name, substituteType(member, substitutions)]));
|
|
8772
|
+
return createRecord(type.name, members, type.origin);
|
|
8773
|
+
}
|
|
8774
|
+
return type;
|
|
8775
|
+
}
|
|
8776
|
+
|
|
8777
|
+
// ../compiler/src/checker/generic-class.ts
|
|
8778
|
+
var MAX_DEPTH = 32;
|
|
8779
|
+
function classSubstitutions(info, typeArguments) {
|
|
8780
|
+
return new Map(info.typeParameters.map((parameter, index) => [parameter, typeArguments[index] ?? ANY_TYPE]));
|
|
8781
|
+
}
|
|
8782
|
+
function parentSubstitutions(registry, info, current) {
|
|
8783
|
+
const parent = info.superClass === null ? null : registry.lookupClass(info.superClass);
|
|
8784
|
+
if (parent === null) {
|
|
8785
|
+
return null;
|
|
8786
|
+
}
|
|
8787
|
+
return classSubstitutions(parent, info.superArguments.map((argument) => substituteType(argument, current)));
|
|
8788
|
+
}
|
|
8789
|
+
function substitutionsFor(registry, receiver, owner) {
|
|
8790
|
+
const info = registry.lookupClass(receiver.name);
|
|
8791
|
+
if (info === null) {
|
|
8792
|
+
return /* @__PURE__ */ new Map();
|
|
8793
|
+
}
|
|
8794
|
+
let current = info;
|
|
8795
|
+
let substitutions = classSubstitutions(info, receiver.typeArguments ?? []);
|
|
8796
|
+
for (let depth = 0; current !== null && depth < MAX_DEPTH; depth += 1) {
|
|
8797
|
+
if (current.name === owner) {
|
|
8798
|
+
return substitutions;
|
|
8799
|
+
}
|
|
8800
|
+
const next = parentSubstitutions(registry, current, substitutions);
|
|
8801
|
+
if (next === null) {
|
|
8802
|
+
return /* @__PURE__ */ new Map();
|
|
8803
|
+
}
|
|
8804
|
+
substitutions = next;
|
|
8805
|
+
current = current.superClass === null ? null : registry.lookupClass(current.superClass);
|
|
8806
|
+
}
|
|
8807
|
+
return /* @__PURE__ */ new Map();
|
|
8808
|
+
}
|
|
8809
|
+
function specializeMember(context, receiver, member, property) {
|
|
8810
|
+
const owner = context.declarations.lookupMemberOwner(receiver.name, property);
|
|
8811
|
+
if (owner === null || owner === receiver.name) {
|
|
8812
|
+
const own = context.declarations.lookupClass(receiver.name);
|
|
8813
|
+
if (own === null || own.typeParameters.length === 0 || (receiver.typeArguments ?? []).length === 0) {
|
|
8814
|
+
return member;
|
|
8815
|
+
}
|
|
8816
|
+
return { ...member, type: substituteType(member.type, classSubstitutions(own, receiver.typeArguments ?? [])) };
|
|
8817
|
+
}
|
|
8818
|
+
return { ...member, type: substituteType(member.type, substitutionsFor(context.declarations, receiver, owner)) };
|
|
8819
|
+
}
|
|
8820
|
+
function memberOf(context, receiver, property) {
|
|
8821
|
+
const member = context.declarations.lookupMember(receiver.name, property);
|
|
8822
|
+
return member === null ? null : specializeMember(context, receiver, member, property);
|
|
8823
|
+
}
|
|
8824
|
+
function unify(parameter, argument, names, bindings) {
|
|
8825
|
+
if (parameter.kind === "named" && names.has(parameter.name)) {
|
|
8826
|
+
if (!bindings.has(parameter.name) && argument.kind !== "nil") {
|
|
8827
|
+
bindings.set(parameter.name, argument);
|
|
8828
|
+
}
|
|
8829
|
+
return;
|
|
8830
|
+
}
|
|
8831
|
+
if (parameter.kind === "array" && argument.kind === "array") {
|
|
8832
|
+
unify(parameter.element, argument.element, names, bindings);
|
|
8833
|
+
return;
|
|
8834
|
+
}
|
|
8835
|
+
if (parameter.kind === "optional") {
|
|
8836
|
+
unify(parameter.element, argument.kind === "optional" ? argument.element : argument, names, bindings);
|
|
8837
|
+
return;
|
|
8838
|
+
}
|
|
8839
|
+
if (parameter.kind === "map" && argument.kind === "map") {
|
|
8840
|
+
unify(parameter.key, argument.key, names, bindings);
|
|
8841
|
+
unify(parameter.value, argument.value, names, bindings);
|
|
8842
|
+
return;
|
|
8843
|
+
}
|
|
8844
|
+
if (parameter.kind === "named" && argument.kind === "named" && parameter.name === argument.name) {
|
|
8845
|
+
const parameterArguments = parameter.typeArguments ?? [];
|
|
8846
|
+
const argumentArguments = argument.typeArguments ?? [];
|
|
8847
|
+
parameterArguments.forEach((entry, index) => unify(entry, argumentArguments[index] ?? ANY_TYPE, names, bindings));
|
|
8848
|
+
return;
|
|
8849
|
+
}
|
|
8850
|
+
if (parameter.kind === "function" && argument.kind === "function") {
|
|
8851
|
+
parameter.parameters.forEach((entry, index) => unify(entry, argument.parameters[index] ?? ANY_TYPE, names, bindings));
|
|
8852
|
+
unify(parameter.returnType, argument.returnType, names, bindings);
|
|
8853
|
+
}
|
|
8854
|
+
}
|
|
8855
|
+
function inferTypeArguments(typeParameters, parameters, args) {
|
|
8856
|
+
const names = new Set(typeParameters);
|
|
8857
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
8858
|
+
parameters.forEach((parameter, index) => {
|
|
8859
|
+
const argument = args[index];
|
|
8860
|
+
if (argument !== void 0) {
|
|
8861
|
+
unify(parameter, widenInferred(argument), names, bindings);
|
|
8862
|
+
}
|
|
8863
|
+
});
|
|
8864
|
+
return typeParameters.map((parameter) => bindings.get(parameter) ?? ANY_TYPE);
|
|
8865
|
+
}
|
|
8866
|
+
function inheritsFrom(context, name, target) {
|
|
8867
|
+
let current = context.declarations.lookupClass(name);
|
|
8868
|
+
for (let depth = 0; current !== null && depth < MAX_DEPTH; depth += 1) {
|
|
8869
|
+
if (current.name === target || current.interfaces.includes(target)) {
|
|
8870
|
+
return true;
|
|
8871
|
+
}
|
|
8872
|
+
current = current.superClass === null ? null : context.declarations.lookupClass(current.superClass);
|
|
8873
|
+
}
|
|
8874
|
+
return context.declarations.interfaceExtends(name, target);
|
|
8875
|
+
}
|
|
8876
|
+
function satisfies(context, argument, constraint) {
|
|
8877
|
+
if (argument.kind === "named" && constraint.kind === "named") {
|
|
8878
|
+
return argument.name === constraint.name || inheritsFrom(context, argument.name, constraint.name);
|
|
8879
|
+
}
|
|
8880
|
+
return isAssignable(argument, constraint, { allowNil: false });
|
|
8881
|
+
}
|
|
8882
|
+
function checkTypeConstraints(context, name, typeArguments, position2) {
|
|
8883
|
+
const info = context.declarations.lookupClass(name);
|
|
8884
|
+
if (info === null) {
|
|
8885
|
+
return;
|
|
8886
|
+
}
|
|
8887
|
+
info.typeConstraints.forEach((constraint, index) => {
|
|
8888
|
+
const argument = typeArguments[index];
|
|
8889
|
+
if (constraint === null || argument === void 0 || argument.kind === "any" || satisfies(context, argument, constraint)) {
|
|
8890
|
+
return;
|
|
8891
|
+
}
|
|
8892
|
+
const parameter = info.typeParameters[index] ?? "T";
|
|
8893
|
+
const message = `Type argument "${typeToString(argument)}" does not satisfy "${parameter} extends ${typeToString(constraint)}" on class "${name}".`;
|
|
8894
|
+
context.report("check-generic-constraint", message, position2);
|
|
8895
|
+
});
|
|
8896
|
+
}
|
|
8897
|
+
|
|
8352
8898
|
// ../mta-types/src/lua-standard.ts
|
|
8353
8899
|
var LUA_GLOBALS = {
|
|
8354
8900
|
_G: TABLE,
|
|
@@ -8455,8 +9001,8 @@ var MTA_AUDIO_CLIENT = {
|
|
|
8455
9001
|
isSoundPaused: fn([named("Element")], BOOLEAN, 1),
|
|
8456
9002
|
playSFX: fn([STRING, NUMBER, NUMBER, BOOLEAN], named("Element"), 3),
|
|
8457
9003
|
playSFX3D: fn([STRING, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN], named("Element"), 6),
|
|
8458
|
-
playSound: fn([STRING, BOOLEAN, BOOLEAN], named("
|
|
8459
|
-
playSound3D: fn([STRING, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("
|
|
9004
|
+
playSound: fn([STRING, BOOLEAN, BOOLEAN], named("Sound"), 1),
|
|
9005
|
+
playSound3D: fn([STRING, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("Sound3D"), 4),
|
|
8460
9006
|
playSoundFrontEnd: fn([NUMBER], BOOLEAN, 1),
|
|
8461
9007
|
setRadioChannel: fn([NUMBER], BOOLEAN, 1),
|
|
8462
9008
|
setSoundEffectEnabled: fn(
|
|
@@ -8521,7 +9067,7 @@ var MTA_BLIP_CLIENT = {
|
|
|
8521
9067
|
var MTA_BROWSER_CLIENT = {
|
|
8522
9068
|
canBrowserNavigateBack: fn([named("Browser")], BOOLEAN, 1),
|
|
8523
9069
|
canBrowserNavigateForward: fn([named("Browser")], BOOLEAN, 1),
|
|
8524
|
-
createBrowser: fn([NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("
|
|
9070
|
+
createBrowser: fn([NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("Browser"), 3),
|
|
8525
9071
|
executeBrowserJavascript: fn([named("Browser"), STRING], BOOLEAN, 2),
|
|
8526
9072
|
focusBrowser: fn([named("Browser")], BOOLEAN, 1),
|
|
8527
9073
|
getBrowserProperty: fn([named("Browser"), STRING], BOOLEAN, 2),
|
|
@@ -8611,10 +9157,10 @@ var MTA_DISCORD_CLIENT = {
|
|
|
8611
9157
|
// ../mta-types/src/generated/api/mta-drawing-client.ts
|
|
8612
9158
|
var MTA_DRAWING_CLIENT = {
|
|
8613
9159
|
dxConvertPixels: fn([STRING, STRING, NUMBER], STRING, 2),
|
|
8614
|
-
dxCreateFont: fn([STRING, NUMBER, BOOLEAN, STRING], named("
|
|
8615
|
-
dxCreateRenderTarget: fn([NUMBER, NUMBER, BOOLEAN], named("
|
|
8616
|
-
dxCreateScreenSource: fn([NUMBER, NUMBER], named("
|
|
8617
|
-
dxCreateShader: fn([STRING, NUMBER, NUMBER, BOOLEAN, STRING], tupleOf([named("
|
|
9160
|
+
dxCreateFont: fn([STRING, NUMBER, BOOLEAN, STRING], named("DxFont"), 1),
|
|
9161
|
+
dxCreateRenderTarget: fn([NUMBER, NUMBER, BOOLEAN], named("DxRenderTarget"), 2),
|
|
9162
|
+
dxCreateScreenSource: fn([NUMBER, NUMBER], named("DxScreenSource"), 2),
|
|
9163
|
+
dxCreateShader: fn([STRING, NUMBER, NUMBER, BOOLEAN, STRING], tupleOf([named("DxShader"), STRING]), 1),
|
|
8618
9164
|
dxCreateTexture: fn(
|
|
8619
9165
|
[
|
|
8620
9166
|
STRING,
|
|
@@ -9232,22 +9778,22 @@ var MTA_GUI_CLIENT = {
|
|
|
9232
9778
|
guiComboBoxSetOpen: fn([named("Element"), BOOLEAN], BOOLEAN, 2),
|
|
9233
9779
|
guiComboBoxSetSelected: fn([named("Element"), NUMBER], BOOLEAN, 2),
|
|
9234
9780
|
guiCreateBrowser: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN, BOOLEAN, named("GuiElement")], named("GuiBrowser"), 6),
|
|
9235
|
-
guiCreateButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("
|
|
9236
|
-
guiCreateCheckBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, BOOLEAN, named("GuiElement")], named("
|
|
9237
|
-
guiCreateComboBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("
|
|
9238
|
-
guiCreateEdit: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("
|
|
9239
|
-
guiCreateFont: fn([STRING, NUMBER], named("
|
|
9240
|
-
guiCreateGridList: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("
|
|
9241
|
-
guiCreateLabel: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("
|
|
9781
|
+
guiCreateButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiButton"), 5),
|
|
9782
|
+
guiCreateCheckBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, BOOLEAN, named("GuiElement")], named("GuiCheckbox"), 6),
|
|
9783
|
+
guiCreateComboBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiCombobox"), 5),
|
|
9784
|
+
guiCreateEdit: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiEdit"), 5),
|
|
9785
|
+
guiCreateFont: fn([STRING, NUMBER], named("GuiFont"), 1),
|
|
9786
|
+
guiCreateGridList: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("GuiGridList"), 4),
|
|
9787
|
+
guiCreateLabel: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiLabel"), 5),
|
|
9242
9788
|
guiCreateMemo: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiMemo"), 5),
|
|
9243
9789
|
guiCreateProgressBar: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("Element"), 4),
|
|
9244
|
-
guiCreateRadioButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("
|
|
9790
|
+
guiCreateRadioButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiRadioButton"), 5),
|
|
9245
9791
|
guiCreateScrollBar: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN, named("GuiElement")], named("GuiElement"), 5),
|
|
9246
9792
|
guiCreateScrollPane: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("Element"), 4),
|
|
9247
|
-
guiCreateStaticImage: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("
|
|
9248
|
-
guiCreateTab: fn([STRING, named("GuiElement")], named("
|
|
9249
|
-
guiCreateTabPanel: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("
|
|
9250
|
-
guiCreateWindow: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN], named("
|
|
9793
|
+
guiCreateStaticImage: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiStaticImage"), 5),
|
|
9794
|
+
guiCreateTab: fn([STRING, named("GuiElement")], named("GuiTab"), 2),
|
|
9795
|
+
guiCreateTabPanel: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("GuiTabPanel"), 4),
|
|
9796
|
+
guiCreateWindow: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN], named("GuiWindow"), 5),
|
|
9251
9797
|
guiDeleteTab: fn([named("Element"), named("Element")], BOOLEAN, 2),
|
|
9252
9798
|
guiEditGetCaretIndex: fn([named("Element")], NUMBER, 1),
|
|
9253
9799
|
guiEditGetMaxLength: fn([named("GuiEdit")], NUMBER, 1),
|
|
@@ -11590,7 +12136,7 @@ var MTA_OOP_1 = [
|
|
|
11590
12136
|
),
|
|
11591
12137
|
oopClass(
|
|
11592
12138
|
"DxFont",
|
|
11593
|
-
|
|
12139
|
+
"Element",
|
|
11594
12140
|
[
|
|
11595
12141
|
oopMethod("getHeight", "client", "dxGetFontHeight", fn([NUMBER, ANY], NUMBER, 0)),
|
|
11596
12142
|
oopMethod("getSize", "client", "dxGetTextSize", fn([STRING, NUMBER, NUMBER, NUMBER, ANY, BOOLEAN, BOOLEAN], tupleOf([NUMBER, NUMBER]), 1)),
|
|
@@ -11601,14 +12147,14 @@ var MTA_OOP_1 = [
|
|
|
11601
12147
|
),
|
|
11602
12148
|
oopClass(
|
|
11603
12149
|
"DxRenderTarget",
|
|
11604
|
-
|
|
12150
|
+
"Element",
|
|
11605
12151
|
[],
|
|
11606
12152
|
[],
|
|
11607
12153
|
oopConstructor("client", fn([NUMBER, NUMBER, BOOLEAN], named("DxRenderTarget"), 2), "dxCreateRenderTarget")
|
|
11608
12154
|
),
|
|
11609
12155
|
oopClass(
|
|
11610
12156
|
"DxScreenSource",
|
|
11611
|
-
|
|
12157
|
+
"Element",
|
|
11612
12158
|
[
|
|
11613
12159
|
oopMethod("update", "client", "dxUpdateScreenSource", fn([BOOLEAN], BOOLEAN, 0))
|
|
11614
12160
|
],
|
|
@@ -11621,14 +12167,14 @@ var MTA_OOP_1 = [
|
|
|
11621
12167
|
var MTA_OOP_2 = [
|
|
11622
12168
|
oopClass(
|
|
11623
12169
|
"DxShader",
|
|
11624
|
-
|
|
12170
|
+
"Element",
|
|
11625
12171
|
[],
|
|
11626
12172
|
[],
|
|
11627
12173
|
oopConstructor("client", fn([STRING, NUMBER, NUMBER, BOOLEAN, STRING], named("DxShader"), 1), "dxCreateShader")
|
|
11628
12174
|
),
|
|
11629
12175
|
oopClass(
|
|
11630
12176
|
"DxTexture",
|
|
11631
|
-
|
|
12177
|
+
"Element",
|
|
11632
12178
|
[
|
|
11633
12179
|
oopMethod("getPixels", "client", "dxGetTexturePixels", fn([ANY, ANY, NUMBER, NUMBER, NUMBER, ANY], STRING, 1)),
|
|
11634
12180
|
oopMethod("setEdge", "client", "dxSetTextureEdge", fn([STRING, NUMBER], BOOLEAN, 1)),
|
|
@@ -11917,7 +12463,7 @@ var MTA_OOP_3 = [
|
|
|
11917
12463
|
),
|
|
11918
12464
|
oopClass(
|
|
11919
12465
|
"GuiButton",
|
|
11920
|
-
|
|
12466
|
+
"GuiElement",
|
|
11921
12467
|
[],
|
|
11922
12468
|
[],
|
|
11923
12469
|
oopConstructor("client", fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("Element")], named("GuiButton"), 6), "guiCreateButton")
|
|
@@ -11974,7 +12520,7 @@ var MTA_OOP_3 = [
|
|
|
11974
12520
|
),
|
|
11975
12521
|
oopClass(
|
|
11976
12522
|
"GuiElement",
|
|
11977
|
-
|
|
12523
|
+
"Element",
|
|
11978
12524
|
[
|
|
11979
12525
|
oopProperty("alpha", "client", "guiGetAlpha", NUMBER),
|
|
11980
12526
|
oopMethod("blur", "client", "guiBlur", fn([], BOOLEAN, 0)),
|
|
@@ -12027,7 +12573,7 @@ var MTA_OOP_3 = [
|
|
|
12027
12573
|
),
|
|
12028
12574
|
oopClass(
|
|
12029
12575
|
"GuiFont",
|
|
12030
|
-
|
|
12576
|
+
"Element",
|
|
12031
12577
|
[],
|
|
12032
12578
|
[],
|
|
12033
12579
|
oopConstructor("client", fn([STRING, NUMBER], named("GuiFont"), 1), "guiCreateFont")
|
|
@@ -12115,7 +12661,7 @@ var MTA_OOP_3 = [
|
|
|
12115
12661
|
),
|
|
12116
12662
|
oopClass(
|
|
12117
12663
|
"GuiRadioButton",
|
|
12118
|
-
|
|
12664
|
+
"GuiElement",
|
|
12119
12665
|
[
|
|
12120
12666
|
oopMethod("getSelected", "client", "guiRadioButtonGetSelected", fn([], BOOLEAN, 0)),
|
|
12121
12667
|
oopProperty("selected", "client", "guiRadioButtonGetSelected", BOOLEAN),
|
|
@@ -12176,7 +12722,7 @@ var MTA_OOP_4 = [
|
|
|
12176
12722
|
),
|
|
12177
12723
|
oopClass(
|
|
12178
12724
|
"Light",
|
|
12179
|
-
|
|
12725
|
+
"Element",
|
|
12180
12726
|
[
|
|
12181
12727
|
oopProperty("color", "client", "getLightColor", tupleOf([NUMBER, NUMBER, NUMBER])),
|
|
12182
12728
|
oopProperty("direction", "client", "getLightDirection", tupleOf([NUMBER, NUMBER, NUMBER])),
|
|
@@ -13186,6 +13732,46 @@ var DeclarationRegistry = class {
|
|
|
13186
13732
|
}
|
|
13187
13733
|
return null;
|
|
13188
13734
|
}
|
|
13735
|
+
lookupMemberOwner(name, member) {
|
|
13736
|
+
const visited = /* @__PURE__ */ new Set();
|
|
13737
|
+
let current = this.lookupClass(name);
|
|
13738
|
+
while (current !== null && !visited.has(current.name)) {
|
|
13739
|
+
if (current.members.has(member)) {
|
|
13740
|
+
return current.name;
|
|
13741
|
+
}
|
|
13742
|
+
visited.add(current.name);
|
|
13743
|
+
current = current.superClass === null ? null : this.lookupClass(current.superClass);
|
|
13744
|
+
}
|
|
13745
|
+
return null;
|
|
13746
|
+
}
|
|
13747
|
+
lookupStaticMember(name, member) {
|
|
13748
|
+
const visited = /* @__PURE__ */ new Set();
|
|
13749
|
+
let current = this.lookupClass(name);
|
|
13750
|
+
while (current !== null && !visited.has(current.name)) {
|
|
13751
|
+
const found = current.statics.get(member);
|
|
13752
|
+
if (found !== void 0) {
|
|
13753
|
+
return found;
|
|
13754
|
+
}
|
|
13755
|
+
visited.add(current.name);
|
|
13756
|
+
current = current.superClass === null ? null : this.lookupClass(current.superClass);
|
|
13757
|
+
}
|
|
13758
|
+
return null;
|
|
13759
|
+
}
|
|
13760
|
+
collectStatics(name) {
|
|
13761
|
+
const collected = /* @__PURE__ */ new Map();
|
|
13762
|
+
const visited = /* @__PURE__ */ new Set();
|
|
13763
|
+
let current = this.lookupClass(name);
|
|
13764
|
+
while (current !== null && !visited.has(current.name)) {
|
|
13765
|
+
for (const [member, info] of current.statics) {
|
|
13766
|
+
if (!collected.has(member)) {
|
|
13767
|
+
collected.set(member, info);
|
|
13768
|
+
}
|
|
13769
|
+
}
|
|
13770
|
+
visited.add(current.name);
|
|
13771
|
+
current = current.superClass === null ? null : this.lookupClass(current.superClass);
|
|
13772
|
+
}
|
|
13773
|
+
return [...collected.values()];
|
|
13774
|
+
}
|
|
13189
13775
|
lookupMember(name, member) {
|
|
13190
13776
|
const visited = /* @__PURE__ */ new Set();
|
|
13191
13777
|
const found = this.lookupClassMember(name, member, visited);
|
|
@@ -13217,7 +13803,17 @@ function buildRegistry() {
|
|
|
13217
13803
|
procedural: member.procedural
|
|
13218
13804
|
});
|
|
13219
13805
|
}
|
|
13220
|
-
registry.declareClass({
|
|
13806
|
+
registry.declareClass({
|
|
13807
|
+
name: declaration.name,
|
|
13808
|
+
typeParameters: [],
|
|
13809
|
+
typeConstraints: [],
|
|
13810
|
+
superClass: declaration.parent,
|
|
13811
|
+
superArguments: [],
|
|
13812
|
+
interfaces: [],
|
|
13813
|
+
members,
|
|
13814
|
+
statics: /* @__PURE__ */ new Map(),
|
|
13815
|
+
position: MTA_POSITION
|
|
13816
|
+
});
|
|
13221
13817
|
}
|
|
13222
13818
|
return registry;
|
|
13223
13819
|
}
|
|
@@ -13304,12 +13900,22 @@ function missingKeys(source, target) {
|
|
|
13304
13900
|
}
|
|
13305
13901
|
return missing2;
|
|
13306
13902
|
}
|
|
13307
|
-
function
|
|
13903
|
+
function expandCandidate(option, resolveNominal) {
|
|
13904
|
+
if (option.kind === "record") {
|
|
13905
|
+
return option;
|
|
13906
|
+
}
|
|
13907
|
+
if (option.kind !== "named") {
|
|
13908
|
+
return null;
|
|
13909
|
+
}
|
|
13910
|
+
const shape = resolveNominal?.(option.name) ?? null;
|
|
13911
|
+
return shape === null || shape.kind !== "interface" ? null : { kind: "record", name: option.name, origin: null, members: shape.members };
|
|
13912
|
+
}
|
|
13913
|
+
function missingKeyHint(source, target, resolveNominal) {
|
|
13308
13914
|
if (source.kind !== "record" || source.isLiteral !== true) {
|
|
13309
13915
|
return "";
|
|
13310
13916
|
}
|
|
13311
13917
|
const options = target.kind === "union" ? target.options : [target];
|
|
13312
|
-
const candidates3 = options.
|
|
13918
|
+
const candidates3 = options.map((option) => expandCandidate(option, resolveNominal)).filter((option) => option !== null);
|
|
13313
13919
|
const candidate = chooseCandidate(source, candidates3);
|
|
13314
13920
|
if (candidate === null) {
|
|
13315
13921
|
return "";
|
|
@@ -13357,39 +13963,6 @@ function mergeIntersection(context, parts, position2) {
|
|
|
13357
13963
|
return createObjectType(members);
|
|
13358
13964
|
}
|
|
13359
13965
|
|
|
13360
|
-
// ../compiler/src/checker/type-substitution.ts
|
|
13361
|
-
function substituteType(type, substitutions) {
|
|
13362
|
-
if (type.kind === "named") {
|
|
13363
|
-
return substitutions.get(type.name) ?? type;
|
|
13364
|
-
}
|
|
13365
|
-
if (type.kind === "array") {
|
|
13366
|
-
return createArray(substituteType(type.element, substitutions));
|
|
13367
|
-
}
|
|
13368
|
-
if (type.kind === "map") {
|
|
13369
|
-
return createMap(substituteType(type.key, substitutions), substituteType(type.value, substitutions));
|
|
13370
|
-
}
|
|
13371
|
-
if (type.kind === "optional") {
|
|
13372
|
-
return createOptional(substituteType(type.element, substitutions));
|
|
13373
|
-
}
|
|
13374
|
-
if (type.kind === "union") {
|
|
13375
|
-
return createUnion(type.options.map((option) => substituteType(option, substitutions)));
|
|
13376
|
-
}
|
|
13377
|
-
if (type.kind === "function") {
|
|
13378
|
-
const parameters = type.parameters.map((parameter) => substituteType(parameter, substitutions));
|
|
13379
|
-
const returnType = substituteType(type.returnType, substitutions);
|
|
13380
|
-
const variadicType = type.variadicType === void 0 ? void 0 : substituteType(type.variadicType, substitutions);
|
|
13381
|
-
return createFunction(parameters, returnType, type.minimumArguments, type.isVariadic, type.parameterNames, variadicType);
|
|
13382
|
-
}
|
|
13383
|
-
if (type.kind === "tuple") {
|
|
13384
|
-
return createTuple(type.elements.map((element) => substituteType(element, substitutions)));
|
|
13385
|
-
}
|
|
13386
|
-
if (type.kind === "record") {
|
|
13387
|
-
const members = new Map([...type.members].map(([name, member]) => [name, substituteType(member, substitutions)]));
|
|
13388
|
-
return createRecord(type.name, members, type.origin);
|
|
13389
|
-
}
|
|
13390
|
-
return type;
|
|
13391
|
-
}
|
|
13392
|
-
|
|
13393
13966
|
// ../compiler/src/checker/context.ts
|
|
13394
13967
|
var BUILTIN_TYPES = {
|
|
13395
13968
|
any: ANY_TYPE,
|
|
@@ -13405,6 +13978,7 @@ var BUILTIN_TYPES = {
|
|
|
13405
13978
|
};
|
|
13406
13979
|
var TABLE_ANNOTATION = "table";
|
|
13407
13980
|
var MAP_ARGUMENTS = 2;
|
|
13981
|
+
var MAX_GENERIC_DEPTH = 8;
|
|
13408
13982
|
var PROJECT_POSITION = { line: 0, column: 0, offset: 0 };
|
|
13409
13983
|
function nilHint(source, target, mode) {
|
|
13410
13984
|
if (mode !== "strict" || source.kind !== "nil" || target.kind === "nil" || target.kind === "optional") {
|
|
@@ -13417,18 +13991,23 @@ var CheckContext = class {
|
|
|
13417
13991
|
declarations = new DeclarationRegistry();
|
|
13418
13992
|
diagnostics = [];
|
|
13419
13993
|
reported = /* @__PURE__ */ new Set();
|
|
13420
|
-
|
|
13994
|
+
flow = createFlow();
|
|
13421
13995
|
types = /* @__PURE__ */ new Map();
|
|
13422
13996
|
references = /* @__PURE__ */ new Set();
|
|
13423
13997
|
declaredGlobals = /* @__PURE__ */ new Map();
|
|
13998
|
+
moduleGlobals = /* @__PURE__ */ new Map();
|
|
13424
13999
|
externalReferences = /* @__PURE__ */ new Map();
|
|
13425
14000
|
unknownTypes = /* @__PURE__ */ new Map();
|
|
14001
|
+
eventReferences = /* @__PURE__ */ new Set();
|
|
14002
|
+
globalReferences = /* @__PURE__ */ new Set();
|
|
13426
14003
|
calledMembers = /* @__PURE__ */ new Set();
|
|
14004
|
+
staticAccess = /* @__PURE__ */ new Set();
|
|
13427
14005
|
typeParameters = /* @__PURE__ */ new Set();
|
|
13428
14006
|
generatedMembers = /* @__PURE__ */ new Map();
|
|
13429
14007
|
mode;
|
|
13430
14008
|
environment;
|
|
13431
14009
|
mtaClasses;
|
|
14010
|
+
contracts = [];
|
|
13432
14011
|
isDeclarationFile = false;
|
|
13433
14012
|
returnStack = [];
|
|
13434
14013
|
methodStack = [];
|
|
@@ -13454,33 +14033,28 @@ var CheckContext = class {
|
|
|
13454
14033
|
declareModuleGlobal(symbol) {
|
|
13455
14034
|
this.binder.declareGlobal(symbol);
|
|
13456
14035
|
this.declaredGlobals.set(symbol.name, symbol.position);
|
|
14036
|
+
this.moduleGlobals.set(symbol.name, symbol.type);
|
|
13457
14037
|
}
|
|
13458
|
-
|
|
13459
|
-
this.
|
|
14038
|
+
get flowState() {
|
|
14039
|
+
return this.flow;
|
|
13460
14040
|
}
|
|
13461
|
-
|
|
13462
|
-
|
|
14041
|
+
setFlow(state) {
|
|
14042
|
+
this.flow = state;
|
|
13463
14043
|
}
|
|
13464
|
-
|
|
13465
|
-
this.
|
|
14044
|
+
applyFlowFacts(facts) {
|
|
14045
|
+
applyFacts(this.flow, facts);
|
|
14046
|
+
}
|
|
14047
|
+
markUnreachable() {
|
|
14048
|
+
this.flow.reachable = false;
|
|
14049
|
+
}
|
|
14050
|
+
get isNarrowed() {
|
|
14051
|
+
return this.flow.facts.size > 0;
|
|
13466
14052
|
}
|
|
13467
14053
|
forgetNarrowing(path) {
|
|
13468
|
-
|
|
13469
|
-
for (const key of [...frame.keys()]) {
|
|
13470
|
-
if (key === path || key.startsWith(`${path}.`) || path.startsWith(`${key}.`)) {
|
|
13471
|
-
frame.delete(key);
|
|
13472
|
-
}
|
|
13473
|
-
}
|
|
13474
|
-
}
|
|
14054
|
+
forgetPath(this.flow, path);
|
|
13475
14055
|
}
|
|
13476
14056
|
narrowedType(path) {
|
|
13477
|
-
|
|
13478
|
-
const found = this.narrowings[index]?.get(path);
|
|
13479
|
-
if (found !== void 0) {
|
|
13480
|
-
return found;
|
|
13481
|
-
}
|
|
13482
|
-
}
|
|
13483
|
-
return null;
|
|
14057
|
+
return this.flow.facts.get(path) ?? null;
|
|
13484
14058
|
}
|
|
13485
14059
|
predeclareClass(info) {
|
|
13486
14060
|
this.predeclared.set(info.name, info);
|
|
@@ -13490,20 +14064,20 @@ var CheckContext = class {
|
|
|
13490
14064
|
this.predeclared.delete(name);
|
|
13491
14065
|
return info;
|
|
13492
14066
|
}
|
|
13493
|
-
|
|
13494
|
-
return this.predeclared.has(name);
|
|
13495
|
-
}
|
|
13496
|
-
awaitsDeclaration(name) {
|
|
14067
|
+
pendingDeclarationOf(name) {
|
|
13497
14068
|
const seen = /* @__PURE__ */ new Set();
|
|
13498
14069
|
let current = this.declarations.lookupClass(name);
|
|
13499
14070
|
while (current !== null && !seen.has(current.name)) {
|
|
13500
14071
|
if (this.predeclared.has(current.name)) {
|
|
13501
|
-
return
|
|
14072
|
+
return current.name;
|
|
13502
14073
|
}
|
|
13503
14074
|
seen.add(current.name);
|
|
13504
14075
|
current = current.superClass === null ? null : this.declarations.lookupClass(current.superClass);
|
|
13505
14076
|
}
|
|
13506
|
-
return
|
|
14077
|
+
return null;
|
|
14078
|
+
}
|
|
14079
|
+
awaitsDeclaration(name) {
|
|
14080
|
+
return this.pendingDeclarationOf(name) !== null;
|
|
13507
14081
|
}
|
|
13508
14082
|
insideFunction() {
|
|
13509
14083
|
return this.returnStack.length > 0;
|
|
@@ -13547,6 +14121,12 @@ var CheckContext = class {
|
|
|
13547
14121
|
isTypeParameter(name) {
|
|
13548
14122
|
return this.typeParameters.has(name);
|
|
13549
14123
|
}
|
|
14124
|
+
noteGlobalReference(name) {
|
|
14125
|
+
this.globalReferences.add(name);
|
|
14126
|
+
}
|
|
14127
|
+
noteEventReference(name) {
|
|
14128
|
+
this.eventReferences.add(name);
|
|
14129
|
+
}
|
|
13550
14130
|
noteUnknownType(name, position2) {
|
|
13551
14131
|
if (!this.unknownTypes.has(name)) {
|
|
13552
14132
|
this.unknownTypes.set(name, position2);
|
|
@@ -13636,17 +14216,57 @@ var CheckContext = class {
|
|
|
13636
14216
|
const parameters = annotation.parameters.map((parameter) => this.resolveAnnotation(parameter));
|
|
13637
14217
|
const optional = parameters.findIndex((parameter) => parameter.kind === "optional");
|
|
13638
14218
|
const minimum = optional === -1 ? parameters.length : optional;
|
|
13639
|
-
return createFunction(parameters, this.resolveAnnotation(annotation.returnType), minimum, annotation.isVariadic);
|
|
14219
|
+
return createFunction(parameters, this.resolveAnnotation(annotation.returnType), minimum, annotation.isVariadic, [...annotation.parameterNames]);
|
|
13640
14220
|
}
|
|
13641
14221
|
return this.resolveNamedAnnotation(annotation.name, annotation.typeArguments, annotation.position);
|
|
13642
14222
|
}
|
|
14223
|
+
nominalShape(name) {
|
|
14224
|
+
const declaredInterface = this.declarations.lookupInterface(name);
|
|
14225
|
+
if (declaredInterface !== null) {
|
|
14226
|
+
const ancestors = this.declarations.allInterfaces().filter((other) => this.declarations.interfaceExtends(name, other.name));
|
|
14227
|
+
return {
|
|
14228
|
+
kind: "interface",
|
|
14229
|
+
members: new Map(this.declarations.collectInterfaceContract(name).map((member) => [member.name, member.type])),
|
|
14230
|
+
ancestors: new Set(ancestors.map((other) => other.name))
|
|
14231
|
+
};
|
|
14232
|
+
}
|
|
14233
|
+
const declaredClass = this.declarations.lookupClass(name);
|
|
14234
|
+
if (declaredClass === null) {
|
|
14235
|
+
return null;
|
|
14236
|
+
}
|
|
14237
|
+
return {
|
|
14238
|
+
kind: "class",
|
|
14239
|
+
members: new Map(this.declarations.collectMembers(name).map((member) => [member.name, member.type])),
|
|
14240
|
+
ancestors: this.classAncestors(name)
|
|
14241
|
+
};
|
|
14242
|
+
}
|
|
14243
|
+
classAncestors(name) {
|
|
14244
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
14245
|
+
let current = this.declarations.lookupClass(name);
|
|
14246
|
+
while (current !== null && !ancestors.has(current.name)) {
|
|
14247
|
+
ancestors.add(current.name);
|
|
14248
|
+
for (const contract of current.interfaces) {
|
|
14249
|
+
ancestors.add(contract);
|
|
14250
|
+
for (const other of this.declarations.allInterfaces()) {
|
|
14251
|
+
if (this.declarations.interfaceExtends(contract, other.name)) {
|
|
14252
|
+
ancestors.add(other.name);
|
|
14253
|
+
}
|
|
14254
|
+
}
|
|
14255
|
+
}
|
|
14256
|
+
current = current.superClass === null ? null : this.declarations.lookupClass(current.superClass);
|
|
14257
|
+
}
|
|
14258
|
+
return ancestors;
|
|
14259
|
+
}
|
|
14260
|
+
assignability() {
|
|
14261
|
+
return { allowNil: this.allowNil, resolveNominal: (name) => this.nominalShape(name) };
|
|
14262
|
+
}
|
|
13643
14263
|
expectAssignable(source, target, position2, subject) {
|
|
13644
|
-
if (isAssignable(source, target,
|
|
14264
|
+
if (isAssignable(source, target, this.assignability())) {
|
|
13645
14265
|
return;
|
|
13646
14266
|
}
|
|
13647
14267
|
const received = isLiteralType(target) || target.kind === "union" ? source : widenLiteral(source);
|
|
13648
14268
|
const message = `${subject} expects "${typeToString(target)}" but received "${typeToString(received)}".`;
|
|
13649
|
-
const hint = `${nilHint(source, target, this.mode)}${missingKeyHint(source, target)}`;
|
|
14269
|
+
const hint = `${nilHint(source, target, this.mode)}${missingKeyHint(source, target, (name) => this.nominalShape(name))}`;
|
|
13650
14270
|
this.report("check-type-mismatch", `${message}${hint}`, position2);
|
|
13651
14271
|
}
|
|
13652
14272
|
declareProject(project) {
|
|
@@ -13692,6 +14312,25 @@ var CheckContext = class {
|
|
|
13692
14312
|
}
|
|
13693
14313
|
return createMap(this.resolveAnnotation(key), this.resolveAnnotation(value));
|
|
13694
14314
|
}
|
|
14315
|
+
resolveClassAnnotation(name, typeArguments, position2) {
|
|
14316
|
+
const declared = this.declarations.lookupClass(name)?.typeParameters ?? [];
|
|
14317
|
+
const resolved2 = typeArguments.map((argument) => this.resolveAnnotation(argument));
|
|
14318
|
+
if (declared.length === 0) {
|
|
14319
|
+
return createNamed(name);
|
|
14320
|
+
}
|
|
14321
|
+
if (resolved2.length !== declared.length) {
|
|
14322
|
+
const expected = declared.length === 1 ? "1 type argument" : `${declared.length} type arguments`;
|
|
14323
|
+
this.report("check-generic-arity", `Class "${name}" expects ${expected} but received ${resolved2.length}.`, position2);
|
|
14324
|
+
}
|
|
14325
|
+
const specialized = createNamed(name, declared.map((unused, index) => resolved2[index] ?? ANY_TYPE));
|
|
14326
|
+
if (namedNesting(specialized) > MAX_GENERIC_DEPTH) {
|
|
14327
|
+
const message = `Class "${name}" is nested more than ${MAX_GENERIC_DEPTH} levels deep here. Name the inner type with a "type" alias.`;
|
|
14328
|
+
this.report("check-generic-depth", message, position2);
|
|
14329
|
+
return createNamed(name);
|
|
14330
|
+
}
|
|
14331
|
+
checkTypeConstraints(this, name, specialized.typeArguments ?? [], position2);
|
|
14332
|
+
return specialized;
|
|
14333
|
+
}
|
|
13695
14334
|
resolveNamedAnnotation(name, typeArguments, position2) {
|
|
13696
14335
|
const builtin = BUILTIN_TYPES[name];
|
|
13697
14336
|
if (builtin !== void 0) {
|
|
@@ -13706,7 +14345,7 @@ var CheckContext = class {
|
|
|
13706
14345
|
const alias = this.binder.lookupAlias(name);
|
|
13707
14346
|
if (alias === null) {
|
|
13708
14347
|
this.noteUnknownType(name, position2);
|
|
13709
|
-
return
|
|
14348
|
+
return this.resolveClassAnnotation(name, typeArguments, position2);
|
|
13710
14349
|
}
|
|
13711
14350
|
if (typeArguments.length !== alias.parameters.length) {
|
|
13712
14351
|
const expected = alias.parameters.length === 1 ? "1 type argument" : `${alias.parameters.length} type arguments`;
|
|
@@ -13963,6 +14602,73 @@ function checkOverrides(context, info, statement) {
|
|
|
13963
14602
|
}
|
|
13964
14603
|
}
|
|
13965
14604
|
|
|
14605
|
+
// ../compiler/src/checker/metamethods.ts
|
|
14606
|
+
var CONTRACTS = [
|
|
14607
|
+
{ name: "__tostring", parameters: 0, returns: "string", documentation: 'Renders the instance for "tostring" and string coercion.' },
|
|
14608
|
+
{ name: "__eq", parameters: 1, returns: "boolean", documentation: 'Compares two instances of the same class with "==".' },
|
|
14609
|
+
{ name: "__lt", parameters: 1, returns: "boolean", documentation: 'Orders two instances with "<" and ">".' },
|
|
14610
|
+
{ name: "__le", parameters: 1, returns: "boolean", documentation: 'Orders two instances with "<=" and ">=".' },
|
|
14611
|
+
{ name: "__len", parameters: 0, returns: "number", documentation: 'Answers the length operator "#".' },
|
|
14612
|
+
{ name: "__concat", parameters: 1, returns: "any", documentation: 'Answers the concatenation operator "..".' },
|
|
14613
|
+
{ name: "__unm", parameters: 0, returns: "any", documentation: "Answers unary minus." },
|
|
14614
|
+
{ name: "__add", parameters: 1, returns: "any", documentation: 'Answers "+".' },
|
|
14615
|
+
{ name: "__sub", parameters: 1, returns: "any", documentation: 'Answers "-".' },
|
|
14616
|
+
{ name: "__mul", parameters: 1, returns: "any", documentation: 'Answers "*".' },
|
|
14617
|
+
{ name: "__div", parameters: 1, returns: "any", documentation: 'Answers "/".' },
|
|
14618
|
+
{ name: "__mod", parameters: 1, returns: "any", documentation: 'Answers "%".' },
|
|
14619
|
+
{ name: "__pow", parameters: 1, returns: "any", documentation: 'Answers "^".' }
|
|
14620
|
+
];
|
|
14621
|
+
var BLOCKED = {
|
|
14622
|
+
__index: "it replaces member lookup, which the class helper owns",
|
|
14623
|
+
__newindex: "it swallows a field write, which the class helper owns",
|
|
14624
|
+
__call: "it makes an instance callable, which hides construction",
|
|
14625
|
+
__gc: "Lua 5.1 does not run it for a table",
|
|
14626
|
+
__metatable: "it hides the metatable the class helper needs",
|
|
14627
|
+
__mode: "it turns instances into weak references the class helper cannot track"
|
|
14628
|
+
};
|
|
14629
|
+
var METAMETHOD_CONTRACTS = new Map(CONTRACTS.map((contract) => [contract.name, contract]));
|
|
14630
|
+
function isMetamethodName(name) {
|
|
14631
|
+
return name.startsWith("__");
|
|
14632
|
+
}
|
|
14633
|
+
function isAllowedMetamethod(name) {
|
|
14634
|
+
return METAMETHOD_CONTRACTS.has(name);
|
|
14635
|
+
}
|
|
14636
|
+
function isMetamethodMember(member) {
|
|
14637
|
+
return member.kind === "class-method" && !member.isStatic && isAllowedMetamethod(member.name);
|
|
14638
|
+
}
|
|
14639
|
+
function reportReturn(context, className, contract, type, member) {
|
|
14640
|
+
if (contract.returns === "any" || type.kind === "any" || type.kind === contract.returns) {
|
|
14641
|
+
return;
|
|
14642
|
+
}
|
|
14643
|
+
const message = `Metamethod "${contract.name}" of class "${className}" must return "${contract.returns}" but returns "${typeToString(type)}".`;
|
|
14644
|
+
context.report("check-invalid-metamethod", message, member.position);
|
|
14645
|
+
}
|
|
14646
|
+
function checkMetamethod(context, className, member, type) {
|
|
14647
|
+
const contract = METAMETHOD_CONTRACTS.get(member.name);
|
|
14648
|
+
if (contract === void 0 || type.kind !== "function") {
|
|
14649
|
+
return;
|
|
14650
|
+
}
|
|
14651
|
+
if (type.parameters.length !== contract.parameters) {
|
|
14652
|
+
const expected = contract.parameters === 1 ? "1 parameter" : `${contract.parameters} parameters`;
|
|
14653
|
+
const message = `Metamethod "${contract.name}" of class "${className}" takes ${expected} beside "self" but declares ${type.parameters.length}.`;
|
|
14654
|
+
context.report("check-invalid-metamethod", message, member.position);
|
|
14655
|
+
}
|
|
14656
|
+
reportReturn(context, className, contract, type.returnType, member);
|
|
14657
|
+
}
|
|
14658
|
+
function reportRejectedMetamethod(context, className, member) {
|
|
14659
|
+
if (member.kind !== "class-method" || !isMetamethodName(member.name) || isAllowedMetamethod(member.name)) {
|
|
14660
|
+
return;
|
|
14661
|
+
}
|
|
14662
|
+
const blocked = BLOCKED[member.name];
|
|
14663
|
+
if (blocked !== void 0) {
|
|
14664
|
+
context.report("check-blocked-metamethod", `Metamethod "${member.name}" cannot be declared on class "${className}" because ${blocked}.`, member.position);
|
|
14665
|
+
return;
|
|
14666
|
+
}
|
|
14667
|
+
const known = [...METAMETHOD_CONTRACTS.keys()].map((name) => `"${name}"`).join(", ");
|
|
14668
|
+
const message = `"${member.name}" is not a metamethod Luam exposes on class "${className}". Declared metamethods are ${known}.`;
|
|
14669
|
+
context.report("check-blocked-metamethod", message, member.position);
|
|
14670
|
+
}
|
|
14671
|
+
|
|
13966
14672
|
// ../compiler/src/checker/accessor-names.ts
|
|
13967
14673
|
function capitalize(name) {
|
|
13968
14674
|
return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
@@ -14047,6 +14753,25 @@ var KNOWN_DECORATORS = /* @__PURE__ */ new Map([
|
|
|
14047
14753
|
diagnostics: [CONFLICT]
|
|
14048
14754
|
}
|
|
14049
14755
|
],
|
|
14756
|
+
[
|
|
14757
|
+
"Validated",
|
|
14758
|
+
{
|
|
14759
|
+
name: "Validated",
|
|
14760
|
+
documentation: "Generates runtime checks for the declared field types.",
|
|
14761
|
+
targets: ["class"],
|
|
14762
|
+
generates: [
|
|
14763
|
+
"`ClassName.validate(value: table): ClassName`, returning the value or raising a Lua error naming the path and the expected type.",
|
|
14764
|
+
"`ClassName.matches(value: table): boolean`, the same check without raising."
|
|
14765
|
+
],
|
|
14766
|
+
rules: [
|
|
14767
|
+
"Both are static, so they are called on the class and never on an instance.",
|
|
14768
|
+
"The check walks the declared field types with a depth, entry-count and string-length limit, and a failure names the path and the expected type but never the value.",
|
|
14769
|
+
"A field whose type has no runtime shape is `check-unreifiable-type`, reported before anything is emitted.",
|
|
14770
|
+
"It is the only decorator that adds runtime code beyond the class helper; a class without it emits nothing extra."
|
|
14771
|
+
],
|
|
14772
|
+
diagnostics: [CONFLICT, "`check-unreifiable-type` when a field type cannot be checked at runtime."]
|
|
14773
|
+
}
|
|
14774
|
+
],
|
|
14050
14775
|
[
|
|
14051
14776
|
"Serializable",
|
|
14052
14777
|
{
|
|
@@ -14137,6 +14862,102 @@ var KNOWN_DECORATORS = /* @__PURE__ */ new Map([
|
|
|
14137
14862
|
]
|
|
14138
14863
|
]);
|
|
14139
14864
|
|
|
14865
|
+
// ../compiler/src/checker/validation-descriptor.ts
|
|
14866
|
+
var MAX_EXPANSION = 8;
|
|
14867
|
+
var PRIMITIVE_KINDS = {
|
|
14868
|
+
nil: "nil",
|
|
14869
|
+
boolean: "boolean",
|
|
14870
|
+
number: "number",
|
|
14871
|
+
string: "string",
|
|
14872
|
+
table: "table",
|
|
14873
|
+
thread: "thread",
|
|
14874
|
+
userdata: "userdata",
|
|
14875
|
+
function: "function"
|
|
14876
|
+
};
|
|
14877
|
+
function quote2(value) {
|
|
14878
|
+
return `'${value.replace(/([\\'])/g, "\\$1").replace(/\n/g, "\\n")}'`;
|
|
14879
|
+
}
|
|
14880
|
+
function failed(type) {
|
|
14881
|
+
return { lua: null, unreifiable: typeToString(type) };
|
|
14882
|
+
}
|
|
14883
|
+
function entries2(parts) {
|
|
14884
|
+
return `{ ${parts.join(", ")} }`;
|
|
14885
|
+
}
|
|
14886
|
+
function combine(parts, render2) {
|
|
14887
|
+
const broken = parts.find((part) => part.lua === null);
|
|
14888
|
+
if (broken !== void 0) {
|
|
14889
|
+
return broken;
|
|
14890
|
+
}
|
|
14891
|
+
return { lua: render2(parts.map((part) => part.lua)), unreifiable: null };
|
|
14892
|
+
}
|
|
14893
|
+
function namedDescriptor(context, type, name, seen) {
|
|
14894
|
+
if (context.declarations.lookupClass(name) !== null) {
|
|
14895
|
+
return { lua: entries2([`kind = 'instance'`, `name = ${quote2(name)}`]), unreifiable: null };
|
|
14896
|
+
}
|
|
14897
|
+
if (context.declarations.lookupEnum(name) !== null) {
|
|
14898
|
+
return { lua: entries2([`kind = 'number'`]), unreifiable: null };
|
|
14899
|
+
}
|
|
14900
|
+
if (context.declarations.lookupInterface(name) === null || seen.has(name) || seen.size >= MAX_EXPANSION) {
|
|
14901
|
+
return failed(type);
|
|
14902
|
+
}
|
|
14903
|
+
const members = context.declarations.collectMembers(name);
|
|
14904
|
+
const nested = /* @__PURE__ */ new Set([...seen, name]);
|
|
14905
|
+
const parts = members.map((member) => describe(context, member.type, nested));
|
|
14906
|
+
return combine(parts, (values) => {
|
|
14907
|
+
const rendered = members.map((member, index) => entries2([`key = ${quote2(member.name)}`, `value = ${values[index] ?? ""}`]));
|
|
14908
|
+
return entries2([`kind = 'record'`, `name = ${quote2(name)}`, `members = ${entries2(rendered)}`]);
|
|
14909
|
+
});
|
|
14910
|
+
}
|
|
14911
|
+
function describe(context, type, seen = /* @__PURE__ */ new Set()) {
|
|
14912
|
+
const primitive = PRIMITIVE_KINDS[type.kind];
|
|
14913
|
+
if (primitive !== void 0) {
|
|
14914
|
+
return { lua: entries2([`kind = ${quote2(primitive)}`]), unreifiable: null };
|
|
14915
|
+
}
|
|
14916
|
+
if (type.kind === "string-literal") {
|
|
14917
|
+
return { lua: entries2([`kind = 'literal'`, `value = ${quote2(type.value)}`]), unreifiable: null };
|
|
14918
|
+
}
|
|
14919
|
+
if (type.kind === "boolean-literal" || type.kind === "number-literal") {
|
|
14920
|
+
return { lua: entries2([`kind = 'literal'`, `value = ${String(type.value)}`]), unreifiable: null };
|
|
14921
|
+
}
|
|
14922
|
+
if (type.kind === "optional") {
|
|
14923
|
+
return combine([describe(context, type.element, seen)], (values) => entries2([`kind = 'optional'`, `element = ${values[0] ?? ""}`]));
|
|
14924
|
+
}
|
|
14925
|
+
if (type.kind === "array") {
|
|
14926
|
+
return combine([describe(context, type.element, seen)], (values) => entries2([`kind = 'array'`, `element = ${values[0] ?? ""}`]));
|
|
14927
|
+
}
|
|
14928
|
+
if (type.kind === "map") {
|
|
14929
|
+
return combine(
|
|
14930
|
+
[describe(context, type.key, seen), describe(context, type.value, seen)],
|
|
14931
|
+
(values) => entries2([`kind = 'map'`, `key = ${values[0] ?? ""}`, `value = ${values[1] ?? ""}`])
|
|
14932
|
+
);
|
|
14933
|
+
}
|
|
14934
|
+
if (type.kind === "union") {
|
|
14935
|
+
return combine(
|
|
14936
|
+
type.options.map((option) => describe(context, option, seen)),
|
|
14937
|
+
(values) => entries2([`kind = 'union'`, `options = ${entries2(values)}`])
|
|
14938
|
+
);
|
|
14939
|
+
}
|
|
14940
|
+
if (type.kind === "record") {
|
|
14941
|
+
const members = [...type.members];
|
|
14942
|
+
const parts = members.map(([, member]) => describe(context, member, seen));
|
|
14943
|
+
return combine(parts, (values) => {
|
|
14944
|
+
const rendered = members.map(([key], index) => entries2([`key = ${quote2(key)}`, `value = ${values[index] ?? ""}`]));
|
|
14945
|
+
return entries2([`kind = 'record'`, `name = ${quote2(type.name)}`, `members = ${entries2(rendered)}`]);
|
|
14946
|
+
});
|
|
14947
|
+
}
|
|
14948
|
+
if (type.kind === "named") {
|
|
14949
|
+
return namedDescriptor(context, type, type.name, seen);
|
|
14950
|
+
}
|
|
14951
|
+
return failed(type);
|
|
14952
|
+
}
|
|
14953
|
+
function classDescriptor(context, className, fields) {
|
|
14954
|
+
const parts = fields.map((field2) => describe(context, field2.type));
|
|
14955
|
+
return combine(parts, (values) => {
|
|
14956
|
+
const rendered = fields.map((field2, index) => entries2([`key = ${quote2(field2.name)}`, `value = ${values[index] ?? ""}`]));
|
|
14957
|
+
return entries2([`kind = 'record'`, `name = ${quote2(className)}`, `members = ${entries2(rendered)}`]);
|
|
14958
|
+
});
|
|
14959
|
+
}
|
|
14960
|
+
|
|
14140
14961
|
// ../compiler/src/checker/decorators.ts
|
|
14141
14962
|
function memberExpression(field2) {
|
|
14142
14963
|
return {
|
|
@@ -14163,6 +14984,7 @@ function accessorMethod(field2, decorator, name) {
|
|
|
14163
14984
|
name,
|
|
14164
14985
|
isConstructor: false,
|
|
14165
14986
|
isSynthetic: true,
|
|
14987
|
+
isStatic: false,
|
|
14166
14988
|
parameters: decorator === "Getter" ? [] : [value],
|
|
14167
14989
|
returnAnnotation: decorator === "Getter" ? field2.annotation : voidAnnotation,
|
|
14168
14990
|
body,
|
|
@@ -14171,7 +14993,7 @@ function accessorMethod(field2, decorator, name) {
|
|
|
14171
14993
|
};
|
|
14172
14994
|
}
|
|
14173
14995
|
function generatedMethod(field2, name, parameters, returnAnnotation, kind, fields) {
|
|
14174
|
-
return { kind: "class-method", name, isConstructor: false, isSynthetic: true, parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
|
|
14996
|
+
return { kind: "class-method", name, isConstructor: false, isSynthetic: true, isStatic: false, parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
|
|
14175
14997
|
}
|
|
14176
14998
|
function typeName(name, node) {
|
|
14177
14999
|
return { kind: "type-name", name, typeArguments: [], position: node.position };
|
|
@@ -14201,6 +15023,46 @@ function validateDecorators(context, decorators, target) {
|
|
|
14201
15023
|
function decoratorFor(name, classDecorators, fieldDecorators) {
|
|
14202
15024
|
return fieldDecorators.find((decorator) => decorator.name === name) ?? classDecorators.find((decorator) => decorator.name === name) ?? null;
|
|
14203
15025
|
}
|
|
15026
|
+
function staticMethod(statement, name, returnAnnotation, kind, descriptor) {
|
|
15027
|
+
const value = { name: "value", annotation: typeName("table", statement), isVararg: false, position: statement.position };
|
|
15028
|
+
return {
|
|
15029
|
+
kind: "class-method",
|
|
15030
|
+
name,
|
|
15031
|
+
isConstructor: false,
|
|
15032
|
+
isSynthetic: true,
|
|
15033
|
+
isStatic: true,
|
|
15034
|
+
parameters: [value],
|
|
15035
|
+
returnAnnotation,
|
|
15036
|
+
body: [],
|
|
15037
|
+
decorators: [],
|
|
15038
|
+
generated: { kind, fields: [], descriptor },
|
|
15039
|
+
position: statement.position
|
|
15040
|
+
};
|
|
15041
|
+
}
|
|
15042
|
+
function expandValidated(context, statement, classDecorators, fieldTypes, occupied, generated) {
|
|
15043
|
+
const found = classDecorators.find((decorator) => decorator.name === "Validated");
|
|
15044
|
+
if (found === void 0) {
|
|
15045
|
+
return;
|
|
15046
|
+
}
|
|
15047
|
+
const fields = [...fieldTypes].map(([field2, type]) => ({ name: field2.name, type, position: field2.position }));
|
|
15048
|
+
const described = classDescriptor(context, statement.name, fields);
|
|
15049
|
+
if (described.lua === null) {
|
|
15050
|
+
const message = `Decorator "@Validated" cannot check type "${described.unreifiable}", which has no runtime shape. Remove the field, or narrow it to a checkable type.`;
|
|
15051
|
+
context.report("check-unreifiable-type", message, found.position);
|
|
15052
|
+
return;
|
|
15053
|
+
}
|
|
15054
|
+
for (const [name, kind, annotation] of [
|
|
15055
|
+
["validate", "validate", typeName(statement.name, statement)],
|
|
15056
|
+
["matches", "matches", typeName("boolean", statement)]
|
|
15057
|
+
]) {
|
|
15058
|
+
if (occupied.has(name)) {
|
|
15059
|
+
context.report("check-decorator-conflict", `Decorator "@Validated" would generate "${name}", which is already declared by "${occupied.get(name)}".`, found.position);
|
|
15060
|
+
continue;
|
|
15061
|
+
}
|
|
15062
|
+
occupied.set(name, statement.name);
|
|
15063
|
+
generated.push(staticMethod(statement, name, annotation, kind, described.lua));
|
|
15064
|
+
}
|
|
15065
|
+
}
|
|
14204
15066
|
function expandClassDecorators(context, statement, fieldTypes) {
|
|
14205
15067
|
const generated = [];
|
|
14206
15068
|
const occupied = new Map(statement.members.filter((member) => member.kind === "class-method").map((member) => [member.name, member.name]));
|
|
@@ -14262,6 +15124,7 @@ function expandClassDecorators(context, statement, fieldTypes) {
|
|
|
14262
15124
|
Serializable: ["toTable", typeName("table", statement), "serializable"],
|
|
14263
15125
|
Deserialize: ["fromTable", typeName("void", statement), "deserialize"]
|
|
14264
15126
|
};
|
|
15127
|
+
expandValidated(context, statement, classDecorators, fieldTypes, occupied, generated);
|
|
14265
15128
|
for (const [decorator, [name, returnAnnotation, kind]] of Object.entries(classMethods)) {
|
|
14266
15129
|
const found = classDecorators.find((value) => value.name === decorator);
|
|
14267
15130
|
if (found !== void 0 && !occupied.has(name)) {
|
|
@@ -17520,6 +18383,9 @@ function checkEventUsage(context, expression) {
|
|
|
17520
18383
|
return;
|
|
17521
18384
|
}
|
|
17522
18385
|
const name = eventName(expression);
|
|
18386
|
+
if (name !== null) {
|
|
18387
|
+
context.noteEventReference(name);
|
|
18388
|
+
}
|
|
17523
18389
|
const custom = name === null ? null : context.declarations.lookupEvent(name);
|
|
17524
18390
|
const declared = name === null ? null : eventEnvironment(name);
|
|
17525
18391
|
if (name === null || custom?.environment === "shared" || custom?.environment === context.environment || declared === null || declared === context.environment) {
|
|
@@ -17662,6 +18528,105 @@ function specializeEventCall(context, expression, signature) {
|
|
|
17662
18528
|
return candidate === null ? null : specialize(signature, candidate);
|
|
17663
18529
|
}
|
|
17664
18530
|
|
|
18531
|
+
// ../compiler/src/checker/method-receiver.ts
|
|
18532
|
+
var SELF_PARAMETER = "self";
|
|
18533
|
+
function resolveNonNominalMethod(receiver, method) {
|
|
18534
|
+
if (receiver.kind !== "record") {
|
|
18535
|
+
return null;
|
|
18536
|
+
}
|
|
18537
|
+
const member = receiver.members.get(method);
|
|
18538
|
+
return member !== void 0 && member.kind === "function" ? member : null;
|
|
18539
|
+
}
|
|
18540
|
+
function withoutSelfParameter(signature) {
|
|
18541
|
+
const names = signature.parameterNames;
|
|
18542
|
+
if (names === void 0 || names[0] !== SELF_PARAMETER) {
|
|
18543
|
+
return signature;
|
|
18544
|
+
}
|
|
18545
|
+
const minimum = Math.max(0, signature.minimumArguments - 1);
|
|
18546
|
+
return createFunction(signature.parameters.slice(1), signature.returnType, minimum, signature.isVariadic, names.slice(1), signature.variadicType);
|
|
18547
|
+
}
|
|
18548
|
+
|
|
18549
|
+
// ../compiler/src/checker/resource-exports.ts
|
|
18550
|
+
var RESOURCE_LOOKUP = "getResourceFromName";
|
|
18551
|
+
var EXPORTS_TABLE = "exports";
|
|
18552
|
+
var CALL_FUNCTION = "call";
|
|
18553
|
+
function literalString(expression) {
|
|
18554
|
+
return expression?.kind === "string-literal" ? expression.value : null;
|
|
18555
|
+
}
|
|
18556
|
+
function resourceOfLookup(expression) {
|
|
18557
|
+
if (expression?.kind !== "call-expression" || expression.callee.kind !== "identifier" || expression.callee.name !== RESOURCE_LOOKUP) {
|
|
18558
|
+
return null;
|
|
18559
|
+
}
|
|
18560
|
+
return literalString(expression.args[0]);
|
|
18561
|
+
}
|
|
18562
|
+
function resourceOfExports(expression) {
|
|
18563
|
+
if (expression.kind === "member-expression" && expression.object.kind === "identifier" && expression.object.name === EXPORTS_TABLE) {
|
|
18564
|
+
return expression.property;
|
|
18565
|
+
}
|
|
18566
|
+
if (expression.kind !== "index-expression" || expression.object.kind !== "identifier" || expression.object.name !== EXPORTS_TABLE) {
|
|
18567
|
+
return null;
|
|
18568
|
+
}
|
|
18569
|
+
return literalString(expression.index);
|
|
18570
|
+
}
|
|
18571
|
+
function abiType(context, text) {
|
|
18572
|
+
const scanned = scan(text);
|
|
18573
|
+
if (scanned.diagnostics.length > 0) {
|
|
18574
|
+
return ANY_TYPE;
|
|
18575
|
+
}
|
|
18576
|
+
try {
|
|
18577
|
+
return context.resolveAnnotation(parseTypeAnnotation(new TokenStream(scanned.tokens)));
|
|
18578
|
+
} catch {
|
|
18579
|
+
return ANY_TYPE;
|
|
18580
|
+
}
|
|
18581
|
+
}
|
|
18582
|
+
function signatureOf(context, entry) {
|
|
18583
|
+
const parameters = entry.parameters.map((parameter) => abiType(context, parameter.type));
|
|
18584
|
+
const names = entry.parameters.map((parameter) => parameter.name);
|
|
18585
|
+
const minimum = Math.min(Math.max(entry.minimumArguments, 0), parameters.length);
|
|
18586
|
+
return createFunction(parameters, abiType(context, entry.returns), minimum, entry.variadic, names);
|
|
18587
|
+
}
|
|
18588
|
+
function checkSide(context, entry, resource, expression) {
|
|
18589
|
+
if (canReference(context.environment, entry.side)) {
|
|
18590
|
+
return;
|
|
18591
|
+
}
|
|
18592
|
+
const message = `Export "${entry.name}" of resource "${resource}" is ${entry.side}-only and cannot be called from a "${context.environment}" file.`;
|
|
18593
|
+
context.report("check-resource-export-side", message, expression.position);
|
|
18594
|
+
}
|
|
18595
|
+
function checkKnownExport(context, resource, name, args, expression) {
|
|
18596
|
+
const entry = lookupAbiExport(context.contracts, resource, name);
|
|
18597
|
+
if (entry === null) {
|
|
18598
|
+
const known = context.contracts.find((contract) => contract.resource === resource)?.exports.map((declared) => `"${declared.name}"`).join(", ");
|
|
18599
|
+
const hint = known === void 0 || known.length === 0 ? " It exports nothing." : ` It exports ${known}.`;
|
|
18600
|
+
checkValueList(context, args);
|
|
18601
|
+
context.report("check-unknown-resource-export", `Resource "${resource}" has no export "${name}".${hint}`, expression.position);
|
|
18602
|
+
return ANY_TYPE;
|
|
18603
|
+
}
|
|
18604
|
+
checkSide(context, entry, resource, expression);
|
|
18605
|
+
return checkSignature(context, args, signatureOf(context, entry), expression.position);
|
|
18606
|
+
}
|
|
18607
|
+
function checkResourceCall(context, expression) {
|
|
18608
|
+
if (context.contracts.length === 0) {
|
|
18609
|
+
return null;
|
|
18610
|
+
}
|
|
18611
|
+
if (expression.method !== null) {
|
|
18612
|
+
const resource2 = resourceOfExports(expression.callee);
|
|
18613
|
+
if (resource2 === null || !knowsResource(context.contracts, resource2)) {
|
|
18614
|
+
return null;
|
|
18615
|
+
}
|
|
18616
|
+
return checkKnownExport(context, resource2, expression.method, expression.args, expression);
|
|
18617
|
+
}
|
|
18618
|
+
if (expression.callee.kind !== "identifier" || expression.callee.name !== CALL_FUNCTION) {
|
|
18619
|
+
return null;
|
|
18620
|
+
}
|
|
18621
|
+
const resource = resourceOfLookup(expression.args[0]);
|
|
18622
|
+
const name = literalString(expression.args[1]);
|
|
18623
|
+
if (resource === null || name === null || !knowsResource(context.contracts, resource)) {
|
|
18624
|
+
return null;
|
|
18625
|
+
}
|
|
18626
|
+
checkValueList(context, expression.args.slice(0, 2));
|
|
18627
|
+
return checkKnownExport(context, resource, name, expression.args.slice(2), expression);
|
|
18628
|
+
}
|
|
18629
|
+
|
|
17665
18630
|
// ../mta-types/src/library-members.ts
|
|
17666
18631
|
var MATH_MEMBERS = {
|
|
17667
18632
|
abs: fn([NUMBER], NUMBER, 1),
|
|
@@ -17731,11 +18696,11 @@ var ELEMENT_TYPES = [
|
|
|
17731
18696
|
{ name: "Camera", parent: "Element" },
|
|
17732
18697
|
{ name: "ColShape", parent: "Element" },
|
|
17733
18698
|
{ name: "Connection", parent: null },
|
|
17734
|
-
{ name: "DxFont", parent:
|
|
17735
|
-
{ name: "DxRenderTarget", parent:
|
|
17736
|
-
{ name: "DxScreenSource", parent:
|
|
17737
|
-
{ name: "DxShader", parent:
|
|
17738
|
-
{ name: "DxTexture", parent:
|
|
18699
|
+
{ name: "DxFont", parent: "Element" },
|
|
18700
|
+
{ name: "DxRenderTarget", parent: "Element" },
|
|
18701
|
+
{ name: "DxScreenSource", parent: "Element" },
|
|
18702
|
+
{ name: "DxShader", parent: "Element" },
|
|
18703
|
+
{ name: "DxTexture", parent: "Element" },
|
|
17739
18704
|
{ name: "Effect", parent: "Element" },
|
|
17740
18705
|
{ name: "Element", parent: null },
|
|
17741
18706
|
{ name: "Engine", parent: null },
|
|
@@ -17744,21 +18709,21 @@ var ELEMENT_TYPES = [
|
|
|
17744
18709
|
{ name: "EngineTXD", parent: null },
|
|
17745
18710
|
{ name: "File", parent: null },
|
|
17746
18711
|
{ name: "GuiBrowser", parent: "GuiElement" },
|
|
17747
|
-
{ name: "GuiButton", parent:
|
|
18712
|
+
{ name: "GuiButton", parent: "GuiElement" },
|
|
17748
18713
|
{ name: "GuiCheckbox", parent: "GuiElement" },
|
|
17749
18714
|
{ name: "GuiCombobox", parent: "GuiElement" },
|
|
17750
18715
|
{ name: "GuiEdit", parent: "GuiElement" },
|
|
17751
|
-
{ name: "GuiElement", parent:
|
|
17752
|
-
{ name: "GuiFont", parent:
|
|
18716
|
+
{ name: "GuiElement", parent: "Element" },
|
|
18717
|
+
{ name: "GuiFont", parent: "Element" },
|
|
17753
18718
|
{ name: "GuiGridList", parent: "GuiElement" },
|
|
17754
18719
|
{ name: "GuiLabel", parent: "GuiElement" },
|
|
17755
18720
|
{ name: "GuiMemo", parent: "GuiElement" },
|
|
17756
|
-
{ name: "GuiRadioButton", parent:
|
|
18721
|
+
{ name: "GuiRadioButton", parent: "GuiElement" },
|
|
17757
18722
|
{ name: "GuiStaticImage", parent: "GuiElement" },
|
|
17758
18723
|
{ name: "GuiTab", parent: "GuiElement" },
|
|
17759
18724
|
{ name: "GuiTabPanel", parent: "GuiElement" },
|
|
17760
18725
|
{ name: "GuiWindow", parent: "GuiElement" },
|
|
17761
|
-
{ name: "Light", parent:
|
|
18726
|
+
{ name: "Light", parent: "Element" },
|
|
17762
18727
|
{ name: "Marker", parent: "Element" },
|
|
17763
18728
|
{ name: "Material", parent: "Element" },
|
|
17764
18729
|
{ name: "Object", parent: "Element" },
|
|
@@ -17914,25 +18879,54 @@ function checkInterfaceMember(context, name, members, expression) {
|
|
|
17914
18879
|
context.report("check-unknown-member", `Interface "${name}" has no member "${expression.property}". Declared members: ${keys}.`, expression.position);
|
|
17915
18880
|
return ANY_TYPE;
|
|
17916
18881
|
}
|
|
17917
|
-
function
|
|
17918
|
-
const
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17922
|
-
const member = context.declarations.
|
|
18882
|
+
function isUserClassReference(context, name) {
|
|
18883
|
+
const symbol = context.binder.lookup(name);
|
|
18884
|
+
return symbol !== null && !symbol.isLocal && context.declarations.lookupClass(name) !== null;
|
|
18885
|
+
}
|
|
18886
|
+
function resolveStaticMember(context, className, expression) {
|
|
18887
|
+
const member = context.declarations.lookupStaticMember(className, expression.property);
|
|
17923
18888
|
if (member !== null) {
|
|
17924
18889
|
if (member.deprecated === true) {
|
|
17925
18890
|
context.warn("check-deprecated-use", `Member "${expression.property}" is deprecated.`, expression.position);
|
|
17926
18891
|
}
|
|
18892
|
+
context.staticAccess.add(expression);
|
|
17927
18893
|
return member.type;
|
|
17928
18894
|
}
|
|
17929
|
-
if (
|
|
17930
|
-
|
|
17931
|
-
}
|
|
17932
|
-
if (context.awaitsDeclaration(name)) {
|
|
18895
|
+
if (context.awaitsDeclaration(className)) {
|
|
18896
|
+
context.staticAccess.add(expression);
|
|
17933
18897
|
return ANY_TYPE;
|
|
17934
18898
|
}
|
|
17935
|
-
const
|
|
18899
|
+
const instance = context.declarations.lookupMember(className, expression.property);
|
|
18900
|
+
const hint = instance === null ? "" : ` It is an instance member, so read it from a value of "${className}".`;
|
|
18901
|
+
context.report("check-unknown-member", `Class "${className}" has no static member "${expression.property}".${hint}`, expression.position);
|
|
18902
|
+
return ANY_TYPE;
|
|
18903
|
+
}
|
|
18904
|
+
function resolveNamedMember(context, receiver, expression) {
|
|
18905
|
+
const name = receiver.name;
|
|
18906
|
+
const enumeration = context.declarations.lookupEnum(name);
|
|
18907
|
+
if (enumeration !== null) {
|
|
18908
|
+
return checkEnumMember(context, name, enumeration.members, expression);
|
|
18909
|
+
}
|
|
18910
|
+
const member = memberOf(context, receiver, expression.property);
|
|
18911
|
+
if (member !== null) {
|
|
18912
|
+
if (member.deprecated === true) {
|
|
18913
|
+
context.warn("check-deprecated-use", `Member "${expression.property}" is deprecated.`, expression.position);
|
|
18914
|
+
}
|
|
18915
|
+
return member.type;
|
|
18916
|
+
}
|
|
18917
|
+
if (isMtaElement(context, name)) {
|
|
18918
|
+
return resolveMtaMember(context, name, expression.property, expression.position)?.type ?? ANY_TYPE;
|
|
18919
|
+
}
|
|
18920
|
+
const staticMember = context.declarations.lookupStaticMember(name, expression.property);
|
|
18921
|
+
if (staticMember !== null) {
|
|
18922
|
+
const message = `"${expression.property}" is a static member of class "${name}". Read it as "${name}.${expression.property}".`;
|
|
18923
|
+
context.report("check-static-receiver", message, expression.position);
|
|
18924
|
+
return staticMember.type;
|
|
18925
|
+
}
|
|
18926
|
+
if (context.awaitsDeclaration(name)) {
|
|
18927
|
+
return ANY_TYPE;
|
|
18928
|
+
}
|
|
18929
|
+
const contract = context.declarations.lookupClass(name) === null ? context.declarations.lookupInterface(name) : null;
|
|
17936
18930
|
if (contract === null) {
|
|
17937
18931
|
return null;
|
|
17938
18932
|
}
|
|
@@ -17948,6 +18942,29 @@ function nativeConstructor(context, name) {
|
|
|
17948
18942
|
const constructor = symbol.type.members.get(NATIVE_CONSTRUCTOR);
|
|
17949
18943
|
return constructor === void 0 || constructor.kind !== "function" ? null : constructor;
|
|
17950
18944
|
}
|
|
18945
|
+
function constructorParameters(context, className) {
|
|
18946
|
+
const constructor = context.declarations.lookupMember(className, "constructor");
|
|
18947
|
+
return constructor?.type.kind === "function" ? constructor.type.parameters : [];
|
|
18948
|
+
}
|
|
18949
|
+
function resolveConstructorArguments(context, expression, typeParameters) {
|
|
18950
|
+
const explicit = expression.typeArguments.map((argument) => context.resolveAnnotation(argument));
|
|
18951
|
+
if (typeParameters.length === 0) {
|
|
18952
|
+
if (explicit.length > 0) {
|
|
18953
|
+
context.report("check-generic-arity", `Class "${expression.className}" does not accept type arguments.`, expression.position);
|
|
18954
|
+
}
|
|
18955
|
+
return [];
|
|
18956
|
+
}
|
|
18957
|
+
if (explicit.length === typeParameters.length) {
|
|
18958
|
+
return explicit;
|
|
18959
|
+
}
|
|
18960
|
+
if (explicit.length > 0) {
|
|
18961
|
+
const expected = typeParameters.length === 1 ? "1 type argument" : `${typeParameters.length} type arguments`;
|
|
18962
|
+
context.report("check-generic-arity", `Class "${expression.className}" expects ${expected} but received ${explicit.length}.`, expression.position);
|
|
18963
|
+
return typeParameters.map((unused, index) => explicit[index] ?? ANY_TYPE);
|
|
18964
|
+
}
|
|
18965
|
+
const argumentTypes = expression.args.map((argument) => checkExpression(context, argument));
|
|
18966
|
+
return inferTypeArguments(typeParameters, constructorParameters(context, expression.className), argumentTypes);
|
|
18967
|
+
}
|
|
17951
18968
|
function checkNewExpression(context, expression) {
|
|
17952
18969
|
if (context.declarations.lookupClass(expression.className) === null) {
|
|
17953
18970
|
const constructor2 = nativeConstructor(context, expression.className);
|
|
@@ -17961,17 +18978,25 @@ function checkNewExpression(context, expression) {
|
|
|
17961
18978
|
context.report("check-unknown-class", `Class "${expression.className}" is not defined.`, expression.position);
|
|
17962
18979
|
return ANY_TYPE;
|
|
17963
18980
|
}
|
|
17964
|
-
|
|
17965
|
-
|
|
17966
|
-
|
|
18981
|
+
const pending = context.insideFunction() ? null : context.pendingDeclarationOf(expression.className);
|
|
18982
|
+
if (pending !== null) {
|
|
18983
|
+
const subject = pending === expression.className ? `Class "${pending}"` : `Class "${expression.className}" extends "${pending}", which`;
|
|
18984
|
+
context.report("check-class-before-declaration", `${subject} is declared further down this file, so it does not exist yet at this point.`, expression.position);
|
|
17967
18985
|
}
|
|
18986
|
+
const info = context.declarations.lookupClass(expression.className);
|
|
18987
|
+
const typeArguments = resolveConstructorArguments(context, expression, info?.typeParameters ?? []);
|
|
18988
|
+
checkTypeConstraints(context, expression.className, typeArguments, expression.position);
|
|
17968
18989
|
const constructor = context.declarations.lookupMember(expression.className, "constructor");
|
|
17969
18990
|
if (constructor !== null && constructor.type.kind === "function") {
|
|
17970
|
-
|
|
18991
|
+
const substitutions = info === null ? /* @__PURE__ */ new Map() : classSubstitutions(info, typeArguments);
|
|
18992
|
+
const signature = substituteType(constructor.type, substitutions);
|
|
18993
|
+
if (signature.kind === "function") {
|
|
18994
|
+
checkSignature(context, expression.args, signature, expression.position);
|
|
18995
|
+
}
|
|
17971
18996
|
} else {
|
|
17972
18997
|
expression.args.forEach((argument) => checkExpression(context, argument));
|
|
17973
18998
|
}
|
|
17974
|
-
return createNamed(expression.className);
|
|
18999
|
+
return createNamed(expression.className, typeArguments);
|
|
17975
19000
|
}
|
|
17976
19001
|
function resolveSuperMethod(context, expression) {
|
|
17977
19002
|
const frame = context.currentClassMethod();
|
|
@@ -18060,14 +19085,14 @@ function isShapeOption(context, option) {
|
|
|
18060
19085
|
}
|
|
18061
19086
|
return context.declarations.lookupInterface(option.name) !== null || context.declarations.lookupClass(option.name) !== null;
|
|
18062
19087
|
}
|
|
18063
|
-
function
|
|
19088
|
+
function memberOf2(context, option, property) {
|
|
18064
19089
|
if (option.kind === "record") {
|
|
18065
19090
|
return option.members.get(property) ?? null;
|
|
18066
19091
|
}
|
|
18067
19092
|
return option.kind === "named" ? context.declarations.lookupMember(option.name, property)?.type ?? null : null;
|
|
18068
19093
|
}
|
|
18069
19094
|
function optionMemberType(context, option, property) {
|
|
18070
|
-
return isShapeOption(context, option) ?
|
|
19095
|
+
return isShapeOption(context, option) ? memberOf2(context, option, property) : null;
|
|
18071
19096
|
}
|
|
18072
19097
|
function resolveUnionMember(context, type, expression) {
|
|
18073
19098
|
if (!type.options.every((option) => isShapeOption(context, option))) {
|
|
@@ -18076,7 +19101,7 @@ function resolveUnionMember(context, type, expression) {
|
|
|
18076
19101
|
const resolved2 = [];
|
|
18077
19102
|
const missing2 = [];
|
|
18078
19103
|
for (const option of type.options) {
|
|
18079
|
-
const member =
|
|
19104
|
+
const member = memberOf2(context, option, expression.property);
|
|
18080
19105
|
if (member === null) {
|
|
18081
19106
|
missing2.push(`"${typeToString(option)}"`);
|
|
18082
19107
|
} else {
|
|
@@ -18243,26 +19268,6 @@ function conditionFacts(context, condition) {
|
|
|
18243
19268
|
collectFacts(context, condition, facts);
|
|
18244
19269
|
return facts;
|
|
18245
19270
|
}
|
|
18246
|
-
function alwaysExits(body) {
|
|
18247
|
-
const last = body[body.length - 1];
|
|
18248
|
-
if (last === void 0) {
|
|
18249
|
-
return false;
|
|
18250
|
-
}
|
|
18251
|
-
if (last.kind === "return-statement" || last.kind === "break-statement") {
|
|
18252
|
-
return true;
|
|
18253
|
-
}
|
|
18254
|
-
if (last.kind !== "if-statement" || last.alternate === null) {
|
|
18255
|
-
return false;
|
|
18256
|
-
}
|
|
18257
|
-
return last.clauses.every((clause) => alwaysExits(clause.body)) && alwaysExits(last.alternate);
|
|
18258
|
-
}
|
|
18259
|
-
function guardFacts(context, statement) {
|
|
18260
|
-
const [clause] = statement.kind === "if-statement" ? statement.clauses : [];
|
|
18261
|
-
if (statement.kind !== "if-statement" || statement.alternate !== null || statement.clauses.length !== 1 || clause === void 0) {
|
|
18262
|
-
return /* @__PURE__ */ new Map();
|
|
18263
|
-
}
|
|
18264
|
-
return alwaysExits(clause.body) ? negatedFacts(context, clause.condition) : /* @__PURE__ */ new Map();
|
|
18265
|
-
}
|
|
18266
19271
|
function negatedFacts(context, condition) {
|
|
18267
19272
|
const facts = /* @__PURE__ */ new Map();
|
|
18268
19273
|
if (condition.kind === "binary-expression" && condition.operator === "or") {
|
|
@@ -18293,23 +19298,58 @@ var ITERATOR_FUNCTIONS = /* @__PURE__ */ new Set(["pairs", "ipairs"]);
|
|
|
18293
19298
|
function checkBlock(context, body) {
|
|
18294
19299
|
context.binder.pushScope();
|
|
18295
19300
|
checkStatements(context, body);
|
|
19301
|
+
const declared = context.binder.currentScopeNames();
|
|
18296
19302
|
context.binder.popScope();
|
|
19303
|
+
for (const name of declared) {
|
|
19304
|
+
context.forgetNarrowing(name);
|
|
19305
|
+
}
|
|
18297
19306
|
}
|
|
18298
|
-
function
|
|
18299
|
-
|
|
19307
|
+
function branch(context, entry, facts, body) {
|
|
19308
|
+
const state = cloneFlow(entry);
|
|
19309
|
+
applyFacts(state, facts);
|
|
19310
|
+
context.setFlow(state);
|
|
18300
19311
|
checkBlock(context, body);
|
|
18301
|
-
context.
|
|
19312
|
+
return context.flowState;
|
|
18302
19313
|
}
|
|
18303
19314
|
function checkIf(context, clauses, alternate) {
|
|
19315
|
+
const exits = [];
|
|
19316
|
+
let current = context.flowState;
|
|
18304
19317
|
for (const clause of clauses) {
|
|
19318
|
+
context.setFlow(current);
|
|
18305
19319
|
checkExpression(context, clause.condition);
|
|
18306
|
-
|
|
19320
|
+
const taken = conditionFacts(context, clause.condition);
|
|
19321
|
+
const skipped = cloneFlow(current);
|
|
19322
|
+
applyFacts(skipped, negatedFacts(context, clause.condition));
|
|
19323
|
+
exits.push(branch(context, current, taken, clause.body));
|
|
19324
|
+
current = skipped;
|
|
18307
19325
|
}
|
|
18308
19326
|
if (alternate === null) {
|
|
18309
|
-
|
|
19327
|
+
exits.push(current);
|
|
19328
|
+
} else {
|
|
19329
|
+
context.setFlow(current);
|
|
19330
|
+
checkBlock(context, alternate);
|
|
19331
|
+
exits.push(context.flowState);
|
|
18310
19332
|
}
|
|
18311
|
-
|
|
18312
|
-
|
|
19333
|
+
context.setFlow(joinFlows(exits));
|
|
19334
|
+
}
|
|
19335
|
+
function checkLoopBody(context, body, facts) {
|
|
19336
|
+
forgetAssignedPaths(context, body);
|
|
19337
|
+
const entry = context.flowState;
|
|
19338
|
+
const state = cloneFlow(entry);
|
|
19339
|
+
applyFacts(state, facts);
|
|
19340
|
+
context.setFlow(state);
|
|
19341
|
+
checkBlock(context, body);
|
|
19342
|
+
context.setFlow(entry);
|
|
19343
|
+
}
|
|
19344
|
+
function checkWhile(context, statement) {
|
|
19345
|
+
forgetAssignedPaths(context, statement.body);
|
|
19346
|
+
checkExpression(context, statement.condition);
|
|
19347
|
+
checkLoopBody(context, statement.body, conditionFacts(context, statement.condition));
|
|
19348
|
+
context.applyFlowFacts(negatedFacts(context, statement.condition));
|
|
19349
|
+
}
|
|
19350
|
+
function checkRepeat(context, statement) {
|
|
19351
|
+
checkLoopBody(context, statement.body, /* @__PURE__ */ new Map());
|
|
19352
|
+
checkExpression(context, statement.condition);
|
|
18313
19353
|
}
|
|
18314
19354
|
function checkNumericFor(context, statement) {
|
|
18315
19355
|
const bounds = [statement.start, statement.limit, statement.step].filter((value) => value !== null);
|
|
@@ -18320,10 +19360,13 @@ function checkNumericFor(context, statement) {
|
|
|
18320
19360
|
}
|
|
18321
19361
|
}
|
|
18322
19362
|
forgetAssignedPaths(context, statement.body);
|
|
19363
|
+
const entry = context.flowState;
|
|
19364
|
+
context.setFlow(cloneFlow(entry));
|
|
18323
19365
|
context.binder.pushScope();
|
|
18324
19366
|
context.binder.declare({ name: statement.variable.name, type: NUMBER_TYPE, isLocal: true, position: statement.variable.position, origin: "local" });
|
|
18325
19367
|
checkStatements(context, statement.body);
|
|
18326
19368
|
context.binder.popScope();
|
|
19369
|
+
context.setFlow(entry);
|
|
18327
19370
|
}
|
|
18328
19371
|
function iteratedTypes(context, iterators) {
|
|
18329
19372
|
const [iterator] = iterators;
|
|
@@ -18344,6 +19387,8 @@ function checkGenericFor(context, statement) {
|
|
|
18344
19387
|
statement.iterators.forEach((iterator) => checkExpression(context, iterator));
|
|
18345
19388
|
const iterated = iteratedTypes(context, statement.iterators);
|
|
18346
19389
|
forgetAssignedPaths(context, statement.body);
|
|
19390
|
+
const entry = context.flowState;
|
|
19391
|
+
context.setFlow(cloneFlow(entry));
|
|
18347
19392
|
context.binder.pushScope();
|
|
18348
19393
|
statement.variables.forEach((variable, index) => {
|
|
18349
19394
|
const inferred = iterated[index] ?? ANY_TYPE;
|
|
@@ -18352,6 +19397,7 @@ function checkGenericFor(context, statement) {
|
|
|
18352
19397
|
});
|
|
18353
19398
|
checkStatements(context, statement.body);
|
|
18354
19399
|
context.binder.popScope();
|
|
19400
|
+
context.setFlow(entry);
|
|
18355
19401
|
}
|
|
18356
19402
|
|
|
18357
19403
|
// ../compiler/src/checker/events.ts
|
|
@@ -18412,15 +19458,19 @@ function minimumArguments(context, parameters) {
|
|
|
18412
19458
|
}
|
|
18413
19459
|
function buildFunctionType(context, parameters, returnAnnotation, contextual = null) {
|
|
18414
19460
|
const isVariadic = parameters.some((parameter) => parameter.isVararg);
|
|
18415
|
-
const
|
|
18416
|
-
|
|
19461
|
+
const named2 = parameters.filter((parameter) => !parameter.isVararg);
|
|
19462
|
+
const types = named2.map((parameter, index) => parameter.annotation === null ? contextual?.parameters[index] ?? ANY_TYPE : context.resolveAnnotation(parameter.annotation));
|
|
19463
|
+
const names = named2.map((parameter) => parameter.name);
|
|
19464
|
+
return createFunction(types, context.resolveAnnotation(returnAnnotation), minimumArguments(context, parameters), isVariadic, names);
|
|
18417
19465
|
}
|
|
18418
|
-
function checkFunctionBody(context, parameters, returnAnnotation, body, signature,
|
|
19466
|
+
function checkFunctionBody(context, parameters, returnAnnotation, body, signature, selfType2) {
|
|
18419
19467
|
forgetAssignedPaths(context, body);
|
|
19468
|
+
const entry = context.flowState;
|
|
19469
|
+
context.setFlow(cloneFlow(entry));
|
|
18420
19470
|
context.binder.pushScope();
|
|
18421
19471
|
context.pushReturnType(returnAnnotation === null ? null : context.resolveAnnotation(returnAnnotation));
|
|
18422
|
-
if (
|
|
18423
|
-
context.binder.declare({ name: "self", type:
|
|
19472
|
+
if (selfType2 !== null) {
|
|
19473
|
+
context.binder.declare({ name: "self", type: selfType2, isLocal: true, position: ORIGIN });
|
|
18424
19474
|
}
|
|
18425
19475
|
let parameterIndex = 0;
|
|
18426
19476
|
for (const parameter of parameters) {
|
|
@@ -18436,6 +19486,7 @@ function checkFunctionBody(context, parameters, returnAnnotation, body, signatur
|
|
|
18436
19486
|
signature.returnType = inferred;
|
|
18437
19487
|
}
|
|
18438
19488
|
context.binder.popScope();
|
|
19489
|
+
context.setFlow(entry);
|
|
18439
19490
|
}
|
|
18440
19491
|
function valueAt(values, valueTypes, index) {
|
|
18441
19492
|
if (values[index] !== void 0) {
|
|
@@ -18459,6 +19510,9 @@ function checkLocal(context, statement) {
|
|
|
18459
19510
|
context.expectAssignable(valueType, declared, value.position, `Variable "${declaration.name}"`);
|
|
18460
19511
|
}
|
|
18461
19512
|
context.binder.declare({ name: declaration.name, type: declared, isLocal: true, position: declaration.position, origin: "local" });
|
|
19513
|
+
if (value !== void 0) {
|
|
19514
|
+
recordAssignedFact(context, declaration.name, valueType, declared);
|
|
19515
|
+
}
|
|
18462
19516
|
});
|
|
18463
19517
|
}
|
|
18464
19518
|
function checkCompoundOperand(context, operator, type, position2) {
|
|
@@ -18472,6 +19526,15 @@ function checkCompoundOperand(context, operator, type, position2) {
|
|
|
18472
19526
|
context.report("check-invalid-operand", `Operator "${operator}" cannot be applied to "${typeToString(type)}".`, position2);
|
|
18473
19527
|
}
|
|
18474
19528
|
}
|
|
19529
|
+
function recordAssignedFact(context, path, valueType, declared) {
|
|
19530
|
+
if (path === null || valueType.kind === "any") {
|
|
19531
|
+
return;
|
|
19532
|
+
}
|
|
19533
|
+
const fact = assignmentFact(widenInferred(valueType), declared);
|
|
19534
|
+
if (fact !== null) {
|
|
19535
|
+
context.applyFlowFacts(/* @__PURE__ */ new Map([[path, fact]]));
|
|
19536
|
+
}
|
|
19537
|
+
}
|
|
18475
19538
|
function checkAssignment(context, statement) {
|
|
18476
19539
|
const valueTypes = checkValueList(context, statement.values);
|
|
18477
19540
|
statement.targets.forEach((target, index) => {
|
|
@@ -18507,6 +19570,7 @@ function checkAssignment(context, statement) {
|
|
|
18507
19570
|
if (value !== void 0) {
|
|
18508
19571
|
context.expectAssignable(valueType, declared, value.position, "Assignment");
|
|
18509
19572
|
}
|
|
19573
|
+
recordAssignedFact(context, pathOf2(target), valueType, declared);
|
|
18510
19574
|
});
|
|
18511
19575
|
}
|
|
18512
19576
|
function checkFunctionDeclaration(context, statement) {
|
|
@@ -18585,18 +19649,19 @@ function checkStatement(context, statement) {
|
|
|
18585
19649
|
case "function-declaration":
|
|
18586
19650
|
return checkFunctionDeclaration(context, statement);
|
|
18587
19651
|
case "return-statement":
|
|
18588
|
-
|
|
19652
|
+
checkReturn(context, statement);
|
|
19653
|
+
context.markUnreachable();
|
|
19654
|
+
return;
|
|
19655
|
+
case "break-statement":
|
|
19656
|
+
case "continue-statement":
|
|
19657
|
+
context.markUnreachable();
|
|
19658
|
+
return;
|
|
18589
19659
|
case "do-statement":
|
|
18590
19660
|
return checkBlock(context, statement.body);
|
|
18591
19661
|
case "while-statement":
|
|
18592
|
-
|
|
18593
|
-
forgetAssignedPaths(context, statement.body);
|
|
18594
|
-
return checkBlock(context, statement.body);
|
|
19662
|
+
return checkWhile(context, statement);
|
|
18595
19663
|
case "repeat-statement":
|
|
18596
|
-
|
|
18597
|
-
checkBlock(context, statement.body);
|
|
18598
|
-
checkExpression(context, statement.condition);
|
|
18599
|
-
return;
|
|
19664
|
+
return checkRepeat(context, statement);
|
|
18600
19665
|
case "if-statement":
|
|
18601
19666
|
return checkIf(context, statement.clauses, statement.alternate);
|
|
18602
19667
|
case "numeric-for-statement":
|
|
@@ -18626,18 +19691,8 @@ function checkStatement(context, statement) {
|
|
|
18626
19691
|
}
|
|
18627
19692
|
}
|
|
18628
19693
|
function checkStatements(context, statements) {
|
|
18629
|
-
let guards = 0;
|
|
18630
19694
|
for (const statement of statements) {
|
|
18631
19695
|
checkStatement(context, statement);
|
|
18632
|
-
const facts = guardFacts(context, statement);
|
|
18633
|
-
if (facts.size > 0) {
|
|
18634
|
-
context.pushNarrowing(facts);
|
|
18635
|
-
guards += 1;
|
|
18636
|
-
}
|
|
18637
|
-
}
|
|
18638
|
-
while (guards > 0) {
|
|
18639
|
-
context.popNarrowing();
|
|
18640
|
-
guards -= 1;
|
|
18641
19696
|
}
|
|
18642
19697
|
}
|
|
18643
19698
|
|
|
@@ -18681,6 +19736,10 @@ function checkMember(context, expression) {
|
|
|
18681
19736
|
checkExpression(context, expression.object);
|
|
18682
19737
|
return context.record(expression, narrowed);
|
|
18683
19738
|
}
|
|
19739
|
+
if (expression.object.kind === "identifier" && isUserClassReference(context, expression.object.name)) {
|
|
19740
|
+
context.references.add(expression.object.name);
|
|
19741
|
+
return context.record(expression, resolveStaticMember(context, expression.object.name, expression));
|
|
19742
|
+
}
|
|
18684
19743
|
if (expression.object.kind === "identifier" && isMtaClassReference(context, expression.object.name)) {
|
|
18685
19744
|
context.references.add(expression.object.name);
|
|
18686
19745
|
return context.record(expression, resolveMtaStaticMember(context, expression.object.name, expression.property, expression.position)?.type ?? ANY_TYPE);
|
|
@@ -18708,7 +19767,7 @@ function checkMember(context, expression) {
|
|
|
18708
19767
|
if (objectType.kind === "map" && isAssignable(STRING_TYPE, objectType.key)) {
|
|
18709
19768
|
return context.record(expression, objectType.value);
|
|
18710
19769
|
}
|
|
18711
|
-
const named2 = objectType.kind === "named" ? resolveNamedMember(context, objectType
|
|
19770
|
+
const named2 = objectType.kind === "named" ? resolveNamedMember(context, objectType, expression) : null;
|
|
18712
19771
|
if (named2 !== null) {
|
|
18713
19772
|
return context.record(expression, named2);
|
|
18714
19773
|
}
|
|
@@ -18765,10 +19824,14 @@ function isLegacySuperCall(expression) {
|
|
|
18765
19824
|
}
|
|
18766
19825
|
function checkMethodCall(context, expression, method, receiver) {
|
|
18767
19826
|
if (receiver.kind !== "named") {
|
|
18768
|
-
|
|
18769
|
-
|
|
19827
|
+
const signature = resolveNonNominalMethod(receiver, method);
|
|
19828
|
+
if (signature === null) {
|
|
19829
|
+
checkValueList(context, expression.args);
|
|
19830
|
+
return ANY_TYPE;
|
|
19831
|
+
}
|
|
19832
|
+
return checkSignature(context, expression.args, withoutSelfParameter(signature), expression.position);
|
|
18770
19833
|
}
|
|
18771
|
-
const declared = context
|
|
19834
|
+
const declared = memberOf(context, receiver, method);
|
|
18772
19835
|
if (declared?.type.kind === "function") {
|
|
18773
19836
|
if (declared.deprecated === true) {
|
|
18774
19837
|
context.warn("check-deprecated-use", `Member "${method}" is deprecated.`, expression.position);
|
|
@@ -18787,6 +19850,10 @@ function checkMethodCall(context, expression, method, receiver) {
|
|
|
18787
19850
|
return checkSignature(context, expression.args, member.type, expression.position);
|
|
18788
19851
|
}
|
|
18789
19852
|
function checkCall(context, expression) {
|
|
19853
|
+
const contracted = checkResourceCall(context, expression);
|
|
19854
|
+
if (contracted !== null) {
|
|
19855
|
+
return context.record(expression, contracted);
|
|
19856
|
+
}
|
|
18790
19857
|
if (isLegacySuperCall(expression)) {
|
|
18791
19858
|
checkValueList(context, expression.args);
|
|
18792
19859
|
context.report("check-invalid-super", 'Call "super(...)" directly instead of "self:super(...)".', expression.position);
|
|
@@ -18804,6 +19871,13 @@ function checkCall(context, expression) {
|
|
|
18804
19871
|
}
|
|
18805
19872
|
return context.record(expression, checkSignature(context, expression.args, constructor, expression.position));
|
|
18806
19873
|
}
|
|
19874
|
+
if (expression.method !== null && expression.callee.kind === "identifier" && isUserClassReference(context, expression.callee.name)) {
|
|
19875
|
+
const name = expression.callee.name;
|
|
19876
|
+
const message = `Call the static member "${expression.method}" as "${name}.${expression.method}(...)". A class value has no "self" to pass.`;
|
|
19877
|
+
context.report("check-static-receiver", message, expression.position);
|
|
19878
|
+
checkValueList(context, expression.args);
|
|
19879
|
+
return context.record(expression, ANY_TYPE);
|
|
19880
|
+
}
|
|
18807
19881
|
if (expression.method === null) {
|
|
18808
19882
|
context.calledMembers.add(expression.callee);
|
|
18809
19883
|
}
|
|
@@ -18880,6 +19954,9 @@ function checkMultiValueExpression(context, expression, expected = null) {
|
|
|
18880
19954
|
if (symbol === null) {
|
|
18881
19955
|
checkGlobalReference(context, expression.name, expression.position);
|
|
18882
19956
|
}
|
|
19957
|
+
if (symbol === null || symbol.isLocal !== true) {
|
|
19958
|
+
context.noteGlobalReference(expression.name);
|
|
19959
|
+
}
|
|
18883
19960
|
return context.record(expression, context.narrowedType(expression.name) ?? symbol?.type ?? ANY_TYPE);
|
|
18884
19961
|
}
|
|
18885
19962
|
case "member-expression":
|
|
@@ -18960,6 +20037,26 @@ function syntheticMethodType(context, member, fieldTypes) {
|
|
|
18960
20037
|
}
|
|
18961
20038
|
return buildFunctionType(context, member.parameters, member.returnAnnotation);
|
|
18962
20039
|
}
|
|
20040
|
+
function checkMemberSpaces(context, info, statement) {
|
|
20041
|
+
for (const member of statement.members) {
|
|
20042
|
+
if (member.isStatic && info.members.has(member.name)) {
|
|
20043
|
+
context.report("check-duplicate-class-member", `Class "${info.name}" declares "${member.name}" as both a static and an instance member.`, member.position);
|
|
20044
|
+
}
|
|
20045
|
+
if (!member.isStatic || info.superClass === null) {
|
|
20046
|
+
continue;
|
|
20047
|
+
}
|
|
20048
|
+
const inherited = context.declarations.lookupStaticMember(info.superClass, member.name);
|
|
20049
|
+
const declared = info.statics.get(member.name);
|
|
20050
|
+
if (inherited === void 0 || inherited === null || declared === void 0) {
|
|
20051
|
+
continue;
|
|
20052
|
+
}
|
|
20053
|
+
const options = { allowNil: context.allowNil };
|
|
20054
|
+
if (!isAssignable(declared.type, inherited.type, options) || !isAssignable(inherited.type, declared.type, options)) {
|
|
20055
|
+
const message = `Static member "${member.name}" must match "${typeToString(inherited.type)}" declared by class "${info.superClass}".`;
|
|
20056
|
+
context.report("check-invalid-override", message, member.position);
|
|
20057
|
+
}
|
|
20058
|
+
}
|
|
20059
|
+
}
|
|
18963
20060
|
function registerMembers(context, info, statement) {
|
|
18964
20061
|
const fieldTypes = /* @__PURE__ */ new Map();
|
|
18965
20062
|
for (const member of statement.members) {
|
|
@@ -18972,7 +20069,13 @@ function registerMembers(context, info, statement) {
|
|
|
18972
20069
|
for (const member of [...statement.members, ...generated]) {
|
|
18973
20070
|
const type = member.kind === "class-field" ? fieldTypes.get(member) ?? ANY_TYPE : member.isSynthetic ? syntheticMethodType(context, member, fieldTypes) : buildFunctionType(context, member.parameters, member.returnAnnotation);
|
|
18974
20071
|
const decorators = member.decorators.map((decorator) => decorator.name);
|
|
18975
|
-
|
|
20072
|
+
if (member.kind === "class-method" && isMetamethodMember(member)) {
|
|
20073
|
+
checkMetamethod(context, info.name, member, type);
|
|
20074
|
+
continue;
|
|
20075
|
+
}
|
|
20076
|
+
reportRejectedMetamethod(context, info.name, member);
|
|
20077
|
+
const space = member.isStatic ? info.statics : info.members;
|
|
20078
|
+
space.set(member.name, {
|
|
18976
20079
|
name: member.name,
|
|
18977
20080
|
type,
|
|
18978
20081
|
isMethod: member.kind === "class-method",
|
|
@@ -18981,6 +20084,7 @@ function registerMembers(context, info, statement) {
|
|
|
18981
20084
|
deprecated: decorators.includes("Deprecated")
|
|
18982
20085
|
});
|
|
18983
20086
|
}
|
|
20087
|
+
checkMemberSpaces(context, info, statement);
|
|
18984
20088
|
return generated;
|
|
18985
20089
|
}
|
|
18986
20090
|
function declareBuilder(context, info, statement) {
|
|
@@ -18997,20 +20101,37 @@ function declareBuilder(context, info, statement) {
|
|
|
18997
20101
|
}
|
|
18998
20102
|
}
|
|
18999
20103
|
members.set("build", { name: "build", type: { kind: "function", parameters: [], minimumArguments: 0, isVariadic: false, returnType: createNamed(statement.name) }, isMethod: true, position: statement.position });
|
|
19000
|
-
context.declarations.declareClass({
|
|
20104
|
+
context.declarations.declareClass({
|
|
20105
|
+
name,
|
|
20106
|
+
typeParameters: [],
|
|
20107
|
+
typeConstraints: [],
|
|
20108
|
+
superClass: null,
|
|
20109
|
+
superArguments: [],
|
|
20110
|
+
interfaces: [],
|
|
20111
|
+
members,
|
|
20112
|
+
statics: /* @__PURE__ */ new Map(),
|
|
20113
|
+
position: statement.position
|
|
20114
|
+
});
|
|
19001
20115
|
context.declareModuleGlobal({ name, type: createNamed(name), isLocal: false, position: statement.position });
|
|
19002
20116
|
}
|
|
20117
|
+
function selfType(info) {
|
|
20118
|
+
return createNamed(info.name, info.typeParameters.map((parameter) => createNamed(parameter)));
|
|
20119
|
+
}
|
|
19003
20120
|
function checkMethodBody(context, info, member) {
|
|
19004
20121
|
const explicitSelf = member.parameters.find((parameter) => parameter.name === "self");
|
|
19005
20122
|
if (explicitSelf !== void 0) {
|
|
19006
20123
|
context.report("check-explicit-self-parameter", 'Class methods receive "self" automatically; remove it from the parameter list.', explicitSelf.position);
|
|
19007
20124
|
}
|
|
19008
|
-
const signature = info.members.get(member.name)?.type;
|
|
20125
|
+
const signature = (member.isStatic ? info.statics : info.members).get(member.name)?.type;
|
|
19009
20126
|
if (signature?.kind !== "function") {
|
|
19010
20127
|
return;
|
|
19011
20128
|
}
|
|
20129
|
+
if (member.isStatic) {
|
|
20130
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature, null);
|
|
20131
|
+
return;
|
|
20132
|
+
}
|
|
19012
20133
|
context.pushClassMethod({ className: info.name, methodName: member.name });
|
|
19013
|
-
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature,
|
|
20134
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature, selfType(info));
|
|
19014
20135
|
context.popClassMethod();
|
|
19015
20136
|
}
|
|
19016
20137
|
function resolveSuperClass(context, statement) {
|
|
@@ -19033,6 +20154,10 @@ function resolveSuperClass(context, statement) {
|
|
|
19033
20154
|
context.report("check-unknown-class", message, statement.position);
|
|
19034
20155
|
return null;
|
|
19035
20156
|
}
|
|
20157
|
+
function resolveClassHeader(context, info, statement) {
|
|
20158
|
+
info.superArguments = statement.superClassArguments.map((argument) => context.resolveAnnotation(argument));
|
|
20159
|
+
info.typeConstraints = statement.typeConstraints.map((constraint) => constraint === null ? null : context.resolveAnnotation(constraint));
|
|
20160
|
+
}
|
|
19036
20161
|
function declareClassInfo(context, statement) {
|
|
19037
20162
|
if (context.declarations.lookupClass(statement.name) !== null) {
|
|
19038
20163
|
context.report("check-duplicate-class", `Class "${statement.name}" is already defined.`, statement.position);
|
|
@@ -19044,11 +20169,16 @@ function declareClassInfo(context, statement) {
|
|
|
19044
20169
|
}
|
|
19045
20170
|
const info = {
|
|
19046
20171
|
name: statement.name,
|
|
20172
|
+
typeParameters: statement.typeParameters,
|
|
20173
|
+
typeConstraints: [],
|
|
19047
20174
|
superClass: null,
|
|
20175
|
+
superArguments: [],
|
|
19048
20176
|
interfaces: statement.interfaces,
|
|
19049
20177
|
members: /* @__PURE__ */ new Map(),
|
|
20178
|
+
statics: /* @__PURE__ */ new Map(),
|
|
19050
20179
|
position: statement.position
|
|
19051
20180
|
};
|
|
20181
|
+
context.noteTypeParameters(statement.typeParameters);
|
|
19052
20182
|
context.declarations.declareClass(info);
|
|
19053
20183
|
context.declareModuleGlobal({ name: info.name, type: createNamed(info.name), isLocal: false, position: statement.position });
|
|
19054
20184
|
return info;
|
|
@@ -19059,6 +20189,7 @@ function declareLocalClass(context, statement) {
|
|
|
19059
20189
|
return null;
|
|
19060
20190
|
}
|
|
19061
20191
|
info.superClass = resolveSuperClass(context, statement);
|
|
20192
|
+
resolveClassHeader(context, info, statement);
|
|
19062
20193
|
return info;
|
|
19063
20194
|
}
|
|
19064
20195
|
function checkClassDeclaration(context, statement) {
|
|
@@ -19172,6 +20303,7 @@ function predeclareModule(context, body) {
|
|
|
19172
20303
|
const declared = declareHeaders(context, body);
|
|
19173
20304
|
for (const entry of declared) {
|
|
19174
20305
|
entry.info.superClass = resolveSuperClass(context, entry.statement);
|
|
20306
|
+
resolveClassHeader(context, entry.info, entry.statement);
|
|
19175
20307
|
}
|
|
19176
20308
|
for (const entry of declared) {
|
|
19177
20309
|
breakCycle(context, entry.info);
|
|
@@ -19231,25 +20363,34 @@ function externalReferences(context) {
|
|
|
19231
20363
|
}
|
|
19232
20364
|
return external;
|
|
19233
20365
|
}
|
|
20366
|
+
function referencedNames(context, external) {
|
|
20367
|
+
const events = [...context.eventReferences].map((name) => `${EVENT_NAME_PREFIX}${name}`);
|
|
20368
|
+
return /* @__PURE__ */ new Set([...external.keys(), ...context.globalReferences, ...context.unknownTypes.keys(), ...events]);
|
|
20369
|
+
}
|
|
19234
20370
|
function check(program2, mode, environment = DEFAULT_ENVIRONMENT, options = {}) {
|
|
19235
20371
|
const ambient = options.ambient ?? EMPTY_AMBIENT;
|
|
19236
20372
|
const project = options.project ?? EMPTY_PROJECT_DECLARATIONS;
|
|
19237
20373
|
const context = new CheckContext(mode, environment, ambient, project, options.oop === true);
|
|
19238
20374
|
context.isDeclarationFile = options.isDeclarationFile === true;
|
|
20375
|
+
context.contracts = options.contracts ?? [];
|
|
19239
20376
|
const structure = context.isDeclarationFile ? checkDeclarationFile(program2.body) : checkJumps(program2.body);
|
|
19240
20377
|
const directives = collectDirectives(program2.body, { isDeclarationFile: context.isDeclarationFile });
|
|
19241
20378
|
predeclareModule(context, program2.body);
|
|
19242
20379
|
checkStatements(context, program2.body);
|
|
19243
20380
|
reportUnknownTypes(context);
|
|
19244
20381
|
reportUnusedSymbols(context, options.noUnusedLocals === true, options.noUnusedParameters === true);
|
|
20382
|
+
const external = externalReferences(context);
|
|
19245
20383
|
return {
|
|
19246
20384
|
diagnostics: sortDiagnostics([...structure, ...directives.diagnostics, ...context.diagnostics]),
|
|
19247
20385
|
types: context.types,
|
|
19248
20386
|
references: context.references,
|
|
20387
|
+
staticAccess: context.staticAccess,
|
|
19249
20388
|
declarations: context.declarations,
|
|
19250
20389
|
aliases: context.binder.resolvedAliases(),
|
|
19251
20390
|
declaredGlobals: context.declaredGlobals,
|
|
19252
|
-
|
|
20391
|
+
moduleGlobals: context.moduleGlobals,
|
|
20392
|
+
externalReferences: external,
|
|
20393
|
+
referencedNames: referencedNames(context, external),
|
|
19253
20394
|
directives: directives.directives,
|
|
19254
20395
|
mode,
|
|
19255
20396
|
environment,
|
|
@@ -19362,8 +20503,8 @@ function finalizeEmission(code, markers, sourceLineOffset = 0) {
|
|
|
19362
20503
|
|
|
19363
20504
|
// ../compiler/src/emitter/state.ts
|
|
19364
20505
|
var INDENT2 = " ";
|
|
19365
|
-
function createEmitState(types, references, generatedMembers) {
|
|
19366
|
-
return { types, references, generatedMembers, helpers: /* @__PURE__ */ new Set(), indent: 0, markers: [], symbol: void 0, loopWrap: false };
|
|
20506
|
+
function createEmitState(types, references, generatedMembers, staticAccess = /* @__PURE__ */ new Set()) {
|
|
20507
|
+
return { types, references, staticAccess, generatedMembers, helpers: /* @__PURE__ */ new Set(), indent: 0, markers: [], symbol: void 0, loopWrap: false };
|
|
19367
20508
|
}
|
|
19368
20509
|
function requireHelper(state, helper) {
|
|
19369
20510
|
if (helper !== null) {
|
|
@@ -19515,6 +20656,10 @@ function emitTable(state, expression) {
|
|
|
19515
20656
|
return `{ ${fields.join(", ")} }`;
|
|
19516
20657
|
}
|
|
19517
20658
|
function emitMember(state, expression) {
|
|
20659
|
+
if (state.staticAccess.has(expression) && expression.object.kind === "identifier") {
|
|
20660
|
+
requireHelper(state, "class");
|
|
20661
|
+
return `getClass(${emitString(expression.object.name)}).${expression.property}`;
|
|
20662
|
+
}
|
|
19518
20663
|
const extension = resolvePropertyExtension(typeOf(state, expression.object), expression.property);
|
|
19519
20664
|
const object = emitExpression(state, expression.object, UNARY_PRECEDENCE);
|
|
19520
20665
|
if (extension === null) {
|
|
@@ -19609,7 +20754,8 @@ function emitMethod(state, className, member) {
|
|
|
19609
20754
|
if (member.generated !== void 0) {
|
|
19610
20755
|
return emitGeneratedMethod(state, className, member);
|
|
19611
20756
|
}
|
|
19612
|
-
|
|
20757
|
+
const parameters = member.isStatic ? member.parameters : [self, ...member.parameters];
|
|
20758
|
+
return withSymbol(state, `${className}${member.isStatic ? "." : ":"}${member.name}`, () => emitFunctionBody(state, parameters, member.body, `${member.name} = function`));
|
|
19613
20759
|
}
|
|
19614
20760
|
function emitGeneratedMethod(state, className, member) {
|
|
19615
20761
|
const fields = member.generated?.fields ?? [];
|
|
@@ -19642,6 +20788,13 @@ function emitGeneratedMethod(state, className, member) {
|
|
|
19642
20788
|
end
|
|
19643
20789
|
end`;
|
|
19644
20790
|
}
|
|
20791
|
+
if (member.generated?.kind === "validate" || member.generated?.kind === "matches") {
|
|
20792
|
+
const helper = member.generated.kind === "validate" ? "__luam_validate" : "__luam_matches";
|
|
20793
|
+
requireHelper(state, "validate");
|
|
20794
|
+
return `${member.name} = function(value)
|
|
20795
|
+
return ${helper}(value, ${member.generated.descriptor ?? "{ kind = 'table' }"})
|
|
20796
|
+
end`;
|
|
20797
|
+
}
|
|
19645
20798
|
if (member.generated?.kind === "to-string") {
|
|
19646
20799
|
const values = names.map((name) => `'${name}=' .. tostring(self.${name})`).join(" .. ', ' .. ");
|
|
19647
20800
|
const body = values.length === 0 ? "''" : values;
|
|
@@ -19677,24 +20830,24 @@ ${names.map((name) => ` self.${name} = values.${name}`).join("\n")}
|
|
|
19677
20830
|
end`;
|
|
19678
20831
|
}
|
|
19679
20832
|
function emitMembers(state, statement) {
|
|
19680
|
-
const
|
|
20833
|
+
const entries3 = [];
|
|
19681
20834
|
state.indent += 1;
|
|
19682
20835
|
for (const member of statement.members) {
|
|
19683
20836
|
if (member.kind === "class-method") {
|
|
19684
|
-
|
|
20837
|
+
entries3.push(indentLine(state, `${markSource(state, member.position.line, `${statement.name}${member.isStatic ? "." : ":"}${member.name}`)}${emitMethod(state, statement.name, member)}`));
|
|
19685
20838
|
continue;
|
|
19686
20839
|
}
|
|
19687
20840
|
if (member.decorators.some((decorator) => decorator.name === "Lazy")) {
|
|
19688
20841
|
continue;
|
|
19689
20842
|
}
|
|
19690
20843
|
const value = member.value === null ? "nil" : emitExpression(state, member.value);
|
|
19691
|
-
|
|
20844
|
+
entries3.push(indentLine(state, `${markSource(state, member.position.line, statement.name)}${member.name} = ${value}`));
|
|
19692
20845
|
}
|
|
19693
20846
|
for (const generated of state.generatedMembers.get(statement) ?? []) {
|
|
19694
|
-
|
|
20847
|
+
entries3.push(indentLine(state, `${markSource(state, generated.position.line, `${statement.name}:${generated.name}`)}${emitMethod(state, statement.name, generated)}`));
|
|
19695
20848
|
}
|
|
19696
20849
|
state.indent -= 1;
|
|
19697
|
-
return
|
|
20850
|
+
return entries3;
|
|
19698
20851
|
}
|
|
19699
20852
|
function emitClassHeader(statement) {
|
|
19700
20853
|
const name = emitString(statement.name);
|
|
@@ -19720,15 +20873,15 @@ ${assignments}
|
|
|
19720
20873
|
return value
|
|
19721
20874
|
end`);
|
|
19722
20875
|
state.indent += 1;
|
|
19723
|
-
const
|
|
20876
|
+
const entries3 = methods.map((method) => indentLine(state, method));
|
|
19724
20877
|
state.indent -= 1;
|
|
19725
|
-
return [`class '${name}' {`,
|
|
20878
|
+
return [`class '${name}' {`, entries3.join(",\n"), "}"].join("\n");
|
|
19726
20879
|
}
|
|
19727
20880
|
function emitClassDeclaration(state, statement) {
|
|
19728
20881
|
requireHelper(state, "class");
|
|
19729
20882
|
const header = emitClassHeader(statement);
|
|
19730
|
-
const
|
|
19731
|
-
const declaration =
|
|
20883
|
+
const entries3 = emitMembers(state, statement);
|
|
20884
|
+
const declaration = entries3.length === 0 ? `${header} {}` : [`${header} {`, entries3.join(",\n"), indentLine(state, "}")].join("\n");
|
|
19732
20885
|
const builder = emitBuilder(state, statement);
|
|
19733
20886
|
return builder === null ? declaration : `${declaration}
|
|
19734
20887
|
${builder}`;
|
|
@@ -19923,8 +21076,8 @@ function emitBlock(state, statements) {
|
|
|
19923
21076
|
}
|
|
19924
21077
|
return lines;
|
|
19925
21078
|
}
|
|
19926
|
-
function emit2(program2, types, references, generatedMembers = /* @__PURE__ */ new Map(), sourceLineOffset = 0) {
|
|
19927
|
-
const state = createEmitState(types, references, generatedMembers);
|
|
21079
|
+
function emit2(program2, types, references, generatedMembers = /* @__PURE__ */ new Map(), sourceLineOffset = 0, staticAccess = /* @__PURE__ */ new Set()) {
|
|
21080
|
+
const state = createEmitState(types, references, generatedMembers, staticAccess);
|
|
19928
21081
|
const lines = emitBlock(state, program2.body);
|
|
19929
21082
|
const markedCode = lines.length === 0 ? "" : `${lines.join("\n")}
|
|
19930
21083
|
`;
|
|
@@ -20176,7 +21329,7 @@ function erasedEdit(source, span) {
|
|
|
20176
21329
|
}
|
|
20177
21330
|
function canonicalEdit(input, statement, span) {
|
|
20178
21331
|
const { source } = input;
|
|
20179
|
-
const emitted = emit2({ ...input.program, body: [statement] }, input.types, input.references, input.generatedMembers, statement.position.line - 1);
|
|
21332
|
+
const emitted = emit2({ ...input.program, body: [statement] }, input.types, input.references, input.generatedMembers, statement.position.line - 1, input.staticAccess);
|
|
20180
21333
|
const trimmed = span.end < source.length && emitted.code.endsWith("\n") ? emitted.code.slice(0, -1) : emitted.code;
|
|
20181
21334
|
if (trimmed.length === 0) {
|
|
20182
21335
|
return erasedEdit(source, span);
|
|
@@ -20211,15 +21364,16 @@ function builderClassText(input, statement) {
|
|
|
20211
21364
|
}
|
|
20212
21365
|
|
|
20213
21366
|
// ../compiler/src/emitter/preserve-guards.ts
|
|
20214
|
-
|
|
21367
|
+
var NO_STATIC_ACCESS = /* @__PURE__ */ new Set();
|
|
21368
|
+
function isPreservableExpression(expression, types, statics = NO_STATIC_ACCESS) {
|
|
20215
21369
|
switch (expression.kind) {
|
|
20216
21370
|
case "template-literal":
|
|
20217
21371
|
case "new-expression":
|
|
20218
21372
|
return false;
|
|
20219
21373
|
case "member-expression":
|
|
20220
|
-
return resolvePropertyExtension(types.get(expression.object) ?? null, expression.property) === null && isPreservableExpression(expression.object, types);
|
|
21374
|
+
return !statics.has(expression) && resolvePropertyExtension(types.get(expression.object) ?? null, expression.property) === null && isPreservableExpression(expression.object, types, statics);
|
|
20221
21375
|
case "index-expression":
|
|
20222
|
-
return isPreservableExpression(expression.object, types) && isPreservableExpression(expression.index, types);
|
|
21376
|
+
return isPreservableExpression(expression.object, types, statics) && isPreservableExpression(expression.index, types, statics);
|
|
20223
21377
|
case "call-expression":
|
|
20224
21378
|
if (expression.method === null && expression.callee.kind === "identifier" && expression.callee.name === "super") {
|
|
20225
21379
|
return false;
|
|
@@ -20227,43 +21381,43 @@ function isPreservableExpression(expression, types) {
|
|
|
20227
21381
|
if (expression.callee.kind === "member-expression" && resolveCallExtension(types.get(expression.callee.object) ?? null, expression.callee.property) !== null) {
|
|
20228
21382
|
return false;
|
|
20229
21383
|
}
|
|
20230
|
-
return isPreservableExpression(expression.callee, types) && expression.args.every((argument) => isPreservableExpression(argument, types));
|
|
21384
|
+
return isPreservableExpression(expression.callee, types, statics) && expression.args.every((argument) => isPreservableExpression(argument, types, statics));
|
|
20231
21385
|
case "table-expression":
|
|
20232
21386
|
return expression.fields.every(
|
|
20233
|
-
(field2) => (field2.key === null || isPreservableExpression(field2.key, types)) && isPreservableExpression(field2.value, types)
|
|
21387
|
+
(field2) => (field2.key === null || isPreservableExpression(field2.key, types, statics)) && isPreservableExpression(field2.value, types, statics)
|
|
20234
21388
|
);
|
|
20235
21389
|
case "binary-expression":
|
|
20236
|
-
return isPreservableExpression(expression.left, types) && isPreservableExpression(expression.right, types);
|
|
21390
|
+
return isPreservableExpression(expression.left, types, statics) && isPreservableExpression(expression.right, types, statics);
|
|
20237
21391
|
case "unary-expression":
|
|
20238
|
-
return isPreservableExpression(expression.operand, types);
|
|
21392
|
+
return isPreservableExpression(expression.operand, types, statics);
|
|
20239
21393
|
case "group-expression":
|
|
20240
|
-
return isPreservableExpression(expression.expression, types);
|
|
21394
|
+
return isPreservableExpression(expression.expression, types, statics);
|
|
20241
21395
|
default:
|
|
20242
21396
|
return true;
|
|
20243
21397
|
}
|
|
20244
21398
|
}
|
|
20245
|
-
function every(expressions, types) {
|
|
20246
|
-
return expressions.every((expression) => isPreservableExpression(expression, types));
|
|
21399
|
+
function every(expressions, types, statics) {
|
|
21400
|
+
return expressions.every((expression) => isPreservableExpression(expression, types, statics));
|
|
20247
21401
|
}
|
|
20248
|
-
function isPreservableStatement(statement, types) {
|
|
21402
|
+
function isPreservableStatement(statement, types, statics = NO_STATIC_ACCESS) {
|
|
20249
21403
|
switch (statement.kind) {
|
|
20250
21404
|
case "local-statement":
|
|
20251
|
-
return every(statement.values, types);
|
|
21405
|
+
return every(statement.values, types, statics);
|
|
20252
21406
|
case "assignment-statement":
|
|
20253
|
-
return statement.operator === "=" && every(statement.targets, types) && every(statement.values, types);
|
|
21407
|
+
return statement.operator === "=" && every(statement.targets, types, statics) && every(statement.values, types, statics);
|
|
20254
21408
|
case "call-statement":
|
|
20255
|
-
return isPreservableExpression(statement.expression, types);
|
|
21409
|
+
return isPreservableExpression(statement.expression, types, statics);
|
|
20256
21410
|
case "return-statement":
|
|
20257
|
-
return every(statement.values, types);
|
|
21411
|
+
return every(statement.values, types, statics);
|
|
20258
21412
|
case "while-statement":
|
|
20259
21413
|
case "repeat-statement":
|
|
20260
|
-
return isPreservableExpression(statement.condition, types);
|
|
21414
|
+
return isPreservableExpression(statement.condition, types, statics);
|
|
20261
21415
|
case "if-statement":
|
|
20262
|
-
return statement.clauses.every((clause) => isPreservableExpression(clause.condition, types));
|
|
21416
|
+
return statement.clauses.every((clause) => isPreservableExpression(clause.condition, types, statics));
|
|
20263
21417
|
case "numeric-for-statement":
|
|
20264
|
-
return isPreservableExpression(statement.start, types) && isPreservableExpression(statement.limit, types) && (statement.step === null || isPreservableExpression(statement.step, types));
|
|
21418
|
+
return isPreservableExpression(statement.start, types, statics) && isPreservableExpression(statement.limit, types, statics) && (statement.step === null || isPreservableExpression(statement.step, types, statics));
|
|
20265
21419
|
case "generic-for-statement":
|
|
20266
|
-
return every(statement.iterators, types);
|
|
21420
|
+
return every(statement.iterators, types, statics);
|
|
20267
21421
|
case "break-statement":
|
|
20268
21422
|
case "declare-statement":
|
|
20269
21423
|
case "do-statement":
|
|
@@ -20391,7 +21545,7 @@ function classEdits(input, statement, spans) {
|
|
|
20391
21545
|
edits.push({ start: span.start, end, replacement: isLazyField(member) ? longComment(text) : blankSpan(text) });
|
|
20392
21546
|
continue;
|
|
20393
21547
|
}
|
|
20394
|
-
if (member.kind === "class-method") {
|
|
21548
|
+
if (member.kind === "class-method" && !member.isStatic) {
|
|
20395
21549
|
const self = selfEdit(source, member, span);
|
|
20396
21550
|
if (self === null) {
|
|
20397
21551
|
return null;
|
|
@@ -20505,7 +21659,7 @@ function surgery(collector, statement) {
|
|
|
20505
21659
|
const edits2 = classEdits(input, statement, { span, members: input.spans });
|
|
20506
21660
|
return edits2 === null ? null : { edits: edits2, wrapsBody: false };
|
|
20507
21661
|
}
|
|
20508
|
-
if (loopBody(statement) === null || !isPreservableStatement(statement, input.types)) {
|
|
21662
|
+
if (loopBody(statement) === null || !isPreservableStatement(statement, input.types, input.staticAccess)) {
|
|
20509
21663
|
return null;
|
|
20510
21664
|
}
|
|
20511
21665
|
const edits = loopEdits(input, statement);
|
|
@@ -20534,7 +21688,7 @@ function visit(collector, statement, wrapped) {
|
|
|
20534
21688
|
descend(collector, statement, false, surgical.wrapsBody);
|
|
20535
21689
|
return;
|
|
20536
21690
|
}
|
|
20537
|
-
if (isPreservableStatement(statement, collector.input.types) && keepsScaffolding(statement)) {
|
|
21691
|
+
if (isPreservableStatement(statement, collector.input.types, collector.input.staticAccess) && keepsScaffolding(statement)) {
|
|
20538
21692
|
const inherited = statement.kind === "do-statement" || statement.kind === "if-statement" ? wrapped : false;
|
|
20539
21693
|
descend(collector, statement, inherited, false);
|
|
20540
21694
|
return;
|
|
@@ -20665,6 +21819,7 @@ function compile(source, options = {}) {
|
|
|
20665
21819
|
const isDeclarationFile = options.filePath !== void 0 && isDeclarationPath(options.filePath);
|
|
20666
21820
|
const checked = check(parsed.program, mode, environment, {
|
|
20667
21821
|
ambient: options.ambient ?? EMPTY_AMBIENT,
|
|
21822
|
+
contracts: options.contracts ?? [],
|
|
20668
21823
|
project: options.project ?? EMPTY_PROJECT_DECLARATIONS,
|
|
20669
21824
|
isDeclarationFile,
|
|
20670
21825
|
oop: settings.oop,
|
|
@@ -20678,7 +21833,9 @@ function compile(source, options = {}) {
|
|
|
20678
21833
|
environment,
|
|
20679
21834
|
declarations: ownDeclarations(checked.declarations, options.ambient),
|
|
20680
21835
|
declaredGlobals: checked.declaredGlobals,
|
|
21836
|
+
moduleGlobals: checked.moduleGlobals,
|
|
20681
21837
|
externalReferences: checked.externalReferences,
|
|
21838
|
+
referencedNames: checked.referencedNames,
|
|
20682
21839
|
directives: checked.directives,
|
|
20683
21840
|
topLevelReturn: findTopLevelReturn(parsed.program.body),
|
|
20684
21841
|
events: checked.events
|
|
@@ -20687,7 +21844,7 @@ function compile(source, options = {}) {
|
|
|
20687
21844
|
return { ...shared, code: null, requiredHelpers: [], lines: [] };
|
|
20688
21845
|
}
|
|
20689
21846
|
const references = reachedNames(checked.references, options.projectReferences);
|
|
20690
|
-
const emitted = emit2(parsed.program, checked.types, references, checked.generatedMembers);
|
|
21847
|
+
const emitted = emit2(parsed.program, checked.types, references, checked.generatedMembers, 0, checked.staticAccess);
|
|
20691
21848
|
const preserved = emitPreservingSource({
|
|
20692
21849
|
source,
|
|
20693
21850
|
program: parsed.program,
|
|
@@ -20697,6 +21854,7 @@ function compile(source, options = {}) {
|
|
|
20697
21854
|
types: checked.types,
|
|
20698
21855
|
references,
|
|
20699
21856
|
generatedMembers: checked.generatedMembers,
|
|
21857
|
+
staticAccess: checked.staticAccess,
|
|
20700
21858
|
development: options.development === true
|
|
20701
21859
|
});
|
|
20702
21860
|
const required = new Set(emitted.requiredHelpers);
|
|
@@ -20768,6 +21926,199 @@ function fingerprintDeclarations(declarations) {
|
|
|
20768
21926
|
const events = declarations.events.map(eventText);
|
|
20769
21927
|
return hashString([...classes, ...interfaces, ...enums, ...globals, ...events].sort(compareText).join(";"));
|
|
20770
21928
|
}
|
|
21929
|
+
function appendText(entries3, name, text) {
|
|
21930
|
+
const existing = entries3.get(name);
|
|
21931
|
+
entries3.set(name, existing === void 0 ? text : `${existing}|${text}`);
|
|
21932
|
+
}
|
|
21933
|
+
function fingerprintByName(declarations) {
|
|
21934
|
+
const entries3 = /* @__PURE__ */ new Map();
|
|
21935
|
+
for (const info of declarations.classes) {
|
|
21936
|
+
appendText(entries3, info.name, classText(info));
|
|
21937
|
+
}
|
|
21938
|
+
for (const info of declarations.interfaces) {
|
|
21939
|
+
appendText(entries3, info.name, interfaceText(info));
|
|
21940
|
+
}
|
|
21941
|
+
for (const info of declarations.enums) {
|
|
21942
|
+
appendText(entries3, info.name, enumText(info));
|
|
21943
|
+
}
|
|
21944
|
+
for (const info of declarations.globals) {
|
|
21945
|
+
appendText(entries3, info.name, globalText(info));
|
|
21946
|
+
}
|
|
21947
|
+
for (const info of declarations.events) {
|
|
21948
|
+
appendText(entries3, `${EVENT_NAME_PREFIX}${info.name}`, eventText(info));
|
|
21949
|
+
}
|
|
21950
|
+
return new Map([...entries3].map(([name, text]) => [name, hashString(text)]));
|
|
21951
|
+
}
|
|
21952
|
+
|
|
21953
|
+
// ../compiler/src/project/dependency-graph.ts
|
|
21954
|
+
var MAX_CLOSURE_SIZE = 512;
|
|
21955
|
+
function indexOwners(nodes, environment) {
|
|
21956
|
+
const owners = /* @__PURE__ */ new Map();
|
|
21957
|
+
for (const node of nodes) {
|
|
21958
|
+
if (!canReference(environment, node.environment)) {
|
|
21959
|
+
continue;
|
|
21960
|
+
}
|
|
21961
|
+
for (const name of node.provides.keys()) {
|
|
21962
|
+
const existing = owners.get(name);
|
|
21963
|
+
if (existing === void 0) {
|
|
21964
|
+
owners.set(name, [node]);
|
|
21965
|
+
continue;
|
|
21966
|
+
}
|
|
21967
|
+
existing.push(node);
|
|
21968
|
+
}
|
|
21969
|
+
}
|
|
21970
|
+
return owners;
|
|
21971
|
+
}
|
|
21972
|
+
function walk3(node, owners) {
|
|
21973
|
+
const visited = /* @__PURE__ */ new Set();
|
|
21974
|
+
const pending = [...node.requires, ...node.provides.keys()];
|
|
21975
|
+
while (pending.length > 0) {
|
|
21976
|
+
const name = pending.pop();
|
|
21977
|
+
if (name === void 0 || visited.has(name)) {
|
|
21978
|
+
continue;
|
|
21979
|
+
}
|
|
21980
|
+
visited.add(name);
|
|
21981
|
+
if (visited.size > MAX_CLOSURE_SIZE) {
|
|
21982
|
+
return null;
|
|
21983
|
+
}
|
|
21984
|
+
for (const owner of owners.get(name) ?? []) {
|
|
21985
|
+
for (const required of owner.requires) {
|
|
21986
|
+
if (!visited.has(required)) {
|
|
21987
|
+
pending.push(required);
|
|
21988
|
+
}
|
|
21989
|
+
}
|
|
21990
|
+
}
|
|
21991
|
+
}
|
|
21992
|
+
return visited;
|
|
21993
|
+
}
|
|
21994
|
+
function ownerText(owners, name) {
|
|
21995
|
+
const list = owners.get(name) ?? [];
|
|
21996
|
+
return `${name}=${list.map((owner) => `${owner.path}:${owner.provides.get(name) ?? ""}`).sort().join("+")}`;
|
|
21997
|
+
}
|
|
21998
|
+
function createDependencyGraph(nodes) {
|
|
21999
|
+
const byPath = new Map(nodes.map((node) => [node.path, node]));
|
|
22000
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
22001
|
+
const closures = /* @__PURE__ */ new Map();
|
|
22002
|
+
const keys = /* @__PURE__ */ new Map();
|
|
22003
|
+
function ownersFor(environment) {
|
|
22004
|
+
const cached = indexes.get(environment);
|
|
22005
|
+
if (cached !== void 0) {
|
|
22006
|
+
return cached;
|
|
22007
|
+
}
|
|
22008
|
+
const owners = indexOwners(nodes, environment);
|
|
22009
|
+
indexes.set(environment, owners);
|
|
22010
|
+
return owners;
|
|
22011
|
+
}
|
|
22012
|
+
function closureOf(path) {
|
|
22013
|
+
if (closures.has(path)) {
|
|
22014
|
+
return closures.get(path) ?? null;
|
|
22015
|
+
}
|
|
22016
|
+
const node = byPath.get(path);
|
|
22017
|
+
const closure = node === void 0 ? null : walk3(node, ownersFor(node.environment));
|
|
22018
|
+
closures.set(path, closure);
|
|
22019
|
+
return closure;
|
|
22020
|
+
}
|
|
22021
|
+
function keyOf(path) {
|
|
22022
|
+
if (keys.has(path)) {
|
|
22023
|
+
return keys.get(path) ?? null;
|
|
22024
|
+
}
|
|
22025
|
+
const node = byPath.get(path);
|
|
22026
|
+
const closure = closureOf(path);
|
|
22027
|
+
if (node === void 0 || closure === null) {
|
|
22028
|
+
keys.set(path, null);
|
|
22029
|
+
return null;
|
|
22030
|
+
}
|
|
22031
|
+
const owners = ownersFor(node.environment);
|
|
22032
|
+
const key = hashString([...closure].sort().map((name) => ownerText(owners, name)).join(";"));
|
|
22033
|
+
keys.set(path, key);
|
|
22034
|
+
return key;
|
|
22035
|
+
}
|
|
22036
|
+
return {
|
|
22037
|
+
closureOf,
|
|
22038
|
+
keyOf,
|
|
22039
|
+
dependentsOf: (names) => {
|
|
22040
|
+
const dependents = /* @__PURE__ */ new Set();
|
|
22041
|
+
for (const node of nodes) {
|
|
22042
|
+
const closure = closureOf(node.path);
|
|
22043
|
+
if (closure === null) {
|
|
22044
|
+
dependents.add(node.path);
|
|
22045
|
+
continue;
|
|
22046
|
+
}
|
|
22047
|
+
for (const name of names) {
|
|
22048
|
+
if (closure.has(name)) {
|
|
22049
|
+
dependents.add(node.path);
|
|
22050
|
+
break;
|
|
22051
|
+
}
|
|
22052
|
+
}
|
|
22053
|
+
}
|
|
22054
|
+
return dependents;
|
|
22055
|
+
},
|
|
22056
|
+
providedBy: (paths) => {
|
|
22057
|
+
const names = /* @__PURE__ */ new Set();
|
|
22058
|
+
for (const path of paths) {
|
|
22059
|
+
for (const name of byPath.get(path)?.provides.keys() ?? []) {
|
|
22060
|
+
names.add(name);
|
|
22061
|
+
}
|
|
22062
|
+
}
|
|
22063
|
+
return names;
|
|
22064
|
+
}
|
|
22065
|
+
};
|
|
22066
|
+
}
|
|
22067
|
+
|
|
22068
|
+
// ../compiler/src/project/ambient-scope.ts
|
|
22069
|
+
function optionsKey(options) {
|
|
22070
|
+
return `${options.strict ? "strict" : ""}|${options.oop ? "oop" : ""}|${options.noUnusedLocals ? "nul" : ""}|${options.noUnusedParameters ? "nup" : ""}`;
|
|
22071
|
+
}
|
|
22072
|
+
function declaresNothing(declarations) {
|
|
22073
|
+
const { classes, interfaces, enums, globals, events } = declarations;
|
|
22074
|
+
return classes.length === 0 && interfaces.length === 0 && enums.length === 0 && globals.length === 0 && events.length === 0;
|
|
22075
|
+
}
|
|
22076
|
+
function sharedEnums(collected) {
|
|
22077
|
+
const declared = new Set(collected.flatMap((entry) => entry.declarations.enums.map((enumeration) => enumeration.name)));
|
|
22078
|
+
if (declared.size === 0) {
|
|
22079
|
+
return declared;
|
|
22080
|
+
}
|
|
22081
|
+
return new Set(collected.flatMap((entry) => entry.externalReferences.filter((name) => declared.has(name))));
|
|
22082
|
+
}
|
|
22083
|
+
function baseKey(context) {
|
|
22084
|
+
const mode = context.development ? "development" : "release";
|
|
22085
|
+
const contracts = context.contracts.map((contract) => serializeAbi(contract)).join(";");
|
|
22086
|
+
return `${optionsKey(context.options)}|${mode}|${JSON.stringify(context.project.globals)}|${[...context.references].sort().join(",")}|${hashString(contracts)}`;
|
|
22087
|
+
}
|
|
22088
|
+
function environmentKeys(collected) {
|
|
22089
|
+
const keys = {};
|
|
22090
|
+
for (const environment of ALL_ENVIRONMENTS) {
|
|
22091
|
+
const visible = collected.filter((entry) => canReference(environment, entry.environment));
|
|
22092
|
+
keys[environment] = hashString(visible.map((entry) => `${entry.path}=${entry.fingerprint}`).join(";"));
|
|
22093
|
+
}
|
|
22094
|
+
return keys;
|
|
22095
|
+
}
|
|
22096
|
+
function createResolver(collected) {
|
|
22097
|
+
const visible = /* @__PURE__ */ new Map();
|
|
22098
|
+
const merged = /* @__PURE__ */ new Map();
|
|
22099
|
+
for (const environment of ALL_ENVIRONMENTS) {
|
|
22100
|
+
const entries3 = collected.filter((entry) => canReference(environment, entry.environment) && !declaresNothing(entry.declarations));
|
|
22101
|
+
visible.set(environment, entries3);
|
|
22102
|
+
merged.set(environment, mergeAmbient(entries3.map((entry) => entry.declarations)));
|
|
22103
|
+
}
|
|
22104
|
+
return (entry) => {
|
|
22105
|
+
if (declaresNothing(entry.declarations)) {
|
|
22106
|
+
return merged.get(entry.environment) ?? EMPTY_AMBIENT;
|
|
22107
|
+
}
|
|
22108
|
+
const entries3 = visible.get(entry.environment) ?? [];
|
|
22109
|
+
return mergeAmbient(entries3.filter((candidate) => candidate.path !== entry.path).map((candidate) => candidate.declarations));
|
|
22110
|
+
};
|
|
22111
|
+
}
|
|
22112
|
+
function createAmbientScope(collected, context) {
|
|
22113
|
+
const graph = createDependencyGraph(collected);
|
|
22114
|
+
const base = baseKey(context);
|
|
22115
|
+
const fallback = environmentKeys(collected);
|
|
22116
|
+
return {
|
|
22117
|
+
graph,
|
|
22118
|
+
keyFor: (entry) => hashString(`${base}|${graph.keyOf(entry.path) ?? fallback[entry.environment]}`),
|
|
22119
|
+
resolve: createResolver(collected)
|
|
22120
|
+
};
|
|
22121
|
+
}
|
|
20771
22122
|
|
|
20772
22123
|
// ../compiler/src/project/module-graph.ts
|
|
20773
22124
|
function buildSymbolTable(modules) {
|
|
@@ -20828,52 +22179,12 @@ function validateModuleReferences(modules) {
|
|
|
20828
22179
|
function flattenDiagnostics(modules) {
|
|
20829
22180
|
return modules.flatMap((module) => module.diagnostics.map((diagnostic) => ({ path: module.path, diagnostic })));
|
|
20830
22181
|
}
|
|
20831
|
-
function optionsKey(options) {
|
|
20832
|
-
return `${options.strict ? "strict" : ""}|${options.oop ? "oop" : ""}|${options.noUnusedLocals ? "nul" : ""}|${options.noUnusedParameters ? "nup" : ""}`;
|
|
20833
|
-
}
|
|
20834
|
-
function sharedEnums(collected) {
|
|
20835
|
-
const declared = new Set(collected.flatMap((entry) => entry.declarations.enums.map((enumeration) => enumeration.name)));
|
|
20836
|
-
if (declared.size === 0) {
|
|
20837
|
-
return declared;
|
|
20838
|
-
}
|
|
20839
|
-
return new Set(collected.flatMap((entry) => entry.externalReferences.filter((name) => declared.has(name))));
|
|
20840
|
-
}
|
|
20841
|
-
function ambientKeys(collected, context) {
|
|
20842
|
-
const keys = {};
|
|
20843
|
-
const { project, references, options } = context;
|
|
20844
|
-
const mode = context.development ? "development" : "release";
|
|
20845
|
-
const projectKey = `${optionsKey(options)}|${mode}|${JSON.stringify(project.globals)}|${[...references].sort().join(",")}`;
|
|
20846
|
-
for (const environment of ALL_ENVIRONMENTS) {
|
|
20847
|
-
const visible = collected.filter((entry) => canReference(environment, entry.environment));
|
|
20848
|
-
keys[environment] = hashString(`${projectKey}|${visible.map((entry) => `${entry.path}=${entry.fingerprint}`).join(";")}`);
|
|
20849
|
-
}
|
|
20850
|
-
return keys;
|
|
20851
|
-
}
|
|
20852
|
-
function declaresNothing(declarations) {
|
|
20853
|
-
const { classes, interfaces, enums, globals, events } = declarations;
|
|
20854
|
-
return classes.length === 0 && interfaces.length === 0 && enums.length === 0 && globals.length === 0 && events.length === 0;
|
|
20855
|
-
}
|
|
20856
|
-
function createAmbientResolver(collected) {
|
|
20857
|
-
const visible = /* @__PURE__ */ new Map();
|
|
20858
|
-
const merged = /* @__PURE__ */ new Map();
|
|
20859
|
-
for (const environment of ALL_ENVIRONMENTS) {
|
|
20860
|
-
const entries2 = collected.filter((entry) => canReference(environment, entry.environment) && !declaresNothing(entry.declarations));
|
|
20861
|
-
visible.set(environment, entries2);
|
|
20862
|
-
merged.set(environment, mergeAmbient(entries2.map((entry) => entry.declarations)));
|
|
20863
|
-
}
|
|
20864
|
-
return (entry) => {
|
|
20865
|
-
if (declaresNothing(entry.declarations)) {
|
|
20866
|
-
return merged.get(entry.environment) ?? EMPTY_AMBIENT;
|
|
20867
|
-
}
|
|
20868
|
-
const entries2 = visible.get(entry.environment) ?? [];
|
|
20869
|
-
return mergeAmbient(entries2.filter((candidate) => candidate.path !== entry.path).map((candidate) => candidate.declarations));
|
|
20870
|
-
};
|
|
20871
|
-
}
|
|
20872
22182
|
function compileModule(file, ambient, context) {
|
|
20873
22183
|
const result = compile(file.source, {
|
|
20874
22184
|
filePath: file.path,
|
|
20875
22185
|
...file.environment === void 0 ? {} : { environment: file.environment },
|
|
20876
22186
|
ambient,
|
|
22187
|
+
contracts: context.contracts,
|
|
20877
22188
|
project: context.project,
|
|
20878
22189
|
projectReferences: context.projectReferences,
|
|
20879
22190
|
compilerOptions: context.compilerOptions,
|
|
@@ -20887,7 +22198,7 @@ function compileModule(file, ambient, context) {
|
|
|
20887
22198
|
requiredHelpers: result.requiredHelpers,
|
|
20888
22199
|
declaredGlobals: result.declaredGlobals,
|
|
20889
22200
|
externalReferences: result.externalReferences,
|
|
20890
|
-
contributions: toContributions(result.directives, result.environment),
|
|
22201
|
+
contributions: toContributions(result.directives, result.environment, result.moduleGlobals),
|
|
20891
22202
|
diagnostics: result.diagnostics,
|
|
20892
22203
|
lines: result.lines,
|
|
20893
22204
|
topLevelReturn: result.topLevelReturn,
|
|
@@ -20928,20 +22239,22 @@ function createProjectCache() {
|
|
|
20928
22239
|
environment: result.environment,
|
|
20929
22240
|
declarations: result.declarations,
|
|
20930
22241
|
externalReferences: [...result.externalReferences.keys()],
|
|
20931
|
-
fingerprint: fingerprintDeclarations(result.declarations)
|
|
22242
|
+
fingerprint: fingerprintDeclarations(result.declarations),
|
|
22243
|
+
provides: fingerprintByName(result.declarations),
|
|
22244
|
+
requires: result.referencedNames
|
|
20932
22245
|
};
|
|
20933
22246
|
declarationCache.set(file.path, entry);
|
|
20934
22247
|
return entry;
|
|
20935
22248
|
}
|
|
20936
22249
|
function moduleFor(pair, context, reused) {
|
|
20937
22250
|
const { file, entry } = pair;
|
|
20938
|
-
const ambientKey = context.
|
|
22251
|
+
const ambientKey = context.scope.keyFor(entry);
|
|
20939
22252
|
const cached = moduleCache.get(file.path);
|
|
20940
22253
|
if (cached !== void 0 && cached.hash === entry.hash && cached.ambientKey === ambientKey) {
|
|
20941
22254
|
reused.count += 1;
|
|
20942
22255
|
return cached.module;
|
|
20943
22256
|
}
|
|
20944
|
-
const module = compileModule(file, context.resolve(entry), context);
|
|
22257
|
+
const module = compileModule(file, context.scope.resolve(entry), context);
|
|
20945
22258
|
moduleCache.set(file.path, { hash: entry.hash, ambientKey, module });
|
|
20946
22259
|
return module;
|
|
20947
22260
|
}
|
|
@@ -20955,9 +22268,10 @@ function createProjectCache() {
|
|
|
20955
22268
|
const collected = pairs.map((pair) => pair.entry);
|
|
20956
22269
|
const projectReferences = sharedEnums(collected);
|
|
20957
22270
|
const development = options.development === true;
|
|
22271
|
+
const contracts = options.contracts ?? [];
|
|
20958
22272
|
const context = {
|
|
20959
|
-
|
|
20960
|
-
|
|
22273
|
+
scope: createAmbientScope(collected, { project, references: projectReferences, options: compilerOptions, development, contracts }),
|
|
22274
|
+
contracts,
|
|
20961
22275
|
project,
|
|
20962
22276
|
projectReferences,
|
|
20963
22277
|
compilerOptions,
|
|
@@ -21037,8 +22351,8 @@ function materialize(build, resource, includeMap) {
|
|
|
21037
22351
|
const bundled = materializeBundles(resource, build.bundles, helperContent);
|
|
21038
22352
|
return { ...build, scripts: bundled.scripts, map: includeMap ? bundled.map : null };
|
|
21039
22353
|
}
|
|
21040
|
-
function diagnosticSources(files,
|
|
21041
|
-
const paths = new Set(
|
|
22354
|
+
function diagnosticSources(files, entries3) {
|
|
22355
|
+
const paths = new Set(entries3.map((entry) => entry.path));
|
|
21042
22356
|
return new Map(files.filter((file) => paths.has(file.path)).map((file) => [file.path, file.source]));
|
|
21043
22357
|
}
|
|
21044
22358
|
function runCompile(root, config, options = {}) {
|
|
@@ -21046,10 +22360,11 @@ function runCompile(root, config, options = {}) {
|
|
|
21046
22360
|
const tracker = options.tracker ?? createPhaseTracker();
|
|
21047
22361
|
const started = performance.now();
|
|
21048
22362
|
tracker.begin("discovery");
|
|
21049
|
-
const excluded = [config.outDir];
|
|
22363
|
+
const excluded = [config.outDir, config.contracts];
|
|
21050
22364
|
const sources = discoverSources(root, config.sources, excluded);
|
|
21051
22365
|
const inputs = readProjectInputs(root, { assets: config.assets, environment: config.environment, excluded });
|
|
21052
|
-
const
|
|
22366
|
+
const contracts = readDependencyContracts(root, config);
|
|
22367
|
+
const diagnostics = [...sources.diagnostics, ...inputs.diagnostics, ...contracts.diagnostics];
|
|
21053
22368
|
if (hasCliErrors(diagnostics)) {
|
|
21054
22369
|
tracker.end("failed");
|
|
21055
22370
|
return {
|
|
@@ -21062,13 +22377,15 @@ function runCompile(root, config, options = {}) {
|
|
|
21062
22377
|
environmentTemplate: null,
|
|
21063
22378
|
phases: tracker.durations(),
|
|
21064
22379
|
sources: /* @__PURE__ */ new Map(),
|
|
21065
|
-
map: null
|
|
22380
|
+
map: null,
|
|
22381
|
+
contract: null
|
|
21066
22382
|
};
|
|
21067
22383
|
}
|
|
21068
22384
|
tracker.begin("compile", sources.files.length);
|
|
21069
22385
|
const declarations = projectDeclarations(inputs.declared?.entries ?? null, config.environment.file);
|
|
21070
22386
|
const project = cache3.compile(sources.files, {
|
|
21071
22387
|
project: declarations,
|
|
22388
|
+
contracts: contracts.contracts,
|
|
21072
22389
|
compilerOptions: config.compilerOptions,
|
|
21073
22390
|
development: options.development === true,
|
|
21074
22391
|
onProgress: (event) => tracker.advance(event.item, event.index, event.total)
|
|
@@ -21095,13 +22412,14 @@ function runCompile(root, config, options = {}) {
|
|
|
21095
22412
|
environmentTemplate: inputs.deployed === null ? null : renderEnvironmentTemplate(inputs.deployed),
|
|
21096
22413
|
phases: tracker.durations(),
|
|
21097
22414
|
sources: diagnosticSources(sources.files, assembly.diagnostics),
|
|
21098
|
-
map: build?.map ?? null
|
|
22415
|
+
map: build?.map ?? null,
|
|
22416
|
+
contract: build === null ? null : buildResourceAbi(config.name, project.modules.flatMap((module) => module.contributions))
|
|
21099
22417
|
};
|
|
21100
22418
|
}
|
|
21101
22419
|
|
|
21102
22420
|
// src/build/resource-map-file.ts
|
|
21103
|
-
import { existsSync as existsSync5, mkdirSync as
|
|
21104
|
-
import { dirname as
|
|
22421
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync7, readdirSync as readdirSync2, unlinkSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22422
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join4, posix, relative as relative2, resolve as resolve9 } from "node:path";
|
|
21105
22423
|
var RESOURCE_MAP_SUFFIX = ".luam-map.json";
|
|
21106
22424
|
function isObject(value) {
|
|
21107
22425
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -21166,10 +22484,10 @@ function reason(error) {
|
|
|
21166
22484
|
return error instanceof Error ? error.message : String(error);
|
|
21167
22485
|
}
|
|
21168
22486
|
function resourceMapPath(root, config) {
|
|
21169
|
-
return
|
|
22487
|
+
return resolve9(root, config.outDir, `${config.name}${RESOURCE_MAP_SUFFIX}`);
|
|
21170
22488
|
}
|
|
21171
22489
|
function explicitResourceMapPath(root, path) {
|
|
21172
|
-
return isAbsolute3(path) ? path :
|
|
22490
|
+
return isAbsolute3(path) ? path : resolve9(root, path);
|
|
21173
22491
|
}
|
|
21174
22492
|
function writeResourceMap(root, config, map) {
|
|
21175
22493
|
const path = resourceMapPath(root, config);
|
|
@@ -21179,15 +22497,15 @@ function writeResourceMap(root, config, map) {
|
|
|
21179
22497
|
}
|
|
21180
22498
|
return;
|
|
21181
22499
|
}
|
|
21182
|
-
|
|
22500
|
+
mkdirSync3(dirname3(path), { recursive: true });
|
|
21183
22501
|
const content = serializeResourceMap(map);
|
|
21184
|
-
if (!existsSync5(path) ||
|
|
21185
|
-
|
|
22502
|
+
if (!existsSync5(path) || readFileSync7(path, "utf8") !== content) {
|
|
22503
|
+
writeFileSync4(path, content, "utf8");
|
|
21186
22504
|
}
|
|
21187
22505
|
}
|
|
21188
22506
|
function readResourceMap(path) {
|
|
21189
22507
|
try {
|
|
21190
|
-
const value = JSON.parse(
|
|
22508
|
+
const value = JSON.parse(readFileSync7(path, "utf8"));
|
|
21191
22509
|
if (isObject(value) && Number.isInteger(value.version) && value.version !== RESOURCE_MAP_VERSION) {
|
|
21192
22510
|
return { map: null, error: `Resource map version ${String(value.version)} is not supported.` };
|
|
21193
22511
|
}
|
|
@@ -21201,13 +22519,13 @@ function isSearchable(name) {
|
|
|
21201
22519
|
return !name.startsWith(".") && !SKIPPED_DIRECTORIES.has(name);
|
|
21202
22520
|
}
|
|
21203
22521
|
function collectResourceMaps(directory, found) {
|
|
21204
|
-
let
|
|
22522
|
+
let entries3;
|
|
21205
22523
|
try {
|
|
21206
|
-
|
|
22524
|
+
entries3 = readdirSync2(directory, { withFileTypes: true });
|
|
21207
22525
|
} catch {
|
|
21208
22526
|
return;
|
|
21209
22527
|
}
|
|
21210
|
-
for (const entry of
|
|
22528
|
+
for (const entry of entries3) {
|
|
21211
22529
|
const absolute = join4(directory, entry.name);
|
|
21212
22530
|
if (entry.isDirectory()) {
|
|
21213
22531
|
if (isSearchable(entry.name)) {
|
|
@@ -21231,8 +22549,8 @@ function discoverResourceMap(root) {
|
|
|
21231
22549
|
}
|
|
21232
22550
|
|
|
21233
22551
|
// src/build/resource-writer.ts
|
|
21234
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
21235
|
-
import { dirname as
|
|
22552
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22553
|
+
import { dirname as dirname4, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve11 } from "node:path";
|
|
21236
22554
|
|
|
21237
22555
|
// src/build/lua-tokens.ts
|
|
21238
22556
|
var WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\r", "\v", "\f"]);
|
|
@@ -21289,7 +22607,7 @@ function readLongBracket2(source, start, level, file) {
|
|
|
21289
22607
|
return end + closing.length;
|
|
21290
22608
|
}
|
|
21291
22609
|
function readShortString(source, start, file) {
|
|
21292
|
-
const
|
|
22610
|
+
const quote3 = source[start];
|
|
21293
22611
|
let index = start + 1;
|
|
21294
22612
|
while (index < source.length) {
|
|
21295
22613
|
const char = source[index];
|
|
@@ -21297,7 +22615,7 @@ function readShortString(source, start, file) {
|
|
|
21297
22615
|
index += 2;
|
|
21298
22616
|
continue;
|
|
21299
22617
|
}
|
|
21300
|
-
if (char ===
|
|
22618
|
+
if (char === quote3) {
|
|
21301
22619
|
return index + 1;
|
|
21302
22620
|
}
|
|
21303
22621
|
if (char === "\n") {
|
|
@@ -21436,7 +22754,7 @@ function minifyLuaFiles(files) {
|
|
|
21436
22754
|
|
|
21437
22755
|
// src/build/resource-prune.ts
|
|
21438
22756
|
import { existsSync as existsSync6, readdirSync as readdirSync3, rmdirSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
21439
|
-
import { join as join5, relative as relative3, resolve as
|
|
22757
|
+
import { join as join5, relative as relative3, resolve as resolve10 } from "node:path";
|
|
21440
22758
|
var GENERATED_MANIFEST = "meta.xml";
|
|
21441
22759
|
var GENERATED_EXTENSION = ".lua";
|
|
21442
22760
|
var PROTECTED = /* @__PURE__ */ new Set([ENVIRONMENT_FILE, ".env.local"]);
|
|
@@ -21453,14 +22771,14 @@ function isGenerated(relativePath2, options) {
|
|
|
21453
22771
|
return options.generatedRoots.some((root) => isUnderRoot(relativePath2, root));
|
|
21454
22772
|
}
|
|
21455
22773
|
function removeEmptyDirectories(targetDir, directory) {
|
|
21456
|
-
if (
|
|
22774
|
+
if (resolve10(directory) === resolve10(targetDir)) {
|
|
21457
22775
|
return;
|
|
21458
22776
|
}
|
|
21459
22777
|
if (readdirSync3(directory).length > 0) {
|
|
21460
22778
|
return;
|
|
21461
22779
|
}
|
|
21462
22780
|
rmdirSync(directory);
|
|
21463
|
-
removeEmptyDirectories(targetDir,
|
|
22781
|
+
removeEmptyDirectories(targetDir, resolve10(directory, ".."));
|
|
21464
22782
|
}
|
|
21465
22783
|
function pruneResource(targetDir, keep, options) {
|
|
21466
22784
|
if (!existsSync6(targetDir)) {
|
|
@@ -21513,7 +22831,7 @@ function resourceFiles(build) {
|
|
|
21513
22831
|
return files;
|
|
21514
22832
|
}
|
|
21515
22833
|
function resolveInside(targetDir, path) {
|
|
21516
|
-
const absolute =
|
|
22834
|
+
const absolute = resolve11(targetDir, path);
|
|
21517
22835
|
const inside = relative4(targetDir, absolute);
|
|
21518
22836
|
if (inside.startsWith("..") || isAbsolute4(inside)) {
|
|
21519
22837
|
throw new Error(`The generated file "${path}" resolves outside the resource directory "${targetDir}".`);
|
|
@@ -21521,11 +22839,11 @@ function resolveInside(targetDir, path) {
|
|
|
21521
22839
|
return absolute;
|
|
21522
22840
|
}
|
|
21523
22841
|
function writeIfChanged(absolute, content) {
|
|
21524
|
-
if (existsSync7(absolute) &&
|
|
22842
|
+
if (existsSync7(absolute) && readFileSync8(absolute).equals(content)) {
|
|
21525
22843
|
return false;
|
|
21526
22844
|
}
|
|
21527
|
-
|
|
21528
|
-
|
|
22845
|
+
mkdirSync4(dirname4(absolute), { recursive: true });
|
|
22846
|
+
writeFileSync5(absolute, content);
|
|
21529
22847
|
return true;
|
|
21530
22848
|
}
|
|
21531
22849
|
function writeEnvironmentFile(targetDir, template) {
|
|
@@ -21536,8 +22854,8 @@ function writeEnvironmentFile(targetDir, template) {
|
|
|
21536
22854
|
if (existsSync7(absolute)) {
|
|
21537
22855
|
return false;
|
|
21538
22856
|
}
|
|
21539
|
-
|
|
21540
|
-
|
|
22857
|
+
mkdirSync4(dirname4(absolute), { recursive: true });
|
|
22858
|
+
writeFileSync5(absolute, template, "utf8");
|
|
21541
22859
|
return true;
|
|
21542
22860
|
}
|
|
21543
22861
|
function writeResource(targetDir, build, options) {
|
|
@@ -21561,7 +22879,7 @@ function writeResource(targetDir, build, options) {
|
|
|
21561
22879
|
advance(path);
|
|
21562
22880
|
}
|
|
21563
22881
|
for (const asset of build.assets) {
|
|
21564
|
-
if (writeIfChanged(resolveInside(targetDir, asset.path),
|
|
22882
|
+
if (writeIfChanged(resolveInside(targetDir, asset.path), readFileSync8(resolve11(options.root, asset.source)))) {
|
|
21565
22883
|
written.push(asset.path);
|
|
21566
22884
|
advance(asset.path);
|
|
21567
22885
|
continue;
|
|
@@ -21678,16 +22996,16 @@ function reportBuildOutcome(context, outcome, action) {
|
|
|
21678
22996
|
}
|
|
21679
22997
|
|
|
21680
22998
|
// src/commands/resource-targets.ts
|
|
21681
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
22999
|
+
import { isAbsolute as isAbsolute5, resolve as resolve12 } from "node:path";
|
|
21682
23000
|
function resolveBuildTarget(root, config) {
|
|
21683
|
-
return
|
|
23001
|
+
return resolve12(root, config.outDir, config.name);
|
|
21684
23002
|
}
|
|
21685
23003
|
function resolveServerTarget(root, config) {
|
|
21686
23004
|
if (config.serverPath === null) {
|
|
21687
23005
|
return null;
|
|
21688
23006
|
}
|
|
21689
|
-
const serverRoot = isAbsolute5(config.serverPath) ? config.serverPath :
|
|
21690
|
-
return
|
|
23007
|
+
const serverRoot = isAbsolute5(config.serverPath) ? config.serverPath : resolve12(root, config.serverPath);
|
|
23008
|
+
return resolve12(serverRoot, config.resourcesDir, config.name);
|
|
21691
23009
|
}
|
|
21692
23010
|
|
|
21693
23011
|
// src/reporting/progress-renderer.ts
|
|
@@ -21732,7 +23050,7 @@ function createProgressRenderer(reporter, options = {}) {
|
|
|
21732
23050
|
paint(reporter.style.eraseLine());
|
|
21733
23051
|
dirty = false;
|
|
21734
23052
|
}
|
|
21735
|
-
function
|
|
23053
|
+
function render2(event) {
|
|
21736
23054
|
const columns = Math.max(20, reporter.capability.columns - 1);
|
|
21737
23055
|
const line2 = activeLine(reporter, event);
|
|
21738
23056
|
paint(`${reporter.style.eraseLine()}${line2.slice(0, columns)}`);
|
|
@@ -21752,7 +23070,7 @@ function createProgressRenderer(reporter, options = {}) {
|
|
|
21752
23070
|
if (frames > 0 && now() - lastPaintAt < throttleMs) {
|
|
21753
23071
|
return;
|
|
21754
23072
|
}
|
|
21755
|
-
|
|
23073
|
+
render2(event);
|
|
21756
23074
|
}
|
|
21757
23075
|
return {
|
|
21758
23076
|
listen: (event) => {
|
|
@@ -21810,6 +23128,9 @@ async function runBuildCommand(context, options = {}) {
|
|
|
21810
23128
|
return EXIT_DIAGNOSTICS;
|
|
21811
23129
|
}
|
|
21812
23130
|
writeResourceMap(context.root, context.config, writtenMap(outcome.map, minify));
|
|
23131
|
+
if (outcome.contract !== null && outcome.contract.exports.length > 0) {
|
|
23132
|
+
writeResourceContract(context.root, context.config, outcome.contract);
|
|
23133
|
+
}
|
|
21813
23134
|
tracker.end();
|
|
21814
23135
|
renderer.clear();
|
|
21815
23136
|
reportBuildOutcome(context, outcome, "Build");
|
|
@@ -21860,6 +23181,298 @@ function registerCheckCommand(program2, runtime) {
|
|
|
21860
23181
|
});
|
|
21861
23182
|
}
|
|
21862
23183
|
|
|
23184
|
+
// src/commands/config-command.ts
|
|
23185
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23186
|
+
import { dirname as dirname5, relative as relative5, resolve as resolve13 } from "node:path";
|
|
23187
|
+
|
|
23188
|
+
// ../compiler/src/project/config-reader.ts
|
|
23189
|
+
var Reader = class {
|
|
23190
|
+
text;
|
|
23191
|
+
index = 0;
|
|
23192
|
+
problems = [];
|
|
23193
|
+
constructor(text) {
|
|
23194
|
+
this.text = text;
|
|
23195
|
+
}
|
|
23196
|
+
position() {
|
|
23197
|
+
const before = this.text.slice(0, this.index);
|
|
23198
|
+
const lines = before.split("\n");
|
|
23199
|
+
return { line: lines.length, column: (lines[lines.length - 1]?.length ?? 0) + 1 };
|
|
23200
|
+
}
|
|
23201
|
+
fail(message) {
|
|
23202
|
+
const { line: line2, column } = this.position();
|
|
23203
|
+
this.problems.push({ line: line2, column, message });
|
|
23204
|
+
return null;
|
|
23205
|
+
}
|
|
23206
|
+
skipComment() {
|
|
23207
|
+
if (!this.text.startsWith("--", this.index)) {
|
|
23208
|
+
return false;
|
|
23209
|
+
}
|
|
23210
|
+
if (this.text.startsWith("--[[", this.index)) {
|
|
23211
|
+
const end2 = this.text.indexOf("]]", this.index + 4);
|
|
23212
|
+
this.index = end2 === -1 ? this.text.length : end2 + 2;
|
|
23213
|
+
return true;
|
|
23214
|
+
}
|
|
23215
|
+
const end = this.text.indexOf("\n", this.index);
|
|
23216
|
+
this.index = end === -1 ? this.text.length : end + 1;
|
|
23217
|
+
return true;
|
|
23218
|
+
}
|
|
23219
|
+
skip() {
|
|
23220
|
+
for (; ; ) {
|
|
23221
|
+
const before = this.index;
|
|
23222
|
+
while (this.index < this.text.length && /\s/.test(this.text[this.index] ?? "")) {
|
|
23223
|
+
this.index += 1;
|
|
23224
|
+
}
|
|
23225
|
+
this.skipComment();
|
|
23226
|
+
if (this.index === before) {
|
|
23227
|
+
return;
|
|
23228
|
+
}
|
|
23229
|
+
}
|
|
23230
|
+
}
|
|
23231
|
+
done() {
|
|
23232
|
+
this.skip();
|
|
23233
|
+
return this.index >= this.text.length;
|
|
23234
|
+
}
|
|
23235
|
+
peek() {
|
|
23236
|
+
this.skip();
|
|
23237
|
+
return this.text[this.index] ?? "";
|
|
23238
|
+
}
|
|
23239
|
+
take(value) {
|
|
23240
|
+
this.skip();
|
|
23241
|
+
if (!this.text.startsWith(value, this.index)) {
|
|
23242
|
+
return false;
|
|
23243
|
+
}
|
|
23244
|
+
this.index += value.length;
|
|
23245
|
+
return true;
|
|
23246
|
+
}
|
|
23247
|
+
word() {
|
|
23248
|
+
this.skip();
|
|
23249
|
+
const match = /^[A-Za-z_][A-Za-z0-9_]*/.exec(this.text.slice(this.index));
|
|
23250
|
+
if (match === null) {
|
|
23251
|
+
return null;
|
|
23252
|
+
}
|
|
23253
|
+
this.index += match[0].length;
|
|
23254
|
+
return match[0];
|
|
23255
|
+
}
|
|
23256
|
+
literal() {
|
|
23257
|
+
this.skip();
|
|
23258
|
+
const rest = this.text.slice(this.index);
|
|
23259
|
+
const string = /^(\[\[[\s\S]*?\]\]|'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*")/.exec(rest);
|
|
23260
|
+
if (string !== null) {
|
|
23261
|
+
this.index += string[0].length;
|
|
23262
|
+
return "string";
|
|
23263
|
+
}
|
|
23264
|
+
const number = /^-?(?:0[xX][0-9a-fA-F]+|\d+\.?\d*(?:[eE][-+]?\d+)?|\.\d+)/.exec(rest);
|
|
23265
|
+
if (number !== null) {
|
|
23266
|
+
this.index += number[0].length;
|
|
23267
|
+
return "number";
|
|
23268
|
+
}
|
|
23269
|
+
const word = /^(true|false|nil)\b/.exec(rest);
|
|
23270
|
+
if (word === null) {
|
|
23271
|
+
return null;
|
|
23272
|
+
}
|
|
23273
|
+
this.index += word[0].length;
|
|
23274
|
+
return word[0] === "nil" ? "nil" : "boolean";
|
|
23275
|
+
}
|
|
23276
|
+
key() {
|
|
23277
|
+
this.skip();
|
|
23278
|
+
if (this.take("[")) {
|
|
23279
|
+
const rest = this.text.slice(this.index);
|
|
23280
|
+
const quoted2 = /^'([A-Za-z_][A-Za-z0-9_]*)'|^"([A-Za-z_][A-Za-z0-9_]*)"/.exec(rest);
|
|
23281
|
+
if (quoted2 === null) {
|
|
23282
|
+
return null;
|
|
23283
|
+
}
|
|
23284
|
+
this.index += quoted2[0].length;
|
|
23285
|
+
return this.take("]") && this.take("=") ? quoted2[1] ?? quoted2[2] ?? null : null;
|
|
23286
|
+
}
|
|
23287
|
+
const start = this.index;
|
|
23288
|
+
const word = this.word();
|
|
23289
|
+
if (word === null || !this.take("=") || this.peek() === "=") {
|
|
23290
|
+
this.index = start;
|
|
23291
|
+
return null;
|
|
23292
|
+
}
|
|
23293
|
+
return word;
|
|
23294
|
+
}
|
|
23295
|
+
};
|
|
23296
|
+
|
|
23297
|
+
// ../compiler/src/project/config-extractor.ts
|
|
23298
|
+
var GENERATED_MARKER = '# Generated by "luam config" from';
|
|
23299
|
+
var MAX_SOURCE_BYTES = 262144;
|
|
23300
|
+
var MAX_DEPTH2 = 8;
|
|
23301
|
+
var MAX_ENTRIES = 512;
|
|
23302
|
+
function renderRecord(fields) {
|
|
23303
|
+
return `{ ${fields.map(([name, type]) => `${name}: ${type}`).join(", ")} }`;
|
|
23304
|
+
}
|
|
23305
|
+
function render(value) {
|
|
23306
|
+
if (value.kind === "literal") {
|
|
23307
|
+
return value.type === "nil" ? "any" : value.type;
|
|
23308
|
+
}
|
|
23309
|
+
if (value.kind === "array") {
|
|
23310
|
+
return `${value.element}[]`;
|
|
23311
|
+
}
|
|
23312
|
+
return value.kind === "record" && value.fields.length > 0 ? renderRecord(value.fields) : "table";
|
|
23313
|
+
}
|
|
23314
|
+
function unify2(types) {
|
|
23315
|
+
const unique = [...new Set(types)];
|
|
23316
|
+
return unique.length === 1 ? unique[0] ?? "any" : "any";
|
|
23317
|
+
}
|
|
23318
|
+
function readTable2(reader, depth) {
|
|
23319
|
+
if (depth > MAX_DEPTH2) {
|
|
23320
|
+
return reader.fail(`A table nested deeper than ${MAX_DEPTH2} levels is not extracted.`);
|
|
23321
|
+
}
|
|
23322
|
+
const fields = [];
|
|
23323
|
+
const elements = [];
|
|
23324
|
+
for (let count = 0; ; count += 1) {
|
|
23325
|
+
if (reader.take("}")) {
|
|
23326
|
+
break;
|
|
23327
|
+
}
|
|
23328
|
+
if (count > MAX_ENTRIES) {
|
|
23329
|
+
return reader.fail(`A table with more than ${MAX_ENTRIES} entries is not extracted.`);
|
|
23330
|
+
}
|
|
23331
|
+
const key = reader.key();
|
|
23332
|
+
const value = readValue(reader, depth + 1);
|
|
23333
|
+
if (value === null) {
|
|
23334
|
+
return null;
|
|
23335
|
+
}
|
|
23336
|
+
if (key === null) {
|
|
23337
|
+
elements.push(render(value));
|
|
23338
|
+
} else {
|
|
23339
|
+
fields.push([key, render(value)]);
|
|
23340
|
+
}
|
|
23341
|
+
if (!reader.take(",") && !reader.take(";") && reader.peek() !== "}") {
|
|
23342
|
+
return reader.fail('Expected "," or "}" in a table.');
|
|
23343
|
+
}
|
|
23344
|
+
}
|
|
23345
|
+
if (fields.length > 0 && elements.length > 0) {
|
|
23346
|
+
return { kind: "table" };
|
|
23347
|
+
}
|
|
23348
|
+
return elements.length > 0 ? { kind: "array", element: unify2(elements) } : { kind: "record", fields };
|
|
23349
|
+
}
|
|
23350
|
+
function readValue(reader, depth) {
|
|
23351
|
+
if (reader.take("{")) {
|
|
23352
|
+
return readTable2(reader, depth);
|
|
23353
|
+
}
|
|
23354
|
+
const literal2 = reader.literal();
|
|
23355
|
+
if (literal2 === null) {
|
|
23356
|
+
return reader.fail("Only literals and table constructors are extracted. Declare this value by hand.");
|
|
23357
|
+
}
|
|
23358
|
+
if (reader.peek() === "." || reader.peek() === "(" || reader.peek() === "+") {
|
|
23359
|
+
return reader.fail("An expression is not extracted. Declare this value by hand.");
|
|
23360
|
+
}
|
|
23361
|
+
return { kind: "literal", type: literal2 };
|
|
23362
|
+
}
|
|
23363
|
+
function extractConfigDeclarations(source) {
|
|
23364
|
+
if (source.length > MAX_SOURCE_BYTES) {
|
|
23365
|
+
return { declarations: [], problems: [{ line: 1, column: 1, message: `A file larger than ${MAX_SOURCE_BYTES} bytes is not extracted.` }] };
|
|
23366
|
+
}
|
|
23367
|
+
const reader = new Reader(source);
|
|
23368
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
23369
|
+
while (!reader.done()) {
|
|
23370
|
+
reader.take("local");
|
|
23371
|
+
const name = reader.word();
|
|
23372
|
+
if (name === null || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || !reader.take("=")) {
|
|
23373
|
+
reader.fail("Only a top-level assignment of a literal or a table is extracted.");
|
|
23374
|
+
break;
|
|
23375
|
+
}
|
|
23376
|
+
const value = readValue(reader, 1);
|
|
23377
|
+
if (value === null) {
|
|
23378
|
+
break;
|
|
23379
|
+
}
|
|
23380
|
+
declarations.set(name, render(value));
|
|
23381
|
+
reader.take(";");
|
|
23382
|
+
}
|
|
23383
|
+
return { declarations: [...declarations].map(([name, type]) => ({ name, type })), problems: reader.problems };
|
|
23384
|
+
}
|
|
23385
|
+
function renderConfigDeclarations(source, declarations) {
|
|
23386
|
+
const lines = declarations.map((declaration) => `declare ${declaration.name}: ${declaration.type}`);
|
|
23387
|
+
return `${GENERATED_MARKER} "${source}". Do not edit.
|
|
23388
|
+
|
|
23389
|
+
${lines.join("\n")}
|
|
23390
|
+
`;
|
|
23391
|
+
}
|
|
23392
|
+
function isGeneratedDeclaration(text) {
|
|
23393
|
+
return text.startsWith(GENERATED_MARKER);
|
|
23394
|
+
}
|
|
23395
|
+
|
|
23396
|
+
// src/commands/config-command.ts
|
|
23397
|
+
var DEFAULT_CONFIG_SOURCE = "config.lua";
|
|
23398
|
+
var DEFAULT_CONFIG_OUTPUT = "config.d.luam";
|
|
23399
|
+
function escapes(root, path) {
|
|
23400
|
+
const inside = relative5(root, path);
|
|
23401
|
+
return inside.startsWith("..") || resolve13(root, inside) !== path;
|
|
23402
|
+
}
|
|
23403
|
+
function readSource2(root, source, reporter) {
|
|
23404
|
+
const path = resolve13(root, source);
|
|
23405
|
+
if (escapes(root, path)) {
|
|
23406
|
+
reporter.error(`Config declarations read only inside the project, but "${source}" points outside it.`);
|
|
23407
|
+
return null;
|
|
23408
|
+
}
|
|
23409
|
+
if (!existsSync8(path)) {
|
|
23410
|
+
reporter.error(`Config declarations found no file at "${source}".`);
|
|
23411
|
+
return null;
|
|
23412
|
+
}
|
|
23413
|
+
try {
|
|
23414
|
+
return readFileSync9(path, "utf8");
|
|
23415
|
+
} catch {
|
|
23416
|
+
reporter.error(`Config declarations could not read "${source}".`);
|
|
23417
|
+
return null;
|
|
23418
|
+
}
|
|
23419
|
+
}
|
|
23420
|
+
function writable(root, out, reporter) {
|
|
23421
|
+
const path = resolve13(root, out);
|
|
23422
|
+
if (escapes(root, path)) {
|
|
23423
|
+
reporter.error(`Config declarations write only inside the project, but "${out}" points outside it.`);
|
|
23424
|
+
return null;
|
|
23425
|
+
}
|
|
23426
|
+
if (existsSync8(path) && !isGeneratedDeclaration(readFileSync9(path, "utf8"))) {
|
|
23427
|
+
reporter.error(`"${out}" was not generated by this command and was left alone. Choose another path with --out.`);
|
|
23428
|
+
return null;
|
|
23429
|
+
}
|
|
23430
|
+
return path;
|
|
23431
|
+
}
|
|
23432
|
+
function runConfigCommand(root, reporter, options = {}) {
|
|
23433
|
+
const source = options.source ?? DEFAULT_CONFIG_SOURCE;
|
|
23434
|
+
const out = options.out ?? DEFAULT_CONFIG_OUTPUT;
|
|
23435
|
+
const text = readSource2(root, source, reporter);
|
|
23436
|
+
if (text === null) {
|
|
23437
|
+
return EXIT_DIAGNOSTICS;
|
|
23438
|
+
}
|
|
23439
|
+
const extracted = extractConfigDeclarations(text);
|
|
23440
|
+
for (const problem of extracted.problems) {
|
|
23441
|
+
reporter.warn(`${source}:${problem.line}:${problem.column} ${problem.message}`);
|
|
23442
|
+
}
|
|
23443
|
+
if (extracted.declarations.length === 0) {
|
|
23444
|
+
reporter.error(`Config declarations found nothing to declare in "${source}".`);
|
|
23445
|
+
return EXIT_DIAGNOSTICS;
|
|
23446
|
+
}
|
|
23447
|
+
const rendered = renderConfigDeclarations(source, extracted.declarations);
|
|
23448
|
+
if (options.write !== true) {
|
|
23449
|
+
reporter.info(rendered.trimEnd());
|
|
23450
|
+
reporter.info(`Config declarations would write ${extracted.declarations.length} name(s) to "${out}". Pass --write to save it.`);
|
|
23451
|
+
return EXIT_OK;
|
|
23452
|
+
}
|
|
23453
|
+
const path = writable(root, out, reporter);
|
|
23454
|
+
if (path === null) {
|
|
23455
|
+
return EXIT_DIAGNOSTICS;
|
|
23456
|
+
}
|
|
23457
|
+
mkdirSync5(dirname5(path), { recursive: true });
|
|
23458
|
+
writeFileSync6(path, rendered, "utf8");
|
|
23459
|
+
reporter.info(`Config declarations wrote ${extracted.declarations.length} name(s) to "${out}".`);
|
|
23460
|
+
return EXIT_OK;
|
|
23461
|
+
}
|
|
23462
|
+
|
|
23463
|
+
// src/cli/registry/config-registration.ts
|
|
23464
|
+
function registerConfigCommand(program2, runtime) {
|
|
23465
|
+
const command = program2.command("config").description('Derive a declaration file from the literal data in a native "config.lua".');
|
|
23466
|
+
addProjectOptions(command).addOption(valueOption("--source <path>", 'Native Lua file to read. Defaults to "config.lua".')).addOption(valueOption("--out <path>", 'Declaration file to write. Defaults to "config.d.luam".')).addOption(new Option("--write", "Write the declaration file instead of printing it."));
|
|
23467
|
+
command.action((options) => {
|
|
23468
|
+
runtime.exitCode = runConfigCommand(commandRoot(runtime, options), runtime.reporter, {
|
|
23469
|
+
source: options.source ?? null,
|
|
23470
|
+
out: options.out ?? null,
|
|
23471
|
+
write: options.write === true
|
|
23472
|
+
});
|
|
23473
|
+
});
|
|
23474
|
+
}
|
|
23475
|
+
|
|
21863
23476
|
// src/commands/ensure-runner.ts
|
|
21864
23477
|
function hasChanges(result) {
|
|
21865
23478
|
return result.written.length > 0 || result.removed.length > 0;
|
|
@@ -21884,7 +23497,7 @@ function restartResource(scope, serverConsole) {
|
|
|
21884
23497
|
reporter.success(`Restarted "${scope.context.config.name}" through the owned server console.`);
|
|
21885
23498
|
return true;
|
|
21886
23499
|
}
|
|
21887
|
-
function
|
|
23500
|
+
function failed2(outcome) {
|
|
21888
23501
|
return { ok: false, outcome, sync: null, restarted: false };
|
|
21889
23502
|
}
|
|
21890
23503
|
async function runOnce(scope, target, cache3, options) {
|
|
@@ -21907,7 +23520,7 @@ async function runOnce(scope, target, cache3, options) {
|
|
|
21907
23520
|
if (outcome.build === null) {
|
|
21908
23521
|
reportBuildOutcome(context, outcome, "Build");
|
|
21909
23522
|
reporter.warn("Skipping sync and restart because the build reported errors.");
|
|
21910
|
-
return
|
|
23523
|
+
return failed2(outcome);
|
|
21911
23524
|
}
|
|
21912
23525
|
const writeOptions = trackedWriteOptions(context.root, context.config, outcome.environmentTemplate, tracker);
|
|
21913
23526
|
reportBuildOutcome(context, outcome, "Build");
|
|
@@ -21955,8 +23568,8 @@ function reportRebuildSeparator(reporter, at = /* @__PURE__ */ new Date()) {
|
|
|
21955
23568
|
}
|
|
21956
23569
|
|
|
21957
23570
|
// src/watch/source-watcher.ts
|
|
21958
|
-
import { existsSync as
|
|
21959
|
-
import { relative as
|
|
23571
|
+
import { existsSync as existsSync9, watch } from "node:fs";
|
|
23572
|
+
import { relative as relative6, resolve as resolve14 } from "node:path";
|
|
21960
23573
|
var DEFAULT_DEBOUNCE_MS = 120;
|
|
21961
23574
|
function watchSources(root, sources, onChange, debounceMs = DEFAULT_DEBOUNCE_MS) {
|
|
21962
23575
|
const resolver = createSourceResolver(sources);
|
|
@@ -21972,12 +23585,12 @@ function watchSources(root, sources, onChange, debounceMs = DEFAULT_DEBOUNCE_MS)
|
|
|
21972
23585
|
}, debounceMs);
|
|
21973
23586
|
};
|
|
21974
23587
|
const isWatched = (directory, filename) => {
|
|
21975
|
-
const path = normalizePattern(
|
|
23588
|
+
const path = normalizePattern(relative6(root, resolve14(directory, filename)));
|
|
21976
23589
|
return path.endsWith(SOURCE_EXTENSION) && resolver.resolve(path).matches.length > 0;
|
|
21977
23590
|
};
|
|
21978
23591
|
for (const entry of resolver.roots) {
|
|
21979
|
-
const absolute =
|
|
21980
|
-
if (!
|
|
23592
|
+
const absolute = resolve14(root, entry);
|
|
23593
|
+
if (!existsSync9(absolute)) {
|
|
21981
23594
|
continue;
|
|
21982
23595
|
}
|
|
21983
23596
|
watchers.push(
|
|
@@ -22184,12 +23797,12 @@ function parseMtaLogLine(line2, activeResource, fallback = /* @__PURE__ */ new D
|
|
|
22184
23797
|
}
|
|
22185
23798
|
|
|
22186
23799
|
// src/logging/server-log-follower.ts
|
|
22187
|
-
import { closeSync, existsSync as
|
|
22188
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
23800
|
+
import { closeSync, existsSync as existsSync10, openSync, readSync, statSync as statSync4 } from "node:fs";
|
|
23801
|
+
import { isAbsolute as isAbsolute6, resolve as resolve15 } from "node:path";
|
|
22189
23802
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
22190
23803
|
function resolveServerLogPath(root, serverPath) {
|
|
22191
|
-
const server = isAbsolute6(serverPath) ? serverPath :
|
|
22192
|
-
return
|
|
23804
|
+
const server = isAbsolute6(serverPath) ? serverPath : resolve15(root, serverPath);
|
|
23805
|
+
return resolve15(server, "mods/deathmatch/logs/server.log");
|
|
22193
23806
|
}
|
|
22194
23807
|
function identity(path) {
|
|
22195
23808
|
const stats = statSync4(path);
|
|
@@ -22214,7 +23827,7 @@ function followServerLog(path, onLine, options = {}) {
|
|
|
22214
23827
|
let initialized = false;
|
|
22215
23828
|
let closed = false;
|
|
22216
23829
|
const poll = () => {
|
|
22217
|
-
if (closed || !
|
|
23830
|
+
if (closed || !existsSync10(path)) {
|
|
22218
23831
|
return;
|
|
22219
23832
|
}
|
|
22220
23833
|
try {
|
|
@@ -22330,9 +23943,9 @@ function connectServerConsoleInput(input, output, interrupt) {
|
|
|
22330
23943
|
|
|
22331
23944
|
// src/server/server-executable-resolver.ts
|
|
22332
23945
|
import { realpathSync, statSync as statSync5 } from "node:fs";
|
|
22333
|
-
import { isAbsolute as isAbsolute7, relative as
|
|
23946
|
+
import { isAbsolute as isAbsolute7, relative as relative7, resolve as resolve16 } from "node:path";
|
|
22334
23947
|
function isInside(root, path) {
|
|
22335
|
-
const pathFromRoot =
|
|
23948
|
+
const pathFromRoot = relative7(root, path);
|
|
22336
23949
|
return pathFromRoot.length === 0 || !pathFromRoot.startsWith("..") && !isAbsolute7(pathFromRoot);
|
|
22337
23950
|
}
|
|
22338
23951
|
function candidates2(platform) {
|
|
@@ -22345,14 +23958,14 @@ function candidates2(platform) {
|
|
|
22345
23958
|
throw new Error(`Local MTA server startup is not supported on platform "${platform}". Use Windows or Linux.`);
|
|
22346
23959
|
}
|
|
22347
23960
|
function resolveServerExecutable(options) {
|
|
22348
|
-
const serverRoot =
|
|
23961
|
+
const serverRoot = resolve16(options.root, options.serverPath);
|
|
22349
23962
|
const names = options.configured === null ? candidates2(options.platform ?? process.platform) : [options.configured];
|
|
22350
23963
|
const attempted = [];
|
|
22351
|
-
if (options.configured !== null && (isAbsolute7(options.configured) || !isInside(serverRoot,
|
|
23964
|
+
if (options.configured !== null && (isAbsolute7(options.configured) || !isInside(serverRoot, resolve16(serverRoot, options.configured)))) {
|
|
22352
23965
|
throw new Error(`Configured development.server.executable must stay inside serverPath but received "${options.configured}".`);
|
|
22353
23966
|
}
|
|
22354
23967
|
for (const name of names) {
|
|
22355
|
-
const path =
|
|
23968
|
+
const path = resolve16(serverRoot, name);
|
|
22356
23969
|
attempted.push(path);
|
|
22357
23970
|
try {
|
|
22358
23971
|
if (!statSync5(path).isFile()) {
|
|
@@ -22670,7 +24283,7 @@ function registerEnsureCommand(program2, runtime) {
|
|
|
22670
24283
|
}
|
|
22671
24284
|
|
|
22672
24285
|
// src/cli/registry/init-registration.ts
|
|
22673
|
-
import { resolve as
|
|
24286
|
+
import { resolve as resolve18 } from "node:path";
|
|
22674
24287
|
|
|
22675
24288
|
// src/commands/init-command.ts
|
|
22676
24289
|
import { basename as basename2 } from "node:path";
|
|
@@ -22732,7 +24345,7 @@ function renderManifest(source, details) {
|
|
|
22732
24345
|
}
|
|
22733
24346
|
|
|
22734
24347
|
// src/scaffold/template-files.ts
|
|
22735
|
-
import { existsSync as
|
|
24348
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "node:fs";
|
|
22736
24349
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
22737
24350
|
|
|
22738
24351
|
// ../template/src/template.ts
|
|
@@ -22748,10 +24361,10 @@ function bundledTemplatePath(source) {
|
|
|
22748
24361
|
}
|
|
22749
24362
|
function resolveTemplatePath(source) {
|
|
22750
24363
|
const packaged = fileURLToPath2(resolveTemplateUrl(source));
|
|
22751
|
-
return
|
|
24364
|
+
return existsSync11(packaged) ? packaged : bundledTemplatePath(source);
|
|
22752
24365
|
}
|
|
22753
24366
|
function readTemplateSource(source) {
|
|
22754
|
-
return
|
|
24367
|
+
return readFileSync10(resolveTemplatePath(source), "utf8");
|
|
22755
24368
|
}
|
|
22756
24369
|
|
|
22757
24370
|
// src/scaffold/scaffold-plan.ts
|
|
@@ -22767,19 +24380,19 @@ function buildScaffoldPlan(details) {
|
|
|
22767
24380
|
}
|
|
22768
24381
|
|
|
22769
24382
|
// src/scaffold/scaffold-writer.ts
|
|
22770
|
-
import { existsSync as
|
|
22771
|
-
import { dirname as
|
|
24383
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24384
|
+
import { dirname as dirname6, resolve as resolve17 } from "node:path";
|
|
22772
24385
|
function writeScaffold(targetDir, plan, force) {
|
|
22773
24386
|
const written = [];
|
|
22774
24387
|
const skipped = [];
|
|
22775
24388
|
for (const file of plan.files) {
|
|
22776
|
-
const absolute =
|
|
22777
|
-
if (!force &&
|
|
24389
|
+
const absolute = resolve17(targetDir, file.path);
|
|
24390
|
+
if (!force && existsSync12(absolute)) {
|
|
22778
24391
|
skipped.push(file.path);
|
|
22779
24392
|
continue;
|
|
22780
24393
|
}
|
|
22781
|
-
|
|
22782
|
-
|
|
24394
|
+
mkdirSync6(dirname6(absolute), { recursive: true });
|
|
24395
|
+
writeFileSync7(absolute, file.content, "utf8");
|
|
22783
24396
|
written.push(file.path);
|
|
22784
24397
|
}
|
|
22785
24398
|
return { written: written.sort((left, right) => left.localeCompare(right)), skipped: skipped.sort((left, right) => left.localeCompare(right)) };
|
|
@@ -22829,7 +24442,7 @@ function registerInitCommand(program2, runtime) {
|
|
|
22829
24442
|
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());
|
|
22830
24443
|
command.action(async (path, options) => {
|
|
22831
24444
|
const root = commandRoot(runtime, options);
|
|
22832
|
-
const target = path === void 0 ? root :
|
|
24445
|
+
const target = path === void 0 ? root : resolve18(root, path);
|
|
22833
24446
|
runtime.exitCode = await runInitCommand(target, runtime.logger, {
|
|
22834
24447
|
name: options.name ?? null,
|
|
22835
24448
|
force: options.force === true,
|
|
@@ -22847,7 +24460,7 @@ async function runSetupCommand(reporter, options) {
|
|
|
22847
24460
|
reporter.detail("Supported commands: code, code-insiders, cursor, codium, windsurf.");
|
|
22848
24461
|
return EXIT_DIAGNOSTICS;
|
|
22849
24462
|
}
|
|
22850
|
-
let
|
|
24463
|
+
let failed3 = false;
|
|
22851
24464
|
for (const editor of editors) {
|
|
22852
24465
|
if (options.editorService.hasExtension(editor)) {
|
|
22853
24466
|
reporter.success(`${editor.name}: Luam is already installed.`);
|
|
@@ -22866,12 +24479,12 @@ async function runSetupCommand(reporter, options) {
|
|
|
22866
24479
|
const result = await options.editorService.install(editor);
|
|
22867
24480
|
if (result.error !== null) {
|
|
22868
24481
|
reporter.error(`${editor.name}: installation failed. ${result.error}`);
|
|
22869
|
-
|
|
24482
|
+
failed3 = true;
|
|
22870
24483
|
continue;
|
|
22871
24484
|
}
|
|
22872
24485
|
reporter.success(`${editor.name}: installed from the ${result.source}.`);
|
|
22873
24486
|
}
|
|
22874
|
-
return
|
|
24487
|
+
return failed3 ? EXIT_DIAGNOSTICS : EXIT_OK;
|
|
22875
24488
|
}
|
|
22876
24489
|
|
|
22877
24490
|
// src/editor/installation-prompt.ts
|
|
@@ -22953,12 +24566,12 @@ function registerServerCommand(program2, runtime) {
|
|
|
22953
24566
|
}
|
|
22954
24567
|
|
|
22955
24568
|
// src/commands/trace-command.ts
|
|
22956
|
-
import { existsSync as
|
|
24569
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
|
|
22957
24570
|
function defaultMapPath(root, options, reporter) {
|
|
22958
24571
|
const loaded = loadManifest(root, { path: options.manifestPath, mode: manifestMode("trace"), env: options.env });
|
|
22959
24572
|
if (loaded.config !== null) {
|
|
22960
24573
|
const configured = resourceMapPath(root, loaded.config);
|
|
22961
|
-
if (
|
|
24574
|
+
if (existsSync13(configured)) {
|
|
22962
24575
|
return configured;
|
|
22963
24576
|
}
|
|
22964
24577
|
}
|
|
@@ -22978,7 +24591,7 @@ function readStandardInput() {
|
|
|
22978
24591
|
return "";
|
|
22979
24592
|
}
|
|
22980
24593
|
try {
|
|
22981
|
-
return
|
|
24594
|
+
return readFileSync11(0, "utf8");
|
|
22982
24595
|
} catch {
|
|
22983
24596
|
return "";
|
|
22984
24597
|
}
|
|
@@ -23012,30 +24625,30 @@ function runTraceCommand(root, reporter, options) {
|
|
|
23012
24625
|
reporter.detail('A generated line cannot be resolved there. Reproduce the error under "luam dev" or "luam ensure" for a source position.');
|
|
23013
24626
|
return EXIT_DIAGNOSTICS;
|
|
23014
24627
|
}
|
|
23015
|
-
let
|
|
24628
|
+
let failed3 = false;
|
|
23016
24629
|
for (const line2 of lines) {
|
|
23017
24630
|
const generated = parseTracePosition(line2);
|
|
23018
24631
|
if (generated === null) {
|
|
23019
24632
|
reporter.error(`Trace could not find a file and line in "${line2}".`);
|
|
23020
|
-
|
|
24633
|
+
failed3 = true;
|
|
23021
24634
|
continue;
|
|
23022
24635
|
}
|
|
23023
24636
|
const file = generatedFile(loaded.map.resource, generated.file);
|
|
23024
24637
|
const resolution = resolveResourcePosition(loaded.map, file, generated.line);
|
|
23025
24638
|
if (resolution.status === "unknown-version") {
|
|
23026
24639
|
reporter.error(`Resource map version ${resolution.version} is not supported.`);
|
|
23027
|
-
|
|
24640
|
+
failed3 = true;
|
|
23028
24641
|
continue;
|
|
23029
24642
|
}
|
|
23030
24643
|
if (resolution.status === "uncovered") {
|
|
23031
24644
|
reporter.error(`Resource map does not cover "${generated.file}:${generated.line}".`);
|
|
23032
|
-
|
|
24645
|
+
failed3 = true;
|
|
23033
24646
|
continue;
|
|
23034
24647
|
}
|
|
23035
24648
|
const symbol = resolution.position.symbol === void 0 ? "" : ` (${resolution.position.symbol})`;
|
|
23036
24649
|
reporter.raw(`${resolution.position.file}:${resolution.position.line}${symbol}`);
|
|
23037
24650
|
}
|
|
23038
|
-
return
|
|
24651
|
+
return failed3 ? EXIT_DIAGNOSTICS : EXIT_OK;
|
|
23039
24652
|
}
|
|
23040
24653
|
|
|
23041
24654
|
// src/cli/registry/trace-registration.ts
|
|
@@ -23056,6 +24669,7 @@ function registerTraceCommand(program2, runtime) {
|
|
|
23056
24669
|
var COMMAND_REGISTRARS = [
|
|
23057
24670
|
registerBuildCommand,
|
|
23058
24671
|
registerCheckCommand,
|
|
24672
|
+
registerConfigCommand,
|
|
23059
24673
|
registerDevCommand,
|
|
23060
24674
|
registerDoctorCommand,
|
|
23061
24675
|
registerEnsureCommand,
|