Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions _packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,38 @@
},
"types": "./dist/typeFlags.enum.d.ts",
"default": "./dist/typeFlags.js"
},
"#signatureKind": {
"@typescript/source": {
"types": "./src/signatureKind.enum.ts",
"default": "./src/signatureKind.ts"
},
"types": "./dist/signatureKind.enum.d.ts",
"default": "./dist/signatureKind.js"
},
"#signatureFlags": {
"@typescript/source": {
"types": "./src/signatureFlags.enum.ts",
"default": "./src/signatureFlags.ts"
},
"types": "./dist/signatureFlags.enum.d.ts",
"default": "./dist/signatureFlags.js"
},
"#objectFlags": {
"@typescript/source": {
"types": "./src/objectFlags.enum.ts",
"default": "./src/objectFlags.ts"
},
"types": "./dist/objectFlags.enum.d.ts",
"default": "./dist/objectFlags.js"
},
"#elementFlags": {
"@typescript/source": {
"types": "./src/elementFlags.enum.ts",
"default": "./src/elementFlags.ts"
},
"types": "./dist/elementFlags.enum.d.ts",
"default": "./dist/elementFlags.js"
}
},
"exports": {
Expand Down
375 changes: 360 additions & 15 deletions _packages/api/src/async/api.ts

Large diffs are not rendered by default.

211 changes: 209 additions & 2 deletions _packages/api/src/base/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
* - `Async = true`: Methods return Promise<T> (async)
*/

import { ElementFlags } from "#elementFlags";
import { ObjectFlags } from "#objectFlags";
import { SignatureFlags } from "#signatureFlags";
import { SignatureKind } from "#signatureKind";
import { SymbolFlags } from "#symbolFlags";
import { TypeFlags } from "#typeFlags";
import type {
Expand All @@ -26,7 +30,7 @@ import type {
} from "../proto.ts";
import type { MaybeAsync } from "./types.ts";

export { SymbolFlags, TypeFlags };
export { ElementFlags, ObjectFlags, SignatureFlags, SignatureKind, SymbolFlags, TypeFlags };

/**
* A document identifier that can be either a file name (path string) or a document URI object.
Expand Down Expand Up @@ -201,6 +205,30 @@ export interface Checker<Async extends boolean> {
getTypeOfSymbol(symbol: Symbol<Async>): MaybeAsync<Async, Type<Async> | undefined>;
getTypeOfSymbol(symbols: readonly Symbol<Async>[]): MaybeAsync<Async, (Type<Async> | undefined)[]>;

/**
* Get the declared type of a symbol (e.g. the aliased type for type alias symbols).
*/
getDeclaredTypeOfSymbol(symbol: Symbol<Async>): MaybeAsync<Async, Type<Async> | undefined>;

/**
* Get the type at a specific node location.
*/
getTypeAtLocation(node: Node): MaybeAsync<Async, Type<Async> | undefined>;
getTypeAtLocation(nodes: readonly Node[]): MaybeAsync<Async, (Type<Async> | undefined)[]>;

/**
* Get the call or construct signatures of a type.
* @param type The type to get signatures from
* @param kind 0 for call signatures, 1 for construct signatures
*/
getSignaturesOfType(type: Type<Async>, kind: SignatureKind): MaybeAsync<Async, readonly Signature<Async>[]>;

/**
* Get the type at a specific position in a file.
*/
getTypeAtPosition(file: DocumentIdentifier, position: number): MaybeAsync<Async, Type<Async> | undefined>;
getTypeAtPosition(file: DocumentIdentifier, positions: readonly number[]): MaybeAsync<Async, (Type<Async> | undefined)[]>;

/**
* Resolve a name to a symbol at a given location.
* @param name The name to resolve
Expand All @@ -214,6 +242,41 @@ export interface Checker<Async extends boolean> {
location?: Node | DocumentPosition,
excludeGlobals?: boolean,
): MaybeAsync<Async, Symbol<Async> | undefined>;

/**
* Get the contextual type for an expression node.
*/
getContextualType(node: Node): MaybeAsync<Async, Type<Async> | undefined>;

/**
* Get the base type of a literal type (e.g. `number` for `42`).
*/
getBaseTypeOfLiteralType(type: Type<Async>): MaybeAsync<Async, Type<Async> | undefined>;

/**
* Get the value symbol of a shorthand property assignment.
*/
getShorthandAssignmentValueSymbol(node: Node): MaybeAsync<Async, Symbol<Async> | undefined>;

/**
* Get the narrowed type of a symbol at a specific location.
*/
getTypeOfSymbolAtLocation(symbol: Symbol<Async>, location: Node): MaybeAsync<Async, Type<Async> | undefined>;

/**
* Intrinsic type getters.
*/
getAnyType(): MaybeAsync<Async, Type<Async>>;
getStringType(): MaybeAsync<Async, Type<Async>>;
getNumberType(): MaybeAsync<Async, Type<Async>>;
getBooleanType(): MaybeAsync<Async, Type<Async>>;
getVoidType(): MaybeAsync<Async, Type<Async>>;
getUndefinedType(): MaybeAsync<Async, Type<Async>>;
getNullType(): MaybeAsync<Async, Type<Async>>;
getNeverType(): MaybeAsync<Async, Type<Async>>;
getUnknownType(): MaybeAsync<Async, Type<Async>>;
getBigIntType(): MaybeAsync<Async, Type<Async>>;
getESSymbolType(): MaybeAsync<Async, Type<Async>>;
}

export interface NodeHandle<Async extends boolean> {
Expand Down Expand Up @@ -246,14 +309,158 @@ export interface Symbol<Async extends boolean> {
readonly declarations: readonly NodeHandle<Async>[];
/** Node handle for the value declaration of this symbol */
readonly valueDeclaration: NodeHandle<Async> | undefined;

/** Get the parent symbol, if any */
getParent(): MaybeAsync<Async, Symbol<Async> | undefined>;
/** Get the members of this symbol */
getMembers(): MaybeAsync<Async, readonly Symbol<Async>[]>;
/** Get the exports of this symbol */
getExports(): MaybeAsync<Async, readonly Symbol<Async>[]>;
}

/**
* Base interface for a TypeScript type.
*
* Use TypeFlags to determine the specific kind of type and access
* kind-specific properties. For example:
*
* ```ts
* if (type.flags & TypeFlags.StringLiteral) {
* console.log((type as LiteralType).value); // string
* }
* ```
*/
export interface Type<Async extends boolean> {
/** Unique identifier for this type */
readonly id: string;
/** Type flags */
/** Type flags — use to determine the specific kind of type */
readonly flags: TypeFlags;

/** Get the symbol associated with this type, if any */
getSymbol(): MaybeAsync<Async, Symbol<Async> | undefined>;
}

/** Literal types: StringLiteral, NumberLiteral, BigIntLiteral, BooleanLiteral */
export interface LiteralType<Async extends boolean> extends Type<Async> {
/** The literal value */
readonly value: string | number | boolean;
}

/** Object types (TypeFlags.Object) */
export interface ObjectType<Async extends boolean> extends Type<Async> {
/** Object flags — use to determine the specific kind of object type */
readonly objectFlags: ObjectFlags;
}

/** Type references (ObjectFlags.Reference) — e.g. Array<string>, Map<K, V> */
export interface TypeReference<Async extends boolean> extends ObjectType<Async> {
/** Get the generic target type (e.g. Array for Array<string>) */
getTarget(): MaybeAsync<Async, Type<Async>>;
}

/** Interface types — classes and interfaces (ObjectFlags.ClassOrInterface) */
export interface InterfaceType<Async extends boolean> extends TypeReference<Async> {
/** Get all type parameters (outer + local, excluding thisType) */
getTypeParameters(): MaybeAsync<Async, readonly Type<Async>[]>;
/** Get outer type parameters from enclosing declarations */
getOuterTypeParameters(): MaybeAsync<Async, readonly Type<Async>[]>;
/** Get local type parameters declared on this interface/class */
getLocalTypeParameters(): MaybeAsync<Async, readonly Type<Async>[]>;
}

/** Tuple types (ObjectFlags.Tuple) */
export interface TupleType<Async extends boolean> extends InterfaceType<Async> {
/** Per-element flags (Required, Optional, Rest, Variadic) */
readonly elementFlags: readonly ElementFlags[];
/** Number of initial required or optional elements */
readonly fixedLength: number;
/** Whether the tuple is readonly */
readonly readonly: boolean;
}

/** Union or intersection types (TypeFlags.Union | TypeFlags.Intersection) */
export interface UnionOrIntersectionType<Async extends boolean> extends Type<Async> {
/** Get the constituent types */
getTypes(): MaybeAsync<Async, readonly Type<Async>[]>;
}

/** Union types (TypeFlags.Union) */
export interface UnionType<Async extends boolean> extends UnionOrIntersectionType<Async> {
}

/** Intersection types (TypeFlags.Intersection) */
export interface IntersectionType<Async extends boolean> extends UnionOrIntersectionType<Async> {
}

/** Type parameters (TypeFlags.TypeParameter) */
export interface TypeParameter<Async extends boolean> extends Type<Async> {
}

/** Index types — keyof T (TypeFlags.Index) */
export interface IndexType<Async extends boolean> extends Type<Async> {
/** Get the target type T in `keyof T` */
getTarget(): MaybeAsync<Async, Type<Async>>;
}

/** Indexed access types — T[K] (TypeFlags.IndexedAccess) */
export interface IndexedAccessType<Async extends boolean> extends Type<Async> {
/** Get the object type T in `T[K]` */
getObjectType(): MaybeAsync<Async, Type<Async>>;
/** Get the index type K in `T[K]` */
getIndexType(): MaybeAsync<Async, Type<Async>>;
}

/** Conditional types — T extends U ? X : Y (TypeFlags.Conditional) */
export interface ConditionalType<Async extends boolean> extends Type<Async> {
/** Get the check type T in `T extends U ? X : Y` */
getCheckType(): MaybeAsync<Async, Type<Async>>;
/** Get the extends type U in `T extends U ? X : Y` */
getExtendsType(): MaybeAsync<Async, Type<Async>>;
}

/** Substitution types (TypeFlags.Substitution) */
export interface SubstitutionType<Async extends boolean> extends Type<Async> {
/** Get the base/target type */
getBaseType(): MaybeAsync<Async, Type<Async>>;
/** Get the constraint */
getConstraint(): MaybeAsync<Async, Type<Async>>;
}

/** Template literal types (TypeFlags.TemplateLiteral) */
export interface TemplateLiteralType<Async extends boolean> extends Type<Async> {
/** Text segments (always one more than the number of type spans) */
readonly texts: readonly string[];
/** Get the types interspersed between text segments */
getTypes(): MaybeAsync<Async, readonly Type<Async>[]>;
}

/** String mapping types — Uppercase<T>, Lowercase<T>, etc. (TypeFlags.StringMapping) */
export interface StringMappingType<Async extends boolean> extends Type<Async> {
/** Get the mapped type */
getTarget(): MaybeAsync<Async, Type<Async>>;
}

/**
* Base interface for a TypeScript signature.
*/
export interface Signature<Async extends boolean> {
/** Unique identifier for this signature */
readonly id: string;
/** Node handle for the declaration of this signature */
readonly declaration?: NodeHandle<Async> | undefined;
/** Type parameter types */
readonly typeParameters?: readonly Type<Async>[] | undefined;
/** Parameter symbols */
readonly parameters: readonly Symbol<Async>[];
/** This parameter symbol, if any */
readonly thisParameter?: Symbol<Async> | undefined;

/** Get the target signature (for instantiated signatures) */
readonly target?: Signature<Async> | undefined;
/** Whether the last parameter is a rest parameter */
readonly hasRestParameter: boolean;
/** Whether this is a construct signature */
readonly isConstruct: boolean;
/** Whether this is an abstract signature */
readonly isAbstract: boolean;
}
30 changes: 25 additions & 5 deletions _packages/api/src/base/objectRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
SignatureResponse,
SymbolResponse,
TypeResponse,
} from "../proto.ts";
Expand All @@ -13,9 +14,10 @@ export interface Identifiable {
/**
* Factory functions for creating API objects.
*/
export interface ObjectFactories<TSymbol extends Identifiable, TType extends Identifiable> {
export interface ObjectFactories<TSymbol extends Identifiable, TType extends Identifiable, TSignature extends Identifiable = Identifiable> {
createSymbol(data: SymbolResponse): TSymbol;
createType(data: TypeResponse): TType;
createSignature(data: SignatureResponse): TSignature;
}

/**
Expand All @@ -31,16 +33,18 @@ export interface ObjectFactories<TSymbol extends Identifiable, TType extends Ide
export class ObjectRegistry<
TSymbol extends Identifiable,
TType extends Identifiable,
TSignature extends Identifiable = Identifiable,
> {
private symbols: Map<string, TSymbol> = new Map();
private types: Map<string, TType> = new Map();
private factories: ObjectFactories<TSymbol, TType>;
private signatures: Map<string, TSignature> = new Map();
private factories: ObjectFactories<TSymbol, TType, TSignature>;

constructor(factories: ObjectFactories<TSymbol, TType>) {
constructor(factories: ObjectFactories<TSymbol, TType, TSignature>) {
this.factories = factories;
}

getSymbol(data: SymbolResponse): TSymbol {
getOrCreateSymbol(data: SymbolResponse): TSymbol {
let symbol = this.symbols.get(data.id);
if (symbol) {
return symbol;
Expand All @@ -51,7 +55,7 @@ export class ObjectRegistry<
return symbol;
}

getType(data: TypeResponse): TType {
getOrCreateType(data: TypeResponse): TType {
let type = this.types.get(data.id);
if (type) {
return type;
Expand All @@ -62,8 +66,24 @@ export class ObjectRegistry<
return type;
}

getType(id: string): TType | undefined {
return this.types.get(id);
}

getOrCreateSignature(data: SignatureResponse): TSignature {
let signature = this.signatures.get(data.id);
if (signature) {
return signature;
}

signature = this.factories.createSignature(data);
this.signatures.set(data.id, signature);
return signature;
}

clear(): void {
this.symbols.clear();
this.types.clear();
this.signatures.clear();
}
}
10 changes: 10 additions & 0 deletions _packages/api/src/elementFlags.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum ElementFlags {
None = 0,
Required = 1 << 0,
Optional = 1 << 1,
Rest = 1 << 2,
Variadic = 1 << 3,
Fixed = Required | Optional,
Variable = Rest | Variadic,
NonRequired = Optional | Rest | Variadic,
}
11 changes: 11 additions & 0 deletions _packages/api/src/elementFlags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export var ElementFlags: any;
(function (ElementFlags) {
ElementFlags[ElementFlags["None"] = 0] = "None";
ElementFlags[ElementFlags["Required"] = 1] = "Required";
ElementFlags[ElementFlags["Optional"] = 2] = "Optional";
ElementFlags[ElementFlags["Rest"] = 4] = "Rest";
ElementFlags[ElementFlags["Variadic"] = 8] = "Variadic";
ElementFlags[ElementFlags["Fixed"] = 3] = "Fixed";
ElementFlags[ElementFlags["Variable"] = 12] = "Variable";
ElementFlags[ElementFlags["NonRequired"] = 14] = "NonRequired";
})(ElementFlags || (ElementFlags = {}));
3 changes: 0 additions & 3 deletions _packages/api/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -997,9 +997,6 @@ export class RemoteSourceFile extends RemoteNode {
constructor(data: Uint8Array, decoder: TextDecoder) {
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
super(view, decoder, 1, undefined!);
const extendedDataOffset = this.offsetExtendedData + (this.data & NODE_EXTENDED_DATA_MASK);
const idStringIndex = this.view.getUint32(extendedDataOffset + 12, true);
this.id = this.getString(idStringIndex);
}
}

Expand Down
Loading