-
Notifications
You must be signed in to change notification settings - Fork 50
/
index.ts
59 lines (52 loc) · 2.03 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { NodePath, types as t } from '@babel/core';
import generate from '@babel/generator';
import { CorrelatedSpan, Directive, TransformError } from '../transformed-module';
export type PartialCorrelatedSpan = Omit<CorrelatedSpan, 'transformedStart' | 'transformedLength'>;
export type CorrelatedSpansResult = {
errors: Array<TransformError>;
directives: Array<Directive>;
partialSpans: Array<PartialCorrelatedSpan>;
};
export type ContainingTypeInfo = {
inClass: boolean;
className: string | undefined;
contextType: string | undefined;
typeParams: string | undefined;
};
/**
* Given an AST node for an embedded template, determines the appropriate
* instance type to be passed to `@glint/template`'s `ResolveContext`, as well
* as any type parameters that need to be propagated as inputs to the template's
* root generator function.
*
* For example, a template declared within `class MyComponent<T extends string>`
* would give `MyComponent<T>` as the context type, and `<T extends string>` as
* the type params, ultimately resulting in a template function like:
*
* template(function*<T extends string>(𝚪: ResolveContext<MyComponent<T>>){
* // ...
* })
*/
export function getContainingTypeInfo(path: NodePath<any>): ContainingTypeInfo {
let container = findContainingClass(path);
let inClass = Boolean(container);
let className = container?.id?.name;
let contextType = className;
let typeParams = undefined;
let typeParamsNode = container?.typeParameters;
if (t.isTSTypeParameterDeclaration(typeParamsNode)) {
let { params } = typeParamsNode;
typeParams = `<${params.map((param) => generate(param).code).join(', ')}>`;
contextType += `<${params.map((param) => param.name).join(', ')}>`;
}
return { contextType, typeParams, className, inClass };
}
function findContainingClass(path: NodePath<any>): t.Class | null {
let current: NodePath<any> | null = path;
do {
if (t.isClass(current.node)) {
return current.node;
}
} while ((current = current.parentPath));
return null;
}