diff --git a/packages/environment-ember-template-imports/-private/environment/transform.ts b/packages/environment-ember-template-imports/-private/environment/transform.ts index 8b9c2604e..a32d38d42 100644 --- a/packages/environment-ember-template-imports/-private/environment/transform.ts +++ b/packages/environment-ember-template-imports/-private/environment/transform.ts @@ -25,7 +25,10 @@ export const transform: GlintExtensionTransform = ( } else if (isETIDefaultTemplate(ts, node)) { // Annotate that this template is a default export setEmitMetadata(node.expression, { prepend: 'export default ' }); - + return node; + } else if (isETIDefaultSatisfiesTemplate(ts, node)) { + // Annotate that this template is a default export + setEmitMetadata(node.expression.expression, { prepend: 'export default ' }); return node; } else if (isETITemplateExpression(ts, node)) { // Convert '[__T`foo`]' as an expression to just '__T`foo`' @@ -111,18 +114,43 @@ type ETITemplateProperty = ts.PropertyDeclaration & { name: ts.ComputedPropertyName & { expression: ETITemplateLiteral }; }; -type ETIDefaultTemplate = - | (ts.ExpressionStatement & { - expression: ETITemplateLiteral; - }) - | (ts.SatisfiesExpression & { - expression: ETITemplateLiteral; - }); +type ETIDefaultTemplate = ts.ExpressionStatement & { + expression: ETITemplateLiteral; +}; + +type ETIDefaultSatisfiesTemplate = ts.ExpressionStatement & { + expression: ts.SatisfiesExpression & { expression: ETITemplateLiteral }; +}; +/** + * Implicit default export: + * + * ( ) + * ^ ExpressionStatement + * + * ( satisfies ... ) + * ^ SatisfiesExpression + * + * But! + * + * ( const X = satisfies ... ) + * ^ VariableStatement + * + * So when we check for a wrapping SatisfiesExpression, we need to also make sure + * the parent node is not a variable Statement. + */ function isETIDefaultTemplate(ts: TSLib, node: ts.Node): node is ETIDefaultTemplate { + return ts.isExpressionStatement(node) && isETITemplateLiteral(ts, node.expression); +} + +function isETIDefaultSatisfiesTemplate( + ts: TSLib, + node: ts.Node, +): node is ETIDefaultSatisfiesTemplate { return ( - (ts.isExpressionStatement(node) || ts.isSatisfiesExpression(node)) && - isETITemplateLiteral(ts, node.expression) + ts.isExpressionStatement(node) && + ts.isSatisfiesExpression(node.expression) && + isETITemplateLiteral(ts, node.expression.expression) ); } diff --git a/packages/environment-ember-template-imports/__tests__/transformation.test.ts b/packages/environment-ember-template-imports/__tests__/transformation.test.ts index 180b6d9fd..868761644 100644 --- a/packages/environment-ember-template-imports/__tests__/transformation.test.ts +++ b/packages/environment-ember-template-imports/__tests__/transformation.test.ts @@ -234,6 +234,43 @@ describe('Environment: ETI', () => { ); }); + test('single template, no export, with satisfies', () => { + let source = stripIndent` + import type { TOC } from '@ember/component/template-only'; + const hello = satisfies TOC<{ + Blocks: { default: [] } + }>; + `; + + let { meta, sourceFile } = applyTransform(source); + + let declaration = sourceFile.statements[2] as ts.VariableStatement; + let satisfiesExpression = declaration.declarationList.declarations[0] + .initializer! as ts.SatisfiesExpression; + let templateNode = satisfiesExpression.expression; + + let start = source.indexOf(''.length; + + expect(meta).toEqual( + new Map([ + [ + templateNode, + { + templateLocation: { + start, + contentStart, + contentEnd, + end, + }, + }, + ], + ]), + ); + }); + test('multiple templates', () => { let source = stripIndent`