This specification defines the schema for how the indexer expresses VNames for TypeScript declarations. You may find this useful if you are developing an application that relies on TypeScript code you don't want to re-index.
A formal listing of the specification is provided below, but the schema tests may be more useful for real examples.
The signature description language used in this document is similar to regex.
\b\$.*\b
is a variable.$DECLARATION_NAME
is a variable refering to the name of declaration.\[.*\]\?
is matched 0 or 1 times.(hidden)?
is really hidden
or ``.\[.*\]\*
is matched 0 or more times.[a]*
is ``, ora
, oraa
, ...get#$NAME
is really get#foo
if $NAME = foo
.The signature of a TypeScript declaration is defined by the following schema:
$PART[.$PART]*[#type]?
where $PART
is a component of the enclosing declaration scope and #type
is appended to the signature of types. SyntaxKind
s that are types are:
ClassDeclaration
(also a value)EnumDeclaration
(also a value)InterfaceDeclaration
TypeAliasDeclaration
TypeParameter
As an example of this schema, in
class A { public foo: string; } type B = A;
foo
has the signature A.foo
and B
has the signature B#type
.
Signature components ($PART
s in the schema) are defined below.
Form: module
Notes: The first character of TypeScript source file binds to a VName describing the module. The module path is the file path of the module, stripped of .ts
and .d.ts
extensions and relative to the project root. See VName Path for more.
SyntaxKind:
SourceFile
//- FileModule=VName("module", _, _, _, _).node/kind record //- FileModuleAnchor.node/kind anchor //- FileModuleAnchor./kythe/loc/start 0 //- FileModuleAnchor./kythe/loc/end 1 //- FileModuleAnchor defines/binding FileModule
Form: $DECLARATION_NAME | "$DECLARATION_NAME"
Notes: Every named declaration is guaranteed to have a signature of the form $SCOPE[.$SCOPE]*
where $SCOPE
is the name of each encompassing named declaration.
If the declaration is a string literal, its name is wrapped in quotes.
SyntaxKind:
NamespaceImport
Constructor
MethodDeclaration
EnumDeclaration
EnumMember
FunctionDeclaration
Parameter
InterfaceDeclaration
PropertySignature
MethodSignature
VariableDeclaration
PropertyAssignment
TypeAliasDeclaration
TypeParameter
export class Klass { //- @property defines/binding VName("Klass#type.method", _, _, _, _) method() { //- @property defines/binding VName("Klass#type.method.val", _, _, _, _) let val; }; //- @"'propliteral'" defines/binding VName("Klass#type.\"propliteral\"", _, _, _, _) 'propliteral' = 0; }
Form:
$CLASS#type
$CLASS
Notes: Because a class is both a type and a value, it has to be labeled as such. Class members belong to an instance of the class type and have a signature with class component of $CLASS#type
. Static members belong to the class value and have a signature with class component of $CLASS
.
SyntaxKind:
//- @Klass defines/binding VName("Klass#type", _, _, _, _) //- @Klass defines/binding VName("Klass", _, _, _, _) class Klass { //- @member defines/binding VName("Klass#type.member", _, _, _, _) member = 0; //- @staticMember defines/binding VName("Klass.staticMember", _, _, _, _) static staticMember = 0; //- @constructor defines/binding VName("Klass#type.constructor", _, _, _, _) constructor() {} }
Form: $CLASS[#type]?.$PROPERTY
Notes: Instance members on a class have a signature of form $CLASS#type.$PROPERTY
, as they belong to instances of the class type. Static members, which belong to the class value, have a form of $CLASS.$PROPERTY
.
SyntaxKind:
class Klass { //- @prop defines/binding VName("Klass.prop", _, _, _, _) prop; //- @prop defines/binding VName("Klass#type.prop", _, _, _, _) static prop; //- @cprop defines/binding VName("Klass#type.cprop", _, _, _, _) constructor(private cprop: number) {} }
Form:
$DECLARATION_NAME:getter
$DECLARATION_NAME:setter
$DECLARATION_NAME
Notes: Because getters and setters refer to the same property on a class but provide multiple declarations, several distinctions between the declarations are made. Each declaration of a getter and setter will take :getter
and :setter
suffix, respectively.
If a getter for a property is present, the getter will emit a binding the same form as the property it defines. If only a setter is present, the setter will emit a binding of the same form as the property it defines.
SyntaxKind:
class Klass { //- @foo defines/binding VName("Klass.foo:getter", _, _, _, _) //- @foo defines/binding VName("Klass.foo", _, _, _, _) get foo() {} //- @foo defines/binding VName("Klass.foo:setter", _, _, _, _) set foo(newFoo) {} } class KlassNoGetter { //- @foo defines/binding VName("KlassNoGetter.foo:setter", _, _, _, _) //- @foo defines/binding VName("KlassNoGetter.foo", _, _, _, _) set foo(newFoo) {} }
Form:
default
export=
Notes: export default
is semantically equivalent to exporting a variable named default
. export =
exports a variable named export=
.
SyntaxKind:
ExportAssignment
//- @default defines/binding VName("default", _, _, _, _) export default myExport; //- @"export =" defines/binding VName("export=", _, _, _, _) export = { myExport };
Form: a unique, non-deterministic block name.
Notes: The block name is not guaranteed, because declarations within an anonymous block cannot be accessed outside it.
SyntaxKind:
ArrowFunction
Block
that does not have a FunctionDeclaration
or MethodDeclaration
parentlet af = () => { //- @decl defines/binding VName(_, _, _, _, _) let decl; };
Project-specific, defined by the compilation unit passed to the indexer.
Project-specific, defined by the compilation unit passed to the indexer.
See the module name discussion in the README. In short,
a/b/c.ts
will have a file node with path a/b/c.ts
..d.ts
or .ts
extensions, relative to the project root. A TypeScript anchor in a file a/b/c.ts
with project root a/
will define a node with path b/c
.Always typescript
.