124 lines
3.5 KiB
JavaScript
124 lines
3.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/* eslint-disable no-console */
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const vm = require('vm');
|
|
require('dotenv').config();
|
|
|
|
const { closeDatabase, openDatabase } = require('../lib/sqlite');
|
|
const { ensurePlantSchema, rebuildPlantsCatalog } = require('../lib/plants');
|
|
|
|
let ts;
|
|
try {
|
|
ts = require('typescript');
|
|
} catch (error) {
|
|
console.error('The rebuild script needs the "typescript" package in node_modules.');
|
|
console.error('Install dependencies in the repository root before running this script.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const ROOT_DIR = path.resolve(__dirname, '..', '..');
|
|
const BATCH_1_PATH = path.join(ROOT_DIR, 'constants', 'lexiconBatch1.ts');
|
|
const BATCH_2_PATH = path.join(ROOT_DIR, 'constants', 'lexiconBatch2.ts');
|
|
|
|
const resolveTsFilePath = (fromFile, specifier) => {
|
|
if (!specifier.startsWith('.')) return null;
|
|
const fromDirectory = path.dirname(fromFile);
|
|
const absoluteBase = path.resolve(fromDirectory, specifier);
|
|
const candidates = [
|
|
absoluteBase,
|
|
`${absoluteBase}.ts`,
|
|
`${absoluteBase}.tsx`,
|
|
path.join(absoluteBase, 'index.ts'),
|
|
];
|
|
for (const candidate of candidates) {
|
|
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
return candidate;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const loadTsModule = (absolutePath, cache = new Map()) => {
|
|
if (cache.has(absolutePath)) return cache.get(absolutePath);
|
|
|
|
const source = fs.readFileSync(absolutePath, 'utf8');
|
|
const transpiled = ts.transpileModule(source, {
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS,
|
|
target: ts.ScriptTarget.ES2020,
|
|
esModuleInterop: true,
|
|
jsx: ts.JsxEmit.ReactJSX,
|
|
},
|
|
fileName: absolutePath,
|
|
reportDiagnostics: false,
|
|
}).outputText;
|
|
|
|
const module = { exports: {} };
|
|
cache.set(absolutePath, module.exports);
|
|
|
|
const localRequire = (specifier) => {
|
|
const resolvedTsPath = resolveTsFilePath(absolutePath, specifier);
|
|
if (resolvedTsPath) {
|
|
return loadTsModule(resolvedTsPath, cache);
|
|
}
|
|
return require(specifier);
|
|
};
|
|
|
|
const sandbox = {
|
|
module,
|
|
exports: module.exports,
|
|
require: localRequire,
|
|
__dirname: path.dirname(absolutePath),
|
|
__filename: absolutePath,
|
|
console,
|
|
process,
|
|
Buffer,
|
|
setTimeout,
|
|
clearTimeout,
|
|
};
|
|
|
|
vm.runInNewContext(transpiled, sandbox, { filename: absolutePath });
|
|
cache.set(absolutePath, module.exports);
|
|
return module.exports;
|
|
};
|
|
|
|
const loadBatchEntries = () => {
|
|
const batch1Module = loadTsModule(BATCH_1_PATH);
|
|
const batch2Module = loadTsModule(BATCH_2_PATH);
|
|
|
|
const batch1Entries = batch1Module.LEXICON_BATCH_1_ENTRIES;
|
|
const batch2Entries = batch2Module.LEXICON_BATCH_2_ENTRIES;
|
|
|
|
if (!Array.isArray(batch1Entries) || !Array.isArray(batch2Entries)) {
|
|
throw new Error('Could not load lexicon batch entries from TypeScript constants.');
|
|
}
|
|
|
|
return [...batch1Entries, ...batch2Entries];
|
|
};
|
|
|
|
const main = async () => {
|
|
const entries = loadBatchEntries();
|
|
const db = await openDatabase();
|
|
|
|
try {
|
|
await ensurePlantSchema(db);
|
|
const summary = await rebuildPlantsCatalog(db, entries, {
|
|
source: 'local_batch_script',
|
|
preserveExistingIds: true,
|
|
enforceUniqueImages: true,
|
|
});
|
|
|
|
console.log('Rebuild finished successfully.');
|
|
console.log(JSON.stringify(summary, null, 2));
|
|
} finally {
|
|
await closeDatabase(db);
|
|
}
|
|
};
|
|
|
|
main().catch((error) => {
|
|
console.error('Failed to rebuild plants from local batches.');
|
|
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
|
process.exit(1);
|
|
});
|