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
1 change: 1 addition & 0 deletions packages/ember-tsc/src/transform/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type { Directive, default as TransformedModule } from './template/transformed-module.js';
export type { Diagnostic } from './diagnostics/index.js';
export type { TemplateContext } from './template/map-template-contents.js';

export { rewriteModule } from './template/rewrite-module.js';
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { GlintEnvironment } from '../../../config/index.js';
import { assert, TSLib } from '../../util.js';
import { templateToTypescript } from '../template-to-typescript.js';
import { Directive, Range, SourceFile, TransformError } from '../transformed-module.js';
import type { TemplateContext } from '../map-template-contents.js';
import { CorrelatedSpansResult, isEmbeddedInClass, PartialCorrelatedSpan } from './index.js';

export function calculateTaggedTemplateSpans(
Expand All @@ -17,6 +18,7 @@ export function calculateTaggedTemplateSpans(
meta: GlintEmitMetadata | undefined,
script: SourceFile,
environment: GlintEnvironment,
templateContext?: TemplateContext,
): CorrelatedSpansResult {
let directives: Array<Directive> = [];
let errors: Array<TransformError> = [];
Expand Down Expand Up @@ -69,6 +71,7 @@ export function calculateTaggedTemplateSpans(
specialForms,
backingValue: isEmbeddedInClass(ts, node) ? 'this' : undefined,
useJsDoc: environment.isUntypedScript(script.filename),
templateContext,
});

for (let { message, location } of transformedTemplate.errors) {
Expand Down
24 changes: 22 additions & 2 deletions packages/ember-tsc/src/transform/template/map-template-contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,20 @@ export type EmbeddingSyntax = {
suffix: string;
};

/**
* Per-template persistent context. Held by the caller (e.g. VirtualGtsCode)
* across repeated calls so that unchanged templates can skip expensive work.
* One slot per template position — no unbounded growth.
*/
export type TemplateContext = {
template?: string;
ast?: AST.Template;
result?: RewriteResult;
};

export type MapTemplateContentsOptions = {
embeddingSyntax: EmbeddingSyntax;
templateContext?: TemplateContext;
};

/**
Expand All @@ -149,14 +161,22 @@ export type MapTemplateContentsOptions = {
*/
export function mapTemplateContents(
template: string,
{ embeddingSyntax }: MapTemplateContentsOptions,
{ embeddingSyntax, templateContext }: MapTemplateContentsOptions,
callback: (ast: AST.Template | null, mapper: Mapper) => void,
): RewriteResult {
let ast: AST.Template | null = null;
let errors: Array<{ message: string; location: Range | undefined }> = [];
let lineOffsets = calculateLineOffsets(template, embeddingSyntax.prefix.length);
try {
ast = preprocess(template);
if (templateContext && templateContext.template === template && templateContext.ast) {
ast = templateContext.ast;
} else {
ast = preprocess(template);
if (templateContext) {
templateContext.template = template;
templateContext.ast = ast;
}
}
} catch (error) {
let message = getErrorMessage(error);
let location: Range | undefined;
Expand Down
27 changes: 26 additions & 1 deletion packages/ember-tsc/src/transform/template/rewrite-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { assert, TSLib } from '../util.js';

import { CorrelatedSpansResult, PartialCorrelatedSpan } from './inlining/index.js';
import { calculateTaggedTemplateSpans } from './inlining/tagged-strings.js';
import type { TemplateContext } from './map-template-contents.js';
import TransformedModule, {
CorrelatedSpan,
Directive,
Expand Down Expand Up @@ -34,12 +35,14 @@ export function rewriteModule(
{ script }: RewriteInput,
environment: GlintEnvironment,
clientId?: string,
templateContexts?: TemplateContext[],
): TransformedModule | null {
let { errors, directives, partialSpans } = calculateCorrelatedSpans(
ts,
script,
environment,
clientId,
templateContexts,
);

if (!partialSpans.length && !errors.length) {
Expand All @@ -64,6 +67,7 @@ function calculateCorrelatedSpans(
script: SourceFile,
environment: GlintEnvironment,
clientId?: string,
templateContexts?: TemplateContext[],
): CorrelatedSpansResult {
let directives: Array<Directive> = [];
let errors: Array<TransformError> = [];
Expand Down Expand Up @@ -108,6 +112,11 @@ function calculateCorrelatedSpans(
return { errors, directives, partialSpans };
}

// Index into templateContexts by traversal order. If templates are reordered
// in an edit, the string check in mapTemplateContents will miss — cache goes
// cold for one cycle, then re-populates correctly.
let templateIndex = 0;

ts.transform(ast, [
(context) =>
function visit<T extends ts.Node>(node: T): T {
Expand All @@ -119,7 +128,19 @@ function calculateCorrelatedSpans(
// https://discord.com/channels/480462759797063690/717767358743183412/1259061848632721480
if (ts.isTaggedTemplateExpression(node)) {
let meta = emitMetadata.get(node);
let result = calculateTaggedTemplateSpans(ts, node, meta, script, environment);
let templateContext: TemplateContext | undefined;
if (templateContexts) {
templateContext = templateContexts[templateIndex] ??= {};
}
templateIndex++;
let result = calculateTaggedTemplateSpans(
ts,
node,
meta,
script,
environment,
templateContext,
);

directives.push(...result.directives);
errors.push(...result.errors);
Expand All @@ -133,6 +154,10 @@ function calculateCorrelatedSpans(
},
]);

if (templateContexts) {
templateContexts.length = templateIndex;
}

return { errors, directives, partialSpans };
}

Expand Down
Loading
Loading