@tilua/parser 1.0.1 → 1.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/README.md CHANGED
@@ -298,6 +298,18 @@ call needed it — and the receiver is passed as the call's first argument. An
298
298
  answer of `undefined` leaves an ordinary Luau method call, which is what
299
299
  `text:upper()` wants, since a string already answers to it.
300
300
 
301
+ A call can also carry more than was written. Every hook is told `at`, where
302
+ the call was written (`{ file, line, column }`), and `arguments`: each one's
303
+ type, that type as text, the code it was written as, and, for a name, the
304
+ code of what it names. An answer's `prepend` lists Luau expressions to pass
305
+ ahead of the written arguments. `globalCall` answers for a call to a global,
306
+ such as `print(x)`, and `globalValue` for a global read as a value, such as
307
+ `local p = print`. A local with the same name belongs to the author, and no
308
+ hook is asked about it. A runtime can read `__LINES__`, the bundle's line map
309
+ (`nil` outside a bundle), to turn a line Luau reports back into a place in the
310
+ project. `console:log`, `print` and `error` in `@tilua-types/lua` are built on
311
+ these hooks.
312
+
301
313
  The compiler lowers the language and nothing else: `filter` appears nowhere in
302
314
  it.
303
315
 
@@ -406,6 +418,14 @@ method's type is `(this: Dog, ...) => R`, so `rex:speak()` supplies it the way
406
418
  `function T:m()` supplies `self`. `new Dog(x)` *is* `Dog.new(x)` — the same
407
419
  function, callable by hand and passable as a value.
408
420
 
421
+ **`public` and `private`** go before a member — `private balance = 0`,
422
+ `private static function check()`, `public get size()`. Leaving it out means
423
+ public. A private member can be reached only inside the body of the class that
424
+ declared it, including functions nested in its methods; a subclass is outside,
425
+ as in TypeScript. It is a type check and nothing more: the member is an
426
+ ordinary key at runtime. `public` and `private` stay ordinary names elsewhere,
427
+ so `private: boolean` is still a field.
428
+
409
429
  A declaration names two things. As a **type**, `Dog` is the type of its
410
430
  instances, nominal the same way a `declare class` is: a table with the same
411
431
  members is not one, and only `Dog` and what extends it are assignable to it.
package/dist/index.cjs CHANGED
@@ -1830,6 +1830,19 @@ var Parser = class {
1830
1830
  }
