import test from "node:test" import assert from "node:assert/strict" import {readdirSync,readFileSync} from "node:fs" import {join} from "node:path" import {fileURLToPath} from "node:url" import ts from "typescript" // Native containers cannot render literal text, including a same-line JSX space. const textComponents=new Set(["Text","Body","Title"]) function rawText(source:string,file="fixture.tsx"):string[]{ const ast=ts.createSourceFile(file,source,ts.ScriptTarget.Latest,true,ts.ScriptKind.TSX),errors:string[]=[] function visit(node:ts.Node){ if(ts.isJsxText(node)&&node.text&&(!/^\s*$/.test(node.text)||!/[\r\n]/.test(node.text))){ const parent=node.parent,name=ts.isJsxElement(parent)?parent.openingElement.tagName.getText(ast):"fragment" if(!textComponents.has(name)){const {line}=ast.getLineAndCharacterOfPosition(node.pos);errors.push(`${file}:${line+1} ${name}: ${JSON.stringify(node.text)}`)} } ts.forEachChild(node,visit) } visit(ast);return errors } function files(dir:string):string[]{return readdirSync(dir,{withFileTypes:true}).flatMap(e=>e.isDirectory()?files(join(dir,e.name)):e.name.endsWith(".tsx")?[join(dir,e.name)]:[])} test("native text check distinguishes literal spaces from formatting and Text content",()=>{ assert.equal(rawText('hello world next').length,1) assert.equal(rawText('bare text').length,1) assert.equal(rawText('<>hello ').length,1) assert.deepEqual(rawText('\n hello world\n body\n'),[]) }) test("App screens and components contain no text outside text components",()=>{ const root=fileURLToPath(new URL("../",import.meta.url)) const errors=[...files(join(root,"app")),...files(join(root,"src"))].flatMap(file=>rawText(readFileSync(file,"utf8"),file)) assert.deepEqual(errors,[],errors.join("\n")) })