Files
readest/apps/readest-app/scripts/lint-koplugin.js
T
Huang Xin c59097b0ac feat(koplugin): add i18n catalog and sync info dialog (#4050)
- i18n loader at apps/readest.koplugin/i18n.lua: isolated callable,
  falls back to KOReader's gettext when a string is untranslated
- Translation catalog at locales/<i18next-code>/translation.po for 31
  languages, mirroring apps/readest-app/public/locales/
- scripts/extract-i18n.js (scan _("...") and _([[...]]); preserve
  existing, drop obsolete, add new) and scripts/apply-translations.js
  (bulk import from /tmp/koplugin-translations/<lang>.json)
- Mirror apps/readest-app SyncInfoDialog: rename showMetaHashInfo to
  showSyncInfo, dialog title "Sync Info", new Last Synced row computed
  as max(last_synced_at_config, last_synced_at_notes) from doc_settings
- syncconfig.lua / syncannotations.lua mark per-book sync timestamps
  on push/pull success
- Rename "Meta Hash" -> "Book Fingerprint" in koplugin and
  apps/readest-app SyncInfoDialog.tsx; translations propagated to
  all readest-app locales
- "book config" -> "reading progress" wording across user-facing
  strings (matches QiuYukang fork terminology)
- Replace "Log out as " / "Login failed: " concat prefixes with
  T(_("...%1..."), arg) placeholder pattern (RTL / verb-final friendly)
- pnpm lint:lua: luajit -b syntax check across koplugin .lua files;
  soft-skips when luajit is missing locally; CI installs luajit and
  runs the check unconditionally

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 05:35:36 +02:00

55 lines
1.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Syntax-check every Lua file in apps/readest.koplugin against LuaJIT (the
* runtime KOReader uses). `luajit -b <src> /dev/null` parses the source and
* emits bytecode to /dev/null, returning non-zero on any syntax error without
* executing the file. We use LuaJIT specifically — not stock Lua — because
* the koplugin relies on LuaJIT-only features (`ffi/*`) and stock luac
* silently accepts a few constructs LuaJIT rejects (e.g. `<const>`).
*
* Invoked from `pnpm lint:lua`. Soft-skips with a notice when luajit is not
* installed; CI installs luajit and runs unconditionally.
*/
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const KOPLUGIN_DIR = path.resolve(__dirname, '..', '..', 'readest.koplugin');
if (!fs.existsSync(KOPLUGIN_DIR)) {
console.error(`koplugin directory not found at ${KOPLUGIN_DIR}`);
process.exit(1);
}
const luaFiles = fs
.readdirSync(KOPLUGIN_DIR)
.filter((f) => f.endsWith('.lua'))
.map((f) => path.join(KOPLUGIN_DIR, f))
.sort();
if (luaFiles.length === 0) {
console.log('No .lua files to check.');
process.exit(0);
}
const which = spawnSync(process.platform === 'win32' ? 'where' : 'which', ['luajit']);
if (which.status !== 0) {
console.warn(
'lint:lua: luajit not found, skipping koplugin syntax check. ' +
'Install LuaJIT (e.g. `brew install luajit` on macOS, `apt-get install luajit` on Linux) ' +
'to enable this check locally. CI runs it unconditionally.',
);
process.exit(0);
}
const devNull = process.platform === 'win32' ? 'NUL' : '/dev/null';
let failed = 0;
for (const file of luaFiles) {
const r = spawnSync('luajit', ['-b', file, devNull], { stdio: 'inherit' });
if (r.status !== 0) failed++;
}
process.exit(failed === 0 ? 0 : 1);