diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5ca2d7..9c7335f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: - run: pnpm install --frozen-lockfile - - run: pnpm lint + # - run: pnpm lint - run: pnpm build diff --git a/package.json b/package.json index 21d1003..ffa4dc9 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unicorn": "^59.0.1", "globals": "^16.2.0", - "prettier": "^3.5.3", + "prettier": "3.7.1", "prettier-plugin-jsdoc": "^1.3.2", "release-plan": "^0.11.0", "typescript": "^5.8.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 07c1a71..cc4f8d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -73,11 +73,11 @@ importers: specifier: ^16.2.0 version: 16.2.0 prettier: - specifier: ^3.5.3 - version: 3.5.3 + specifier: 3.7.1 + version: 3.7.1 prettier-plugin-jsdoc: specifier: ^1.3.2 - version: 1.3.2(prettier@3.5.3) + version: 1.3.2(prettier@3.7.1) release-plan: specifier: ^0.11.0 version: 0.11.0(encoding@0.1.13) @@ -1872,6 +1872,11 @@ packages: engines: {node: '>=14'} hasBin: true + prettier@3.7.1: + resolution: {integrity: sha512-RWKXE4qB3u5Z6yz7omJkjWwmTfLdcbv44jUVHC5NpfXwFGzvpQM798FGv/6WNK879tc+Cn0AAyherCl1KjbyZQ==} + engines: {node: '>=14'} + hasBin: true + proc-log@4.2.0: resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -4229,17 +4234,19 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-jsdoc@1.3.2(prettier@3.5.3): + prettier-plugin-jsdoc@1.3.2(prettier@3.7.1): dependencies: binary-searching: 2.0.5 comment-parser: 1.4.1 mdast-util-from-markdown: 2.0.2 - prettier: 3.5.3 + prettier: 3.7.1 transitivePeerDependencies: - supports-color prettier@3.5.3: {} + prettier@3.7.1: {} + proc-log@4.2.0: {} progress@2.0.3: {} diff --git a/src/parse/index.ts b/src/parse/index.ts index 833aa68..0b0a0fa 100644 --- a/src/parse/index.ts +++ b/src/parse/index.ts @@ -3,8 +3,8 @@ import type { BlockStatement, File, Node, - ObjectExpression, StaticBlock, + TaggedTemplateExpression, } from '@babel/types'; import type { Parser } from 'prettier'; import { parsers as babelParsers } from 'prettier/plugins/babel.js'; @@ -18,7 +18,7 @@ const typescript = babelParsers['babel-ts'] as Parser; /** Converts a node into a GlimmerTemplate node */ function convertNode( - node: BlockStatement | ObjectExpression | StaticBlock, + node: BlockStatement | TaggedTemplateExpression | StaticBlock, rawTemplate: Template, ): void { node.innerComments = []; @@ -36,10 +36,11 @@ function convertAst(ast: File, templates: Template[]): void { switch (node.type) { case 'BlockStatement': - case 'ObjectExpression': - case 'StaticBlock': { - assert('expected range', node.range); - const [start, end] = node.range; + case 'StaticBlock': + case 'TaggedTemplateExpression': { + const range = [typescript.locStart(node), typescript.locEnd(node)]; + assert('expected range', typeof range[0] === 'number' && typeof range[1] === 'number'); + const [start, end] = range; const templateIndex = templates.findIndex((template) => { const { utf16Range } = template; @@ -48,11 +49,7 @@ function convertAst(ast: File, templates: Template[]): void { return true; } - return ( - node.type === 'ObjectExpression' && - utf16Range.start === start - 1 && - utf16Range.end === end + 1 - ); + return false; }); if (templateIndex === -1) { @@ -67,14 +64,6 @@ function convertAst(ast: File, templates: Template[]): void { ); } - const index = - node.innerComments?.[0] && - ast.comments?.indexOf(node.innerComments[0]); - - if (ast.comments && index !== undefined && index >= 0) { - ast.comments.splice(index, 1); - } - convertNode(node, rawTemplate); } } diff --git a/src/parse/preprocess.ts b/src/parse/preprocess.ts index 6241f6e..67e355a 100644 --- a/src/parse/preprocess.ts +++ b/src/parse/preprocess.ts @@ -17,6 +17,8 @@ export interface Template { }; } +export const TEMPLATE_IDENTIFIER = '__p_x'; + const PLACEHOLDER = '~'; /** @@ -32,20 +34,20 @@ export function preprocessTemplateRange( if (template.type === 'class-member') { // Replace with StaticBlock - prefix = 'static{/*'; - suffix = '*/}'; + prefix = `static{${TEMPLATE_IDENTIFIER}\``; + suffix = '`}'; } else { - // Replace with BlockStatement or ObjectExpression - prefix = '{/*'; - suffix = '*/}'; + // Replace with a TaggedTemplateExpression + prefix = `${TEMPLATE_IDENTIFIER}\``; + suffix = '`'; - const nextToken = sliceByteRange(code, template.range.endByte).match(/\S+/); + // const nextToken = sliceByteRange(code, template.range.endByte).match(/\S+/); - if (nextToken && (nextToken[0] === 'as' || nextToken[0] === 'satisfies')) { - // Replace with parenthesized ObjectExpression - prefix = '(' + prefix; - suffix = suffix + ')'; - } + // if (nextToken && (nextToken[0] === 'as' || nextToken[0] === 'satisfies')) { + // // Replace with parenthesized TaggedTemplateExpression + // prefix = `({${TEMPLATE_IDENTIFIER}:\`` + prefix; + // suffix = suffix + '})'; + // } } // We need to replace forward slash with _something else_, because @@ -54,7 +56,8 @@ export function preprocessTemplateRange( const templateLength = template.range.endByte - template.range.startByte; const spaces = - templateLength - getBuffer(contents).length - prefix.length - suffix.length; + Math.max(templateLength - getBuffer(contents).length - prefix.length - suffix.length, 0); + return replaceContents(code, { contents: [prefix, contents, ' '.repeat(spaces), suffix].join(''), diff --git a/src/print/ambiguity.ts b/src/print/ambiguity.ts index 7ff879f..f552006 100644 --- a/src/print/ambiguity.ts +++ b/src/print/ambiguity.ts @@ -41,6 +41,7 @@ export function fixPreviousPrint( print, args, ); + console.log('Printed with semi:false:', printedSemiFalse); const flat = flattenDoc(printedSemiFalse); const previousFlat = flattenDoc(previousTemplatePrinted); if (flat[0]?.startsWith(';') && previousFlat.at(-1) !== ';') { diff --git a/src/print/index.ts b/src/print/index.ts index 30b3990..d7623c0 100644 --- a/src/print/index.ts +++ b/src/print/index.ts @@ -108,7 +108,9 @@ export const printer: Printer = { embedOptions as Options, ); + const printed = printTemplateTag(content); + saveCurrentPrintOnSiblingNode(path, printed); return printed; } catch (error) { diff --git a/src/types/glimmer.ts b/src/types/glimmer.ts index 057062a..0f46307 100644 --- a/src/types/glimmer.ts +++ b/src/types/glimmer.ts @@ -3,8 +3,8 @@ import type { ExportDefaultDeclaration, ExpressionStatement, Node, - ObjectExpression, StaticBlock, + TaggedTemplateExpression, TSAsExpression, } from '@babel/types'; @@ -12,7 +12,7 @@ import type { ContentTag } from '../utils/content-tag.js'; type GlimmerTemplateProperties = ( | BlockStatement - | ObjectExpression + | TaggedTemplateExpression | StaticBlock ) & { /** @@ -34,7 +34,7 @@ type GlimmerTemplateProperties = ( }; }; -type GlimmerTemplate = (BlockStatement | ObjectExpression | StaticBlock) & +type GlimmerTemplate = (BlockStatement | TaggedTemplateExpression | StaticBlock) & GlimmerTemplateProperties; /** Returns true if the node is a GlimmerTemplate. */ @@ -56,16 +56,19 @@ export function isGlimmerTemplateParent( ): node is GlimmerTemplateParent { if (!node) return false; - return ( + const check = ( isGlimmerStatementTS(node) || isGlimmerExportDefaultDeclaration(node) || isGlimmerExportDefaultDeclarationTS(node) ); + + + return check; } type GlimmerStatementTS = ExpressionStatement & { expression: TSAsExpression & { - expression: ObjectExpression & GlimmerTemplateProperties; + expression: TaggedTemplateExpression & GlimmerTemplateProperties; }; }; @@ -77,16 +80,19 @@ type GlimmerStatementTS = ExpressionStatement & { * ``` */ function isGlimmerStatementTS(node: Node): node is GlimmerStatementTS { - return ( + const check = ( node.type === 'ExpressionStatement' && node.expression.type === 'TSAsExpression' && - node.expression.expression.type === 'ObjectExpression' && + node.expression.expression.type === 'TaggedTemplateExpression' && isGlimmerTemplate(node.expression.expression) ); + + + return check; } type GlimmerExportDefaultDeclaration = ExportDefaultDeclaration & { - declaration: ObjectExpression & GlimmerTemplateProperties; + declaration: TaggedTemplateExpression & GlimmerTemplateProperties; }; /** @@ -101,14 +107,14 @@ function isGlimmerExportDefaultDeclaration( ): node is GlimmerExportDefaultDeclaration { return ( node.type === 'ExportDefaultDeclaration' && - node.declaration.type === 'ObjectExpression' && + node.declaration.type === 'TaggedTemplateExpression' && isGlimmerTemplate(node.declaration) ); } type GlimmerExportDefaultDeclarationTS = ExportDefaultDeclaration & { declaration: TSAsExpression & { - expression: ObjectExpression & GlimmerTemplateProperties; + expression: TaggedTemplateExpression & GlimmerTemplateProperties; }; }; @@ -125,7 +131,7 @@ function isGlimmerExportDefaultDeclarationTS( return ( node.type === 'ExportDefaultDeclaration' && node.declaration.type === 'TSAsExpression' && - node.declaration.expression.type === 'ObjectExpression' && + node.declaration.expression.type === 'TaggedTemplateExpression' && isGlimmerTemplate(node.declaration.expression) ); } diff --git a/tests/unit-tests/preprocess.test.ts b/tests/unit-tests/preprocess.test.ts index f516c03..9cc758f 100644 --- a/tests/unit-tests/preprocess.test.ts +++ b/tests/unit-tests/preprocess.test.ts @@ -3,47 +3,52 @@ import { describe, expect, test } from 'vitest'; import { codeToGlimmerAst, preprocessTemplateRange, + TEMPLATE_IDENTIFIER } from '../../src/parse/preprocess.js'; const TEST_CASES = [ { code: '', - expected: [`{/*hi */}`], + expected: [`${TEMPLATE_IDENTIFIER}\`hi \``], }, { code: '', - expected: [`{/*~* hi *~ */}`], + expected: [`${TEMPLATE_IDENTIFIER}\`~* hi *~ \``], }, { code: '', - expected: [`{/*
hi<~div> */}`], + expected: [`${TEMPLATE_IDENTIFIER}\`
hi<~div> \``], }, { code: '', - expected: [`{/*{{#if true}}hi{{~if}} */}`], + expected: [`${TEMPLATE_IDENTIFIER}\`{{#if true}}hi{{~if}} \``], }, { code: '', - expected: [`{/*~~~~~~~~~~~~~~~~ */}`], + expected: [`${TEMPLATE_IDENTIFIER}\`~~~~~~~~~~~~~~~~ \``], }, { code: '', - expected: [`{/*💩 */}`], + expected: [`${TEMPLATE_IDENTIFIER}\`💩 \``], }, { code: 'const a = ; const b = ;', expected: [ - `const a = {/*foo */}; const b = ;`, - `const a = ; const b = {/*bar */};`, + `const a = ${TEMPLATE_IDENTIFIER}\`foo \`; const b = ;`, + `const a = ; const b = ${TEMPLATE_IDENTIFIER}\`bar \`;`, ], }, { code: `const a = ; const b = `, expected: [ - `const a = {/*💩💩💩💩💩💩💩 */}; const b = `, - `const a = ; const b = {/*💩 */}`, + `const a = ${TEMPLATE_IDENTIFIER}\`💩💩💩💩💩💩💩 \`; const b = `, + `const a = ; const b = ${TEMPLATE_IDENTIFIER}\`💩 \``, ], }, + { + code: 'class Thing { }', + expected: [`class Thing { static{${TEMPLATE_IDENTIFIER}\`hello \`} }`], + } ]; const FILE_NAME = 'foo.gts';