33 lines
1.8 KiB
TypeScript
33 lines
1.8 KiB
TypeScript
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('<View><Text>hello world</Text> <Text>next</Text></View>').length,1)
|
|
assert.equal(rawText('<View>bare text</View>').length,1)
|
|
assert.equal(rawText('<><Text>hello</Text> </>').length,1)
|
|
assert.deepEqual(rawText('<View>\n <Text>hello world</Text>\n <Body>body</Body>\n</View>'),[])
|
|
})
|
|
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"))
|
|
})
|