Skip to content

Commit f95dde3

Browse files
committed
lint and benchmark
1 parent bcc17b3 commit f95dde3

3 files changed

Lines changed: 151 additions & 10 deletions

File tree

scripts/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Translation and localization tools.
7171
General-purpose utility scripts.
7272

7373
- **image-map.js** - Image mapping and analysis tools
74+
- **bench.js** - Run simple performance benchmarks for load/extract/process paths
7475

7576
## 🚀 Usage
7677

@@ -84,6 +85,15 @@ npm run build
8485
node scripts/analysis/analyze_pageset.js path/to/pageset.gridset
8586
node scripts/analysis/extract_vocabulary.js path/to/pageset.gridset
8687
npx ts-node scripts/conversion/txt-to-gridset.ts input.tsv output.gridset
88+
89+
# Benchmark a processor by file type (loadIntoTree)
90+
node scripts/bench.js --file examples/example.gridset
91+
92+
# Benchmark text extraction
93+
node scripts/bench.js --file examples/example.obz --mode extract --iterations 10
94+
95+
# Benchmark translation processing
96+
node scripts/bench.js --file examples/example.sps --mode process --iterations 3
8797
```
8898

8999
## 🔑 Environment Variables

scripts/bench.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const os = require('os');
6+
const { performance } = require('perf_hooks');
7+
8+
function requireLibrary() {
9+
const distPath = path.resolve(__dirname, '../dist');
10+
try {
11+
// eslint-disable-next-line global-require, import/no-dynamic-require
12+
return require(distPath);
13+
} catch (error) {
14+
console.error('Unable to load the built library from dist/. Have you run "npm run build"?');
15+
throw error;
16+
}
17+
}
18+
19+
const ENGINE_TO_EXT = {
20+
dot: '.dot',
21+
opml: '.opml',
22+
obf: '.obf',
23+
obz: '.obz',
24+
obfset: '.obfset',
25+
gridset: '.gridset',
26+
gridsetx: '.gridsetx',
27+
snap: '.sps',
28+
spb: '.spb',
29+
touchchat: '.ce',
30+
excel: '.xlsx',
31+
applepanels: '.plist',
32+
asterics: '.grd',
33+
};
34+
35+
function parseArgs(argv) {
36+
const args = {
37+
file: '',
38+
engine: '',
39+
mode: 'load',
40+
iterations: 5,
41+
};
42+
for (let i = 2; i < argv.length; i += 1) {
43+
const value = argv[i + 1];
44+
if (argv[i] === '--file' && value) {
45+
args.file = value;
46+
i += 1;
47+
} else if (argv[i] === '--engine' && value) {
48+
args.engine = value;
49+
i += 1;
50+
} else if (argv[i] === '--mode' && value) {
51+
args.mode = value;
52+
i += 1;
53+
} else if (argv[i] === '--iterations' && value) {
54+
args.iterations = Math.max(1, Number(value));
55+
i += 1;
56+
}
57+
}
58+
return args;
59+
}
60+
61+
function detectExtension(inputPath, engineOverride) {
62+
if (engineOverride) {
63+
const key = engineOverride.toLowerCase();
64+
return ENGINE_TO_EXT[key] || engineOverride;
65+
}
66+
const ext = path.extname(inputPath);
67+
return ext || '';
68+
}
69+
70+
function mean(values) {
71+
return values.reduce((sum, v) => sum + v, 0) / values.length;
72+
}
73+
74+
function percentile(values, p) {
75+
const sorted = [...values].sort((a, b) => a - b);
76+
const idx = Math.min(sorted.length - 1, Math.floor(sorted.length * p));
77+
return sorted[idx];
78+
}
79+
80+
async function main() {
81+
const args = parseArgs(process.argv);
82+
if (!args.file) {
83+
console.error('Usage: node scripts/bench.js --file <path> [--engine <name>] [--mode load|extract|process] [--iterations N]');
84+
process.exit(1);
85+
}
86+
87+
const inputPath = path.resolve(process.cwd(), args.file);
88+
if (!fs.existsSync(inputPath)) {
89+
console.error(`File not found: ${inputPath}`);
90+
process.exit(1);
91+
}
92+
93+
const { getProcessor } = requireLibrary();
94+
const extension = detectExtension(inputPath, args.engine);
95+
const processor = getProcessor(extension);
96+
const iterations = args.iterations;
97+
98+
let translations = null;
99+
if (args.mode === 'process') {
100+
const texts = await processor.extractTexts(inputPath);
101+
translations = new Map();
102+
texts.slice(0, 50).forEach((text) => {
103+
if (typeof text === 'string' && text.trim().length > 0) {
104+
translations.set(text, `${text}-bench`);
105+
}
106+
});
107+
}
108+
109+
const timings = [];
110+
for (let i = 0; i < iterations; i += 1) {
111+
const start = performance.now();
112+
if (args.mode === 'extract') {
113+
await processor.extractTexts(inputPath);
114+
} else if (args.mode === 'process') {
115+
const outputPath = path.join(os.tmpdir(), `aac-bench-${Date.now()}-${i}${extension}`);
116+
await processor.processTexts(inputPath, translations || new Map(), outputPath);
117+
} else {
118+
await processor.loadIntoTree(inputPath);
119+
}
120+
timings.push(performance.now() - start);
121+
}
122+
123+
const avg = mean(timings);
124+
const p95 = percentile(timings, 0.95);
125+
126+
console.log('Bench results');
127+
console.log(`- file: ${inputPath}`);
128+
console.log(`- engine: ${args.engine || extension}`);
129+
console.log(`- mode: ${args.mode}`);
130+
console.log(`- iterations: ${iterations}`);
131+
console.log(`- avg ms: ${avg.toFixed(2)}`);
132+
console.log(`- p95 ms: ${p95.toFixed(2)}`);
133+
}
134+
135+
main().catch((error) => {
136+
console.error(error);
137+
process.exit(1);
138+
});

test/processors/gridset/symbols.test.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,7 @@ describe('gridset symbols utilities', () => {
5252
};
5353

5454
const refs = extractSymbolReferences(tree);
55-
expect(refs).toEqual([
56-
'[tawasl]/animals/cat.png',
57-
'[widgit]/food/apple.png',
58-
]);
55+
expect(refs).toEqual(['[tawasl]/animals/cat.png', '[widgit]/food/apple.png']);
5956

6057
const usage = analyzeSymbolUsage(tree);
6158
expect(usage.totalSymbols).toBe(2);
@@ -65,11 +62,7 @@ describe('gridset symbols utilities', () => {
6562
});
6663

6764
it('creates embedded filenames for symbol references', () => {
68-
expect(symbolReferenceToFilename('[widgit]/food/apple.png', 2, 3)).toBe(
69-
'2-3-0-text-0.png'
70-
);
71-
expect(symbolReferenceToFilename('[widgit]/food/apple', 1, 1)).toBe(
72-
'1-1-0-text-0.png'
73-
);
65+
expect(symbolReferenceToFilename('[widgit]/food/apple.png', 2, 3)).toBe('2-3-0-text-0.png');
66+
expect(symbolReferenceToFilename('[widgit]/food/apple', 1, 1)).toBe('1-1-0-text-0.png');
7467
});
7568
});

0 commit comments

Comments
 (0)