From 5bf8304c2bcc8a0009c90adb1fc48dd55054861b Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Tue, 23 Jun 2026 17:51:01 -0400 Subject: [PATCH 1/2] Skip and report unparseable files in the @context search codemod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The codemod called transformContextSearch per file with no error handling, so a single module whose template the parser rejects threw out of the loop and aborted the entire run — masking every file after it. Running the codemod over a large body of card source is exactly where that bites. Wrap the per-file transform in try/catch: on a parse throw, record the file in a new "unparseable" bucket and continue. Such modules can't be migrated mechanically (and don't compile as-is), so they're left untouched and listed in a "Skipped unparseable file(s)" section at the end alongside the migrated and hand-migration reports. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01R4n4P6G1vFdSvSZaKkFK5f --- .../scripts/codemod/context-search/run.ts | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/realm-server/scripts/codemod/context-search/run.ts b/packages/realm-server/scripts/codemod/context-search/run.ts index 2cf51b4e9cc..8082e983f66 100644 --- a/packages/realm-server/scripts/codemod/context-search/run.ts +++ b/packages/realm-server/scripts/codemod/context-search/run.ts @@ -1,7 +1,9 @@ // CLI for the `@context` search codemod. Dry-run by default; pass `--write` to // apply. Walks the given files/directories for `.gts` card source, migrates the // usages it can transform mechanically, and reports the ones it can't so they -// can be migrated by hand. +// can be migrated by hand. A file whose template can't be parsed is skipped and +// reported (left untouched) rather than aborting the whole sweep — such a module +// already fails to compile, so it's out of scope here. // // node scripts/codemod/context-search/run.ts [--write] @@ -62,10 +64,20 @@ async function main(): Promise { let files = collectGtsFiles(paths); let transformed: string[] = []; let reported: { file: string; reasons: string[] }[] = []; + let unparseable: { file: string; error: string }[] = []; for (let file of files) { let source = readFileSync(file, 'utf8'); - let result = transformContextSearch(source, { filename: file }); + let result; + try { + result = transformContextSearch(source, { filename: file }); + } catch (err) { + // The transformer threw while parsing this module's template, so it can't + // be migrated mechanically (and would not compile as-is either). Record it + // and keep going so a single bad module doesn't mask every file after it. + unparseable.push({ file, error: (err as Error).message.split('\n')[0] }); + continue; + } if (result.status === 'transformed') { transformed.push(file); if (write && result.output !== source) { @@ -97,6 +109,16 @@ async function main(): Promise { } } + if (unparseable.length > 0) { + console.log( + `\nSkipped ${unparseable.length} unparseable file(s) (left untouched):`, + ); + for (let { file, error } of unparseable) { + console.log(` ⚠ ${file}`); + console.log(` - ${error}`); + } + } + if (!write && transformed.length > 0) { console.log('\nRe-run with --write to apply.'); } From c2856f96cc01bc26d284fcb403fb2dc46c3b4f28 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Tue, 23 Jun 2026 18:17:28 -0400 Subject: [PATCH 2/2] Type the per-file result and extract the parse error defensively MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address review feedback: `let result;` was an implicit `any` under realm-server's `noImplicitAny` (and `scripts/` is in the tsconfig `include`, so it would fail `lint:types`) — annotate it `TransformResult`. Also derive the skip-path message via `err instanceof Error ? err.message : String(err)` so a non-Error throw can't crash the report. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01R4n4P6G1vFdSvSZaKkFK5f --- .../realm-server/scripts/codemod/context-search/run.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/realm-server/scripts/codemod/context-search/run.ts b/packages/realm-server/scripts/codemod/context-search/run.ts index 8082e983f66..cb094560d3a 100644 --- a/packages/realm-server/scripts/codemod/context-search/run.ts +++ b/packages/realm-server/scripts/codemod/context-search/run.ts @@ -12,7 +12,7 @@ import { join, resolve } from 'path'; import * as prettier from 'prettier'; -import { transformContextSearch } from './transform.ts'; +import { transformContextSearch, type TransformResult } from './transform.ts'; // Format the migrated source through the repo's prettier config (with // prettier-plugin-ember-template-tag for `.gts`) so the structural edits land as @@ -68,14 +68,15 @@ async function main(): Promise { for (let file of files) { let source = readFileSync(file, 'utf8'); - let result; + let result: TransformResult; try { result = transformContextSearch(source, { filename: file }); } catch (err) { // The transformer threw while parsing this module's template, so it can't // be migrated mechanically (and would not compile as-is either). Record it // and keep going so a single bad module doesn't mask every file after it. - unparseable.push({ file, error: (err as Error).message.split('\n')[0] }); + let message = err instanceof Error ? err.message : String(err); + unparseable.push({ file, error: message.split('\n')[0] }); continue; } if (result.status === 'transformed') {