@thigasdevelopment/luam 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lua/async.lua +118 -118
- package/luam.mjs +363 -96
- package/package.json +1 -1
- package/template/README.md +0 -120
- package/template/config.lua +0 -14
- package/template/env +0 -11
- package/template/framework/bootstrap-client.luam +0 -9
- package/template/framework/bootstrap-server.luam +0 -9
- package/template/framework/command.luam +0 -54
- package/template/framework/core.luam +0 -58
- package/template/framework/event.luam +0 -39
- package/template/framework/listener.luam +0 -40
- package/template/framework/loader.luam +0 -73
- package/template/framework/thread-pool.luam +0 -27
- package/template/gitignore +0 -7
- package/template/src/client/commands/ping-command.luam +0 -8
- package/template/src/client/main.luam +0 -5
- package/template/src/server/commands/hello-command.luam +0 -9
- package/template/src/server/handlers/player-join-listener.luam +0 -9
- package/template/src/server/main.luam +0 -11
- package/template/src/shared/config.luam +0 -5
- package/template/src/shared/framework/command.luam +0 -54
- package/template/src/shared/framework/core.luam +0 -58
- package/template/src/shared/framework/event.luam +0 -39
- package/template/src/shared/framework/listener.luam +0 -40
- package/template/src/shared/framework/loader.luam +0 -73
- package/template/src/shared/framework/thread-pool.luam +0 -27
package/luam.mjs
CHANGED
|
@@ -212,7 +212,7 @@ var EXIT_DIAGNOSTICS = 1;
|
|
|
212
212
|
var EXIT_USAGE = 2;
|
|
213
213
|
|
|
214
214
|
// src/cli/usage.ts
|
|
215
|
-
var VERSION = true ? "0.
|
|
215
|
+
var VERSION = true ? "0.4.0" : "0.0.0-dev";
|
|
216
216
|
var USAGE = [
|
|
217
217
|
"luam \u2014 the Luam compiler for Multi Theft Auto resources.",
|
|
218
218
|
"",
|
|
@@ -279,7 +279,7 @@ function classify(raw) {
|
|
|
279
279
|
return { value, kind: value.length > 0 && Number.isFinite(Number(value)) ? "number" : "string" };
|
|
280
280
|
}
|
|
281
281
|
function parseEnvFile(source) {
|
|
282
|
-
const
|
|
282
|
+
const entries2 = [];
|
|
283
283
|
const errors = [];
|
|
284
284
|
source.split(/\r?\n/).forEach((raw, index) => {
|
|
285
285
|
const trimmed = raw.trim();
|
|
@@ -293,9 +293,9 @@ function parseEnvFile(source) {
|
|
|
293
293
|
return;
|
|
294
294
|
}
|
|
295
295
|
const { value, kind } = classify(match[2]);
|
|
296
|
-
|
|
296
|
+
entries2.push({ key: match[1], value, kind, line: line2 });
|
|
297
297
|
});
|
|
298
|
-
return { entries, errors };
|
|
298
|
+
return { entries: entries2, errors };
|
|
299
299
|
}
|
|
300
300
|
function isSensitiveKey(key) {
|
|
301
301
|
return SENSITIVE.test(key);
|
|
@@ -759,27 +759,27 @@ var PROCESS_GLOBAL = "process";
|
|
|
759
759
|
var PROCESS_ENV = "process.env";
|
|
760
760
|
var ENV_GLOBAL = "env";
|
|
761
761
|
var VALUE_TYPES = { boolean: BOOLEAN, number: NUMBER, string: STRING };
|
|
762
|
-
function envMembers(
|
|
762
|
+
function envMembers(entries2) {
|
|
763
763
|
const members = /* @__PURE__ */ new Map();
|
|
764
|
-
for (const entry of
|
|
764
|
+
for (const entry of entries2) {
|
|
765
765
|
members.set(entry.key, { name: entry.key, type: VALUE_TYPES[entry.kind] });
|
|
766
766
|
}
|
|
767
767
|
return [...members.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
768
768
|
}
|
|
769
|
-
function environmentDeclaration(
|
|
770
|
-
const env = record(PROCESS_ENV, envMembers(
|
|
769
|
+
function environmentDeclaration(entries2, origin) {
|
|
770
|
+
const env = record(PROCESS_ENV, envMembers(entries2), origin);
|
|
771
771
|
const process2 = record(PROCESS_GLOBAL, [{ name: ENV_GLOBAL, type: env }], origin);
|
|
772
772
|
return { name: PROCESS_GLOBAL, environment: "server", source: "project", type: process2 };
|
|
773
773
|
}
|
|
774
|
-
function envDeclaration(
|
|
775
|
-
const env = record(ENV_GLOBAL, envMembers(
|
|
774
|
+
function envDeclaration(entries2, origin) {
|
|
775
|
+
const env = record(ENV_GLOBAL, envMembers(entries2), origin);
|
|
776
776
|
return { name: ENV_GLOBAL, environment: "server", source: "project", type: env };
|
|
777
777
|
}
|
|
778
|
-
function projectDeclarations(
|
|
779
|
-
if (
|
|
778
|
+
function projectDeclarations(entries2, origin) {
|
|
779
|
+
if (entries2 === null) {
|
|
780
780
|
return EMPTY_PROJECT_DECLARATIONS;
|
|
781
781
|
}
|
|
782
|
-
return { globals: [environmentDeclaration(
|
|
782
|
+
return { globals: [environmentDeclaration(entries2, origin), envDeclaration(entries2, origin)] };
|
|
783
783
|
}
|
|
784
784
|
|
|
785
785
|
// ../compiler/src/checker/ambient.ts
|
|
@@ -792,9 +792,9 @@ function ambientFromRegistry(registry) {
|
|
|
792
792
|
globals: registry.allGlobals()
|
|
793
793
|
};
|
|
794
794
|
}
|
|
795
|
-
function withoutNames(
|
|
795
|
+
function withoutNames(entries2, excluded) {
|
|
796
796
|
const names = new Set(excluded.map((entry) => entry.name));
|
|
797
|
-
return
|
|
797
|
+
return entries2.filter((entry) => !names.has(entry.name));
|
|
798
798
|
}
|
|
799
799
|
function ownDeclarations(registry, ambient) {
|
|
800
800
|
const all = ambientFromRegistry(registry);
|
|
@@ -916,6 +916,15 @@ function createNamed(name) {
|
|
|
916
916
|
function createRecord(name, members, origin = null) {
|
|
917
917
|
return { kind: "record", name, origin, members };
|
|
918
918
|
}
|
|
919
|
+
function renameRecord(type, name) {
|
|
920
|
+
return type.kind === "record" ? createRecord(name, type.members, type.origin) : type;
|
|
921
|
+
}
|
|
922
|
+
function createObjectType(members) {
|
|
923
|
+
const keys = [...members].map(
|
|
924
|
+
([name, member]) => member.kind === "optional" ? `${name}?: ${typeToString(member.element)}` : `${name}: ${typeToString(member)}`
|
|
925
|
+
);
|
|
926
|
+
return createRecord(keys.length === 0 ? "{}" : `{ ${keys.join(", ")} }`, members);
|
|
927
|
+
}
|
|
919
928
|
function createFunction(parameters, returnType, minimumArguments2, isVariadic = false) {
|
|
920
929
|
return { kind: "function", parameters, returnType, minimumArguments: minimumArguments2 ?? parameters.length, isVariadic };
|
|
921
930
|
}
|
|
@@ -1022,6 +1031,21 @@ function isFunctionAssignable(source, target, options) {
|
|
|
1022
1031
|
}
|
|
1023
1032
|
return target.returnType.kind === "void" || isAssignable(source.returnType, target.returnType, options);
|
|
1024
1033
|
}
|
|
1034
|
+
function isRecordAssignable(source, target, options) {
|
|
1035
|
+
for (const [name, member] of target.members) {
|
|
1036
|
+
const value = source.members.get(name);
|
|
1037
|
+
if (value === void 0) {
|
|
1038
|
+
if (member.kind !== "optional") {
|
|
1039
|
+
return false;
|
|
1040
|
+
}
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
if (!isAssignable(value, member, options)) {
|
|
1044
|
+
return false;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
return true;
|
|
1048
|
+
}
|
|
1025
1049
|
function isAssignable(source, target, options = { allowNil: false }) {
|
|
1026
1050
|
if (source.kind === "any" || target.kind === "any" || target.kind === "unknown") {
|
|
1027
1051
|
return true;
|
|
@@ -1053,6 +1077,9 @@ function isAssignable(source, target, options = { allowNil: false }) {
|
|
|
1053
1077
|
if (target.kind === "table") {
|
|
1054
1078
|
return isTableLike(source) || source.kind === "record";
|
|
1055
1079
|
}
|
|
1080
|
+
if (target.kind === "record") {
|
|
1081
|
+
return source.kind === "record" ? isRecordAssignable(source, target, options) : source.kind === "table";
|
|
1082
|
+
}
|
|
1056
1083
|
if (target.kind === "array") {
|
|
1057
1084
|
return source.kind === "table" || source.kind === "array" && isAssignable(source.element, target.element, options);
|
|
1058
1085
|
}
|
|
@@ -4831,6 +4858,14 @@ var DeclarationRegistry = class {
|
|
|
4831
4858
|
lookupInterface(name) {
|
|
4832
4859
|
return this.interfaces.get(name) ?? null;
|
|
4833
4860
|
}
|
|
4861
|
+
interfaceExtends(name, target, visited = /* @__PURE__ */ new Set()) {
|
|
4862
|
+
const current = this.lookupInterface(name);
|
|
4863
|
+
if (current === null || visited.has(name)) {
|
|
4864
|
+
return false;
|
|
4865
|
+
}
|
|
4866
|
+
visited.add(name);
|
|
4867
|
+
return current.superInterfaces.some((parent) => parent === target || this.interfaceExtends(parent, target, visited));
|
|
4868
|
+
}
|
|
4834
4869
|
declareEnum(info) {
|
|
4835
4870
|
this.enums.set(info.name, info);
|
|
4836
4871
|
}
|
|
@@ -4846,24 +4881,42 @@ var DeclarationRegistry = class {
|
|
|
4846
4881
|
allEnums() {
|
|
4847
4882
|
return [...this.enums.values()];
|
|
4848
4883
|
}
|
|
4849
|
-
|
|
4884
|
+
collectInterfaceMembers(name, collected, visited) {
|
|
4885
|
+
const current = this.lookupInterface(name);
|
|
4886
|
+
if (current === null || visited.has(current.name)) {
|
|
4887
|
+
return;
|
|
4888
|
+
}
|
|
4889
|
+
visited.add(current.name);
|
|
4890
|
+
for (const [memberName, member] of current.members) {
|
|
4891
|
+
if (!collected.has(memberName)) {
|
|
4892
|
+
collected.set(memberName, member);
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
for (const parent of current.superInterfaces) {
|
|
4896
|
+
this.collectInterfaceMembers(parent, collected, visited);
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
collectMembers(name) {
|
|
4850
4900
|
const collected = /* @__PURE__ */ new Map();
|
|
4851
4901
|
const visited = /* @__PURE__ */ new Set();
|
|
4852
|
-
let current = this.lookupClass(
|
|
4902
|
+
let current = this.lookupClass(name);
|
|
4853
4903
|
while (current !== null && !visited.has(current.name)) {
|
|
4854
|
-
for (const [
|
|
4855
|
-
if (!collected.has(
|
|
4856
|
-
collected.set(
|
|
4904
|
+
for (const [name2, member] of current.members) {
|
|
4905
|
+
if (!collected.has(name2)) {
|
|
4906
|
+
collected.set(name2, member);
|
|
4857
4907
|
}
|
|
4858
4908
|
}
|
|
4859
4909
|
visited.add(current.name);
|
|
4860
4910
|
current = current.superClass === null ? null : this.lookupClass(current.superClass);
|
|
4861
4911
|
}
|
|
4912
|
+
if (current === null && this.lookupClass(name) === null) {
|
|
4913
|
+
this.collectInterfaceMembers(name, collected, visited);
|
|
4914
|
+
}
|
|
4862
4915
|
return [...collected.values()];
|
|
4863
4916
|
}
|
|
4864
|
-
lookupMember(
|
|
4917
|
+
lookupMember(name, member) {
|
|
4865
4918
|
const visited = /* @__PURE__ */ new Set();
|
|
4866
|
-
let current = this.lookupClass(
|
|
4919
|
+
let current = this.lookupClass(name);
|
|
4867
4920
|
while (current !== null && !visited.has(current.name)) {
|
|
4868
4921
|
const found = current.members.get(member);
|
|
4869
4922
|
if (found !== void 0) {
|
|
@@ -4872,7 +4925,9 @@ var DeclarationRegistry = class {
|
|
|
4872
4925
|
visited.add(current.name);
|
|
4873
4926
|
current = current.superClass === null ? null : this.lookupClass(current.superClass);
|
|
4874
4927
|
}
|
|
4875
|
-
|
|
4928
|
+
const collected = /* @__PURE__ */ new Map();
|
|
4929
|
+
this.collectInterfaceMembers(name, collected, visited);
|
|
4930
|
+
return collected.get(member) ?? null;
|
|
4876
4931
|
}
|
|
4877
4932
|
};
|
|
4878
4933
|
|
|
@@ -4987,6 +5042,7 @@ var CheckContext = class {
|
|
|
4987
5042
|
methodStack = [];
|
|
4988
5043
|
projectEnvironments = /* @__PURE__ */ new Map();
|
|
4989
5044
|
ambientClasses = /* @__PURE__ */ new Set();
|
|
5045
|
+
ambientInterfaces = /* @__PURE__ */ new Set();
|
|
4990
5046
|
constructor(mode, environment, ambient = EMPTY_AMBIENT, project = EMPTY_PROJECT_DECLARATIONS, oop = false) {
|
|
4991
5047
|
this.mode = mode;
|
|
4992
5048
|
this.environment = environment;
|
|
@@ -5008,6 +5064,9 @@ var CheckContext = class {
|
|
|
5008
5064
|
isAmbientClass(name) {
|
|
5009
5065
|
return this.ambientClasses.has(name);
|
|
5010
5066
|
}
|
|
5067
|
+
isAmbientInterface(name) {
|
|
5068
|
+
return this.ambientInterfaces.has(name);
|
|
5069
|
+
}
|
|
5011
5070
|
noteExternalReference(name, position2) {
|
|
5012
5071
|
if (!this.externalReferences.has(name)) {
|
|
5013
5072
|
this.externalReferences.set(name, position2);
|
|
@@ -5057,6 +5116,16 @@ var CheckContext = class {
|
|
|
5057
5116
|
if (annotation.kind === "type-union") {
|
|
5058
5117
|
return createUnion(annotation.options.map((option) => this.resolveAnnotation(option)));
|
|
5059
5118
|
}
|
|
5119
|
+
if (annotation.kind === "type-object") {
|
|
5120
|
+
const members = /* @__PURE__ */ new Map();
|
|
5121
|
+
for (const member of annotation.members) {
|
|
5122
|
+
members.set(member.name, this.resolveAnnotation(member.annotation));
|
|
5123
|
+
}
|
|
5124
|
+
return createObjectType(members);
|
|
5125
|
+
}
|
|
5126
|
+
if (annotation.kind === "type-tuple") {
|
|
5127
|
+
return createTuple(annotation.elements.map((element) => this.resolveAnnotation(element)));
|
|
5128
|
+
}
|
|
5060
5129
|
if (annotation.kind === "type-function") {
|
|
5061
5130
|
const parameters = annotation.parameters.map((parameter) => this.resolveAnnotation(parameter));
|
|
5062
5131
|
const optional = parameters.findIndex((parameter) => parameter.kind === "optional");
|
|
@@ -5088,6 +5157,7 @@ var CheckContext = class {
|
|
|
5088
5157
|
this.binder.declareGlobal({ name: info.name, type: createNamed(info.name), isLocal: false, position: info.position });
|
|
5089
5158
|
}
|
|
5090
5159
|
for (const info of ambient.interfaces) {
|
|
5160
|
+
this.ambientInterfaces.add(info.name);
|
|
5091
5161
|
this.declarations.declareInterface(info);
|
|
5092
5162
|
}
|
|
5093
5163
|
for (const info of ambient.enums) {
|
|
@@ -5387,7 +5457,7 @@ function expandClassDecorators(context, statement, fieldTypes) {
|
|
|
5387
5457
|
const occupied = new Map(statement.members.filter((member) => member.kind === "class-method").map((member) => [member.name, member.name]));
|
|
5388
5458
|
const classDecorators = validateDecorators(context, statement.decorators, "class");
|
|
5389
5459
|
for (const member of statement.members) {
|
|
5390
|
-
if (member.kind === "class-method") {
|
|
5460
|
+
if (member.kind === "class-method" || member.name === "constructor") {
|
|
5391
5461
|
validateDecorators(context, member.decorators, "method");
|
|
5392
5462
|
continue;
|
|
5393
5463
|
}
|
|
@@ -5969,7 +6039,11 @@ function resolveNamedMember(context, name, expression) {
|
|
|
5969
6039
|
return resolveMtaMember(context, name, expression.property, expression.position)?.type ?? ANY_TYPE;
|
|
5970
6040
|
}
|
|
5971
6041
|
const contract = context.declarations.lookupClass(name) === null ? context.declarations.lookupInterface(name) : null;
|
|
5972
|
-
|
|
6042
|
+
if (contract === null) {
|
|
6043
|
+
return null;
|
|
6044
|
+
}
|
|
6045
|
+
const members = new Map(context.declarations.collectMembers(name).map((member2) => [member2.name, member2]));
|
|
6046
|
+
return checkInterfaceMember(context, name, members, expression);
|
|
5973
6047
|
}
|
|
5974
6048
|
var NATIVE_CONSTRUCTOR = "new";
|
|
5975
6049
|
function nativeConstructor(context, name) {
|
|
@@ -6334,6 +6408,10 @@ function registerMembers(context, info, statement) {
|
|
|
6334
6408
|
return generated;
|
|
6335
6409
|
}
|
|
6336
6410
|
function checkMethodBody(context, info, member) {
|
|
6411
|
+
const explicitSelf = member.parameters.find((parameter) => parameter.name === "self");
|
|
6412
|
+
if (explicitSelf !== void 0) {
|
|
6413
|
+
context.report("check-explicit-self-parameter", 'Class methods receive "self" automatically; remove it from the parameter list.', explicitSelf.position);
|
|
6414
|
+
}
|
|
6337
6415
|
context.pushClassMethod({ className: info.name, methodName: member.name });
|
|
6338
6416
|
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, createNamed(info.name));
|
|
6339
6417
|
context.popClassMethod();
|
|
@@ -6360,7 +6438,7 @@ function checkInterfaces(context, info) {
|
|
|
6360
6438
|
context.report("check-unknown-interface", `Class "${info.name}" implements "${name}", which is not defined.`, info.position);
|
|
6361
6439
|
continue;
|
|
6362
6440
|
}
|
|
6363
|
-
for (const member of
|
|
6441
|
+
for (const member of context.declarations.collectMembers(contract.name)) {
|
|
6364
6442
|
checkContract(context, info, name, member);
|
|
6365
6443
|
}
|
|
6366
6444
|
}
|
|
@@ -6418,11 +6496,46 @@ function checkInterfaceDeclaration(context, statement) {
|
|
|
6418
6496
|
return;
|
|
6419
6497
|
}
|
|
6420
6498
|
const members = /* @__PURE__ */ new Map();
|
|
6499
|
+
for (const name of new Set(statement.superInterfaces)) {
|
|
6500
|
+
const parent = context.declarations.lookupInterface(name);
|
|
6501
|
+
if (name === statement.name || context.declarations.interfaceExtends(name, statement.name)) {
|
|
6502
|
+
context.report("check-interface-cycle", `Interface "${statement.name}" creates an inheritance cycle through "${name}".`, statement.position);
|
|
6503
|
+
} else if (parent === null) {
|
|
6504
|
+
context.noteExternalReference(name, statement.position);
|
|
6505
|
+
context.report("check-unknown-interface", `Interface "${statement.name}" extends "${name}", which is not defined.`, statement.position);
|
|
6506
|
+
} else if (context.isAmbientInterface(name)) {
|
|
6507
|
+
context.noteExternalReference(name, statement.position);
|
|
6508
|
+
}
|
|
6509
|
+
}
|
|
6510
|
+
if (new Set(statement.superInterfaces).size !== statement.superInterfaces.length) {
|
|
6511
|
+
context.report("check-duplicate-interface-parent", `Interface "${statement.name}" extends the same interface more than once.`, statement.position);
|
|
6512
|
+
}
|
|
6421
6513
|
for (const member of statement.members) {
|
|
6422
6514
|
const type = member.kind === "interface-field" ? context.resolveAnnotation(member.annotation) : buildFunctionType(context, member.parameters, member.returnAnnotation);
|
|
6423
|
-
|
|
6515
|
+
const info = { name: member.name, type, isMethod: member.kind === "interface-method", position: member.position };
|
|
6516
|
+
if (members.has(member.name)) {
|
|
6517
|
+
context.report("check-duplicate-interface-member", `Interface "${statement.name}" declares member "${member.name}" more than once.`, member.position);
|
|
6518
|
+
} else {
|
|
6519
|
+
members.set(member.name, info);
|
|
6520
|
+
}
|
|
6424
6521
|
}
|
|
6425
|
-
|
|
6522
|
+
const inherited = /* @__PURE__ */ new Map();
|
|
6523
|
+
for (const parent of statement.superInterfaces) {
|
|
6524
|
+
for (const member of context.declarations.collectMembers(parent)) {
|
|
6525
|
+
const existing = members.get(member.name) ?? inherited.get(member.name);
|
|
6526
|
+
if (existing !== void 0 && (existing.isMethod !== member.isMethod || typeToString(existing.type) !== typeToString(member.type))) {
|
|
6527
|
+
context.report("check-conflicting-interface-member", `Interface "${statement.name}" inherits conflicting declarations of "${member.name}".`, statement.position);
|
|
6528
|
+
} else if (existing === void 0) {
|
|
6529
|
+
inherited.set(member.name, member);
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
context.declarations.declareInterface({
|
|
6534
|
+
name: statement.name,
|
|
6535
|
+
superInterfaces: statement.superInterfaces,
|
|
6536
|
+
members,
|
|
6537
|
+
position: statement.position
|
|
6538
|
+
});
|
|
6426
6539
|
}
|
|
6427
6540
|
function checkEnumDeclaration(context, statement) {
|
|
6428
6541
|
if (context.declarations.lookupEnum(statement.name) !== null) {
|
|
@@ -6582,6 +6695,23 @@ function checkReturn(context, statement) {
|
|
|
6582
6695
|
}
|
|
6583
6696
|
return;
|
|
6584
6697
|
}
|
|
6698
|
+
if (expected.kind === "tuple") {
|
|
6699
|
+
if (valueTypes.length !== expected.elements.length) {
|
|
6700
|
+
const message = `This function declares ${expected.elements.length} return values but returns ${valueTypes.length}.`;
|
|
6701
|
+
context.report("check-return-mismatch", message, statement.position);
|
|
6702
|
+
return;
|
|
6703
|
+
}
|
|
6704
|
+
valueTypes.forEach((type, index) => {
|
|
6705
|
+
const value2 = statement.values[Math.min(index, statement.values.length - 1)];
|
|
6706
|
+
context.expectAssignable(type, expected.elements[index] ?? ANY_TYPE, value2?.position ?? statement.position, `Return value ${index + 1}`);
|
|
6707
|
+
});
|
|
6708
|
+
return;
|
|
6709
|
+
}
|
|
6710
|
+
if (valueTypes.length > 1) {
|
|
6711
|
+
const message = `This function declares one return value of type "${typeToString(expected)}" but returns ${valueTypes.length} values.`;
|
|
6712
|
+
context.report("check-return-mismatch", message, statement.position);
|
|
6713
|
+
return;
|
|
6714
|
+
}
|
|
6585
6715
|
const first = valueTypes[0];
|
|
6586
6716
|
const value = statement.values[0];
|
|
6587
6717
|
if (first === void 0 || value === void 0) {
|
|
@@ -6628,9 +6758,12 @@ function checkStatement(context, statement) {
|
|
|
6628
6758
|
return checkNumericFor(context, statement);
|
|
6629
6759
|
case "generic-for-statement":
|
|
6630
6760
|
return checkGenericFor(context, statement);
|
|
6631
|
-
case "type-alias-statement":
|
|
6632
|
-
|
|
6761
|
+
case "type-alias-statement": {
|
|
6762
|
+
const resolved = context.resolveAnnotation(statement.annotation);
|
|
6763
|
+
const named2 = statement.annotation.kind === "type-object" ? renameRecord(resolved, statement.name) : resolved;
|
|
6764
|
+
context.binder.declareAlias(statement.name, named2);
|
|
6633
6765
|
return;
|
|
6766
|
+
}
|
|
6634
6767
|
case "declare-statement":
|
|
6635
6768
|
return checkDeclareStatement(context, statement);
|
|
6636
6769
|
case "class-declaration":
|
|
@@ -6988,22 +7121,22 @@ function emitMethod(state, className, member) {
|
|
|
6988
7121
|
return withSymbol(state, `${className}:${member.name}`, () => emitFunctionBody(state, [self, ...member.parameters], member.body, `${member.name} = function`));
|
|
6989
7122
|
}
|
|
6990
7123
|
function emitMembers(state, statement) {
|
|
6991
|
-
const
|
|
7124
|
+
const entries2 = [];
|
|
6992
7125
|
state.indent += 1;
|
|
6993
7126
|
for (const member of statement.members) {
|
|
6994
7127
|
if (member.kind === "class-method") {
|
|
6995
|
-
|
|
7128
|
+
entries2.push(indentLine(state, `${markSource(state, member.position.line, `${statement.name}:${member.name}`)}${emitMethod(state, statement.name, member)}`));
|
|
6996
7129
|
continue;
|
|
6997
7130
|
}
|
|
6998
7131
|
if (member.value !== null) {
|
|
6999
|
-
|
|
7132
|
+
entries2.push(indentLine(state, `${markSource(state, member.position.line, statement.name)}${member.name} = ${emitExpression(state, member.value)}`));
|
|
7000
7133
|
}
|
|
7001
7134
|
}
|
|
7002
7135
|
for (const generated of state.generatedMembers.get(statement) ?? []) {
|
|
7003
|
-
|
|
7136
|
+
entries2.push(indentLine(state, `${markSource(state, generated.position.line, `${statement.name}:${generated.name}`)}${emitMethod(state, statement.name, generated)}`));
|
|
7004
7137
|
}
|
|
7005
7138
|
state.indent -= 1;
|
|
7006
|
-
return
|
|
7139
|
+
return entries2;
|
|
7007
7140
|
}
|
|
7008
7141
|
function emitClassHeader(statement) {
|
|
7009
7142
|
const name = emitString(statement.name);
|
|
@@ -7012,11 +7145,11 @@ function emitClassHeader(statement) {
|
|
|
7012
7145
|
function emitClassDeclaration(state, statement) {
|
|
7013
7146
|
requireHelper(state, "class");
|
|
7014
7147
|
const header = emitClassHeader(statement);
|
|
7015
|
-
const
|
|
7016
|
-
if (
|
|
7148
|
+
const entries2 = emitMembers(state, statement);
|
|
7149
|
+
if (entries2.length === 0) {
|
|
7017
7150
|
return `${header} {}`;
|
|
7018
7151
|
}
|
|
7019
|
-
return [`${header} {`,
|
|
7152
|
+
return [`${header} {`, entries2.join(",\n"), indentLine(state, "}")].join("\n");
|
|
7020
7153
|
}
|
|
7021
7154
|
function emitEnumDeclaration(state, statement) {
|
|
7022
7155
|
if (!state.references.has(statement.name)) {
|
|
@@ -7781,13 +7914,45 @@ function parseFunctionType(stream) {
|
|
|
7781
7914
|
return { kind: "type-function", parameters, isVariadic, returnType, position: position2 };
|
|
7782
7915
|
}
|
|
7783
7916
|
function parseGroupedType(stream) {
|
|
7784
|
-
stream.expect("punctuation", "(");
|
|
7917
|
+
const position2 = stream.expect("punctuation", "(").position;
|
|
7785
7918
|
const inner = parseTypeAnnotation(stream);
|
|
7786
|
-
if (stream.
|
|
7787
|
-
|
|
7919
|
+
if (!stream.match("punctuation", ",")) {
|
|
7920
|
+
stream.expect("punctuation", ")");
|
|
7921
|
+
return inner;
|
|
7788
7922
|
}
|
|
7923
|
+
const elements = [inner];
|
|
7924
|
+
do {
|
|
7925
|
+
elements.push(parseTypeAnnotation(stream));
|
|
7926
|
+
} while (stream.match("punctuation", ","));
|
|
7789
7927
|
stream.expect("punctuation", ")");
|
|
7790
|
-
return
|
|
7928
|
+
return { kind: "type-tuple", elements, position: position2 };
|
|
7929
|
+
}
|
|
7930
|
+
function parseObjectMember(stream) {
|
|
7931
|
+
const token = stream.expectName();
|
|
7932
|
+
const annotation = parseNamedAnnotation(stream, "field");
|
|
7933
|
+
if (annotation === null) {
|
|
7934
|
+
throw stream.error(`Key "${token.value}" of an object type requires a type annotation.`, "parse-invalid-type");
|
|
7935
|
+
}
|
|
7936
|
+
return { name: token.value, annotation, position: token.position };
|
|
7937
|
+
}
|
|
7938
|
+
function parseObjectType(stream) {
|
|
7939
|
+
const position2 = stream.expect("punctuation", "{").position;
|
|
7940
|
+
const members = [];
|
|
7941
|
+
const declared = /* @__PURE__ */ new Set();
|
|
7942
|
+
while (!stream.check("punctuation", "}") && !stream.isEof()) {
|
|
7943
|
+
if (stream.match("punctuation", ";") || stream.match("punctuation", ",")) {
|
|
7944
|
+
continue;
|
|
7945
|
+
}
|
|
7946
|
+
const member = parseObjectMember(stream);
|
|
7947
|
+
if (declared.has(member.name)) {
|
|
7948
|
+
stream.report("parse-duplicate-key", `Object type key "${member.name}" is declared more than once.`, member.position);
|
|
7949
|
+
continue;
|
|
7950
|
+
}
|
|
7951
|
+
declared.add(member.name);
|
|
7952
|
+
members.push(member);
|
|
7953
|
+
}
|
|
7954
|
+
stream.expect("punctuation", "}");
|
|
7955
|
+
return { kind: "type-object", members, position: position2 };
|
|
7791
7956
|
}
|
|
7792
7957
|
function parsePrimaryType(stream) {
|
|
7793
7958
|
if (stream.check("keyword", "function")) {
|
|
@@ -7796,6 +7961,9 @@ function parsePrimaryType(stream) {
|
|
|
7796
7961
|
if (stream.check("identifier", FUNCTION_TYPE)) {
|
|
7797
7962
|
return parseFunctionType(stream);
|
|
7798
7963
|
}
|
|
7964
|
+
if (stream.check("punctuation", "{")) {
|
|
7965
|
+
return parseObjectType(stream);
|
|
7966
|
+
}
|
|
7799
7967
|
return stream.check("punctuation", "(") ? parseGroupedType(stream) : parseTypeName(stream);
|
|
7800
7968
|
}
|
|
7801
7969
|
function parsePostfixType(stream) {
|
|
@@ -8125,16 +8293,24 @@ function parseForStatement(stream) {
|
|
|
8125
8293
|
}
|
|
8126
8294
|
|
|
8127
8295
|
// ../compiler/src/parser/recovery.ts
|
|
8128
|
-
|
|
8296
|
+
var BRACE_TERMINATORS = /* @__PURE__ */ new Set(["}"]);
|
|
8297
|
+
function isTerminator(stream, terminators) {
|
|
8298
|
+
const token = stream.current();
|
|
8299
|
+
if (token.kind !== "punctuation" && token.kind !== "keyword") {
|
|
8300
|
+
return false;
|
|
8301
|
+
}
|
|
8302
|
+
return terminators.has(token.value);
|
|
8303
|
+
}
|
|
8304
|
+
function recoverInBlock(stream, error, terminators = BRACE_TERMINATORS) {
|
|
8129
8305
|
stream.diagnostics.push(error.diagnostic);
|
|
8130
8306
|
if (stream.isEof()) {
|
|
8131
8307
|
return;
|
|
8132
8308
|
}
|
|
8133
8309
|
const start = stream.current();
|
|
8134
|
-
while (!stream.isEof() && !stream
|
|
8310
|
+
while (!stream.isEof() && !isTerminator(stream, terminators) && stream.current().position.line === start.position.line) {
|
|
8135
8311
|
stream.next();
|
|
8136
8312
|
}
|
|
8137
|
-
if (!stream.isEof() && !stream
|
|
8313
|
+
if (!stream.isEof() && !isTerminator(stream, terminators) && stream.current().position.offset === start.position.offset) {
|
|
8138
8314
|
stream.next();
|
|
8139
8315
|
}
|
|
8140
8316
|
}
|
|
@@ -8244,7 +8420,10 @@ function isDeclarationStart(stream) {
|
|
|
8244
8420
|
if (offset > 0 && token.value !== "class") {
|
|
8245
8421
|
return false;
|
|
8246
8422
|
}
|
|
8247
|
-
|
|
8423
|
+
if (token.value === "class") {
|
|
8424
|
+
return isClassHeader(stream, offset);
|
|
8425
|
+
}
|
|
8426
|
+
return token.value === "interface" ? stream.checkAhead(offset + 2, "punctuation", "{") || stream.checkAhead(offset + 2, "keyword", "extends") : stream.checkAhead(offset + 2, "punctuation", "{");
|
|
8248
8427
|
}
|
|
8249
8428
|
function skipDecoratorArguments(stream) {
|
|
8250
8429
|
let depth = 0;
|
|
@@ -8271,6 +8450,21 @@ function parseDecorators(stream) {
|
|
|
8271
8450
|
return decorators;
|
|
8272
8451
|
}
|
|
8273
8452
|
function parseClassMethod(stream, token, decorators) {
|
|
8453
|
+
stream.expect("operator", "=");
|
|
8454
|
+
const expression = parseFunctionExpression(stream);
|
|
8455
|
+
return {
|
|
8456
|
+
kind: "class-method",
|
|
8457
|
+
name: token.value,
|
|
8458
|
+
isConstructor: token.value === "constructor",
|
|
8459
|
+
isSynthetic: false,
|
|
8460
|
+
parameters: expression.parameters,
|
|
8461
|
+
returnAnnotation: expression.returnAnnotation,
|
|
8462
|
+
body: expression.body,
|
|
8463
|
+
decorators,
|
|
8464
|
+
position: token.position
|
|
8465
|
+
};
|
|
8466
|
+
}
|
|
8467
|
+
function parseLegacyClassMethod(stream, token, decorators) {
|
|
8274
8468
|
const parameters = parseParameters(stream);
|
|
8275
8469
|
const returnAnnotation = parseOptionalAnnotation(stream);
|
|
8276
8470
|
const body = parseBraceBlock(stream);
|
|
@@ -8293,6 +8487,9 @@ function parseClassMember(stream) {
|
|
|
8293
8487
|
const decorators = parseDecorators(stream);
|
|
8294
8488
|
const token = stream.expectName();
|
|
8295
8489
|
if (stream.check("punctuation", "(")) {
|
|
8490
|
+
return parseLegacyClassMethod(stream, token, decorators);
|
|
8491
|
+
}
|
|
8492
|
+
if (stream.check("operator", "=") && stream.checkAhead(1, "keyword", "function")) {
|
|
8296
8493
|
return parseClassMethod(stream, token, decorators);
|
|
8297
8494
|
}
|
|
8298
8495
|
const annotation = parseFieldAnnotation(stream);
|
|
@@ -8348,7 +8545,13 @@ function parseInterfaceMember(stream) {
|
|
|
8348
8545
|
function parseInterfaceDeclaration(stream) {
|
|
8349
8546
|
const position2 = stream.next().position;
|
|
8350
8547
|
const name = stream.expect("identifier").value;
|
|
8548
|
+
const superInterfaces = [];
|
|
8351
8549
|
const members = [];
|
|
8550
|
+
if (stream.match("keyword", "extends")) {
|
|
8551
|
+
do {
|
|
8552
|
+
superInterfaces.push(stream.expect("identifier").value);
|
|
8553
|
+
} while (stream.match("punctuation", ","));
|
|
8554
|
+
}
|
|
8352
8555
|
stream.expect("punctuation", "{");
|
|
8353
8556
|
while (!stream.check("punctuation", "}") && !stream.isEof()) {
|
|
8354
8557
|
if (stream.match("punctuation", ";") || stream.match("punctuation", ",")) {
|
|
@@ -8364,7 +8567,7 @@ function parseInterfaceDeclaration(stream) {
|
|
|
8364
8567
|
}
|
|
8365
8568
|
}
|
|
8366
8569
|
stream.expect("punctuation", "}");
|
|
8367
|
-
return { kind: "interface-declaration", name, members, position: position2 };
|
|
8570
|
+
return { kind: "interface-declaration", name, superInterfaces, members, position: position2 };
|
|
8368
8571
|
}
|
|
8369
8572
|
function parseEnumDeclaration(stream) {
|
|
8370
8573
|
const position2 = stream.next().position;
|
|
@@ -8564,14 +8767,14 @@ function parseStatement(stream) {
|
|
|
8564
8767
|
}
|
|
8565
8768
|
return parseExpressionStatement(stream);
|
|
8566
8769
|
}
|
|
8567
|
-
function parseBlockStatement(stream) {
|
|
8770
|
+
function parseBlockStatement(stream, terminators = BRACE_TERMINATORS) {
|
|
8568
8771
|
try {
|
|
8569
8772
|
return parseStatement(stream);
|
|
8570
8773
|
} catch (error) {
|
|
8571
8774
|
if (!(error instanceof ParserError)) {
|
|
8572
8775
|
throw error;
|
|
8573
8776
|
}
|
|
8574
|
-
recoverInBlock(stream, error);
|
|
8777
|
+
recoverInBlock(stream, error, terminators);
|
|
8575
8778
|
return null;
|
|
8576
8779
|
}
|
|
8577
8780
|
}
|
|
@@ -8604,7 +8807,14 @@ function parseBlock(stream, terminators) {
|
|
|
8604
8807
|
if (stream.current().kind === "keyword" && stop.has(stream.current().value)) {
|
|
8605
8808
|
return body;
|
|
8606
8809
|
}
|
|
8607
|
-
const
|
|
8810
|
+
const offset = stream.current().position.offset;
|
|
8811
|
+
const statement = parseBlockStatement(stream, stop);
|
|
8812
|
+
if (statement === null) {
|
|
8813
|
+
if (stream.current().position.offset === offset) {
|
|
8814
|
+
return body;
|
|
8815
|
+
}
|
|
8816
|
+
continue;
|
|
8817
|
+
}
|
|
8608
8818
|
body.push(statement);
|
|
8609
8819
|
if (statement.kind === "return-statement") {
|
|
8610
8820
|
return body;
|
|
@@ -8751,7 +8961,7 @@ function classText(info) {
|
|
|
8751
8961
|
return `class ${info.name}:${info.superClass ?? ""}:${[...info.interfaces].sort(compareText).join(",")}{${membersText(info.members)}}`;
|
|
8752
8962
|
}
|
|
8753
8963
|
function interfaceText(info) {
|
|
8754
|
-
return `interface ${info.name}{${membersText(info.members)}}`;
|
|
8964
|
+
return `interface ${info.name}:${[...info.superInterfaces].sort(compareText).join(",")}{${membersText(info.members)}}`;
|
|
8755
8965
|
}
|
|
8756
8966
|
function enumText(info) {
|
|
8757
8967
|
return `enum ${info.name}{${info.members.join(",")}}`;
|
|
@@ -8809,8 +9019,8 @@ function attribute(name, value) {
|
|
|
8809
9019
|
function textElement(name, value) {
|
|
8810
9020
|
return `${INDENT2}<${name}>${escapeXml(value)}</${name}>`;
|
|
8811
9021
|
}
|
|
8812
|
-
function section(text,
|
|
8813
|
-
return
|
|
9022
|
+
function section(text, entries2) {
|
|
9023
|
+
return entries2.length === 0 ? [] : [`${INDENT2}<!-- ${text} -->`, ...entries2];
|
|
8814
9024
|
}
|
|
8815
9025
|
function infoElement(info) {
|
|
8816
9026
|
const attributes = info.author === void 0 ? [] : [attribute("author", info.author)];
|
|
@@ -8949,16 +9159,16 @@ function createAmbientResolver(collected) {
|
|
|
8949
9159
|
const visible = /* @__PURE__ */ new Map();
|
|
8950
9160
|
const merged = /* @__PURE__ */ new Map();
|
|
8951
9161
|
for (const environment of ALL_ENVIRONMENTS) {
|
|
8952
|
-
const
|
|
8953
|
-
visible.set(environment,
|
|
8954
|
-
merged.set(environment, mergeAmbient(
|
|
9162
|
+
const entries2 = collected.filter((entry) => canReference(environment, entry.environment) && !declaresNothing(entry.declarations));
|
|
9163
|
+
visible.set(environment, entries2);
|
|
9164
|
+
merged.set(environment, mergeAmbient(entries2.map((entry) => entry.declarations)));
|
|
8955
9165
|
}
|
|
8956
9166
|
return (entry) => {
|
|
8957
9167
|
if (declaresNothing(entry.declarations)) {
|
|
8958
9168
|
return merged.get(entry.environment) ?? EMPTY_AMBIENT;
|
|
8959
9169
|
}
|
|
8960
|
-
const
|
|
8961
|
-
return mergeAmbient(
|
|
9170
|
+
const entries2 = visible.get(entry.environment) ?? [];
|
|
9171
|
+
return mergeAmbient(entries2.filter((candidate) => candidate.path !== entry.path).map((candidate) => candidate.declarations));
|
|
8962
9172
|
};
|
|
8963
9173
|
}
|
|
8964
9174
|
function compileModule(file, ambient, context) {
|
|
@@ -9245,12 +9455,12 @@ var MISSING_LOAD_ORDER = 'is listed in "loadOrder" but no source file or asset m
|
|
|
9245
9455
|
function missingEntry(entry) {
|
|
9246
9456
|
return { path: entry, diagnostic: createDiagnostic("project", "project-load-order-missing", `"${entry}" ${MISSING_LOAD_ORDER}`, FILE_START) };
|
|
9247
9457
|
}
|
|
9248
|
-
function resolveLoadOrder(
|
|
9458
|
+
function resolveLoadOrder(entries2, scripts, assets) {
|
|
9249
9459
|
const byScript = new Map(scripts.map((script) => [normalizePath(script.source), script]));
|
|
9250
9460
|
const byAsset = new Map(assets.map((asset) => [normalizePath(asset.source), asset]));
|
|
9251
9461
|
const resolved = { scripts: [], assets: [], diagnostics: [] };
|
|
9252
9462
|
const seen = /* @__PURE__ */ new Set();
|
|
9253
|
-
for (const entry of
|
|
9463
|
+
for (const entry of entries2) {
|
|
9254
9464
|
const path = normalizePath(entry).replace(/^\.\//, "");
|
|
9255
9465
|
const script = byScript.get(path);
|
|
9256
9466
|
const asset = byAsset.get(path);
|
|
@@ -9482,8 +9692,8 @@ function materialize(build, resource, includeMap) {
|
|
|
9482
9692
|
const bundled = materializeBundles(resource, build.bundles, helperContent);
|
|
9483
9693
|
return { ...build, scripts: bundled.scripts, map: includeMap ? bundled.map : null };
|
|
9484
9694
|
}
|
|
9485
|
-
function diagnosticSources(files,
|
|
9486
|
-
const paths = new Set(
|
|
9695
|
+
function diagnosticSources(files, entries2) {
|
|
9696
|
+
const paths = new Set(entries2.map((entry) => entry.path));
|
|
9487
9697
|
return new Map(files.filter((file) => paths.has(file.path)).map((file) => [file.path, file.source]));
|
|
9488
9698
|
}
|
|
9489
9699
|
function runCompile(root, config, options = {}) {
|
|
@@ -9644,13 +9854,13 @@ function isSearchable(name) {
|
|
|
9644
9854
|
return !name.startsWith(".") && !SKIPPED_DIRECTORIES.has(name);
|
|
9645
9855
|
}
|
|
9646
9856
|
function collectResourceMaps(directory, found) {
|
|
9647
|
-
let
|
|
9857
|
+
let entries2;
|
|
9648
9858
|
try {
|
|
9649
|
-
|
|
9859
|
+
entries2 = readdirSync3(directory, { withFileTypes: true });
|
|
9650
9860
|
} catch {
|
|
9651
9861
|
return;
|
|
9652
9862
|
}
|
|
9653
|
-
for (const entry of
|
|
9863
|
+
for (const entry of entries2) {
|
|
9654
9864
|
const absolute = join3(directory, entry.name);
|
|
9655
9865
|
if (entry.isDirectory()) {
|
|
9656
9866
|
if (isSearchable(entry.name)) {
|
|
@@ -9995,9 +10205,9 @@ function pluralize(count, singular, plural = `${singular}s`) {
|
|
|
9995
10205
|
var MAX_ENTRIES_PER_FILE = 10;
|
|
9996
10206
|
var MAX_FILES = 10;
|
|
9997
10207
|
var GUTTER_WIDTH = 6;
|
|
9998
|
-
function groupByFile(
|
|
10208
|
+
function groupByFile(entries2) {
|
|
9999
10209
|
const groups = /* @__PURE__ */ new Map();
|
|
10000
|
-
for (const entry of
|
|
10210
|
+
for (const entry of entries2) {
|
|
10001
10211
|
const group = groups.get(entry.path);
|
|
10002
10212
|
if (group === void 0) {
|
|
10003
10213
|
groups.set(entry.path, [entry]);
|
|
@@ -10044,19 +10254,19 @@ function emit2(reporter, entry, block) {
|
|
|
10044
10254
|
}
|
|
10045
10255
|
reporter.rawWarn(block);
|
|
10046
10256
|
}
|
|
10047
|
-
function reportGroup(reporter, path,
|
|
10257
|
+
function reportGroup(reporter, path, entries2, options) {
|
|
10048
10258
|
const limit = options.maxPerFile ?? MAX_ENTRIES_PER_FILE;
|
|
10049
10259
|
const source = options.sources.get(path);
|
|
10050
10260
|
reporter.raw(reporter.style.paint("strong", path));
|
|
10051
|
-
for (const entry of
|
|
10261
|
+
for (const entry of entries2.slice(0, limit)) {
|
|
10052
10262
|
emit2(reporter, entry, entryBlock(reporter, entry, source));
|
|
10053
10263
|
}
|
|
10054
|
-
if (
|
|
10055
|
-
reporter.detail(` ... and ${pluralize(
|
|
10264
|
+
if (entries2.length > limit) {
|
|
10265
|
+
reporter.detail(` ... and ${pluralize(entries2.length - limit, "more diagnostic")} in this file.`);
|
|
10056
10266
|
}
|
|
10057
10267
|
}
|
|
10058
|
-
function reportGroupedDiagnostics(reporter,
|
|
10059
|
-
const groups = [...groupByFile(
|
|
10268
|
+
function reportGroupedDiagnostics(reporter, entries2, options) {
|
|
10269
|
+
const groups = [...groupByFile(entries2)];
|
|
10060
10270
|
const limit = options.maxFiles ?? MAX_FILES;
|
|
10061
10271
|
for (const [path, group] of groups.slice(0, limit)) {
|
|
10062
10272
|
reportGroup(reporter, path, group, options);
|
|
@@ -10072,9 +10282,9 @@ function formatFileDiagnostic(entry) {
|
|
|
10072
10282
|
const location = `${path}:${diagnostic.position.line}:${diagnostic.position.column}`;
|
|
10073
10283
|
return `${location} ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}`;
|
|
10074
10284
|
}
|
|
10075
|
-
function countFileDiagnostics(
|
|
10076
|
-
const errors =
|
|
10077
|
-
return { errors, warnings:
|
|
10285
|
+
function countFileDiagnostics(entries2) {
|
|
10286
|
+
const errors = entries2.filter((entry) => entry.diagnostic.severity === "error").length;
|
|
10287
|
+
return { errors, warnings: entries2.length - errors };
|
|
10078
10288
|
}
|
|
10079
10289
|
function countCliDiagnostics(diagnostics) {
|
|
10080
10290
|
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
|
|
@@ -10090,8 +10300,8 @@ function reportCliDiagnostics(reporter, diagnostics) {
|
|
|
10090
10300
|
reporter.warn(line2);
|
|
10091
10301
|
}
|
|
10092
10302
|
}
|
|
10093
|
-
function reportPlainFileDiagnostics(reporter,
|
|
10094
|
-
for (const entry of
|
|
10303
|
+
function reportPlainFileDiagnostics(reporter, entries2) {
|
|
10304
|
+
for (const entry of entries2) {
|
|
10095
10305
|
const line2 = formatFileDiagnostic(entry);
|
|
10096
10306
|
if (entry.diagnostic.severity === "error") {
|
|
10097
10307
|
reporter.rawError(line2);
|
|
@@ -10100,12 +10310,12 @@ function reportPlainFileDiagnostics(reporter, entries) {
|
|
|
10100
10310
|
reporter.rawWarn(line2);
|
|
10101
10311
|
}
|
|
10102
10312
|
}
|
|
10103
|
-
function reportFileDiagnostics(reporter,
|
|
10313
|
+
function reportFileDiagnostics(reporter, entries2, sources) {
|
|
10104
10314
|
if (!reporter.capability.interactive) {
|
|
10105
|
-
reportPlainFileDiagnostics(reporter,
|
|
10315
|
+
reportPlainFileDiagnostics(reporter, entries2);
|
|
10106
10316
|
return;
|
|
10107
10317
|
}
|
|
10108
|
-
reportGroupedDiagnostics(reporter,
|
|
10318
|
+
reportGroupedDiagnostics(reporter, entries2, { sources });
|
|
10109
10319
|
}
|
|
10110
10320
|
function formatCounts(counts) {
|
|
10111
10321
|
return `${pluralize(counts.errors, "error")}, ${pluralize(counts.warnings, "warning")}`;
|
|
@@ -11002,11 +11212,11 @@ function readStringArray(source, field, diagnostics, scope = "") {
|
|
|
11002
11212
|
if (!Array.isArray(value) || value.length === 0) {
|
|
11003
11213
|
return report2(diagnostics, `${scope}${field}`, "a non-empty array of strings", value);
|
|
11004
11214
|
}
|
|
11005
|
-
const
|
|
11006
|
-
if (
|
|
11215
|
+
const entries2 = value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
11216
|
+
if (entries2.length !== value.length) {
|
|
11007
11217
|
return report2(diagnostics, `${scope}${field}`, "a non-empty array of strings", value);
|
|
11008
11218
|
}
|
|
11009
|
-
return
|
|
11219
|
+
return entries2.map((entry) => entry.trim());
|
|
11010
11220
|
}
|
|
11011
11221
|
function readObject(source, field, diagnostics, scope = "") {
|
|
11012
11222
|
const value = source[field];
|
|
@@ -11376,10 +11586,70 @@ function runTraceCommand(root, reporter, options) {
|
|
|
11376
11586
|
}
|
|
11377
11587
|
|
|
11378
11588
|
// src/editor/editor-service.ts
|
|
11379
|
-
import { spawnSync } from "node:child_process";
|
|
11380
11589
|
import { mkdtempSync, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
11381
11590
|
import { tmpdir } from "node:os";
|
|
11382
|
-
import { join as
|
|
11591
|
+
import { join as join6 } from "node:path";
|
|
11592
|
+
|
|
11593
|
+
// src/editor/editor-command.ts
|
|
11594
|
+
import { spawnSync } from "node:child_process";
|
|
11595
|
+
import { statSync as statSync4 } from "node:fs";
|
|
11596
|
+
import { extname, isAbsolute as isAbsolute7, join as join5 } from "node:path";
|
|
11597
|
+
var WINDOWS_SEPARATOR = ";";
|
|
11598
|
+
var DEFAULT_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
11599
|
+
var SHELL_EXTENSIONS = /* @__PURE__ */ new Set([".bat", ".cmd"]);
|
|
11600
|
+
var SPAWN_OPTIONS = { encoding: "utf8", shell: false, windowsHide: true, maxBuffer: 1024 * 1024 };
|
|
11601
|
+
function entries(value) {
|
|
11602
|
+
return value.split(WINDOWS_SEPARATOR).map((entry) => entry.trim().replace(/^"|"$/gu, "")).filter((entry) => entry.length > 0);
|
|
11603
|
+
}
|
|
11604
|
+
function present(path) {
|
|
11605
|
+
try {
|
|
11606
|
+
return statSync4(path).isFile();
|
|
11607
|
+
} catch {
|
|
11608
|
+
return false;
|
|
11609
|
+
}
|
|
11610
|
+
}
|
|
11611
|
+
function failure(error) {
|
|
11612
|
+
return { pid: 0, output: [null, "", ""], stdout: "", stderr: "", status: null, signal: null, error };
|
|
11613
|
+
}
|
|
11614
|
+
function resolveWindowsCommand(command) {
|
|
11615
|
+
const extensions = entries(process.env.PATHEXT ?? DEFAULT_EXTENSIONS);
|
|
11616
|
+
const named2 = extname(command).toLowerCase();
|
|
11617
|
+
const suffixes = named2 !== "" && extensions.some((entry) => entry.toLowerCase() === named2) ? [""] : extensions;
|
|
11618
|
+
const rooted = isAbsolute7(command) || command.includes("/") || command.includes("\\");
|
|
11619
|
+
const directories = rooted ? [""] : entries(process.env.PATH ?? process.env.Path ?? "");
|
|
11620
|
+
for (const directory of directories) {
|
|
11621
|
+
for (const suffix of suffixes) {
|
|
11622
|
+
const path = directory === "" ? `${command}${suffix}` : join5(directory, `${command}${suffix}`);
|
|
11623
|
+
if (present(path)) {
|
|
11624
|
+
return path;
|
|
11625
|
+
}
|
|
11626
|
+
}
|
|
11627
|
+
}
|
|
11628
|
+
return null;
|
|
11629
|
+
}
|
|
11630
|
+
function buildInvocation(executable, args) {
|
|
11631
|
+
if (!SHELL_EXTENSIONS.has(extname(executable).toLowerCase())) {
|
|
11632
|
+
return { file: executable, args: [...args], verbatim: false };
|
|
11633
|
+
}
|
|
11634
|
+
const line2 = [executable, ...args].map((token) => `"${token}"`).join(" ");
|
|
11635
|
+
return { file: process.env.COMSPEC ?? "cmd.exe", args: ["/d", "/s", "/c", `"${line2}"`], verbatim: true };
|
|
11636
|
+
}
|
|
11637
|
+
function runEditorCommand(command, args) {
|
|
11638
|
+
if (process.platform !== "win32") {
|
|
11639
|
+
return spawnSync(command, [...args], SPAWN_OPTIONS);
|
|
11640
|
+
}
|
|
11641
|
+
const executable = resolveWindowsCommand(command);
|
|
11642
|
+
if (executable === null) {
|
|
11643
|
+
return failure(new Error(`The command ${command} was not found on PATH.`));
|
|
11644
|
+
}
|
|
11645
|
+
if ([executable, ...args].some((token) => token.includes('"'))) {
|
|
11646
|
+
return failure(new Error(`The command ${command} received an argument that cannot be quoted safely.`));
|
|
11647
|
+
}
|
|
11648
|
+
const invocation = buildInvocation(executable, args);
|
|
11649
|
+
return spawnSync(invocation.file, invocation.args, { ...SPAWN_OPTIONS, windowsVerbatimArguments: invocation.verbatim });
|
|
11650
|
+
}
|
|
11651
|
+
|
|
11652
|
+
// src/editor/editor-service.ts
|
|
11383
11653
|
var EXTENSION_ID = "thigasdevelopment.luam";
|
|
11384
11654
|
var SUPPORTED_EDITORS = [
|
|
11385
11655
|
{ id: "vscode", name: "Visual Studio Code", command: "code" },
|
|
@@ -11390,11 +11660,8 @@ var SUPPORTED_EDITORS = [
|
|
|
11390
11660
|
];
|
|
11391
11661
|
var MAX_VSIX_BYTES = 50 * 1024 * 1024;
|
|
11392
11662
|
var RELEASE_URL = `https://github.com/ThigasDevelopment/luam/releases/download/v${VERSION}/luam-${VERSION}.vsix`;
|
|
11393
|
-
function run(command, args) {
|
|
11394
|
-
return spawnSync(command, [...args], { encoding: "utf8", shell: false, windowsHide: true, maxBuffer: 1024 * 1024 });
|
|
11395
|
-
}
|
|
11396
11663
|
function succeeded(result) {
|
|
11397
|
-
return result.error === void 0 && result.status === 0;
|
|
11664
|
+
return (result.error === void 0 || result.error === null) && result.status === 0;
|
|
11398
11665
|
}
|
|
11399
11666
|
function trustedReleaseHost(url) {
|
|
11400
11667
|
const host = new URL(url).hostname.toLowerCase();
|
|
@@ -11419,11 +11686,11 @@ async function downloadRelease() {
|
|
|
11419
11686
|
return bytes;
|
|
11420
11687
|
}
|
|
11421
11688
|
function installVsix(editor, bytes) {
|
|
11422
|
-
const directory = mkdtempSync(
|
|
11423
|
-
const path =
|
|
11689
|
+
const directory = mkdtempSync(join6(tmpdir(), "luam-"));
|
|
11690
|
+
const path = join6(directory, `luam-${VERSION}.vsix`);
|
|
11424
11691
|
try {
|
|
11425
11692
|
writeFileSync5(path, bytes, { flag: "wx" });
|
|
11426
|
-
const result =
|
|
11693
|
+
const result = runEditorCommand(editor.command, ["--install-extension", path, "--force"]);
|
|
11427
11694
|
return succeeded(result) ? { source: "release", error: null } : { source: null, error: "The editor rejected the release VSIX." };
|
|
11428
11695
|
} finally {
|
|
11429
11696
|
rmSync(directory, { recursive: true, force: true });
|
|
@@ -11432,13 +11699,13 @@ function installVsix(editor, bytes) {
|
|
|
11432
11699
|
function createEditorService() {
|
|
11433
11700
|
let release = null;
|
|
11434
11701
|
return {
|
|
11435
|
-
detect: () => SUPPORTED_EDITORS.filter((editor) => succeeded(
|
|
11702
|
+
detect: () => SUPPORTED_EDITORS.filter((editor) => succeeded(runEditorCommand(editor.command, ["--version"]))),
|
|
11436
11703
|
hasExtension: (editor) => {
|
|
11437
|
-
const result =
|
|
11704
|
+
const result = runEditorCommand(editor.command, ["--list-extensions"]);
|
|
11438
11705
|
return succeeded(result) && result.stdout.split(/\r?\n/u).some((entry) => entry.trim().toLowerCase() === EXTENSION_ID);
|
|
11439
11706
|
},
|
|
11440
11707
|
install: async (editor) => {
|
|
11441
|
-
const marketplace =
|
|
11708
|
+
const marketplace = runEditorCommand(editor.command, ["--install-extension", EXTENSION_ID, "--force"]);
|
|
11442
11709
|
if (succeeded(marketplace)) {
|
|
11443
11710
|
return { source: "marketplace", error: null };
|
|
11444
11711
|
}
|