@tilua/parser 3.0.0 → 3.1.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/dist/index.cjs +423 -83
- package/dist/index.d.cts +73 -3
- package/dist/index.d.ts +73 -3
- package/dist/index.js +412 -82
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
CONFIG_FILE_NAMES: () => CONFIG_FILE_NAMES,
|
|
25
25
|
Keywords: () => Keywords,
|
|
26
26
|
LANGUAGE_GLOBALS: () => LANGUAGE_GLOBALS,
|
|
27
|
+
LUAU_KEYWORDS: () => LUAU_KEYWORDS,
|
|
27
28
|
LexError: () => LexError,
|
|
28
29
|
Operators: () => Operators,
|
|
29
30
|
PRELUDE_SOURCE: () => PRELUDE_SOURCE,
|
|
@@ -45,20 +46,27 @@ __export(index_exports, {
|
|
|
45
46
|
difference: () => difference,
|
|
46
47
|
directivesOf: () => directivesOf,
|
|
47
48
|
equalTypes: () => equalTypes,
|
|
49
|
+
escapeLuauString: () => escapeLuauString,
|
|
48
50
|
falsyType: () => falsyType,
|
|
49
51
|
findConfig: () => findConfig,
|
|
50
52
|
fn: () => fn,
|
|
51
53
|
formatType: () => formatType,
|
|
52
54
|
getBinding: () => getBinding,
|
|
55
|
+
hasMembers: () => hasMembers,
|
|
53
56
|
intersection: () => intersection,
|
|
54
57
|
isAssignable: () => isAssignable,
|
|
55
58
|
isClassType: () => isClassType,
|
|
59
|
+
isFunctionType: () => isFunctionType,
|
|
56
60
|
isGlobal: () => isGlobal,
|
|
61
|
+
isIdentifier: () => isIdentifier,
|
|
62
|
+
isInstanceOf: () => isInstanceOf,
|
|
63
|
+
isLuauName: () => isLuauName,
|
|
57
64
|
isPossiblyFalsy: () => isPossiblyFalsy,
|
|
58
65
|
isPossiblyTruthy: () => isPossiblyTruthy,
|
|
59
66
|
isUnassignedGlobal: () => isUnassignedGlobal,
|
|
60
67
|
literal: () => literal,
|
|
61
68
|
loadConfig: () => loadConfig,
|
|
69
|
+
luauString: () => luauString,
|
|
62
70
|
matchInfer: () => matchInfer,
|
|
63
71
|
moduleCandidates: () => moduleCandidates,
|
|
64
72
|
moduleExports: () => moduleExports,
|
|
@@ -81,6 +89,7 @@ __export(index_exports, {
|
|
|
81
89
|
readDirectives: () => readDirectives,
|
|
82
90
|
resolveModulePath: () => resolveModulePath,
|
|
83
91
|
resolveTypeLibraries: () => resolveTypeLibraries,
|
|
92
|
+
returnsTuple: () => returnsTuple,
|
|
84
93
|
setAliasExpander: () => setAliasExpander,
|
|
85
94
|
setDeferredBound: () => setDeferredBound,
|
|
86
95
|
sourceMapTypes: () => sourceMapTypes,
|
|
@@ -99,7 +108,8 @@ __export(index_exports, {
|
|
|
99
108
|
unknownType: () => unknownType,
|
|
100
109
|
widen: () => widen,
|
|
101
110
|
withAliasName: () => withAliasName,
|
|
102
|
-
withoutAliasName: () => withoutAliasName
|
|
111
|
+
withoutAliasName: () => withoutAliasName,
|
|
112
|
+
withoutNil: () => withoutNil2
|
|
103
113
|
});
|
|
104
114
|
module.exports = __toCommonJS(index_exports);
|
|
105
115
|
|
|
@@ -708,7 +718,7 @@ function bindThis(func, at) {
|
|
|
708
718
|
func.isMethod = true;
|
|
709
719
|
}
|
|
710
720
|
function bindThisParam(params, at) {
|
|
711
|
-
params.unshift({ type: "FunctionParameter", name: "this", ...spanFrom(at, at) });
|
|
721
|
+
params.unshift({ type: "FunctionParameter", name: "this", implicit: true, ...spanFrom(at, at) });
|
|
712
722
|
}
|
|
713
723
|
var ParseError = class extends Error {
|
|
714
724
|
constructor(message, line, column) {
|
|
@@ -1765,7 +1775,7 @@ var Parser = class {
|
|
|
1765
1775
|
};
|
|
1766
1776
|
}
|
|
1767
1777
|
if (isMethod) {
|
|
1768
|
-
func.params.unshift({ type: "FunctionParameter", name: "self", ...spanFrom(target, target) });
|
|
1778
|
+
func.params.unshift({ type: "FunctionParameter", name: "self", implicit: true, ...spanFrom(target, target) });
|
|
1769
1779
|
func.isMethod = true;
|
|
1770
1780
|
}
|
|
1771
1781
|
return {
|
|
@@ -1959,47 +1969,7 @@ var Parser = class {
|
|
|
1959
1969
|
const isStatic = modifiers.has("static");
|
|
1960
1970
|
if (this.checkKeyword("function")) {
|
|
1961
1971
|
this.advance();
|
|
1962
|
-
|
|
1963
|
-
if (modifiers.has("abstract")) {
|
|
1964
|
-
const head = this.parseFunctionHead();
|
|
1965
|
-
const func = {
|
|
1966
|
-
type: "FunctionBody",
|
|
1967
|
-
generics: head.generics,
|
|
1968
|
-
params: head.params,
|
|
1969
|
-
hasVarargs: head.hasVarargs,
|
|
1970
|
-
returnType: head.returnType,
|
|
1971
|
-
predicate: head.predicate,
|
|
1972
|
-
body: { type: "Block", statements: [], ...spanFrom(head.start, this.previous()) },
|
|
1973
|
-
...spanFrom(head.start, this.previous())
|
|
1974
|
-
};
|
|
1975
|
-
if (!isStatic) bindThis(func, start);
|
|
1976
|
-
if (!head.returnType) this.problem("An abstract method has no body to infer from: write its return type");
|
|
1977
|
-
if (this.checkPunctuator("{")) this.problem("An abstract method has no body");
|
|
1978
|
-
return { type: "ClassMethod", name: memberName, isStatic, func, isAbstract: true, ...spanFrom(start, this.previous()) };
|
|
1979
|
-
}
|
|
1980
|
-
const signatures = [];
|
|
1981
|
-
let written = memberName;
|
|
1982
|
-
while (true) {
|
|
1983
|
-
const head = this.parseFunctionHead();
|
|
1984
|
-
if (this.isClassOverloadContinuation(memberName.name, isStatic)) {
|
|
1985
|
-
if (!isStatic) bindThisParam(head.params, start);
|
|
1986
|
-
signatures.push({ ...this.headToSignature(head), name: written });
|
|
1987
|
-
if (isStatic) this.advance();
|
|
1988
|
-
this.expectKeyword("function");
|
|
1989
|
-
written = this.parseIdentifier();
|
|
1990
|
-
continue;
|
|
1991
|
-
}
|
|
1992
|
-
const func = this.headToBody(head, start);
|
|
1993
|
-
if (!isStatic) bindThis(func, start);
|
|
1994
|
-
return {
|
|
1995
|
-
type: "ClassMethod",
|
|
1996
|
-
name: memberName,
|
|
1997
|
-
isStatic,
|
|
1998
|
-
func,
|
|
1999
|
-
signatures: signatures.length ? signatures : void 0,
|
|
2000
|
-
...spanFrom(start, this.previous())
|
|
2001
|
-
};
|
|
2002
|
-
}
|
|
1972
|
+
return this.parseClassMethod(start, modifiers);
|
|
2003
1973
|
}
|
|
2004
1974
|
if (!isStatic && this.checkIdentifierValue("constructor") && this.punctuatorAt(1, "(")) {
|
|
2005
1975
|
this.advance();
|
|
@@ -2009,6 +1979,9 @@ var Parser = class {
|
|
|
2009
1979
|
bindThis(func, start);
|
|
2010
1980
|
return { type: "ClassConstructor", func, ...spanFrom(start, this.previous()) };
|
|
2011
1981
|
}
|
|
1982
|
+
if (this.startsMethodShorthand(0)) {
|
|
1983
|
+
return this.parseClassMethod(start, modifiers);
|
|
1984
|
+
}
|
|
2012
1985
|
if ((this.checkIdentifierValue("get") || this.checkIdentifierValue("set")) && this.peek(1).type === "Identifier" && this.punctuatorAt(2, "(")) {
|
|
2013
1986
|
const kind = this.advance().value;
|
|
2014
1987
|
const memberName = this.parseIdentifier();
|
|
@@ -2038,25 +2011,90 @@ var Parser = class {
|
|
|
2038
2011
|
return { type: "ClassField", name: memberName, isStatic, typeAnnotation, init, ...spanFrom(start, this.previous()) };
|
|
2039
2012
|
}
|
|
2040
2013
|
if (this.recover) {
|
|
2041
|
-
this.softError("Expected a class member: a field,
|
|
2014
|
+
this.softError("Expected a class member: a field, a method, 'constructor', 'get' or 'set'");
|
|
2042
2015
|
this.advance();
|
|
2043
2016
|
return void 0;
|
|
2044
2017
|
}
|
|
2045
|
-
this.error("Expected a class member: a field,
|
|
2018
|
+
this.error("Expected a class member: a field, a method, 'constructor', 'get' or 'set'");
|
|
2019
|
+
}
|
|
2020
|
+
/** A name at `offset` opening a method without `function`: `name(` or
|
|
2021
|
+
* `name<T>(`. A field's name is followed by `:` or `=` instead. */
|
|
2022
|
+
startsMethodShorthand(offset) {
|
|
2023
|
+
if (this.peek(offset).type !== "Identifier") return false;
|
|
2024
|
+
const next = this.peek(offset + 1);
|
|
2025
|
+
return (next.type === "Punctuator" || next.type === "Operator") && (next.value === "(" || next.value === "<");
|
|
2026
|
+
}
|
|
2027
|
+
/** A method, from its name on: `function` (if written) and the modifiers
|
|
2028
|
+
* are behind. */
|
|
2029
|
+
parseClassMethod(start, modifiers) {
|
|
2030
|
+
const isStatic = modifiers.has("static");
|
|
2031
|
+
const memberName = this.parseIdentifier();
|
|
2032
|
+
if (modifiers.has("abstract")) {
|
|
2033
|
+
const head = this.parseFunctionHead();
|
|
2034
|
+
const func = {
|
|
2035
|
+
type: "FunctionBody",
|
|
2036
|
+
generics: head.generics,
|
|
2037
|
+
params: head.params,
|
|
2038
|
+
hasVarargs: head.hasVarargs,
|
|
2039
|
+
returnType: head.returnType,
|
|
2040
|
+
predicate: head.predicate,
|
|
2041
|
+
body: { type: "Block", statements: [], ...spanFrom(head.start, this.previous()) },
|
|
2042
|
+
...spanFrom(head.start, this.previous())
|
|
2043
|
+
};
|
|
2044
|
+
if (!isStatic) bindThis(func, start);
|
|
2045
|
+
if (!head.returnType) this.problem("An abstract method has no body to infer from: write its return type");
|
|
2046
|
+
if (this.checkPunctuator("{")) this.problem("An abstract method has no body");
|
|
2047
|
+
return { type: "ClassMethod", name: memberName, isStatic, func, isAbstract: true, ...spanFrom(start, this.previous()) };
|
|
2048
|
+
}
|
|
2049
|
+
const signatures = [];
|
|
2050
|
+
let written = memberName;
|
|
2051
|
+
while (true) {
|
|
2052
|
+
const head = this.parseFunctionHead();
|
|
2053
|
+
const skip = this.classOverloadContinuation(memberName.name, isStatic);
|
|
2054
|
+
if (skip !== void 0) {
|
|
2055
|
+
if (!isStatic) bindThisParam(head.params, start);
|
|
2056
|
+
signatures.push({ ...this.headToSignature(head), name: written });
|
|
2057
|
+
for (let i = 0; i < skip; i++) this.advance();
|
|
2058
|
+
written = this.parseIdentifier();
|
|
2059
|
+
continue;
|
|
2060
|
+
}
|
|
2061
|
+
const func = this.headToBody(head, start);
|
|
2062
|
+
if (!isStatic) bindThis(func, start);
|
|
2063
|
+
return {
|
|
2064
|
+
type: "ClassMethod",
|
|
2065
|
+
name: memberName,
|
|
2066
|
+
isStatic,
|
|
2067
|
+
func,
|
|
2068
|
+
signatures: signatures.length ? signatures : void 0,
|
|
2069
|
+
...spanFrom(start, this.previous())
|
|
2070
|
+
};
|
|
2071
|
+
}
|
|
2046
2072
|
}
|
|
2047
|
-
/** Give a class method its `this`: a real first parameter, the way
|
|
2048
|
-
* `function T:m()` gets a real `self`. Every later pass — scopes, types,
|
|
2049
|
-
* arity, lowering — then sees an ordinary parameter and needs to know
|
|
2050
|
-
* nothing about classes. */
|
|
2051
2073
|
/** After a bodyless head inside a class body, does another declaration of
|
|
2052
|
-
* the same member follow? Then the head was an overload signature
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2074
|
+
* the same member follow? Then the head was an overload signature, and
|
|
2075
|
+
* this is how many tokens stand before the next one's name: a `;` that
|
|
2076
|
+
* ends the head, as TypeScript writes it, the modifiers, and `function`
|
|
2077
|
+
* when it is written. `undefined` when no overload follows. Each head may
|
|
2078
|
+
* be written either way, with `function` or without. */
|
|
2079
|
+
classOverloadContinuation(name, isStatic) {
|
|
2080
|
+
let offset = 0;
|
|
2081
|
+
if (this.punctuatorAt(0, ";")) offset++;
|
|
2082
|
+
let sawStatic = false;
|
|
2083
|
+
while (true) {
|
|
2084
|
+
const t = this.peek(offset);
|
|
2085
|
+
const word = t.type === "Identifier" ? t.value : void 0;
|
|
2086
|
+
if (word === void 0 || !CLASS_MODIFIERS.has(word) || this.startsMethodShorthand(offset)) break;
|
|
2087
|
+
if (word === "static") sawStatic = true;
|
|
2088
|
+
offset++;
|
|
2089
|
+
}
|
|
2090
|
+
if (sawStatic !== isStatic) return void 0;
|
|
2056
2091
|
const keyword = this.peek(offset);
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2092
|
+
const hasKeyword = keyword.type === "Keyword" && keyword.value === "function";
|
|
2093
|
+
if (hasKeyword) offset++;
|
|
2094
|
+
const named = this.peek(offset);
|
|
2095
|
+
if (!(named.type === "Identifier" && named.value === name)) return void 0;
|
|
2096
|
+
if (!hasKeyword && !this.startsMethodShorthand(offset)) return void 0;
|
|
2097
|
+
return offset;
|
|
2060
2098
|
}
|
|
2061
2099
|
operatorAt(ahead, value) {
|
|
2062
2100
|
const token = this.peek(ahead);
|
|
@@ -3893,6 +3931,10 @@ var Analyzer = class {
|
|
|
3893
3931
|
moduleScope = this.globalScope;
|
|
3894
3932
|
/** How many function bodies enclose the walk. */
|
|
3895
3933
|
functionDepth = 0;
|
|
3934
|
+
/** How many loops enclose the walk inside the nearest function body. A
|
|
3935
|
+
* function starts again at 0: `continue` in `xs:map(x => ...)` has no
|
|
3936
|
+
* loop to go on with, whatever loop the call is written in. */
|
|
3937
|
+
loopDepth = 0;
|
|
3896
3938
|
/** Function declarations already declared by their block's hoisting, with
|
|
3897
3939
|
* the function depth of that block. */
|
|
3898
3940
|
hoisted = /* @__PURE__ */ new Map();
|
|
@@ -4245,11 +4287,11 @@ var Analyzer = class {
|
|
|
4245
4287
|
return;
|
|
4246
4288
|
case "WhileStatement":
|
|
4247
4289
|
this.visitExpression(stmt.condition, scope);
|
|
4248
|
-
this.visitBlockInNewScope(stmt.body, scope);
|
|
4290
|
+
this.inLoop(() => this.visitBlockInNewScope(stmt.body, scope));
|
|
4249
4291
|
return;
|
|
4250
4292
|
case "RepeatStatement": {
|
|
4251
4293
|
const bodyScope = childScope(scope);
|
|
4252
|
-
this.visitBlock(stmt.body, bodyScope);
|
|
4294
|
+
this.inLoop(() => this.visitBlock(stmt.body, bodyScope));
|
|
4253
4295
|
this.visitExpression(stmt.condition, bodyScope);
|
|
4254
4296
|
return;
|
|
4255
4297
|
}
|
|
@@ -4267,14 +4309,14 @@ var Analyzer = class {
|
|
|
4267
4309
|
if (stmt.step) this.visitExpression(stmt.step, scope);
|
|
4268
4310
|
const bodyScope = childScope(scope);
|
|
4269
4311
|
this.declare(bodyScope, stmt.variable.name, "for-numeric", stmt.variable);
|
|
4270
|
-
this.visitBlock(stmt.body, bodyScope);
|
|
4312
|
+
this.inLoop(() => this.visitBlock(stmt.body, bodyScope));
|
|
4271
4313
|
return;
|
|
4272
4314
|
}
|
|
4273
4315
|
case "GenericForStatement": {
|
|
4274
4316
|
this.visitExpression(stmt.iterator, scope);
|
|
4275
4317
|
const bodyScope = childScope(scope);
|
|
4276
4318
|
this.declarePattern(bodyScope, stmt.variable, "for-generic", scope, stmt.kind === "const");
|
|
4277
|
-
this.visitBlock(stmt.body, bodyScope);
|
|
4319
|
+
this.inLoop(() => this.visitBlock(stmt.body, bodyScope));
|
|
4278
4320
|
return;
|
|
4279
4321
|
}
|
|
4280
4322
|
case "ReturnStatement":
|
|
@@ -4282,6 +4324,15 @@ var Analyzer = class {
|
|
|
4282
4324
|
return;
|
|
4283
4325
|
case "BreakStatement":
|
|
4284
4326
|
case "ContinueStatement":
|
|
4327
|
+
if (this.loopDepth === 0) {
|
|
4328
|
+
const word = stmt.type === "BreakStatement" ? "break" : "continue";
|
|
4329
|
+
this.diagnostics.push({
|
|
4330
|
+
node: stmt,
|
|
4331
|
+
message: this.functionDepth > 0 ? `'${word}' is not inside a loop of this function; to skip a value in a callback, 'return' from it` : `'${word}' is not inside a loop`,
|
|
4332
|
+
kind: "outside-loop"
|
|
4333
|
+
});
|
|
4334
|
+
}
|
|
4335
|
+
return;
|
|
4285
4336
|
case "ErrorStatement":
|
|
4286
4337
|
return;
|
|
4287
4338
|
case "DeclareStatement":
|
|
@@ -4337,6 +4388,15 @@ var Analyzer = class {
|
|
|
4337
4388
|
return;
|
|
4338
4389
|
}
|
|
4339
4390
|
}
|
|
4391
|
+
/** Visit a loop's body, where `break` and `continue` have a loop. */
|
|
4392
|
+
inLoop(visit) {
|
|
4393
|
+
this.loopDepth++;
|
|
4394
|
+
try {
|
|
4395
|
+
visit();
|
|
4396
|
+
} finally {
|
|
4397
|
+
this.loopDepth--;
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4340
4400
|
// ---------------- functions ----------------
|
|
4341
4401
|
visitFunctionBody(func, outerScope, isMethod = false) {
|
|
4342
4402
|
const fnScope = childScope(outerScope);
|
|
@@ -4352,11 +4412,14 @@ var Analyzer = class {
|
|
|
4352
4412
|
}
|
|
4353
4413
|
});
|
|
4354
4414
|
this.visitType(func.returnType, fnScope);
|
|
4415
|
+
const loops = this.loopDepth;
|
|
4355
4416
|
this.functionDepth++;
|
|
4417
|
+
this.loopDepth = 0;
|
|
4356
4418
|
try {
|
|
4357
4419
|
this.visitBlock(func.body, fnScope);
|
|
4358
4420
|
} finally {
|
|
4359
4421
|
this.functionDepth--;
|
|
4422
|
+
this.loopDepth = loops;
|
|
4360
4423
|
}
|
|
4361
4424
|
}
|
|
4362
4425
|
/** An overload signature: no body and no bindings, but its types can hold
|
|
@@ -4610,11 +4673,14 @@ declare metatable string: {
|
|
|
4610
4673
|
-- answer \`nil\` rather than JavaScript's -1. \`sort\` takes Lua's comparator
|
|
4611
4674
|
-- (true when \`a\` comes first). \`push\`, \`pop\`, \`shift\`, \`unshift\`,
|
|
4612
4675
|
-- \`sort\` and \`reverse\` change the array; everything else returns a new one.
|
|
4676
|
+
-- A \`filter\` whose test is a guard \u2014 \`v is S\`, or \`v => v ~= nil\` \u2014
|
|
4677
|
+
-- answers an array of what it let through.
|
|
4613
4678
|
declare metatable<T> T[]: {
|
|
4614
4679
|
__index: {
|
|
4615
4680
|
find: (self: T[], test: (value: T, index: number) => boolean) => T | nil,
|
|
4616
4681
|
findIndex: (self: T[], test: (value: T, index: number) => boolean) => number | nil,
|
|
4617
|
-
filter: (self: T[], test: (value: T, index: number) =>
|
|
4682
|
+
filter: (<S extends T>(self: T[], test: (value: T, index: number) => value is S) => S[])
|
|
4683
|
+
& ((self: T[], test: (value: T, index: number) => boolean) => T[]),
|
|
4618
4684
|
map: <U>(self: T[], transform: (value: T, index: number) => U) => U[],
|
|
4619
4685
|
forEach: (self: T[], visit: (value: T, index: number) => nil) => nil,
|
|
4620
4686
|
some: (self: T[], test: (value: T, index: number) => boolean) => boolean,
|
|
@@ -4648,11 +4714,34 @@ declare metatable<T> T[]: {
|
|
|
4648
4714
|
-- \`nil\` when it is missing; an indexer's keys follow the named ones. A
|
|
4649
4715
|
-- member of the table's own with one of these names is what a call reaches,
|
|
4650
4716
|
-- and a class instance, which has a metatable of its own, has none of them.
|
|
4717
|
+
--
|
|
4718
|
+
-- The rest are JavaScript's \`Object\` functions, written as methods of the
|
|
4719
|
+
-- table they take first:
|
|
4720
|
+
--
|
|
4721
|
+
-- point:hasOwn("x") -- Object.hasOwn(point, "x")
|
|
4722
|
+
-- point:assign({ z: 3 }) -- Object.assign(point, { z: 3 })
|
|
4723
|
+
-- point:freeze() -- Object.freeze(point)
|
|
4724
|
+
--
|
|
4725
|
+
-- \`hasOwn\` asks the table itself, not what its metatable's \`__index\`
|
|
4726
|
+
-- lends it. \`assign\` copies each source's members onto the table, later ones
|
|
4727
|
+
-- over earlier ones, skipping a \`nil\` source, and answers the table. \`freeze\`
|
|
4728
|
+
-- is Luau's \`table.freeze\`; under Lua 5.1, which cannot freeze a table, the
|
|
4729
|
+
-- table is answered as it is and \`isFrozen\` is false.
|
|
4651
4730
|
declare metatable<T extends {}> T: {
|
|
4652
4731
|
__index: {
|
|
4653
4732
|
keys: (self: T) => ObjectKeys<T>,
|
|
4654
4733
|
values: (self: T) => ObjectValues<T>,
|
|
4655
4734
|
entries: (self: T) => ObjectEntries<T>,
|
|
4735
|
+
|
|
4736
|
+
hasOwn: (self: T, key: unknown) => boolean,
|
|
4737
|
+
hasOwnProperty: (self: T, key: unknown) => boolean,
|
|
4738
|
+
assign: (<U>(self: T, source: U) => T & U)
|
|
4739
|
+
& (<U, V>(self: T, a: U, b: V) => T & U & V)
|
|
4740
|
+
& (<U, V, W>(self: T, a: U, b: V, c: W) => T & U & V & W)
|
|
4741
|
+
-- Generic like the rest: a plain signature would be tried first.
|
|
4742
|
+
& (<S extends {}>(self: T, ...sources: S[]) => T),
|
|
4743
|
+
freeze: (self: T) => Readonly<T>,
|
|
4744
|
+
isFrozen: (self: T) => boolean,
|
|
4656
4745
|
},
|
|
4657
4746
|
}
|
|
4658
4747
|
`;
|
|
@@ -4753,8 +4842,14 @@ function substitute(t, subst) {
|
|
|
4753
4842
|
if (subst.size === 0) return t;
|
|
4754
4843
|
if (!containsTypeParam(t)) return t;
|
|
4755
4844
|
switch (t.kind) {
|
|
4756
|
-
case "typeParam":
|
|
4757
|
-
|
|
4845
|
+
case "typeParam": {
|
|
4846
|
+
const bound = subst.get(t.name);
|
|
4847
|
+
if (bound) return bound;
|
|
4848
|
+
if (t.constraint && containsTypeParam(t.constraint)) {
|
|
4849
|
+
return { ...t, constraint: substitute(t.constraint, new Map([...subst, [t.name, t]])) };
|
|
4850
|
+
}
|
|
4851
|
+
return t;
|
|
4852
|
+
}
|
|
4758
4853
|
case "array":
|
|
4759
4854
|
return { ...arrayOf(substitute(t.element, subst)), readonly: t.readonly };
|
|
4760
4855
|
case "tuple":
|
|
@@ -4899,6 +4994,10 @@ function unify(param, arg, vars, out, how = "union") {
|
|
|
4899
4994
|
if (arg.kind === "function") {
|
|
4900
4995
|
param.params.forEach((p, i) => arg.params[i] && unify(p.type, arg.params[i].type, vars, out));
|
|
4901
4996
|
unify(param.returns, arg.returns, vars, out);
|
|
4997
|
+
const wanted = param.predicate, given = arg.predicate;
|
|
4998
|
+
if (wanted?.type && given?.type && wanted.param === given.param && !wanted.asserts && !given.asserts) {
|
|
4999
|
+
unify(wanted.type, given.type, vars, out);
|
|
5000
|
+
}
|
|
4902
5001
|
}
|
|
4903
5002
|
return;
|
|
4904
5003
|
case "object":
|
|
@@ -5154,6 +5253,11 @@ function isAssignableInner(a, b) {
|
|
|
5154
5253
|
for (let i = 0; i < n; i++) {
|
|
5155
5254
|
if (!isAssignable(a.params[i].type, b.params[i].type) && !isAssignable(b.params[i].type, a.params[i].type)) return false;
|
|
5156
5255
|
}
|
|
5256
|
+
const wanted = b.predicate;
|
|
5257
|
+
if (wanted?.type && !wanted.asserts) {
|
|
5258
|
+
const given = a.predicate;
|
|
5259
|
+
if (!given?.type || given.asserts || given.param !== wanted.param || !isAssignable(given.type, wanted.type)) return false;
|
|
5260
|
+
}
|
|
5157
5261
|
return isAssignable(a.returns, b.returns);
|
|
5158
5262
|
}
|
|
5159
5263
|
if (b.kind === "typeParam") return false;
|
|
@@ -5288,7 +5392,7 @@ function containsFreeTypeParam(t, seen, bound) {
|
|
|
5288
5392
|
return [...t.properties.values()].some((v) => containsTypeParam(v.type, seen, bound)) || !!t.indexer && (containsTypeParam(t.indexer.key, seen, bound) || containsTypeParam(t.indexer.value, seen, bound));
|
|
5289
5393
|
case "function": {
|
|
5290
5394
|
const inner = t.typeParams?.length ? /* @__PURE__ */ new Set([...bound, ...t.typeParams]) : bound;
|
|
5291
|
-
return t.params.some((p) => containsTypeParam(p.type, seen, inner)) || !!t.varargs && containsTypeParam(t.varargs, seen, inner) || containsTypeParam(t.returns, seen, inner);
|
|
5395
|
+
return t.params.some((p) => containsTypeParam(p.type, seen, inner)) || !!t.varargs && containsTypeParam(t.varargs, seen, inner) || containsTypeParam(t.returns, seen, inner) || !!t.predicate?.type && containsTypeParam(t.predicate.type, seen, inner);
|
|
5292
5396
|
}
|
|
5293
5397
|
case "genericRef":
|
|
5294
5398
|
return t.typeArguments.some((a) => containsTypeParam(a, seen, bound));
|
|
@@ -5713,9 +5817,14 @@ function isFreshLiteralExpr(e) {
|
|
|
5713
5817
|
case "StringLiteral":
|
|
5714
5818
|
case "BooleanLiteral":
|
|
5715
5819
|
case "InterpolatedStringExpression":
|
|
5820
|
+
return true;
|
|
5821
|
+
// A table or array literal widened the literals written in it as it
|
|
5822
|
+
// was read (`widenUnlessAsked`), and keeps what it read from
|
|
5823
|
+
// elsewhere — `{ key: name }`, `[...names]` — so there is nothing
|
|
5824
|
+
// left for the binding to widen.
|
|
5716
5825
|
case "TableExpression":
|
|
5717
5826
|
case "ArrayExpression":
|
|
5718
|
-
return
|
|
5827
|
+
return false;
|
|
5719
5828
|
case "ParenthesizedExpression":
|
|
5720
5829
|
return isFreshLiteralExpr(e.expression);
|
|
5721
5830
|
case "UnaryExpression":
|
|
@@ -5730,6 +5839,30 @@ function isFreshLiteralExpr(e) {
|
|
|
5730
5839
|
return false;
|
|
5731
5840
|
}
|
|
5732
5841
|
}
|
|
5842
|
+
function overloadTier(f) {
|
|
5843
|
+
const takesGuard = f.params.some((p) => p.type.kind === "function" && p.type.predicate?.type && !p.type.predicate.asserts);
|
|
5844
|
+
if (takesGuard) return 0;
|
|
5845
|
+
return (f.typeParams?.length ?? 0) > 0 ? 2 : 1;
|
|
5846
|
+
}
|
|
5847
|
+
function writesLiteral(e) {
|
|
5848
|
+
switch (e.type) {
|
|
5849
|
+
case "NumberLiteral":
|
|
5850
|
+
case "StringLiteral":
|
|
5851
|
+
case "BooleanLiteral":
|
|
5852
|
+
case "InterpolatedStringExpression":
|
|
5853
|
+
return true;
|
|
5854
|
+
case "ParenthesizedExpression":
|
|
5855
|
+
return writesLiteral(e.expression);
|
|
5856
|
+
case "UnaryExpression":
|
|
5857
|
+
return writesLiteral(e.argument);
|
|
5858
|
+
case "IfElseExpression":
|
|
5859
|
+
return e.clauses.some((c) => writesLiteral(c.body)) || writesLiteral(e.alternate);
|
|
5860
|
+
case "BinaryExpression":
|
|
5861
|
+
return (e.operator === "or" || e.operator === "and") && (writesLiteral(e.left) || writesLiteral(e.right));
|
|
5862
|
+
default:
|
|
5863
|
+
return false;
|
|
5864
|
+
}
|
|
5865
|
+
}
|
|
5733
5866
|
function collectInferNames(node) {
|
|
5734
5867
|
const out = [];
|
|
5735
5868
|
const walk = (n) => {
|
|
@@ -8112,7 +8245,9 @@ var TypeAnalyzer = class {
|
|
|
8112
8245
|
const waits = written.map((a, i) => this.waitsOnInference(a, expected[i]));
|
|
8113
8246
|
if (!waits.some(Boolean)) return written.map((a) => this.infer(a, env));
|
|
8114
8247
|
const argTypes = written.map((a, i) => waits[i] ? this.quietly(() => this.infer(a, env)) : this.infer(a, env));
|
|
8115
|
-
const
|
|
8248
|
+
const spread = this.spreadOf(written, selfOf(fns[0]));
|
|
8249
|
+
const provisional = argTypes.map((t, i) => waits[i] ? anyType : t);
|
|
8250
|
+
const picked = this.pickOverload(fns, argTypes, (f) => extra(f, argTypes), spread) ?? this.pickOverload(fns, provisional, (f) => extra(f, provisional), spread);
|
|
8116
8251
|
const subst = picked?.typeParams?.length ? this.inferTypeArgs(picked, extra(picked, argTypes)) : void 0;
|
|
8117
8252
|
written.forEach((a, i) => {
|
|
8118
8253
|
if (!waits[i]) return;
|
|
@@ -8303,6 +8438,16 @@ var TypeAnalyzer = class {
|
|
|
8303
8438
|
}
|
|
8304
8439
|
const id = this.bindingIdByName(p.name, p);
|
|
8305
8440
|
const t = this.paramType(p, env);
|
|
8441
|
+
if (p.default && p.typeAnnotation) {
|
|
8442
|
+
const given = this.infer(p.default, env);
|
|
8443
|
+
const declared = this.resolveType(p.typeAnnotation);
|
|
8444
|
+
if (this.emitDiagnostics && !isAssignable(given, declared)) {
|
|
8445
|
+
this.diagnostics.push({
|
|
8446
|
+
node: p.default,
|
|
8447
|
+
message: `Type '${briefType(given)}' is not assignable to '${briefType(declared)}'` + this.explainMismatch(given, declared)
|
|
8448
|
+
});
|
|
8449
|
+
}
|
|
8450
|
+
}
|
|
8306
8451
|
if (id !== void 0) {
|
|
8307
8452
|
this.bindingType.set(id, t);
|
|
8308
8453
|
this.setBinding(env, id, t);
|
|
@@ -8400,9 +8545,9 @@ var TypeAnalyzer = class {
|
|
|
8400
8545
|
* lets `typeof` declare `(v: number) -> "number"` alongside a trailing
|
|
8401
8546
|
* `<T>(v: T) -> string` and still pick the precise one. */
|
|
8402
8547
|
pickOverload(fns, argTypes, argsFor, spread) {
|
|
8403
|
-
for (const
|
|
8548
|
+
for (const tier of [0, 1, 2]) {
|
|
8404
8549
|
for (const f of fns) {
|
|
8405
|
-
if ((f
|
|
8550
|
+
if (overloadTier(f) !== tier) continue;
|
|
8406
8551
|
if (this.overloadAccepts(f, argsFor ? argsFor(f) : argTypes, spread)) return f;
|
|
8407
8552
|
}
|
|
8408
8553
|
}
|
|
@@ -8428,7 +8573,7 @@ var TypeAnalyzer = class {
|
|
|
8428
8573
|
if (position < 0) return void 0;
|
|
8429
8574
|
const members = this.expand(argTypes[position]).types;
|
|
8430
8575
|
if (members.length > 32) return void 0;
|
|
8431
|
-
const rank = (f) => (
|
|
8576
|
+
const rank = (f) => overloadTier(f) * fns.length + fns.indexOf(f);
|
|
8432
8577
|
const limit = picked ? rank(picked) : Infinity;
|
|
8433
8578
|
const results = [];
|
|
8434
8579
|
for (const member of members) {
|
|
@@ -8821,10 +8966,38 @@ var TypeAnalyzer = class {
|
|
|
8821
8966
|
returns,
|
|
8822
8967
|
void 0,
|
|
8823
8968
|
names,
|
|
8824
|
-
this.resolvePredicate(func.predicate, params)
|
|
8969
|
+
func.predicate || func.returnType ? this.resolvePredicate(func.predicate, params) : this.inferPredicate(func, params, returns, bodyEnv)
|
|
8825
8970
|
), func.params);
|
|
8826
8971
|
});
|
|
8827
8972
|
}
|
|
8973
|
+
/** `v => v ~= nil` is a guard without saying so, as TypeScript reads it:
|
|
8974
|
+
* a body that is one `return` of a boolean which, true, narrows a
|
|
8975
|
+
* parameter — and, false, leaves it exactly what that excludes. Then
|
|
8976
|
+
* `list:filter(v => v ~= nil)` knows what it kept. */
|
|
8977
|
+
inferPredicate(func, params, returns, env) {
|
|
8978
|
+
const only = func.body.statements.length === 1 ? func.body.statements[0] : void 0;
|
|
8979
|
+
if (only?.type !== "ReturnStatement" || !only.argument) return void 0;
|
|
8980
|
+
if (returns.kind === "any" || returns.kind === "never" || !isAssignable(returns, booleanType)) return void 0;
|
|
8981
|
+
const cond = only.argument;
|
|
8982
|
+
for (let i = 0; i < params.length; i++) {
|
|
8983
|
+
const p = func.params[i];
|
|
8984
|
+
if (p.pattern || p.rest) continue;
|
|
8985
|
+
const id = this.bindingIdByName(p.name, p);
|
|
8986
|
+
if (id === void 0) continue;
|
|
8987
|
+
const declared = params[i].type;
|
|
8988
|
+
const key = bindKey(id);
|
|
8989
|
+
const t = forkEnv(env);
|
|
8990
|
+
const f = forkEnv(env);
|
|
8991
|
+
this.silently(() => this.applyNarrowing(cond, env, t, f));
|
|
8992
|
+
const yes = t.get(key);
|
|
8993
|
+
if (!yes || equalTypes(yes, declared) || !isAssignable(yes, declared)) continue;
|
|
8994
|
+
const no = this.expand(f.get(key) ?? declared);
|
|
8995
|
+
const rest = no.kind === "union" ? no.types : [no];
|
|
8996
|
+
if (rest.some((m) => m.kind !== "never" && isAssignable(m, yes))) continue;
|
|
8997
|
+
return { param: i, type: yes, asserts: false };
|
|
8998
|
+
}
|
|
8999
|
+
return void 0;
|
|
9000
|
+
}
|
|
8828
9001
|
/** Where the return types of the function being walked are collected, so
|
|
8829
9002
|
* each is read where it is written — inside the branch that narrowed it —
|
|
8830
9003
|
* rather than in whatever state the body ends in. */
|
|
@@ -9946,6 +10119,27 @@ var TypeAnalyzer = class {
|
|
|
9946
10119
|
elseEnv = whenFalse;
|
|
9947
10120
|
}
|
|
9948
10121
|
branches.push(this.infer(expr.alternate, elseEnv));
|
|
10122
|
+
const bodies = [...expr.clauses.map((c) => c.body), expr.alternate].map(unwrapParens);
|
|
10123
|
+
const isEmpty = (e) => e.type === "TableExpression" && e.fields.length === 0 || e.type === "ArrayExpression" && e.elements.length === 0;
|
|
10124
|
+
const others = union(branches.filter((_, i) => !isEmpty(bodies[i])));
|
|
10125
|
+
const parts = (others.kind === "union" ? others.types : [others]).map((m) => this.expand(m)).filter((m) => !(m.kind === "primitive" && m.name === "nil"));
|
|
10126
|
+
const fits = (e) => {
|
|
10127
|
+
if (!parts.length) return void 0;
|
|
10128
|
+
if (e.type === "ArrayExpression") {
|
|
10129
|
+
if (parts.every((m) => m.kind === "array")) return others;
|
|
10130
|
+
return parts.every((m) => m.kind === "array" || m.kind === "tuple") ? tuple([]) : void 0;
|
|
10131
|
+
}
|
|
10132
|
+
return parts.every((m) => m.kind === "object" && !m.class && [...m.properties.values()].every((prop) => prop.optional)) ? others : void 0;
|
|
10133
|
+
};
|
|
10134
|
+
if (bodies.some(isEmpty) && others.kind !== "never" && others.kind !== "any" && bodies.every((body) => !isEmpty(body) || fits(body))) {
|
|
10135
|
+
const typed = bodies.map((body, i) => {
|
|
10136
|
+
if (!isEmpty(body)) return branches[i];
|
|
10137
|
+
const t = fits(body);
|
|
10138
|
+
this.typeOf.set(body, t);
|
|
10139
|
+
return t;
|
|
10140
|
+
});
|
|
10141
|
+
return union(typed);
|
|
10142
|
+
}
|
|
9949
10143
|
return union(branches);
|
|
9950
10144
|
}
|
|
9951
10145
|
}
|
|
@@ -10252,23 +10446,87 @@ var TypeAnalyzer = class {
|
|
|
10252
10446
|
if (wantedTuple && !asConst) return this.inferTupleLiteral(expr, env, wantedTuple);
|
|
10253
10447
|
const elems = [];
|
|
10254
10448
|
let hadSpread = false;
|
|
10449
|
+
const written = [];
|
|
10255
10450
|
for (const el of expr.elements) {
|
|
10256
10451
|
if (el.type === "SpreadElement") {
|
|
10257
10452
|
hadSpread = true;
|
|
10258
|
-
const
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
else elems.push(unknownType);
|
|
10453
|
+
const spread = this.infer(el.argument, env);
|
|
10454
|
+
written.push({ spread: true, type: spread });
|
|
10455
|
+
elems.push(...this.spreadElements(spread));
|
|
10262
10456
|
} else {
|
|
10263
|
-
|
|
10457
|
+
const t = asConst ? this.inferAsConst(el, env) : this.infer(el, env);
|
|
10458
|
+
written.push({ spread: false, type: asConst ? t : this.widenUnlessAsked(t, el) });
|
|
10459
|
+
elems.push(t);
|
|
10264
10460
|
}
|
|
10265
10461
|
}
|
|
10266
10462
|
if (asConst && !hadSpread) return tuple(elems);
|
|
10463
|
+
if (hadSpread) {
|
|
10464
|
+
const tuples = this.spreadTuples(written);
|
|
10465
|
+
if (tuples) return union(tuples.map((elements) => tuple(elements)));
|
|
10466
|
+
}
|
|
10267
10467
|
return arrayOf(elems.length ? union(elems.map((t, i) => {
|
|
10268
10468
|
const element = expr.elements[i];
|
|
10269
10469
|
return asConst || !element || element.type === "SpreadElement" ? t : this.widenUnlessAsked(t, element);
|
|
10270
10470
|
})) : unknownType);
|
|
10271
10471
|
}
|
|
10472
|
+
/** The tuples an array literal with spreads is, when every spread is a
|
|
10473
|
+
* tuple of known length or a union of them: one per way the unions go.
|
|
10474
|
+
* `undefined` when a spread's length is not known (an array, a tuple
|
|
10475
|
+
* with a rest), or the ways multiply past what is worth listing. */
|
|
10476
|
+
spreadTuples(written) {
|
|
10477
|
+
const MAX = 32;
|
|
10478
|
+
let variants = [[]];
|
|
10479
|
+
for (const { spread, type } of written) {
|
|
10480
|
+
if (!spread) {
|
|
10481
|
+
variants = variants.map((v) => [...v, type]);
|
|
10482
|
+
continue;
|
|
10483
|
+
}
|
|
10484
|
+
const options = this.fixedTuples(type);
|
|
10485
|
+
if (!options) return void 0;
|
|
10486
|
+
const next = [];
|
|
10487
|
+
for (const v of variants) for (const option of options) next.push([...v, ...option]);
|
|
10488
|
+
if (next.length > MAX) return void 0;
|
|
10489
|
+
variants = next;
|
|
10490
|
+
}
|
|
10491
|
+
return variants;
|
|
10492
|
+
}
|
|
10493
|
+
/** A tuple of known length's members, or a union of such tuples' — each
|
|
10494
|
+
* a way the value can be. `nil` in a union spreads nothing. */
|
|
10495
|
+
fixedTuples(t, depth = 0) {
|
|
10496
|
+
if (depth > 8) return void 0;
|
|
10497
|
+
const held = this.expand(t);
|
|
10498
|
+
if (held.kind === "tuple") return held.rest ? void 0 : [held.elements];
|
|
10499
|
+
if (held.kind !== "union") return void 0;
|
|
10500
|
+
const out = [];
|
|
10501
|
+
for (const member of held.types) {
|
|
10502
|
+
if (member.kind === "primitive" && member.name === "nil") continue;
|
|
10503
|
+
const options = this.fixedTuples(member, depth + 1);
|
|
10504
|
+
if (!options) return void 0;
|
|
10505
|
+
out.push(...options);
|
|
10506
|
+
}
|
|
10507
|
+
return out.length ? out : void 0;
|
|
10508
|
+
}
|
|
10509
|
+
/** What `...xs` puts into an array: an array's element, a tuple's members,
|
|
10510
|
+
* and for a union each member's — `...(host ? extra : [])` adds `extra`'s
|
|
10511
|
+
* elements and the empty tuple nothing. Anything else, `unknown`. */
|
|
10512
|
+
spreadElements(t, depth = 0) {
|
|
10513
|
+
const held = this.expand(t);
|
|
10514
|
+
if (depth > 8) return [unknownType];
|
|
10515
|
+
switch (held.kind) {
|
|
10516
|
+
case "array":
|
|
10517
|
+
return [held.element];
|
|
10518
|
+
case "tuple":
|
|
10519
|
+
return tupleMembers(held);
|
|
10520
|
+
case "union":
|
|
10521
|
+
return held.types.filter((m) => !(m.kind === "primitive" && m.name === "nil")).flatMap((m) => this.spreadElements(m, depth + 1));
|
|
10522
|
+
case "typeParam":
|
|
10523
|
+
return held.constraint ? this.spreadElements(held.constraint, depth + 1) : [unknownType];
|
|
10524
|
+
case "any":
|
|
10525
|
+
return [anyType];
|
|
10526
|
+
default:
|
|
10527
|
+
return [unknownType];
|
|
10528
|
+
}
|
|
10529
|
+
}
|
|
10272
10530
|
/** `[a, b, ...more]` where a tuple is wanted: the places it names are the
|
|
10273
10531
|
* tuple's, and what comes after them — more elements, or a spread — is
|
|
10274
10532
|
* its rest. */
|
|
@@ -10279,10 +10537,7 @@ var TypeAnalyzer = class {
|
|
|
10279
10537
|
expr.elements.forEach((element, i) => {
|
|
10280
10538
|
if (element.type === "SpreadElement") {
|
|
10281
10539
|
spread = true;
|
|
10282
|
-
|
|
10283
|
-
if (held.kind === "array") tail.push(held.element);
|
|
10284
|
-
else if (held.kind === "tuple") tail.push(...tupleMembers(held));
|
|
10285
|
-
else tail.push(unknownType);
|
|
10540
|
+
tail.push(...this.spreadElements(this.infer(element.argument, env)));
|
|
10286
10541
|
return;
|
|
10287
10542
|
}
|
|
10288
10543
|
const t = this.widenUnlessAsked(this.infer(element, env), element);
|
|
@@ -10299,6 +10554,7 @@ var TypeAnalyzer = class {
|
|
|
10299
10554
|
* The context was recorded by `applyContext` before the value was
|
|
10300
10555
|
* inferred, so this is a lookup rather than a second pass. */
|
|
10301
10556
|
widenUnlessAsked(value, at) {
|
|
10557
|
+
if (!writesLiteral(at)) return value;
|
|
10302
10558
|
const wanted = this.expectedTypeOf.get(at);
|
|
10303
10559
|
if (value.kind === "literal") {
|
|
10304
10560
|
const arms = this.contextArms.get(at);
|
|
@@ -11671,7 +11927,53 @@ function aliasTargets(config, specifier) {
|
|
|
11671
11927
|
|
|
11672
11928
|
// src/project/sourcemap.ts
|
|
11673
11929
|
var import_node_path4 = require("path");
|
|
11930
|
+
|
|
11931
|
+
// src/luau.ts
|
|
11932
|
+
var LUAU_KEYWORDS = /* @__PURE__ */ new Set([
|
|
11933
|
+
"and",
|
|
11934
|
+
"break",
|
|
11935
|
+
"do",
|
|
11936
|
+
"else",
|
|
11937
|
+
"elseif",
|
|
11938
|
+
"end",
|
|
11939
|
+
"false",
|
|
11940
|
+
"for",
|
|
11941
|
+
"function",
|
|
11942
|
+
"if",
|
|
11943
|
+
"in",
|
|
11944
|
+
"local",
|
|
11945
|
+
"nil",
|
|
11946
|
+
"not",
|
|
11947
|
+
"or",
|
|
11948
|
+
"repeat",
|
|
11949
|
+
"return",
|
|
11950
|
+
"then",
|
|
11951
|
+
"true",
|
|
11952
|
+
"until",
|
|
11953
|
+
"while"
|
|
11954
|
+
]);
|
|
11674
11955
|
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
11956
|
+
function isIdentifier(name) {
|
|
11957
|
+
return IDENTIFIER.test(name);
|
|
11958
|
+
}
|
|
11959
|
+
function isLuauName(name) {
|
|
11960
|
+
return IDENTIFIER.test(name) && !LUAU_KEYWORDS.has(name);
|
|
11961
|
+
}
|
|
11962
|
+
var NAMED_ESCAPES = {
|
|
11963
|
+
"\\": "\\\\",
|
|
11964
|
+
'"': '\\"',
|
|
11965
|
+
"\n": "\\n",
|
|
11966
|
+
"\r": "\\r",
|
|
11967
|
+
" ": "\\t"
|
|
11968
|
+
};
|
|
11969
|
+
function escapeLuauString(text) {
|
|
11970
|
+
return text.replace(/[\\"\x00-\x1f\x7f]/g, (c) => NAMED_ESCAPES[c] ?? `\\${c.charCodeAt(0).toString().padStart(3, "0")}`);
|
|
11971
|
+
}
|
|
11972
|
+
function luauString(text) {
|
|
11973
|
+
return `"${escapeLuauString(text)}"`;
|
|
11974
|
+
}
|
|
11975
|
+
|
|
11976
|
+
// src/project/sourcemap.ts
|
|
11675
11977
|
var INSTANCE_MEMBERS = /* @__PURE__ */ new Set(["Name", "ClassName", "Parent", "Archivable"]);
|
|
11676
11978
|
var SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".tilua", ".luau", ".lua"]);
|
|
11677
11979
|
function sourceMapTypes(text, path, options) {
|
|
@@ -11698,7 +12000,7 @@ function sourceMapTypes(text, path, options) {
|
|
|
11698
12000
|
const alias = aliasFor(segments);
|
|
11699
12001
|
aliasOfNode.set(node, alias);
|
|
11700
12002
|
for (const filePath of node.filePaths ?? []) aliasOfFile.set(fileKey((0, import_node_path4.resolve)(directory, filePath)), alias);
|
|
11701
|
-
const className =
|
|
12003
|
+
const className = isIdentifier(node.className) && options.classes.has(node.className) ? node.className : "Instance";
|
|
11702
12004
|
const taken = options.membersOf?.(className) ?? INSTANCE_MEMBERS;
|
|
11703
12005
|
const members = [];
|
|
11704
12006
|
if (parent) members.push(`Parent: ${parent}`);
|
|
@@ -11707,7 +12009,7 @@ function sourceMapTypes(text, path, options) {
|
|
|
11707
12009
|
if (!isNode(child)) continue;
|
|
11708
12010
|
const childAlias = visit(child, [...segments, child.name], alias);
|
|
11709
12011
|
const service = child.name === child.className && options.classes.has(child.className);
|
|
11710
|
-
if (!
|
|
12012
|
+
if (!isIdentifier(child.name) || taken.has(child.name) && !service || named.has(child.name)) continue;
|
|
11711
12013
|
named.add(child.name);
|
|
11712
12014
|
members.push(`${child.name}: ${childAlias}`);
|
|
11713
12015
|
}
|
|
@@ -11749,6 +12051,34 @@ function fileKey(path) {
|
|
|
11749
12051
|
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
11750
12052
|
}
|
|
11751
12053
|
|
|
12054
|
+
// src/loweringHelpers.ts
|
|
12055
|
+
function withoutNil2(type) {
|
|
12056
|
+
if (!type) return [];
|
|
12057
|
+
const members = type.kind === "union" ? type.types : [type];
|
|
12058
|
+
return members.filter((m) => !(m.kind === "primitive" && m.name === "nil"));
|
|
12059
|
+
}
|
|
12060
|
+
function isFunctionType(type) {
|
|
12061
|
+
const members = withoutNil2(type);
|
|
12062
|
+
return members.length > 0 && members.every((m) => m.kind === "function" || m.kind === "intersection" && m.types.every(isFunctionType));
|
|
12063
|
+
}
|
|
12064
|
+
function everyObject(type, test) {
|
|
12065
|
+
const members = withoutNil2(type);
|
|
12066
|
+
return members.length > 0 && members.every((m) => m.kind === "object" && test(m));
|
|
12067
|
+
}
|
|
12068
|
+
function isInstanceOf(type, className) {
|
|
12069
|
+
return everyObject(type, (m) => m.class !== void 0 && m.class.ancestors.includes(className));
|
|
12070
|
+
}
|
|
12071
|
+
function hasMembers(type, names) {
|
|
12072
|
+
return everyObject(type, (m) => names.every((name) => m.properties.has(name)));
|
|
12073
|
+
}
|
|
12074
|
+
function returnsTuple(receiver, method) {
|
|
12075
|
+
return everyObject(receiver, (m) => {
|
|
12076
|
+
const found = m.properties.get(method)?.type;
|
|
12077
|
+
const signatures = !found ? [] : found.kind === "intersection" ? found.types : [found];
|
|
12078
|
+
return signatures.length > 0 && signatures.every((f) => f.kind === "function" && f.returns.kind === "tuple");
|
|
12079
|
+
});
|
|
12080
|
+
}
|
|
12081
|
+
|
|
11752
12082
|
// src/index.ts
|
|
11753
12083
|
var tilua = {
|
|
11754
12084
|
tokenize,
|
|
@@ -11769,6 +12099,7 @@ var index_default = tilua;
|
|
|
11769
12099
|
CONFIG_FILE_NAMES,
|
|
11770
12100
|
Keywords,
|
|
11771
12101
|
LANGUAGE_GLOBALS,
|
|
12102
|
+
LUAU_KEYWORDS,
|
|
11772
12103
|
LexError,
|
|
11773
12104
|
Operators,
|
|
11774
12105
|
PRELUDE_SOURCE,
|
|
@@ -11789,20 +12120,27 @@ var index_default = tilua;
|
|
|
11789
12120
|
difference,
|
|
11790
12121
|
directivesOf,
|
|
11791
12122
|
equalTypes,
|
|
12123
|
+
escapeLuauString,
|
|
11792
12124
|
falsyType,
|
|
11793
12125
|
findConfig,
|
|
11794
12126
|
fn,
|
|
11795
12127
|
formatType,
|
|
11796
12128
|
getBinding,
|
|
12129
|
+
hasMembers,
|
|
11797
12130
|
intersection,
|
|
11798
12131
|
isAssignable,
|
|
11799
12132
|
isClassType,
|
|
12133
|
+
isFunctionType,
|
|
11800
12134
|
isGlobal,
|
|
12135
|
+
isIdentifier,
|
|
12136
|
+
isInstanceOf,
|
|
12137
|
+
isLuauName,
|
|
11801
12138
|
isPossiblyFalsy,
|
|
11802
12139
|
isPossiblyTruthy,
|
|
11803
12140
|
isUnassignedGlobal,
|
|
11804
12141
|
literal,
|
|
11805
12142
|
loadConfig,
|
|
12143
|
+
luauString,
|
|
11806
12144
|
matchInfer,
|
|
11807
12145
|
moduleCandidates,
|
|
11808
12146
|
moduleExports,
|
|
@@ -11825,6 +12163,7 @@ var index_default = tilua;
|
|
|
11825
12163
|
readDirectives,
|
|
11826
12164
|
resolveModulePath,
|
|
11827
12165
|
resolveTypeLibraries,
|
|
12166
|
+
returnsTuple,
|
|
11828
12167
|
setAliasExpander,
|
|
11829
12168
|
setDeferredBound,
|
|
11830
12169
|
sourceMapTypes,
|
|
@@ -11843,5 +12182,6 @@ var index_default = tilua;
|
|
|
11843
12182
|
unknownType,
|
|
11844
12183
|
widen,
|
|
11845
12184
|
withAliasName,
|
|
11846
|
-
withoutAliasName
|
|
12185
|
+
withoutAliasName,
|
|
12186
|
+
withoutNil
|
|
11847
12187
|
});
|