luaut-parser 1.1.0 → 1.2.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/README.md +1 -2
- package/dist/index.cjs +87 -10
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +87 -10
- package/package.json +1 -4
package/README.md
CHANGED
|
@@ -127,8 +127,7 @@ analyzeTypes(program, scopes, {
|
|
|
127
127
|
(`export { a } from`) and `export * from` are.
|
|
128
128
|
- `setmetatable` and metatables are not modelled.
|
|
129
129
|
- Accessing a property a type does not have yields `unknown` rather than an
|
|
130
|
-
error; assigning to a `readonly` property is not reported
|
|
131
|
-
constraints are not checked at call sites.
|
|
130
|
+
error; assigning to a `readonly` property is not reported.
|
|
132
131
|
|
|
133
132
|
## Development
|
|
134
133
|
|
package/dist/index.cjs
CHANGED
|
@@ -3832,6 +3832,7 @@ var TypeAnalyzer = class {
|
|
|
3832
3832
|
bindingType = /* @__PURE__ */ new Map();
|
|
3833
3833
|
narrowedTypeOf = /* @__PURE__ */ new Map();
|
|
3834
3834
|
typeOfTypeNode = /* @__PURE__ */ new Map();
|
|
3835
|
+
expectedTypeOf = /* @__PURE__ */ new Map();
|
|
3835
3836
|
/** Public: each alias resolved once (generic aliases keep their params as
|
|
3836
3837
|
* `typeParam` nodes in the body). */
|
|
3837
3838
|
aliases = /* @__PURE__ */ new Map();
|
|
@@ -3897,6 +3898,7 @@ var TypeAnalyzer = class {
|
|
|
3897
3898
|
bindingType: this.bindingType,
|
|
3898
3899
|
narrowedTypeOf: this.narrowedTypeOf,
|
|
3899
3900
|
typeOfTypeNode: this.typeOfTypeNode,
|
|
3901
|
+
expectedTypeOf: this.expectedTypeOf,
|
|
3900
3902
|
aliases: this.resolveDeferredAliases(),
|
|
3901
3903
|
diagnostics: this.diagnostics
|
|
3902
3904
|
};
|
|
@@ -4878,16 +4880,76 @@ var TypeAnalyzer = class {
|
|
|
4878
4880
|
return void 0;
|
|
4879
4881
|
}
|
|
4880
4882
|
/** Can this signature be called with these argument types? The signature's
|
|
4881
|
-
* own
|
|
4882
|
-
*
|
|
4883
|
+
* own type parameters stand for what the call would infer, so each is
|
|
4884
|
+
* checked only against its constraint — `<K extends keyof Services>`
|
|
4885
|
+
* accepts `"Players"` but not `""`. */
|
|
4883
4886
|
overloadAccepts(f, argTypes) {
|
|
4884
4887
|
if (!f.varargs && argTypes.length > f.params.length) return false;
|
|
4885
|
-
const
|
|
4888
|
+
const params = this.boundParams(f);
|
|
4886
4889
|
return f.params.every((p, i) => {
|
|
4887
4890
|
if (argTypes[i] === void 0) return p.optional === true;
|
|
4888
|
-
return isAssignable(argTypes[i],
|
|
4891
|
+
return isAssignable(argTypes[i], params[i]);
|
|
4889
4892
|
});
|
|
4890
4893
|
}
|
|
4894
|
+
/** A signature's parameter types as a call site sees them before inference:
|
|
4895
|
+
* each type parameter replaced by its constraint, or by `any` when it has
|
|
4896
|
+
* none — or when the constraint mentions another type parameter, which a
|
|
4897
|
+
* lone argument cannot be checked against without false errors. */
|
|
4898
|
+
boundParams(f) {
|
|
4899
|
+
if (!f.typeParams?.length) return f.params.map((p) => p.type);
|
|
4900
|
+
const bounds = new Map(f.typeParams.map((name) => [name, anyType]));
|
|
4901
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
4902
|
+
const walk = (value) => {
|
|
4903
|
+
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
4904
|
+
seen.add(value);
|
|
4905
|
+
if (value instanceof Map) {
|
|
4906
|
+
value.forEach(walk);
|
|
4907
|
+
return;
|
|
4908
|
+
}
|
|
4909
|
+
const t = value;
|
|
4910
|
+
if (t.kind === "typeParam" && typeof t.name === "string" && bounds.has(t.name) && t.constraint && !containsTypeParam(t.constraint)) {
|
|
4911
|
+
bounds.set(t.name, this.reduceType(t.constraint));
|
|
4912
|
+
}
|
|
4913
|
+
for (const child of Object.values(value)) walk(child);
|
|
4914
|
+
};
|
|
4915
|
+
for (const p of f.params) walk(p.type);
|
|
4916
|
+
return f.params.map((p) => substitute(p.type, bounds));
|
|
4917
|
+
}
|
|
4918
|
+
/** Record what each written argument is expected to be — see
|
|
4919
|
+
* `TypeAnalysis.expectedTypeOf`. */
|
|
4920
|
+
recordExpected(written, fns, selfOf) {
|
|
4921
|
+
written.forEach((arg, j) => {
|
|
4922
|
+
const candidates = [];
|
|
4923
|
+
for (const f of fns) {
|
|
4924
|
+
const i = j + selfOf(f);
|
|
4925
|
+
const param = i < f.params.length ? this.boundParams(f)[i] : f.varargs;
|
|
4926
|
+
if (param) candidates.push(param);
|
|
4927
|
+
}
|
|
4928
|
+
if (candidates.length) this.expectedTypeOf.set(arg, union(candidates));
|
|
4929
|
+
});
|
|
4930
|
+
}
|
|
4931
|
+
/** No signature accepts the call, and the argument count is not the
|
|
4932
|
+
* problem: say which argument is wrong, the way TypeScript does. */
|
|
4933
|
+
reportArguments(call, written, fns, argsFor, selfOf) {
|
|
4934
|
+
if (!this.emitDiagnostics) return;
|
|
4935
|
+
if (fns.length > 1) {
|
|
4936
|
+
this.diagnostics.push({ node: call, message: "No overload matches this call" });
|
|
4937
|
+
return;
|
|
4938
|
+
}
|
|
4939
|
+
const f = fns[0];
|
|
4940
|
+
const args = argsFor(f);
|
|
4941
|
+
const params = this.boundParams(f);
|
|
4942
|
+
const self = selfOf(f);
|
|
4943
|
+
for (let i = 0; i < f.params.length; i++) {
|
|
4944
|
+
const arg = args[i];
|
|
4945
|
+
if (arg === void 0 || isAssignable(arg, params[i])) continue;
|
|
4946
|
+
this.diagnostics.push({
|
|
4947
|
+
node: written[i - self] ?? call,
|
|
4948
|
+
message: `Argument of type '${formatType(arg)}' is not assignable to parameter of type '${briefType(params[i])}'`
|
|
4949
|
+
});
|
|
4950
|
+
return;
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4891
4953
|
/** A required parameter may not follow an optional one — otherwise the
|
|
4892
4954
|
* optional one could never actually be omitted. Same rule as TypeScript,
|
|
4893
4955
|
* and it applies to a default (`a = 1`) as much as to a `?`. */
|
|
@@ -4917,22 +4979,25 @@ var TypeAnalyzer = class {
|
|
|
4917
4979
|
return { min, max: f.varargs ? void 0 : f.params.length };
|
|
4918
4980
|
}
|
|
4919
4981
|
/** Report a call that passes too few or too many arguments. Only fires
|
|
4920
|
-
* when *no* overload accepts the
|
|
4921
|
-
* once, against its first signature.
|
|
4982
|
+
* when *no* overload accepts the count, so an overload set still reports
|
|
4983
|
+
* once, against its first signature. Returns whether the count fits, so
|
|
4984
|
+
* an argument's type is only complained about when its count is right. */
|
|
4922
4985
|
checkArity(node, fns, argCount, selfArgs) {
|
|
4923
|
-
if (!
|
|
4986
|
+
if (!fns.length) return true;
|
|
4924
4987
|
const fits = fns.some((f) => {
|
|
4925
4988
|
const { min: min2, max: max2 } = this.arityOf(f);
|
|
4926
4989
|
const n = argCount + selfArgs;
|
|
4927
4990
|
return n >= min2 && (max2 === void 0 || n <= max2);
|
|
4928
4991
|
});
|
|
4929
|
-
if (fits) return;
|
|
4992
|
+
if (fits) return true;
|
|
4993
|
+
if (!this.emitDiagnostics) return false;
|
|
4930
4994
|
const { min, max } = this.arityOf(fns[0]);
|
|
4931
4995
|
const need = max === void 0 ? `at least ${min - selfArgs}` : min === max ? `${min - selfArgs}` : `${min - selfArgs}-${max - selfArgs}`;
|
|
4932
4996
|
this.diagnostics.push({
|
|
4933
4997
|
node,
|
|
4934
4998
|
message: `Expected ${need} argument${need === "1" ? "" : "s"}, got ${argCount}`
|
|
4935
4999
|
});
|
|
5000
|
+
return false;
|
|
4936
5001
|
}
|
|
4937
5002
|
signatureToFnType(sig) {
|
|
4938
5003
|
const names = sig.generics.map((g) => g.name);
|
|
@@ -5370,11 +5435,13 @@ var TypeAnalyzer = class {
|
|
|
5370
5435
|
const argTypes = expr.arguments.map((a) => this.infer(a, env));
|
|
5371
5436
|
const fns = this.overloadsOf(callee);
|
|
5372
5437
|
if (fns.length) {
|
|
5373
|
-
this.
|
|
5438
|
+
this.recordExpected(expr.arguments, fns, () => 0);
|
|
5439
|
+
const arityFits = this.checkArity(expr, fns, argTypes.length, 0);
|
|
5374
5440
|
const picked = this.pickOverload(fns, argTypes);
|
|
5375
5441
|
if (picked) {
|
|
5376
5442
|
return this.callReturn(picked, this.constArgs(picked, expr.arguments, argTypes, env));
|
|
5377
5443
|
}
|
|
5444
|
+
if (arityFits) this.reportArguments(expr, expr.arguments, fns, () => argTypes, () => 0);
|
|
5378
5445
|
return union(fns.map((f) => this.callReturn(f, argTypes)));
|
|
5379
5446
|
}
|
|
5380
5447
|
return callee.kind === "any" ? anyType : unknownType;
|
|
@@ -5385,13 +5452,16 @@ var TypeAnalyzer = class {
|
|
|
5385
5452
|
const fns = this.overloadsOf(this.propertyType(objType, expr.method.name));
|
|
5386
5453
|
if (fns.length) {
|
|
5387
5454
|
const withSelf = (f) => this.takesSelf(f) ? [objType, ...argTypes] : argTypes;
|
|
5388
|
-
|
|
5455
|
+
const selfOf = (f) => this.takesSelf(f) ? 1 : 0;
|
|
5456
|
+
this.recordExpected(expr.arguments, fns, selfOf);
|
|
5457
|
+
const arityFits = this.checkArity(expr, fns, argTypes.length, this.takesSelf(fns[0]) ? 1 : 0);
|
|
5389
5458
|
const picked = this.pickOverload(fns, argTypes, withSelf);
|
|
5390
5459
|
if (picked) {
|
|
5391
5460
|
const self = this.takesSelf(picked) ? 1 : 0;
|
|
5392
5461
|
const written = this.constArgs(picked, expr.arguments, argTypes, env, self);
|
|
5393
5462
|
return this.callReturn(picked, this.takesSelf(picked) ? [objType, ...written] : written);
|
|
5394
5463
|
}
|
|
5464
|
+
if (arityFits) this.reportArguments(expr, expr.arguments, fns, withSelf, selfOf);
|
|
5395
5465
|
return union(fns.map((f) => this.callReturn(f, withSelf(f))));
|
|
5396
5466
|
}
|
|
5397
5467
|
return objType.kind === "any" ? anyType : unknownType;
|
|
@@ -5839,6 +5909,13 @@ function containsTypeQuery(node) {
|
|
|
5839
5909
|
if (node.type === "TypeofTypeNode") return true;
|
|
5840
5910
|
return Object.values(node).some(containsTypeQuery);
|
|
5841
5911
|
}
|
|
5912
|
+
function briefType(t) {
|
|
5913
|
+
if (t.kind === "union" && t.types.length > 8) {
|
|
5914
|
+
const shown = t.types.slice(0, 6).map(formatType).join(" | ");
|
|
5915
|
+
return `${shown} | ... ${t.types.length - 6} more`;
|
|
5916
|
+
}
|
|
5917
|
+
return formatType(t);
|
|
5918
|
+
}
|
|
5842
5919
|
|
|
5843
5920
|
// src/lib/luau.ts
|
|
5844
5921
|
var import_node_fs = require("fs");
|
package/dist/index.d.cts
CHANGED
|
@@ -1080,6 +1080,12 @@ interface TypeAnalysis {
|
|
|
1080
1080
|
* `typeof x`, a property's type inside `{ ... }`. Inside a generic alias or
|
|
1081
1081
|
* function its parameters stay unresolved (`T`). */
|
|
1082
1082
|
readonly typeOfTypeNode: Map<TypeNode | TypePackNode, Type>;
|
|
1083
|
+
/** What each call argument is expected to be: the parameter it lands on,
|
|
1084
|
+
* with the signature's type parameters replaced by their constraints — a
|
|
1085
|
+
* union when an overload set disagrees. Recorded even for a call that does
|
|
1086
|
+
* not type-check, since that is exactly when an editor wants to offer the
|
|
1087
|
+
* values that would. */
|
|
1088
|
+
readonly expectedTypeOf: Map<Expression, Type>;
|
|
1083
1089
|
/** Top-level type aliases, resolved — and the type names this module
|
|
1084
1090
|
* imports, so tooling treats both alike. */
|
|
1085
1091
|
readonly aliases: Map<string, Type>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1080,6 +1080,12 @@ interface TypeAnalysis {
|
|
|
1080
1080
|
* `typeof x`, a property's type inside `{ ... }`. Inside a generic alias or
|
|
1081
1081
|
* function its parameters stay unresolved (`T`). */
|
|
1082
1082
|
readonly typeOfTypeNode: Map<TypeNode | TypePackNode, Type>;
|
|
1083
|
+
/** What each call argument is expected to be: the parameter it lands on,
|
|
1084
|
+
* with the signature's type parameters replaced by their constraints — a
|
|
1085
|
+
* union when an overload set disagrees. Recorded even for a call that does
|
|
1086
|
+
* not type-check, since that is exactly when an editor wants to offer the
|
|
1087
|
+
* values that would. */
|
|
1088
|
+
readonly expectedTypeOf: Map<Expression, Type>;
|
|
1083
1089
|
/** Top-level type aliases, resolved — and the type names this module
|
|
1084
1090
|
* imports, so tooling treats both alike. */
|
|
1085
1091
|
readonly aliases: Map<string, Type>;
|
package/dist/index.js
CHANGED
|
@@ -3738,6 +3738,7 @@ var TypeAnalyzer = class {
|
|
|
3738
3738
|
bindingType = /* @__PURE__ */ new Map();
|
|
3739
3739
|
narrowedTypeOf = /* @__PURE__ */ new Map();
|
|
3740
3740
|
typeOfTypeNode = /* @__PURE__ */ new Map();
|
|
3741
|
+
expectedTypeOf = /* @__PURE__ */ new Map();
|
|
3741
3742
|
/** Public: each alias resolved once (generic aliases keep their params as
|
|
3742
3743
|
* `typeParam` nodes in the body). */
|
|
3743
3744
|
aliases = /* @__PURE__ */ new Map();
|
|
@@ -3803,6 +3804,7 @@ var TypeAnalyzer = class {
|
|
|
3803
3804
|
bindingType: this.bindingType,
|
|
3804
3805
|
narrowedTypeOf: this.narrowedTypeOf,
|
|
3805
3806
|
typeOfTypeNode: this.typeOfTypeNode,
|
|
3807
|
+
expectedTypeOf: this.expectedTypeOf,
|
|
3806
3808
|
aliases: this.resolveDeferredAliases(),
|
|
3807
3809
|
diagnostics: this.diagnostics
|
|
3808
3810
|
};
|
|
@@ -4784,16 +4786,76 @@ var TypeAnalyzer = class {
|
|
|
4784
4786
|
return void 0;
|
|
4785
4787
|
}
|
|
4786
4788
|
/** Can this signature be called with these argument types? The signature's
|
|
4787
|
-
* own
|
|
4788
|
-
*
|
|
4789
|
+
* own type parameters stand for what the call would infer, so each is
|
|
4790
|
+
* checked only against its constraint — `<K extends keyof Services>`
|
|
4791
|
+
* accepts `"Players"` but not `""`. */
|
|
4789
4792
|
overloadAccepts(f, argTypes) {
|
|
4790
4793
|
if (!f.varargs && argTypes.length > f.params.length) return false;
|
|
4791
|
-
const
|
|
4794
|
+
const params = this.boundParams(f);
|
|
4792
4795
|
return f.params.every((p, i) => {
|
|
4793
4796
|
if (argTypes[i] === void 0) return p.optional === true;
|
|
4794
|
-
return isAssignable(argTypes[i],
|
|
4797
|
+
return isAssignable(argTypes[i], params[i]);
|
|
4795
4798
|
});
|
|
4796
4799
|
}
|
|
4800
|
+
/** A signature's parameter types as a call site sees them before inference:
|
|
4801
|
+
* each type parameter replaced by its constraint, or by `any` when it has
|
|
4802
|
+
* none — or when the constraint mentions another type parameter, which a
|
|
4803
|
+
* lone argument cannot be checked against without false errors. */
|
|
4804
|
+
boundParams(f) {
|
|
4805
|
+
if (!f.typeParams?.length) return f.params.map((p) => p.type);
|
|
4806
|
+
const bounds = new Map(f.typeParams.map((name) => [name, anyType]));
|
|
4807
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
4808
|
+
const walk = (value) => {
|
|
4809
|
+
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
4810
|
+
seen.add(value);
|
|
4811
|
+
if (value instanceof Map) {
|
|
4812
|
+
value.forEach(walk);
|
|
4813
|
+
return;
|
|
4814
|
+
}
|
|
4815
|
+
const t = value;
|
|
4816
|
+
if (t.kind === "typeParam" && typeof t.name === "string" && bounds.has(t.name) && t.constraint && !containsTypeParam(t.constraint)) {
|
|
4817
|
+
bounds.set(t.name, this.reduceType(t.constraint));
|
|
4818
|
+
}
|
|
4819
|
+
for (const child of Object.values(value)) walk(child);
|
|
4820
|
+
};
|
|
4821
|
+
for (const p of f.params) walk(p.type);
|
|
4822
|
+
return f.params.map((p) => substitute(p.type, bounds));
|
|
4823
|
+
}
|
|
4824
|
+
/** Record what each written argument is expected to be — see
|
|
4825
|
+
* `TypeAnalysis.expectedTypeOf`. */
|
|
4826
|
+
recordExpected(written, fns, selfOf) {
|
|
4827
|
+
written.forEach((arg, j) => {
|
|
4828
|
+
const candidates = [];
|
|
4829
|
+
for (const f of fns) {
|
|
4830
|
+
const i = j + selfOf(f);
|
|
4831
|
+
const param = i < f.params.length ? this.boundParams(f)[i] : f.varargs;
|
|
4832
|
+
if (param) candidates.push(param);
|
|
4833
|
+
}
|
|
4834
|
+
if (candidates.length) this.expectedTypeOf.set(arg, union(candidates));
|
|
4835
|
+
});
|
|
4836
|
+
}
|
|
4837
|
+
/** No signature accepts the call, and the argument count is not the
|
|
4838
|
+
* problem: say which argument is wrong, the way TypeScript does. */
|
|
4839
|
+
reportArguments(call, written, fns, argsFor, selfOf) {
|
|
4840
|
+
if (!this.emitDiagnostics) return;
|
|
4841
|
+
if (fns.length > 1) {
|
|
4842
|
+
this.diagnostics.push({ node: call, message: "No overload matches this call" });
|
|
4843
|
+
return;
|
|
4844
|
+
}
|
|
4845
|
+
const f = fns[0];
|
|
4846
|
+
const args = argsFor(f);
|
|
4847
|
+
const params = this.boundParams(f);
|
|
4848
|
+
const self = selfOf(f);
|
|
4849
|
+
for (let i = 0; i < f.params.length; i++) {
|
|
4850
|
+
const arg = args[i];
|
|
4851
|
+
if (arg === void 0 || isAssignable(arg, params[i])) continue;
|
|
4852
|
+
this.diagnostics.push({
|
|
4853
|
+
node: written[i - self] ?? call,
|
|
4854
|
+
message: `Argument of type '${formatType(arg)}' is not assignable to parameter of type '${briefType(params[i])}'`
|
|
4855
|
+
});
|
|
4856
|
+
return;
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4797
4859
|
/** A required parameter may not follow an optional one — otherwise the
|
|
4798
4860
|
* optional one could never actually be omitted. Same rule as TypeScript,
|
|
4799
4861
|
* and it applies to a default (`a = 1`) as much as to a `?`. */
|
|
@@ -4823,22 +4885,25 @@ var TypeAnalyzer = class {
|
|
|
4823
4885
|
return { min, max: f.varargs ? void 0 : f.params.length };
|
|
4824
4886
|
}
|
|
4825
4887
|
/** Report a call that passes too few or too many arguments. Only fires
|
|
4826
|
-
* when *no* overload accepts the
|
|
4827
|
-
* once, against its first signature.
|
|
4888
|
+
* when *no* overload accepts the count, so an overload set still reports
|
|
4889
|
+
* once, against its first signature. Returns whether the count fits, so
|
|
4890
|
+
* an argument's type is only complained about when its count is right. */
|
|
4828
4891
|
checkArity(node, fns, argCount, selfArgs) {
|
|
4829
|
-
if (!
|
|
4892
|
+
if (!fns.length) return true;
|
|
4830
4893
|
const fits = fns.some((f) => {
|
|
4831
4894
|
const { min: min2, max: max2 } = this.arityOf(f);
|
|
4832
4895
|
const n = argCount + selfArgs;
|
|
4833
4896
|
return n >= min2 && (max2 === void 0 || n <= max2);
|
|
4834
4897
|
});
|
|
4835
|
-
if (fits) return;
|
|
4898
|
+
if (fits) return true;
|
|
4899
|
+
if (!this.emitDiagnostics) return false;
|
|
4836
4900
|
const { min, max } = this.arityOf(fns[0]);
|
|
4837
4901
|
const need = max === void 0 ? `at least ${min - selfArgs}` : min === max ? `${min - selfArgs}` : `${min - selfArgs}-${max - selfArgs}`;
|
|
4838
4902
|
this.diagnostics.push({
|
|
4839
4903
|
node,
|
|
4840
4904
|
message: `Expected ${need} argument${need === "1" ? "" : "s"}, got ${argCount}`
|
|
4841
4905
|
});
|
|
4906
|
+
return false;
|
|
4842
4907
|
}
|
|
4843
4908
|
signatureToFnType(sig) {
|
|
4844
4909
|
const names = sig.generics.map((g) => g.name);
|
|
@@ -5276,11 +5341,13 @@ var TypeAnalyzer = class {
|
|
|
5276
5341
|
const argTypes = expr.arguments.map((a) => this.infer(a, env));
|
|
5277
5342
|
const fns = this.overloadsOf(callee);
|
|
5278
5343
|
if (fns.length) {
|
|
5279
|
-
this.
|
|
5344
|
+
this.recordExpected(expr.arguments, fns, () => 0);
|
|
5345
|
+
const arityFits = this.checkArity(expr, fns, argTypes.length, 0);
|
|
5280
5346
|
const picked = this.pickOverload(fns, argTypes);
|
|
5281
5347
|
if (picked) {
|
|
5282
5348
|
return this.callReturn(picked, this.constArgs(picked, expr.arguments, argTypes, env));
|
|
5283
5349
|
}
|
|
5350
|
+
if (arityFits) this.reportArguments(expr, expr.arguments, fns, () => argTypes, () => 0);
|
|
5284
5351
|
return union(fns.map((f) => this.callReturn(f, argTypes)));
|
|
5285
5352
|
}
|
|
5286
5353
|
return callee.kind === "any" ? anyType : unknownType;
|
|
@@ -5291,13 +5358,16 @@ var TypeAnalyzer = class {
|
|
|
5291
5358
|
const fns = this.overloadsOf(this.propertyType(objType, expr.method.name));
|
|
5292
5359
|
if (fns.length) {
|
|
5293
5360
|
const withSelf = (f) => this.takesSelf(f) ? [objType, ...argTypes] : argTypes;
|
|
5294
|
-
|
|
5361
|
+
const selfOf = (f) => this.takesSelf(f) ? 1 : 0;
|
|
5362
|
+
this.recordExpected(expr.arguments, fns, selfOf);
|
|
5363
|
+
const arityFits = this.checkArity(expr, fns, argTypes.length, this.takesSelf(fns[0]) ? 1 : 0);
|
|
5295
5364
|
const picked = this.pickOverload(fns, argTypes, withSelf);
|
|
5296
5365
|
if (picked) {
|
|
5297
5366
|
const self = this.takesSelf(picked) ? 1 : 0;
|
|
5298
5367
|
const written = this.constArgs(picked, expr.arguments, argTypes, env, self);
|
|
5299
5368
|
return this.callReturn(picked, this.takesSelf(picked) ? [objType, ...written] : written);
|
|
5300
5369
|
}
|
|
5370
|
+
if (arityFits) this.reportArguments(expr, expr.arguments, fns, withSelf, selfOf);
|
|
5301
5371
|
return union(fns.map((f) => this.callReturn(f, withSelf(f))));
|
|
5302
5372
|
}
|
|
5303
5373
|
return objType.kind === "any" ? anyType : unknownType;
|
|
@@ -5745,6 +5815,13 @@ function containsTypeQuery(node) {
|
|
|
5745
5815
|
if (node.type === "TypeofTypeNode") return true;
|
|
5746
5816
|
return Object.values(node).some(containsTypeQuery);
|
|
5747
5817
|
}
|
|
5818
|
+
function briefType(t) {
|
|
5819
|
+
if (t.kind === "union" && t.types.length > 8) {
|
|
5820
|
+
const shown = t.types.slice(0, 6).map(formatType).join(" | ");
|
|
5821
|
+
return `${shown} | ... ${t.types.length - 6} more`;
|
|
5822
|
+
}
|
|
5823
|
+
return formatType(t);
|
|
5824
|
+
}
|
|
5748
5825
|
|
|
5749
5826
|
// src/lib/luau.ts
|
|
5750
5827
|
import { readFileSync } from "fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "luaut-parser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "luaut parser for roblox",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -36,8 +36,5 @@
|
|
|
36
36
|
"tsup": "^8.5.1",
|
|
37
37
|
"tsx": "^4.19.0",
|
|
38
38
|
"typescript": "^5.0.4"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"luaut-parser": "^1.0.0"
|
|
42
39
|
}
|
|
43
40
|
}
|