1831
1831
  parseClassMember() {
1832
1832
  const start = this.current();
1833
+ let accessibility;
1834
+ if ((this.checkIdentifierValue("public") || this.checkIdentifierValue("private")) && !this.punctuatorAt(1, ":") && !this.operatorAt(1, "=") && !this.punctuatorAt(1, "(")) {
1835
+ accessibility = this.advance().value;
1836
+ }
1837
+ const member = this.parseClassMemberAfterAccessibility(start);
1838
+ if (!accessibility || !member) return member;
1839
+ if (member.type === "ClassConstructor") {
1840
+ this.problem(`A constructor cannot be '${accessibility}'`);
1841
+ return member;
1842
+ }
1843
+ return { ...member, accessibility };
1844
+ }
1845
+ parseClassMemberAfterAccessibility(start) {
1833
1846
  const isStatic = this.checkIdentifierValue("static") && !this.punctuatorAt(1, ":") && !this.operatorAt(1, "=");
1834
1847
  if (isStatic) this.advance();
1835
1848
  if (this.checkKeyword("function")) {
@@ -4498,7 +4511,12 @@ function substitute(t, subst) {
4498
4511
  return t.name && r.kind === "intersection" && !r.name ? { ...r, name: t.name } : r;
4499
4512
  }
4500
4513
  case "genericRef":
4501
- return { kind: "genericRef", name: t.name, typeArguments: t.typeArguments.map((a) => substitute(a, subst)) };
4514
+ return {
4515
+ kind: "genericRef",
4516
+ name: t.name,
4517
+ typeArguments: t.typeArguments.map((a) => substitute(a, subst)),
4518
+ ...t.origin ? { origin: t.origin } : {}
4519
+ };
4502
4520
  case "keyof":
4503
4521
  return { kind: "keyof", target: substitute(t.target, subst) };
4504
4522
  case "templateLiteral":
@@ -4658,6 +4676,7 @@ function optional(t) {
4658
4676
  return union([t, nilType]);
4659
4677
  }
4660
4678
  function widen(t) {
4679
+ if (isAliasNamed(t)) return t;
4661
4680
  switch (t.kind) {
4662
4681
  case "literal":
4663
4682
  return primitive(t.base);
@@ -4697,7 +4716,7 @@ function isAssignable(rawA, rawB) {
4697
4716
  if (expandAlias) {
4698
4717
  if (a.kind === "genericRef" && b.kind !== "genericRef") a = expandAlias(a);
4699
4718
  else if (b.kind === "genericRef" && a.kind !== "genericRef") b = expandAlias(b);
4700
- else if (a.kind === "genericRef" && b.kind === "genericRef" && a.name !== b.name) {
4719
+ else if (a.kind === "genericRef" && b.kind === "genericRef" && !sameRefTarget(a, b)) {
4701
4720
  a = expandAlias(a);
4702
4721
  b = expandAlias(b);
4703
4722
  }
@@ -4807,10 +4826,17 @@ function isAssignableInner(a, b) {
4807
4826
  }
4808
4827
  if (b.kind === "typeParam") return false;
4809
4828
  if (a.kind === "genericRef" || b.kind === "genericRef") {
4810
- return a.kind === "genericRef" && b.kind === "genericRef" && a.name === b.name && a.typeArguments.length === b.typeArguments.length && a.typeArguments.every((x, i) => equalTypes(x, b.typeArguments[i]));
4829
+ return a.kind === "genericRef" && b.kind === "genericRef" && sameRefTarget(a, b) && a.typeArguments.length === b.typeArguments.length && a.typeArguments.every((x, i) => equalTypes(x, b.typeArguments[i]));
4811
4830
  }
4812
4831
  return false;
4813
4832
  }
4833
+ function isAliasNamed(t) {
4834
+ if (t.kind === "object" || t.kind === "intersection") return t.name !== void 0;
4835
+ return t.alias !== void 0;
4836
+ }
4837
+ function sameRefTarget(a, b) {
4838
+ return a.name === b.name && (!a.origin || !b.origin || a.origin === b.origin);
4839
+ }
4814
4840
  function isNoValue(t) {
4815
4841
  return t.kind === "tuple" && t.elements.length === 0;
4816
4842
  }
@@ -5596,6 +5622,9 @@ var TypeAnalyzer = class {
5596
5622
  aliases = new AliasMap();
5597
5623
  /** Uninstantiated alias definitions, for `Name<Args>` instantiation. */
5598
5624
  aliasDefs = /* @__PURE__ */ new Map();
5625
+ /** Put on every ref to one of `aliasDefs`, so a module that imports the
5626
+ * type expands the ref here rather than by its name there. */
5627
+ origin = { expand: (t) => this.expand(t) };
5599
5628
  /** See `resolveClass`. */
5600
5629
  classTypes = /* @__PURE__ */ new WeakMap();
5601
5630
  /** See `instanceType` — one instance type per `class ... end`. */
@@ -5880,13 +5909,18 @@ var TypeAnalyzer = class {
5880
5909
  classIdentityCount = 0;
5881
5910
  /** The class whose members are being read, so `super` knows its base. */
5882
5911
  currentClass;
5912
+ /** Every class whose body the checker is inside, innermost last — what
5913
+ * decides whether a `private` member may be reached. */
5914
+ enclosingClasses = [];
5883
5915
  withClass(stmt, fn2) {
5884
5916
  const previous = this.currentClass;
5885
5917
  this.currentClass = stmt;
5918
+ this.enclosingClasses.push(stmt);
5886
5919
  try {
5887
5920
  return fn2();
5888
5921
  } finally {
5889
5922
  this.currentClass = previous;
5923
+ this.enclosingClasses.pop();
5890
5924
  }
5891
5925
  }
5892
5926
  /** What the class is known by. A declaration is known by its name, the way
@@ -6004,7 +6038,8 @@ var TypeAnalyzer = class {
6004
6038
  return {
6005
6039
  kind: "genericRef",
6006
6040
  name: stmt.name.name,
6007
- typeArguments: params.map((p) => typeParam(p.name, p.constraint ? this.resolveType(p.constraint) : void 0))
6041
+ typeArguments: params.map((p) => typeParam(p.name, p.constraint ? this.resolveType(p.constraint) : void 0)),
6042
+ origin: this.origin
6008
6043
  };
6009
6044
  }
6010
6045
  /** The class table: the statics, what it inherits from the class it
@@ -6103,8 +6138,11 @@ var TypeAnalyzer = class {
6103
6138
  return shape;
6104
6139
  }
6105
6140
  fillShape(stmt, shape) {
6141
+ const className = this.className(stmt);
6106
6142
  const put = (isStatic, name, property) => {
6107
- (isStatic ? shape.statics : shape.instance).set(name, property);
6143
+ const member = stmt.members.find((m) => m.type !== "ClassConstructor" && m.isStatic === isStatic && m.name.name === name && m.accessibility === "private");
6144
+ const marked = member ? { ...property, private: { owner: stmt, className } } : property;
6145
+ (isStatic ? shape.statics : shape.instance).set(name, marked);
6108
6146
  };
6109
6147
  for (const member of stmt.members) {
6110
6148
  if (member.type !== "ClassField") continue;
@@ -6569,7 +6607,8 @@ var TypeAnalyzer = class {
6569
6607
  return this.expand({
6570
6608
  kind: "genericRef",
6571
6609
  name: node.base,
6572
- typeArguments: node.typeArguments.map((a) => this.resolveType(a))
6610
+ typeArguments: node.typeArguments.map((a) => this.resolveType(a)),
6611
+ origin: this.origin
6573
6612
  });
6574
6613
  }
6575
6614
  const imported = this.importedTypes.get(node.base);
@@ -6582,7 +6621,8 @@ var TypeAnalyzer = class {
6582
6621
  return this.expand({
6583
6622
  kind: "genericRef",
6584
6623
  name,
6585
- typeArguments: node.typeArguments.map((a) => this.resolveType(a))
6624
+ typeArguments: node.typeArguments.map((a) => this.resolveType(a)),
6625
+ origin: this.origin
6586
6626
  });
6587
6627
  }
6588
6628
  return {
@@ -8408,6 +8448,7 @@ var TypeAnalyzer = class {
8408
8448
  * resolving, which is what breaks re-entry on a recursive alias. */
8409
8449
  expand(t) {
8410
8450
  if (t.kind !== "genericRef") return t;
8451
+ if (t.origin && t.origin !== this.origin) return t.origin.expand(t);
8411
8452
  const def = this.aliasDefs.get(t.name);
8412
8453
  if (!def) {
8413
8454
  const imported = this.importedTypes.get(t.name);
@@ -8558,6 +8599,28 @@ var TypeAnalyzer = class {
8558
8599
  message: names.length === 1 ? `'${names[0]}' does not exist on a string` : `'${briefType(key)}' does not name a member of a string`
8559
8600
  });
8560
8601
  }
8602
+ /** A `private` member read from outside the class that declared it —
8603
+ * a subclass counts as outside, as in TypeScript. */
8604
+ checkPrivateMember(node, object, name) {
8605
+ if (!this.emitDiagnostics) return;
8606
+ const raw = this.expand(object);
8607
+ for (const part of raw.kind === "union" ? raw.types : [raw]) {
8608
+ const t = this.deferredAccess(this.expand(part));
8609
+ if (t.kind !== "object") continue;
8610
+ const access = t.properties.get(name)?.private;
8611
+ if (!access || this.insideClass(access.owner)) continue;
8612
+ this.diagnostics.push({
8613
+ node,
8614
+ message: `Property '${name}' is private and only accessible within class '${access.className}'`
8615
+ });
8616
+ return;
8617
+ }
8618
+ }
8619
+ /** Is the code being checked written inside `owner`'s body — its own
8620
+ * methods, or a class or function nested in them? */
8621
+ insideClass(owner) {
8622
+ return this.enclosingClasses.includes(owner);
8623
+ }
8561
8624
  propertyType(raw, name) {
8562
8625
  const t = this.deferredAccess(this.expand(raw));
8563
8626
  if (t.kind === "object") {
@@ -8775,6 +8838,7 @@ var TypeAnalyzer = class {
8775
8838
  }
8776
8839
  case "MemberExpression": {
8777
8840
  const { type: obj, shortCircuits } = this.chainObject(expr, expr.object, env);
8841
+ this.checkPrivateMember(expr.property, obj, expr.property.name);
8778
8842
  const key = this.refKeyOf(expr);
8779
8843
  const narrowed = key === void 0 ? void 0 : env.get(key);
8780
8844
  this.checkStringMember(expr, obj, literal(expr.property.name));
@@ -8910,6 +8974,7 @@ var TypeAnalyzer = class {
8910
8974
  });
8911
8975
  }
8912
8976
  inferMethodCall(expr, objType, env) {
8977
+ this.checkPrivateMember(expr.method, objType, expr.method.name);
8913
8978
  const method = this.propertyType(objType, expr.method.name);
8914
8979
  const united = this.unionSignatures(method);
8915
8980
  const fns = united ?? this.overloadsOf(method);
package/dist/index.d.cts CHANGED
@@ -377,11 +377,16 @@ type ClassMember = ClassField | ClassMethod | ClassAccessor | ClassConstructor;
377
377
  /** The two ways a class is written. Everything after parsing treats them
378
378
  * alike: only the name and the type parameters differ. */
379
379
  type ClassLike = ClassDeclaration | ClassExpression;
380
+ /** `public` / `private` written before a member. Only the type checker reads
381
+ * it: a private member is still an ordinary key at runtime. */
382
+ type ClassAccessibility = "public" | "private";
380
383
  /** `x: number` / `x = 1` / `static count = 0`. An instance field is assigned
381
384
  * when the instance is built, before the constructor body runs; a `static`
382
385
  * one is assigned on the class table, once. */
383
386
  interface ClassField extends BaseNode {
384
387
  type: "ClassField";
388
+ /** Left out, the member is public. */
389
+ accessibility?: ClassAccessibility;
385
390
  name: Identifier;
386
391
  isStatic: boolean;
387
392
  typeAnnotation?: TypeNode;
@@ -391,6 +396,8 @@ interface ClassField extends BaseNode {
391
396
  * A `static` one is a plain function on the class table, with no `this`. */
392
397
  interface ClassMethod extends BaseNode {
393
398
  type: "ClassMethod";
399
+ /** Left out, the member is public. */
400
+ accessibility?: ClassAccessibility;
394
401
  name: Identifier;
395
402
  isStatic: boolean;
396
403
  func: FunctionBody;
@@ -401,6 +408,8 @@ interface ClassMethod extends BaseNode {
401
408
  * property, run as a function. */
402
409
  interface ClassAccessor extends BaseNode {
403
410
  type: "ClassAccessor";
411
+ /** Left out, the member is public. */
412
+ accessibility?: ClassAccessibility;
404
413
  kind: "get" | "set";
405
414
  name: Identifier;
406
415
  isStatic: boolean;
@@ -1117,6 +1126,13 @@ interface ObjectProperty {
1117
1126
  type: Type;
1118
1127
  optional: boolean;
1119
1128
  readonly?: boolean;
1129
+ /** A class member written `private`: reachable only from inside the class
1130
+ * that declared it. `owner` is that class's node, compared by identity;
1131
+ * `className` is how a diagnostic names it. Checked, never lowered. */
1132
+ private?: {
1133
+ owner: object;
1134
+ className: string;
1135
+ };
1120
1136
  }
1121
1137
  interface ObjectType {
1122
1138
  kind: "object";
@@ -1223,6 +1239,15 @@ interface GenericRefType {
1223
1239
  kind: "genericRef";
1224
1240
  name: string;
1225
1241
  typeArguments: Type[];
1242
+ /** The module whose alias this names. A recursive alias is left as a ref
1243
+ * inside its own structure, and that ref travels with the type into every
1244
+ * module that imports it — where `name` may mean nothing, or a different
1245
+ * type. Expanding through `origin` reads the name where it was written. */
1246
+ origin?: TypeOrigin;
1247
+ }
1248
+ /** A module's own alias resolution, handed out on the refs it creates. */
1249
+ interface TypeOrigin {
1250
+ expand(t: GenericRefType): Type;
1226
1251
  }
1227
1252
  /** `keyof T`. */
1228
1253
  interface KeyofType {
@@ -1600,9 +1625,20 @@ declare function resolveTypeLibraries(config: TiluaConfig, host?: ProjectHost):
1600
1625
 
1601
1626
  interface LoweringPlugin {
1602
1627
  /** Luau the plugin needs in the output, by a key it chooses. Each is a
1603
- * file's worth of source with `__NAME__` standing for the local the
1604
- * compiler gives it, and each is emitted once, at the top of the output,
1605
- * only if `use` asked for it:
1628
+ * file's worth of source, emitted once, at the top of the output, only if
1629
+ * `use` asked for it. Two names in it are filled in by the compiler:
1630
+ *
1631
+ * - `__NAME__`, the local the compiler gives this runtime;
1632
+ * - `__LINES__`, an expression holding the bundle's line map —
1633
+ * `{ [bundleLine] = { "src/a.tilua", sourceLine } }` — or `nil` when
1634
+ * the output is not a bundle. It is what turns a line Luau reports at
1635
+ * runtime back into a place in the project;
1636
+ * - `__FAIL__`, the bundle's error reporter, or `nil` outside a bundle:
1637
+ * a function that takes an error and returns it with the bundle's
1638
+ * positions replaced by the project's, followed by a traceback of
1639
+ * those. It is an `xpcall` handler — the one the entry runs under —
1640
+ * so a runtime that runs a callback on a thread of its own can report
1641
+ * that callback's errors the same way.
1606
1642
  *
1607
1643
  * local __NAME__ = {}
1608
1644
  * function __NAME__.filter(t, test) ... end
@@ -1612,24 +1648,84 @@ interface LoweringPlugin {
1612
1648
  * method call, which is what a value that answers to the method itself
1613
1649
  * wants — `text:upper()` reaches Lua's own. */
1614
1650
  methodCall?(call: MethodCall): MethodLowering | undefined;
1651
+ /** What a call to a global — `print(...)`, `error(...)` — becomes. Asked
1652
+ * only when the name really is the global: a local the author called
1653
+ * `print` is theirs. `undefined` leaves the call as it was written. */
1654
+ globalCall?(call: GlobalCall): CallLowering | undefined;
1655
+ /** What a global read as a value — `task.spawn(print, x)`, `local p =
1656
+ * print` — becomes: a Luau expression, usually built from `use(...)`.
1657
+ * There is no call site to describe here, so this is where a plugin
1658
+ * that rewrites calls keeps the rest of the program consistent with it. */
1659
+ globalValue?(value: GlobalValue): string | undefined;
1660
+ }
1661
+ /** Where a call was written. */
1662
+ interface CallSite {
1663
+ /** The file, relative to the project root with `/` separators, or
1664
+ * `undefined` when a single source was compiled with no name. */
1665
+ readonly file: string | undefined;
1666
+ /** 1-based. */
1667
+ readonly line: number;
1668
+ /** 1-based. */
1669
+ readonly column: number;
1670
+ }
1671
+ /** What the compiler knows about one argument that the runtime will not. */
1672
+ interface ArgumentInfo {
1673
+ /** Its type, as the analyzer worked it out. */
1674
+ readonly type: Type | undefined;
1675
+ /** That type as the editor would show it — `(x: number) => number` —
1676
+ * so a library can print it without depending on this package. */
1677
+ readonly typeText: string | undefined;
1678
+ /** The code it was written as, at the call. */
1679
+ readonly source: string;
1680
+ /** For a name, the code of what it names — the value of `const f = ...`,
1681
+ * or the whole `function f() { ... }` — when this file declares it. */
1682
+ readonly declaration?: string;
1683
+ /** Written `...xs`. */
1684
+ readonly spread: boolean;
1685
+ }
1686
+ interface CallContext {
1687
+ /** Where the call was written. */
1688
+ readonly at: CallSite;
1689
+ /** Each written argument, in order. */
1690
+ readonly arguments: readonly ArgumentInfo[];
1691
+ /** The local name the output gives one of `runtime`'s entries, emitting
1692
+ * it if this is the first call that needed it. */
1693
+ use(runtime: string): string;
1615
1694
  }
1616
- interface MethodCall {
1695
+ interface MethodCall extends CallContext {
1617
1696
  /** The name written after `:`. */
1618
1697
  readonly method: string;
1619
1698
  /** The receiver's type, as the analyzer worked it out. `undefined` when
1620
1699
  * nothing typed it, where a plugin should decline rather than guess. */
1621
1700
  readonly receiver: Type | undefined;
1701
+ /** The receiver's name when it is a global — `console` in
1702
+ * `console:log(x)` — and `undefined` for anything else, a local of the
1703
+ * same name included. */
1704
+ readonly receiverGlobal: string | undefined;
1622
1705
  /** How many arguments were written. */
1623
1706
  readonly argumentCount: number;
1624
- /** The local name the output gives one of `runtime`'s entries, emitting
1625
- * it if this is the first call that needed it. */
1707
+ }
1708
+ interface GlobalCall extends CallContext {
1709
+ /** The global called. */
1710
+ readonly name: string;
1711
+ }
1712
+ interface GlobalValue {
1713
+ /** The global read. */
1714
+ readonly name: string;
1715
+ readonly at: CallSite;
1626
1716
  use(runtime: string): string;
1627
1717
  }
1628
- interface MethodLowering {
1718
+ interface CallLowering {
1629
1719
  /** What to call instead: a name, or a `table.member` path — usually built
1630
1720
  * from `use(...)`. */
1631
1721
  readonly callee: string;
1632
- /** Pass the receiver as the first argument. Default: yes. */
1722
+ /** Luau expressions passed ahead of the written arguments — the call
1723
+ * site, say, or a table of what the compiler knew about them. */
1724
+ readonly prepend?: readonly string[];
1725
+ }
1726
+ interface MethodLowering extends CallLowering {
1727
+ /** Pass the receiver as the first argument, after `prepend`. Default:
1728
+ * yes. */
1633
1729
  readonly passReceiver?: boolean;
1634
1730
  }
1635
1731
 
@@ -1679,4 +1775,4 @@ declare const tilua: {
1679
1775
  readonly analyzeTypes: typeof analyzeTypes;
1680
1776
  };
1681
1777
 
1682
- export { type AnalyzeTypesOptions, type AnyType, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallStatement, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
1778
+ export { type AnalyzeTypesOptions, type AnyType, type ArgumentInfo, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallLowering, type CallSite, type CallStatement, type ClassAccessibility, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type GlobalCall, type GlobalValue, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypeOrigin, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
package/dist/index.d.ts CHANGED
@@ -377,11 +377,16 @@ type ClassMember = ClassField | ClassMethod | ClassAccessor | ClassConstructor;
377
377
  /** The two ways a class is written. Everything after parsing treats them
378
378
  * alike: only the name and the type parameters differ. */
379
379
  type ClassLike = ClassDeclaration | ClassExpression;
380
+ /** `public` / `private` written before a member. Only the type checker reads
381
+ * it: a private member is still an ordinary key at runtime. */
382
+ type ClassAccessibility = "public" | "private";
380
383
  /** `x: number` / `x = 1` / `static count = 0`. An instance field is assigned
381
384
  * when the instance is built, before the constructor body runs; a `static`
382
385
  * one is assigned on the class table, once. */
383
386
  interface ClassField extends BaseNode {
384
387
  type: "ClassField";
388
+ /** Left out, the member is public. */
389
+ accessibility?: ClassAccessibility;
385
390
  name: Identifier;
386
391
  isStatic: boolean;
387
392
  typeAnnotation?: TypeNode;
@@ -391,6 +396,8 @@ interface ClassField extends BaseNode {
391
396
  * A `static` one is a plain function on the class table, with no `this`. */
392
397
  interface ClassMethod extends BaseNode {
393
398
  type: "ClassMethod";
399
+ /** Left out, the member is public. */
400
+ accessibility?: ClassAccessibility;
394
401
  name: Identifier;
395
402
  isStatic: boolean;
396
403
  func: FunctionBody;
@@ -401,6 +408,8 @@ interface ClassMethod extends BaseNode {
401
408
  * property, run as a function. */
402
409
  interface ClassAccessor extends BaseNode {
403
410
  type: "ClassAccessor";
411
+ /** Left out, the member is public. */
412
+ accessibility?: ClassAccessibility;
404
413
  kind: "get" | "set";
405
414
  name: Identifier;
406
415
  isStatic: boolean;
@@ -1117,6 +1126,13 @@ interface ObjectProperty {
1117
1126
  type: Type;
1118
1127
  optional: boolean;
1119
1128
  readonly?: boolean;
1129
+ /** A class member written `private`: reachable only from inside the class
1130
+ * that declared it. `owner` is that class's node, compared by identity;
1131
+ * `className` is how a diagnostic names it. Checked, never lowered. */
1132
+ private?: {
1133
+ owner: object;
1134
+ className: string;
1135
+ };
1120
1136
  }
1121
1137
  interface ObjectType {
1122
1138
  kind: "object";
@@ -1223,6 +1239,15 @@ interface GenericRefType {
1223
1239
  kind: "genericRef";
1224
1240
  name: string;
1225
1241
  typeArguments: Type[];
1242
+ /** The module whose alias this names. A recursive alias is left as a ref
1243
+ * inside its own structure, and that ref travels with the type into every
1244
+ * module that imports it — where `name` may mean nothing, or a different
1245
+ * type. Expanding through `origin` reads the name where it was written. */
1246
+ origin?: TypeOrigin;
1247
+ }
1248
+ /** A module's own alias resolution, handed out on the refs it creates. */
1249
+ interface TypeOrigin {
1250
+ expand(t: GenericRefType): Type;
1226
1251
  }
1227
1252
  /** `keyof T`. */
1228
1253
  interface KeyofType {
@@ -1600,9 +1625,20 @@ declare function resolveTypeLibraries(config: TiluaConfig, host?: ProjectHost):
1600
1625
 
1601
1626
  interface LoweringPlugin {
1602
1627
  /** Luau the plugin needs in the output, by a key it chooses. Each is a
1603
- * file's worth of source with `__NAME__` standing for the local the
1604
- * compiler gives it, and each is emitted once, at the top of the output,
1605
- * only if `use` asked for it:
1628
+ * file's worth of source, emitted once, at the top of the output, only if
1629
+ * `use` asked for it. Two names in it are filled in by the compiler:
1630
+ *
1631
+ * - `__NAME__`, the local the compiler gives this runtime;
1632
+ * - `__LINES__`, an expression holding the bundle's line map —
1633
+ * `{ [bundleLine] = { "src/a.tilua", sourceLine } }` — or `nil` when
1634
+ * the output is not a bundle. It is what turns a line Luau reports at
1635
+ * runtime back into a place in the project;
1636
+ * - `__FAIL__`, the bundle's error reporter, or `nil` outside a bundle:
1637
+ * a function that takes an error and returns it with the bundle's
1638
+ * positions replaced by the project's, followed by a traceback of
1639
+ * those. It is an `xpcall` handler — the one the entry runs under —
1640
+ * so a runtime that runs a callback on a thread of its own can report
1641
+ * that callback's errors the same way.
1606
1642
  *
1607
1643
  * local __NAME__ = {}
1608
1644
  * function __NAME__.filter(t, test) ... end
@@ -1612,24 +1648,84 @@ interface LoweringPlugin {
1612
1648
  * method call, which is what a value that answers to the method itself
1613
1649
  * wants — `text:upper()` reaches Lua's own. */
1614
1650
  methodCall?(call: MethodCall): MethodLowering | undefined;
1651
+ /** What a call to a global — `print(...)`, `error(...)` — becomes. Asked
1652
+ * only when the name really is the global: a local the author called
1653
+ * `print` is theirs. `undefined` leaves the call as it was written. */
1654
+ globalCall?(call: GlobalCall): CallLowering | undefined;
1655
+ /** What a global read as a value — `task.spawn(print, x)`, `local p =
1656
+ * print` — becomes: a Luau expression, usually built from `use(...)`.
1657
+ * There is no call site to describe here, so this is where a plugin
1658
+ * that rewrites calls keeps the rest of the program consistent with it. */
1659
+ globalValue?(value: GlobalValue): string | undefined;
1660
+ }
1661
+ /** Where a call was written. */
1662
+ interface CallSite {
1663
+ /** The file, relative to the project root with `/` separators, or
1664
+ * `undefined` when a single source was compiled with no name. */
1665
+ readonly file: string | undefined;
1666
+ /** 1-based. */
1667
+ readonly line: number;
1668
+ /** 1-based. */
1669
+ readonly column: number;
1670
+ }
1671
+ /** What the compiler knows about one argument that the runtime will not. */
1672
+ interface ArgumentInfo {
1673
+ /** Its type, as the analyzer worked it out. */
1674
+ readonly type: Type | undefined;
1675
+ /** That type as the editor would show it — `(x: number) => number` —
1676
+ * so a library can print it without depending on this package. */
1677
+ readonly typeText: string | undefined;
1678
+ /** The code it was written as, at the call. */
1679
+ readonly source: string;
1680
+ /** For a name, the code of what it names — the value of `const f = ...`,
1681
+ * or the whole `function f() { ... }` — when this file declares it. */
1682
+ readonly declaration?: string;
1683
+ /** Written `...xs`. */
1684
+ readonly spread: boolean;
1685
+ }
1686
+ interface CallContext {
1687
+ /** Where the call was written. */
1688
+ readonly at: CallSite;
1689
+ /** Each written argument, in order. */
1690
+ readonly arguments: readonly ArgumentInfo[];
1691
+ /** The local name the output gives one of `runtime`'s entries, emitting
1692
+ * it if this is the first call that needed it. */
1693
+ use(runtime: string): string;
1615
1694
  }
1616
- interface MethodCall {
1695
+ interface MethodCall extends CallContext {
1617
1696
  /** The name written after `:`. */
1618
1697
  readonly method: string;
1619
1698
  /** The receiver's type, as the analyzer worked it out. `undefined` when
1620
1699
  * nothing typed it, where a plugin should decline rather than guess. */
1621
1700
  readonly receiver: Type | undefined;
1701
+ /** The receiver's name when it is a global — `console` in
1702
+ * `console:log(x)` — and `undefined` for anything else, a local of the
1703
+ * same name included. */
1704
+ readonly receiverGlobal: string | undefined;
1622
1705
  /** How many arguments were written. */
1623
1706
  readonly argumentCount: number;
1624
- /** The local name the output gives one of `runtime`'s entries, emitting
1625
- * it if this is the first call that needed it. */
1707
+ }
1708
+ interface GlobalCall extends CallContext {
1709
+ /** The global called. */
1710
+ readonly name: string;
1711
+ }
1712
+ interface GlobalValue {
1713
+ /** The global read. */
1714
+ readonly name: string;
1715
+ readonly at: CallSite;
1626
1716
  use(runtime: string): string;
1627
1717
  }
1628
- interface MethodLowering {
1718
+ interface CallLowering {
1629
1719
  /** What to call instead: a name, or a `table.member` path — usually built
1630
1720
  * from `use(...)`. */
1631
1721
  readonly callee: string;
1632
- /** Pass the receiver as the first argument. Default: yes. */
1722
+ /** Luau expressions passed ahead of the written arguments — the call
1723
+ * site, say, or a table of what the compiler knew about them. */
1724
+ readonly prepend?: readonly string[];
1725
+ }
1726
+ interface MethodLowering extends CallLowering {
1727
+ /** Pass the receiver as the first argument, after `prepend`. Default:
1728
+ * yes. */
1633
1729
  readonly passReceiver?: boolean;
1634
1730
  }
1635
1731
 
@@ -1679,4 +1775,4 @@ declare const tilua: {
1679
1775
  readonly analyzeTypes: typeof analyzeTypes;
1680
1776
  };
1681
1777
 
1682
- export { type AnalyzeTypesOptions, type AnyType, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallStatement, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
1778
+ export { type AnalyzeTypesOptions, type AnyType, type ArgumentInfo, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallLowering, type CallSite, type CallStatement, type ClassAccessibility, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type GlobalCall, type GlobalValue, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypeOrigin, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
package/dist/index.js CHANGED
@@ -1727,6 +1727,19 @@ var Parser = class {
1727
1727
  }
1728
1728
  parseClassMember() {
1729
1729
  const start = this.current();
1730
+ let accessibility;
1731
+ if ((this.checkIdentifierValue("public") || this.checkIdentifierValue("private")) && !this.punctuatorAt(1, ":") && !this.operatorAt(1, "=") && !this.punctuatorAt(1, "(")) {
1732
+ accessibility = this.advance().value;
1733
+ }
1734
+ const member = this.parseClassMemberAfterAccessibility(start);
1735
+ if (!accessibility || !member) return member;
1736
+ if (member.type === "ClassConstructor") {
1737
+ this.problem(`A constructor cannot be '${accessibility}'`);
1738
+ return member;
1739
+ }
1740
+ return { ...member, accessibility };
1741
+ }
1742
+ parseClassMemberAfterAccessibility(start) {
1730
1743
  const isStatic = this.checkIdentifierValue("static") && !this.punctuatorAt(1, ":") && !this.operatorAt(1, "=");
1731
1744
  if (isStatic) this.advance();
1732
1745
  if (this.checkKeyword("function")) {
@@ -4395,7 +4408,12 @@ function substitute(t, subst) {
4395
4408
  return t.name && r.kind === "intersection" && !r.name ? { ...r, name: t.name } : r;
4396
4409
  }
4397
4410
  case "genericRef":
4398
- return { kind: "genericRef", name: t.name, typeArguments: t.typeArguments.map((a) => substitute(a, subst)) };
4411
+ return {
4412
+ kind: "genericRef",
4413
+ name: t.name,
4414
+ typeArguments: t.typeArguments.map((a) => substitute(a, subst)),
4415
+ ...t.origin ? { origin: t.origin } : {}
4416
+ };
4399
4417
  case "keyof":
4400
4418
  return { kind: "keyof", target: substitute(t.target, subst) };
4401
4419
  case "templateLiteral":
@@ -4555,6 +4573,7 @@ function optional(t) {
4555
4573
  return union([t, nilType]);
4556
4574
  }
4557
4575
  function widen(t) {
4576
+ if (isAliasNamed(t)) return t;
4558
4577
  switch (t.kind) {
4559
4578
  case "literal":
4560
4579
  return primitive(t.base);
@@ -4594,7 +4613,7 @@ function isAssignable(rawA, rawB) {
4594
4613
  if (expandAlias) {
4595
4614
  if (a.kind === "genericRef" && b.kind !== "genericRef") a = expandAlias(a);
4596
4615
  else if (b.kind === "genericRef" && a.kind !== "genericRef") b = expandAlias(b);
4597
- else if (a.kind === "genericRef" && b.kind === "genericRef" && a.name !== b.name) {
4616
+ else if (a.kind === "genericRef" && b.kind === "genericRef" && !sameRefTarget(a, b)) {
4598
4617
  a = expandAlias(a);
4599
4618
  b = expandAlias(b);
4600
4619
  }
@@ -4704,10 +4723,17 @@ function isAssignableInner(a, b) {
4704
4723
  }
4705
4724
  if (b.kind === "typeParam") return false;
4706
4725
  if (a.kind === "genericRef" || b.kind === "genericRef") {
4707
- return a.kind === "genericRef" && b.kind === "genericRef" && a.name === b.name && a.typeArguments.length === b.typeArguments.length && a.typeArguments.every((x, i) => equalTypes(x, b.typeArguments[i]));
4726
+ return a.kind === "genericRef" && b.kind === "genericRef" && sameRefTarget(a, b) && a.typeArguments.length === b.typeArguments.length && a.typeArguments.every((x, i) => equalTypes(x, b.typeArguments[i]));
4708
4727
  }
4709
4728
  return false;
4710
4729
  }
4730
+ function isAliasNamed(t) {
4731
+ if (t.kind === "object" || t.kind === "intersection") return t.name !== void 0;
4732
+ return t.alias !== void 0;
4733
+ }
4734
+ function sameRefTarget(a, b) {
4735
+ return a.name === b.name && (!a.origin || !b.origin || a.origin === b.origin);
4736
+ }
4711
4737
  function isNoValue(t) {
4712
4738
  return t.kind === "tuple" && t.elements.length === 0;
4713
4739
  }
@@ -5493,6 +5519,9 @@ var TypeAnalyzer = class {
5493
5519
  aliases = new AliasMap();
5494
5520
  /** Uninstantiated alias definitions, for `Name<Args>` instantiation. */
5495
5521
  aliasDefs = /* @__PURE__ */ new Map();
5522
+ /** Put on every ref to one of `aliasDefs`, so a module that imports the
5523
+ * type expands the ref here rather than by its name there. */
5524
+ origin = { expand: (t) => this.expand(t) };
5496
5525
  /** See `resolveClass`. */
5497
5526
  classTypes = /* @__PURE__ */ new WeakMap();
5498
5527
  /** See `instanceType` — one instance type per `class ... end`. */
@@ -5777,13 +5806,18 @@ var TypeAnalyzer = class {
5777
5806
  classIdentityCount = 0;
5778
5807
  /** The class whose members are being read, so `super` knows its base. */
5779
5808
  currentClass;
5809
+ /** Every class whose body the checker is inside, innermost last — what
5810
+ * decides whether a `private` member may be reached. */
5811
+ enclosingClasses = [];
5780
5812
  withClass(stmt, fn2) {
5781
5813
  const previous = this.currentClass;
5782
5814
  this.currentClass = stmt;
5815
+ this.enclosingClasses.push(stmt);
5783
5816
  try {
5784
5817
  return fn2();
5785
5818
  } finally {
5786
5819
  this.currentClass = previous;
5820
+ this.enclosingClasses.pop();
5787
5821
  }
5788
5822
  }
5789
5823
  /** What the class is known by. A declaration is known by its name, the way
@@ -5901,7 +5935,8 @@ var TypeAnalyzer = class {
5901
5935
  return {
5902
5936
  kind: "genericRef",
5903
5937
  name: stmt.name.name,
5904
- typeArguments: params.map((p) => typeParam(p.name, p.constraint ? this.resolveType(p.constraint) : void 0))
5938
+ typeArguments: params.map((p) => typeParam(p.name, p.constraint ? this.resolveType(p.constraint) : void 0)),
5939
+ origin: this.origin
5905
5940
  };
5906
5941
  }
5907
5942
  /** The class table: the statics, what it inherits from the class it
@@ -6000,8 +6035,11 @@ var TypeAnalyzer = class {
6000
6035
  return shape;
6001
6036
  }
6002
6037
  fillShape(stmt, shape) {
6038
+ const className = this.className(stmt);
6003
6039
  const put = (isStatic, name, property) => {
6004
- (isStatic ? shape.statics : shape.instance).set(name, property);
6040
+ const member = stmt.members.find((m) => m.type !== "ClassConstructor" && m.isStatic === isStatic && m.name.name === name && m.accessibility === "private");
6041
+ const marked = member ? { ...property, private: { owner: stmt, className } } : property;
6042
+ (isStatic ? shape.statics : shape.instance).set(name, marked);
6005
6043
  };
6006
6044
  for (const member of stmt.members) {
6007
6045
  if (member.type !== "ClassField") continue;
@@ -6466,7 +6504,8 @@ var TypeAnalyzer = class {
6466
6504
  return this.expand({
6467
6505
  kind: "genericRef",
6468
6506
  name: node.base,
6469
- typeArguments: node.typeArguments.map((a) => this.resolveType(a))
6507
+ typeArguments: node.typeArguments.map((a) => this.resolveType(a)),
6508
+ origin: this.origin
6470
6509
  });
6471
6510
  }
6472
6511
  const imported = this.importedTypes.get(node.base);
@@ -6479,7 +6518,8 @@ var TypeAnalyzer = class {
6479
6518
  return this.expand({
6480
6519
  kind: "genericRef",
6481
6520
  name,
6482
- typeArguments: node.typeArguments.map((a) => this.resolveType(a))
6521
+ typeArguments: node.typeArguments.map((a) => this.resolveType(a)),
6522
+ origin: this.origin
6483
6523
  });
6484
6524
  }
6485
6525
  return {
@@ -8305,6 +8345,7 @@ var TypeAnalyzer = class {
8305
8345
  * resolving, which is what breaks re-entry on a recursive alias. */
8306
8346
  expand(t) {
8307
8347
  if (t.kind !== "genericRef") return t;
8348
+ if (t.origin && t.origin !== this.origin) return t.origin.expand(t);
8308
8349
  const def = this.aliasDefs.get(t.name);
8309
8350
  if (!def) {
8310
8351
  const imported = this.importedTypes.get(t.name);
@@ -8455,6 +8496,28 @@ var TypeAnalyzer = class {
8455
8496
  message: names.length === 1 ? `'${names[0]}' does not exist on a string` : `'${briefType(key)}' does not name a member of a string`
8456
8497
  });
8457
8498
  }
8499
+ /** A `private` member read from outside the class that declared it —
8500
+ * a subclass counts as outside, as in TypeScript. */
8501
+ checkPrivateMember(node, object, name) {
8502
+ if (!this.emitDiagnostics) return;
8503
+ const raw = this.expand(object);
8504
+ for (const part of raw.kind === "union" ? raw.types : [raw]) {
8505
+ const t = this.deferredAccess(this.expand(part));
8506
+ if (t.kind !== "object") continue;
8507
+ const access = t.properties.get(name)?.private;
8508
+ if (!access || this.insideClass(access.owner)) continue;
8509
+ this.diagnostics.push({
8510
+ node,
8511
+ message: `Property '${name}' is private and only accessible within class '${access.className}'`
8512
+ });
8513
+ return;
8514
+ }
8515
+ }
8516
+ /** Is the code being checked written inside `owner`'s body — its own
8517
+ * methods, or a class or function nested in them? */
8518
+ insideClass(owner) {
8519
+ return this.enclosingClasses.includes(owner);
8520
+ }
8458
8521
  propertyType(raw, name) {
8459
8522
  const t = this.deferredAccess(this.expand(raw));
8460
8523
  if (t.kind === "object") {
@@ -8672,6 +8735,7 @@ var TypeAnalyzer = class {
8672
8735
  }
8673
8736
  case "MemberExpression": {
8674
8737
  const { type: obj, shortCircuits } = this.chainObject(expr, expr.object, env);
8738
+ this.checkPrivateMember(expr.property, obj, expr.property.name);
8675
8739
  const key = this.refKeyOf(expr);
8676
8740
  const narrowed = key === void 0 ? void 0 : env.get(key);
8677
8741
  this.checkStringMember(expr, obj, literal(expr.property.name));
@@ -8807,6 +8871,7 @@ var TypeAnalyzer = class {
8807
8871
  });
8808
8872
  }
8809
8873
  inferMethodCall(expr, objType, env) {
8874
+ this.checkPrivateMember(expr.method, objType, expr.method.name);
8810
8875
  const method = this.propertyType(objType, expr.method.name);
8811
8876
  const united = this.unionSignatures(method);
8812
8877
  const fns = united ?? this.overloadsOf(method);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua/parser",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "tilua parser for roblox",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",