mirror of
https://github.com/actualbudget/actual.git
synced 2026-04-30 02:29:58 -05:00
Refactor inline-loot-core-types script to streamline TypeScript declaration handling and improve output organization. Remove legacy code and directly copy loot-core declaration tree, updating index.d.ts to reference local imports.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Post-build script: generates @types/loot-core.d.ts with declare module blocks
|
||||
* so the published package is self-contained (no external loot-core types).
|
||||
* Post-build script: copies loot-core declaration tree into @types/loot-core
|
||||
* and rewrites index.d.ts to reference it so the published package is self-contained.
|
||||
* Run after vite build; requires loot-core declarations (yarn workspace loot-core exec tsc).
|
||||
*/
|
||||
import fs from 'fs';
|
||||
@@ -11,134 +11,43 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const apiRoot = path.resolve(__dirname, '..');
|
||||
const typesDir = path.join(apiRoot, '@types');
|
||||
const indexDts = path.join(typesDir, 'index.d.ts');
|
||||
const lootCoreDeclRoot = path.resolve(
|
||||
apiRoot,
|
||||
'../loot-core/lib-dist/decl/src',
|
||||
);
|
||||
|
||||
function collectLootCorePaths(content) {
|
||||
const paths = new Set();
|
||||
const re = /['"]loot-core\/([^'"]+)['"]/g;
|
||||
let m;
|
||||
while ((m = re.exec(content)) !== null) paths.add(m[1]);
|
||||
return paths;
|
||||
}
|
||||
|
||||
function resolveDeclFile(subpath) {
|
||||
const base = path.join(lootCoreDeclRoot, subpath);
|
||||
const withExt = base + '.d.ts';
|
||||
const index = path.join(base, 'index.d.ts');
|
||||
if (fs.existsSync(withExt)) return withExt;
|
||||
if (fs.existsSync(index)) return index;
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveRelativePath(fromPath, relSpecifier) {
|
||||
const dir = path.dirname(fromPath);
|
||||
const resolved = path.join(dir, relSpecifier).replace(/\\/g, '/');
|
||||
return path.normalize(resolved).replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
function collectReexports(paths) {
|
||||
const expanded = new Set(paths);
|
||||
const reExportFrom =
|
||||
/export\s+(?:\*\s+from|type\s+\*\s+from|(?:\{[^}]*\})\s+from)\s+['"](\.\.?\/[^'"]+)['"]/g;
|
||||
const reImportFrom =
|
||||
/import\s+(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+)\s+from\s+['"](\.\.?\/[^'"]+)['"]/g;
|
||||
let changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const p of expanded) {
|
||||
const file = resolveDeclFile(p);
|
||||
if (!file) continue;
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
for (const re of [reExportFrom, reImportFrom]) {
|
||||
re.lastIndex = 0;
|
||||
let m;
|
||||
while ((m = re.exec(content)) !== null) {
|
||||
const normalized = resolveRelativePath(p, m[1]);
|
||||
if (!expanded.has(normalized)) {
|
||||
expanded.add(normalized);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
|
||||
function resolveToLootCorePath(currentPath, specifier) {
|
||||
const dir = path.dirname(currentPath);
|
||||
const resolved = path.join(dir, specifier).replace(/\\/g, '/');
|
||||
const normalized = path.normalize(resolved).replace(/\\/g, '/');
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function rewriteRelativeImports(content, currentPath) {
|
||||
function toLootCore(rel) {
|
||||
const normalized = resolveToLootCorePath(currentPath, rel);
|
||||
return `loot-core/${normalized}`;
|
||||
}
|
||||
return content
|
||||
.replace(
|
||||
/(export\s+(?:\*\s+from|type\s+\*\s+from)\s+)['"](\.\.?\/[^'"]+)['"]/g,
|
||||
(_, prefix, rel) => `${prefix}'${toLootCore(rel)}';`,
|
||||
)
|
||||
.replace(
|
||||
/(export\s+(?:type\s+)?(?:\{[^}]*\})\s+from\s+)['"](\.\.?\/[^'"]+)['"]/g,
|
||||
(_, prefix, rel) => `${prefix}'${toLootCore(rel)}';`,
|
||||
)
|
||||
.replace(
|
||||
/(import\s+(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+)\s+from\s+)['"](\.\.?\/[^'"]+)['"]/g,
|
||||
(_, prefix, rel) => `${prefix}'${toLootCore(rel)}'`,
|
||||
)
|
||||
.replace(
|
||||
/(import\s+)['"](\.\.?\/[^'"]+)['"]/g,
|
||||
(_, prefix, rel) => `${prefix}'${toLootCore(rel)}'`,
|
||||
);
|
||||
}
|
||||
|
||||
function buildLootCoreDts(paths) {
|
||||
const blocks = [];
|
||||
for (const p of [...paths].sort()) {
|
||||
const file = resolveDeclFile(p);
|
||||
if (!file) continue;
|
||||
let content = fs.readFileSync(file, 'utf8');
|
||||
content = rewriteRelativeImports(content, p);
|
||||
blocks.push(`declare module 'loot-core/${p}' {\n${content}\n}\n`);
|
||||
}
|
||||
return (
|
||||
'// Inlined loot-core type declarations for @actual-app/api publish.\n' +
|
||||
'// Do not edit by hand; generated by scripts/inline-loot-core-types.mjs.\n\n' +
|
||||
blocks.join('\n')
|
||||
);
|
||||
}
|
||||
const lootCoreDeclSrc = path.resolve(apiRoot, '../loot-core/lib-dist/decl/src');
|
||||
const lootCoreTypesDir = path.join(typesDir, 'loot-core');
|
||||
|
||||
function main() {
|
||||
if (!fs.existsSync(indexDts)) {
|
||||
console.error('Missing @types/index.d.ts; run vite build first.');
|
||||
process.exit(1);
|
||||
}
|
||||
if (!fs.existsSync(lootCoreDeclRoot)) {
|
||||
if (!fs.existsSync(lootCoreDeclSrc)) {
|
||||
console.error(
|
||||
'Missing loot-core declarations; run: yarn workspace loot-core exec tsc',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let indexContent = fs.readFileSync(indexDts, 'utf8');
|
||||
const paths = collectLootCorePaths(indexContent);
|
||||
const allPaths = collectReexports(paths);
|
||||
const lootCoreDts = buildLootCoreDts(allPaths);
|
||||
const lootCoreDtsPath = path.join(typesDir, 'loot-core.d.ts');
|
||||
fs.writeFileSync(lootCoreDtsPath, lootCoreDts, 'utf8');
|
||||
|
||||
const reference = '/// <reference path="./loot-core.d.ts" />\n';
|
||||
if (!indexContent.startsWith(reference.trim())) {
|
||||
indexContent = reference + indexContent;
|
||||
fs.writeFileSync(indexDts, indexContent, 'utf8');
|
||||
// Remove existing loot-core output (dir or legacy single file)
|
||||
if (fs.existsSync(lootCoreTypesDir)) {
|
||||
fs.rmSync(lootCoreTypesDir, { recursive: true });
|
||||
}
|
||||
const legacyDts = path.join(typesDir, 'loot-core.d.ts');
|
||||
if (fs.existsSync(legacyDts)) {
|
||||
fs.rmSync(legacyDts);
|
||||
}
|
||||
|
||||
// Copy declaration tree as-is (relative imports inside files resolve within the tree)
|
||||
fs.cpSync(lootCoreDeclSrc, lootCoreTypesDir, { recursive: true });
|
||||
|
||||
// Rewrite index.d.ts: remove reference, point imports at local ./loot-core/
|
||||
let indexContent = fs.readFileSync(indexDts, 'utf8');
|
||||
indexContent = indexContent.replace(
|
||||
/\/\/\/ <reference path="\.\/loot-core\.d\.ts" \/>\n?/,
|
||||
'',
|
||||
);
|
||||
indexContent = indexContent
|
||||
.replace(/'loot-core\//g, "'./loot-core/")
|
||||
.replace(/"loot-core\//g, '"./loot-core/');
|
||||
fs.writeFileSync(indexDts, indexContent, 'utf8');
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
20
yarn.lock
20
yarn.lock
@@ -24,10 +24,8 @@ __metadata:
|
||||
resolution: "@actual-app/api@workspace:packages/api"
|
||||
dependencies:
|
||||
"@actual-app/crdt": "workspace:^"
|
||||
"@microsoft/api-extractor": "npm:^7.50.1"
|
||||
better-sqlite3: "npm:^12.6.2"
|
||||
compare-versions: "npm:^6.1.1"
|
||||
dts-bundle-generator: "npm:^9.5.1"
|
||||
loot-core: "workspace:^"
|
||||
node-fetch: "npm:^3.3.2"
|
||||
rollup-plugin-visualizer: "npm:^6.0.5"
|
||||
@@ -15086,18 +15084,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dts-bundle-generator@npm:^9.5.1":
|
||||
version: 9.5.1
|
||||
resolution: "dts-bundle-generator@npm:9.5.1"
|
||||
dependencies:
|
||||
typescript: "npm:>=5.0.2"
|
||||
yargs: "npm:^17.6.0"
|
||||
bin:
|
||||
dts-bundle-generator: dist/bin/dts-bundle-generator.js
|
||||
checksum: 10/8abddebcaab0d542afcb62971526beb5ea09f977b92cb06723e6046bde7d2bc9513c8508b937f62d7a46b28827b26fda4c31ed85fe2902e01685741f823a50eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "dunder-proto@npm:1.0.1"
|
||||
@@ -28042,7 +28028,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@npm:>=5.0.2, typescript@npm:^5.0.4, typescript@npm:^5.9.3":
|
||||
"typescript@npm:^5.0.4, typescript@npm:^5.9.3":
|
||||
version: 5.9.3
|
||||
resolution: "typescript@npm:5.9.3"
|
||||
bin:
|
||||
@@ -28062,7 +28048,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@patch:typescript@npm%3A>=5.0.2#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.9.3#optional!builtin<compat/typescript>":
|
||||
"typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.9.3#optional!builtin<compat/typescript>":
|
||||
version: 5.9.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>::version=5.9.3&hash=5786d5"
|
||||
bin:
|
||||
@@ -29912,7 +29898,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs@npm:^17.0.1, yargs@npm:^17.5.1, yargs@npm:^17.6.0, yargs@npm:^17.6.2":
|
||||
"yargs@npm:^17.0.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2":
|
||||
version: 17.7.2
|
||||
resolution: "yargs@npm:17.7.2"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user