@emeryld/rrroutes-export 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/exportFinalizedLeaves.changelog.cli.d.ts +2 -0
- package/dist/exportFinalizedLeaves.changelog.d.ts +27 -0
- package/dist/index.cjs +203 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +203 -70
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1340,9 +1340,11 @@ async function runExportFinalizedLeavesCli(argv) {
|
|
|
1340
1340
|
import fs2 from "fs/promises";
|
|
1341
1341
|
import os from "os";
|
|
1342
1342
|
import path4 from "path";
|
|
1343
|
+
import crypto from "crypto";
|
|
1343
1344
|
import { execFile as execFileCallback, spawn as spawn2 } from "child_process";
|
|
1344
1345
|
import { promisify } from "util";
|
|
1345
1346
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1347
|
+
import ts2 from "typescript";
|
|
1346
1348
|
var execFile = promisify(execFileCallback);
|
|
1347
1349
|
var CHANGESET_CFG_FIELDS = [
|
|
1348
1350
|
"summary",
|
|
@@ -1825,96 +1827,213 @@ async function pathExists(filePath) {
|
|
|
1825
1827
|
return false;
|
|
1826
1828
|
}
|
|
1827
1829
|
}
|
|
1828
|
-
|
|
1829
|
-
const
|
|
1830
|
-
|
|
1831
|
-
|
|
1830
|
+
function isTypeScriptModule(modulePath) {
|
|
1831
|
+
const ext = path4.extname(modulePath).toLowerCase();
|
|
1832
|
+
return ext === ".ts" || ext === ".tsx" || ext === ".mts" || ext === ".cts";
|
|
1833
|
+
}
|
|
1834
|
+
function isJavaScriptModule(modulePath) {
|
|
1835
|
+
const ext = path4.extname(modulePath).toLowerCase();
|
|
1836
|
+
return ext === ".js" || ext === ".mjs" || ext === ".cjs";
|
|
1837
|
+
}
|
|
1838
|
+
async function resolveSnapshotTsconfig(worktreeDir, modulePath, tsconfigOverride) {
|
|
1839
|
+
if (tsconfigOverride) {
|
|
1840
|
+
const resolved = path4.resolve(worktreeDir, tsconfigOverride);
|
|
1841
|
+
if (!await pathExists(resolved)) {
|
|
1842
|
+
throw new Error(`tsconfig not found: ${resolved}`);
|
|
1843
|
+
}
|
|
1844
|
+
return resolved;
|
|
1845
|
+
}
|
|
1846
|
+
let current = path4.dirname(modulePath);
|
|
1847
|
+
const normalizedRoot = normalizePath(path4.resolve(worktreeDir));
|
|
1848
|
+
while (true) {
|
|
1849
|
+
const candidate = path4.join(current, "tsconfig.json");
|
|
1850
|
+
if (await pathExists(candidate)) {
|
|
1851
|
+
return candidate;
|
|
1852
|
+
}
|
|
1853
|
+
const parent = path4.dirname(current);
|
|
1854
|
+
if (parent === current) break;
|
|
1855
|
+
if (!normalizePath(parent).startsWith(normalizedRoot)) break;
|
|
1856
|
+
current = parent;
|
|
1857
|
+
}
|
|
1858
|
+
throw new Error(
|
|
1859
|
+
`Unable to resolve tsconfig for TypeScript module: ${modulePath}. Pass --tsconfig to override.`
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
function toEmittedModulePath(moduleRel) {
|
|
1863
|
+
const normalized = normalizePath(moduleRel);
|
|
1864
|
+
if (normalized.endsWith(".mts")) return normalized.slice(0, -4) + ".mjs";
|
|
1865
|
+
if (normalized.endsWith(".cts")) return normalized.slice(0, -4) + ".cjs";
|
|
1866
|
+
if (normalized.endsWith(".tsx")) return normalized.slice(0, -4) + ".js";
|
|
1867
|
+
if (normalized.endsWith(".ts")) return normalized.slice(0, -3) + ".js";
|
|
1868
|
+
return normalized;
|
|
1869
|
+
}
|
|
1870
|
+
function buildCompileCacheKey(commitSha, moduleRel, tsconfigPath, tsconfigStat) {
|
|
1871
|
+
return crypto.createHash("sha1").update(commitSha).update("\n").update(normalizePath(moduleRel)).update("\n").update(normalizePath(tsconfigPath)).update("\n").update(String(tsconfigStat.mtimeMs)).update("\n").update(String(tsconfigStat.size)).digest("hex");
|
|
1872
|
+
}
|
|
1873
|
+
async function collectFilesRecursive(rootDir) {
|
|
1874
|
+
const files = [];
|
|
1832
1875
|
const walk = async (dir) => {
|
|
1833
1876
|
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
1834
1877
|
for (const entry of entries) {
|
|
1878
|
+
const target = path4.join(dir, entry.name);
|
|
1835
1879
|
if (entry.isDirectory()) {
|
|
1836
|
-
|
|
1837
|
-
await walk(path4.join(dir, entry.name));
|
|
1880
|
+
await walk(target);
|
|
1838
1881
|
continue;
|
|
1839
1882
|
}
|
|
1840
|
-
if (
|
|
1841
|
-
|
|
1842
|
-
filesToScan.push(path4.join(dir, entry.name));
|
|
1843
|
-
}
|
|
1844
|
-
};
|
|
1845
|
-
await walk(worktreeDir);
|
|
1846
|
-
const importRegexes = [
|
|
1847
|
-
/\\bfrom\\s+['\"](\\.[^'\"]+\\.js)['\"]/g,
|
|
1848
|
-
/\\bimport\\(\\s*['\"](\\.[^'\"]+\\.js)['\"]\\s*\\)/g,
|
|
1849
|
-
/\\brequire\\(\\s*['\"](\\.[^'\"]+\\.js)['\"]\\s*\\)/g
|
|
1850
|
-
];
|
|
1851
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1852
|
-
for (const filePath of filesToScan) {
|
|
1853
|
-
const content = await fs2.readFile(filePath, "utf8");
|
|
1854
|
-
for (const regex of importRegexes) {
|
|
1855
|
-
regex.lastIndex = 0;
|
|
1856
|
-
let match = regex.exec(content);
|
|
1857
|
-
while (match) {
|
|
1858
|
-
const specifier = match[1];
|
|
1859
|
-
const resolvedJs = path4.resolve(path4.dirname(filePath), specifier);
|
|
1860
|
-
if (seen.has(resolvedJs)) {
|
|
1861
|
-
match = regex.exec(content);
|
|
1862
|
-
continue;
|
|
1863
|
-
}
|
|
1864
|
-
seen.add(resolvedJs);
|
|
1865
|
-
if (await pathExists(resolvedJs)) {
|
|
1866
|
-
match = regex.exec(content);
|
|
1867
|
-
continue;
|
|
1868
|
-
}
|
|
1869
|
-
const tsCandidates = [
|
|
1870
|
-
resolvedJs.replace(/\\.js$/, ".ts"),
|
|
1871
|
-
resolvedJs.replace(/\\.js$/, ".mts"),
|
|
1872
|
-
resolvedJs.replace(/\\.js$/, ".tsx")
|
|
1873
|
-
];
|
|
1874
|
-
let targetTs;
|
|
1875
|
-
for (const candidate of tsCandidates) {
|
|
1876
|
-
if (await pathExists(candidate)) {
|
|
1877
|
-
targetTs = candidate;
|
|
1878
|
-
break;
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
if (targetTs) {
|
|
1882
|
-
const relImport = normalizePath(path4.relative(path4.dirname(resolvedJs), targetTs));
|
|
1883
|
-
const importPath = relImport.startsWith(".") ? relImport : `./${relImport}`;
|
|
1884
|
-
const shim = `export * from '${importPath}'
|
|
1885
|
-
import * as __all from '${importPath}'
|
|
1886
|
-
export default ('default' in __all ? __all.default : __all)
|
|
1887
|
-
`;
|
|
1888
|
-
await fs2.mkdir(path4.dirname(resolvedJs), { recursive: true });
|
|
1889
|
-
await fs2.writeFile(resolvedJs, shim, "utf8");
|
|
1890
|
-
shimWrites.push(resolvedJs);
|
|
1891
|
-
}
|
|
1892
|
-
match = regex.exec(content);
|
|
1883
|
+
if (entry.isFile()) {
|
|
1884
|
+
files.push(target);
|
|
1893
1885
|
}
|
|
1894
1886
|
}
|
|
1887
|
+
};
|
|
1888
|
+
if (await pathExists(rootDir)) {
|
|
1889
|
+
await walk(rootDir);
|
|
1895
1890
|
}
|
|
1896
|
-
return
|
|
1891
|
+
return files;
|
|
1892
|
+
}
|
|
1893
|
+
function suffixMatchScore(candidate, wanted) {
|
|
1894
|
+
const left = normalizePath(candidate).split("/");
|
|
1895
|
+
const right = normalizePath(wanted).split("/");
|
|
1896
|
+
let score = 0;
|
|
1897
|
+
while (score < left.length && score < right.length) {
|
|
1898
|
+
const a = left[left.length - 1 - score];
|
|
1899
|
+
const b = right[right.length - 1 - score];
|
|
1900
|
+
if (a !== b) break;
|
|
1901
|
+
score += 1;
|
|
1902
|
+
}
|
|
1903
|
+
return score;
|
|
1904
|
+
}
|
|
1905
|
+
async function resolveEmittedEntryPath(emitRoot, moduleRel) {
|
|
1906
|
+
const expected = path4.resolve(emitRoot, toEmittedModulePath(moduleRel));
|
|
1907
|
+
if (await pathExists(expected)) {
|
|
1908
|
+
return expected;
|
|
1909
|
+
}
|
|
1910
|
+
const wantedRel = toEmittedModulePath(moduleRel);
|
|
1911
|
+
const wantedBase = path4.posix.basename(normalizePath(wantedRel));
|
|
1912
|
+
const files = await collectFilesRecursive(emitRoot);
|
|
1913
|
+
const candidates = files.filter(
|
|
1914
|
+
(file) => path4.posix.basename(normalizePath(file)) === wantedBase
|
|
1915
|
+
);
|
|
1916
|
+
if (candidates.length === 0) {
|
|
1917
|
+
return void 0;
|
|
1918
|
+
}
|
|
1919
|
+
candidates.sort(
|
|
1920
|
+
(a, b) => suffixMatchScore(b, wantedRel) - suffixMatchScore(a, wantedRel)
|
|
1921
|
+
);
|
|
1922
|
+
return candidates[0];
|
|
1923
|
+
}
|
|
1924
|
+
async function compileSnapshotEntry(options) {
|
|
1925
|
+
const log = options.log ?? (() => void 0);
|
|
1926
|
+
const tsconfigStat = await fs2.stat(options.tsconfigPath);
|
|
1927
|
+
const cacheKey = buildCompileCacheKey(
|
|
1928
|
+
options.commitSha,
|
|
1929
|
+
options.moduleRel,
|
|
1930
|
+
options.tsconfigPath,
|
|
1931
|
+
{ mtimeMs: tsconfigStat.mtimeMs, size: tsconfigStat.size }
|
|
1932
|
+
);
|
|
1933
|
+
const emitRoot = path4.join(options.cacheRoot, cacheKey, "dist");
|
|
1934
|
+
let emittedEntry = path4.resolve(emitRoot, toEmittedModulePath(options.moduleRel));
|
|
1935
|
+
if (!options.noCache && await pathExists(emittedEntry)) {
|
|
1936
|
+
log(`[changelog] compile cache hit: ${options.commitSha.slice(0, 12)}`);
|
|
1937
|
+
return emittedEntry;
|
|
1938
|
+
}
|
|
1939
|
+
log(
|
|
1940
|
+
`[changelog] compile cache ${options.noCache ? "disabled" : "miss"}: ${options.commitSha.slice(0, 12)}`
|
|
1941
|
+
);
|
|
1942
|
+
await fs2.rm(path4.join(options.cacheRoot, cacheKey), { recursive: true, force: true }).catch(
|
|
1943
|
+
() => void 0
|
|
1944
|
+
);
|
|
1945
|
+
await fs2.mkdir(emitRoot, { recursive: true });
|
|
1946
|
+
const readResult = ts2.readConfigFile(options.tsconfigPath, ts2.sys.readFile);
|
|
1947
|
+
if (readResult.error) {
|
|
1948
|
+
throw new Error(ts2.flattenDiagnosticMessageText(readResult.error.messageText, "\n"));
|
|
1949
|
+
}
|
|
1950
|
+
const parsed = ts2.parseJsonConfigFileContent(
|
|
1951
|
+
readResult.config,
|
|
1952
|
+
ts2.sys,
|
|
1953
|
+
path4.dirname(options.tsconfigPath)
|
|
1954
|
+
);
|
|
1955
|
+
const compilerOptions = {
|
|
1956
|
+
...parsed.options,
|
|
1957
|
+
noEmit: false,
|
|
1958
|
+
declaration: false,
|
|
1959
|
+
declarationMap: false,
|
|
1960
|
+
sourceMap: false,
|
|
1961
|
+
inlineSourceMap: false,
|
|
1962
|
+
composite: false,
|
|
1963
|
+
incremental: false,
|
|
1964
|
+
tsBuildInfoFile: void 0,
|
|
1965
|
+
outDir: emitRoot
|
|
1966
|
+
};
|
|
1967
|
+
const program = ts2.createProgram([options.modulePath], compilerOptions);
|
|
1968
|
+
const emitResult = program.emit();
|
|
1969
|
+
const diagnostics = ts2.getPreEmitDiagnostics(program).concat(emitResult.diagnostics).filter((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error);
|
|
1970
|
+
if (diagnostics.length > 0) {
|
|
1971
|
+
const host = {
|
|
1972
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
1973
|
+
getCurrentDirectory: () => options.worktreeDir,
|
|
1974
|
+
getNewLine: () => "\n"
|
|
1975
|
+
};
|
|
1976
|
+
const message = ts2.formatDiagnosticsWithColorAndContext(diagnostics.slice(0, 20), host);
|
|
1977
|
+
throw new Error(
|
|
1978
|
+
`TypeScript snapshot compile failed for ${options.moduleRel} at ${options.commitSha.slice(0, 12)}:
|
|
1979
|
+
${message}`
|
|
1980
|
+
);
|
|
1981
|
+
}
|
|
1982
|
+
emittedEntry = await resolveEmittedEntryPath(emitRoot, options.moduleRel) ?? emittedEntry;
|
|
1983
|
+
if (!await pathExists(emittedEntry)) {
|
|
1984
|
+
throw new Error(
|
|
1985
|
+
`Compiled snapshot entry was not emitted: ${emittedEntry}. Check module/tsconfig compatibility.`
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
log(`[changelog] compiled snapshot entry: ${emittedEntry}`);
|
|
1989
|
+
return emittedEntry;
|
|
1990
|
+
}
|
|
1991
|
+
async function loadSnapshotExport(options) {
|
|
1992
|
+
return loadChangelogInput(options.entryPath, options.exportName);
|
|
1897
1993
|
}
|
|
1898
1994
|
async function createSnapshot(repoRoot, moduleRel, exportName, commit, tempRoot, tsconfigRel, exportOptions, log) {
|
|
1899
1995
|
const worktreeDir = path4.join(tempRoot, `wt-${commit.sha.slice(0, 12)}`);
|
|
1900
1996
|
await runGit(repoRoot, ["worktree", "add", "--detach", worktreeDir, commit.sha]);
|
|
1901
1997
|
try {
|
|
1902
1998
|
await ensureWorktreeDependencies(repoRoot, worktreeDir);
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1999
|
+
const modulePath = path4.resolve(worktreeDir, moduleRel);
|
|
2000
|
+
let snapshotRuntimePath = modulePath;
|
|
2001
|
+
let resolvedTsconfigPath;
|
|
2002
|
+
if (isTypeScriptModule(modulePath)) {
|
|
2003
|
+
resolvedTsconfigPath = await resolveSnapshotTsconfig(
|
|
2004
|
+
worktreeDir,
|
|
2005
|
+
modulePath,
|
|
2006
|
+
tsconfigRel
|
|
2007
|
+
);
|
|
2008
|
+
log?.(`[changelog] using tsconfig: ${resolvedTsconfigPath}`);
|
|
2009
|
+
const compileCacheRoot = path4.resolve(
|
|
2010
|
+
exportOptions?.cacheDir ?? path4.join(os.tmpdir(), "rrroutes-export-changelog-cache")
|
|
2011
|
+
);
|
|
2012
|
+
snapshotRuntimePath = await compileSnapshotEntry({
|
|
2013
|
+
worktreeDir,
|
|
2014
|
+
moduleRel,
|
|
2015
|
+
modulePath,
|
|
2016
|
+
tsconfigPath: resolvedTsconfigPath,
|
|
2017
|
+
commitSha: commit.sha,
|
|
2018
|
+
cacheRoot: compileCacheRoot,
|
|
2019
|
+
noCache: exportOptions?.noCache,
|
|
2020
|
+
log
|
|
2021
|
+
});
|
|
2022
|
+
} else if (!isJavaScriptModule(modulePath)) {
|
|
2023
|
+
throw new Error(
|
|
2024
|
+
`Unsupported module extension for changelog snapshots: ${modulePath}`
|
|
1907
2025
|
);
|
|
1908
2026
|
}
|
|
1909
|
-
const
|
|
1910
|
-
|
|
1911
|
-
|
|
2027
|
+
const input = await loadSnapshotExport({
|
|
2028
|
+
entryPath: snapshotRuntimePath,
|
|
2029
|
+
exportName
|
|
2030
|
+
});
|
|
1912
2031
|
const payload = await exportFinalizedLeaves(input, {
|
|
1913
2032
|
includeSource: true,
|
|
1914
2033
|
sourceModulePath: modulePath,
|
|
1915
2034
|
sourceExportName: exportName,
|
|
1916
|
-
tsconfigPath,
|
|
1917
|
-
|
|
2035
|
+
tsconfigPath: resolvedTsconfigPath ?? (tsconfigRel ? path4.resolve(worktreeDir, tsconfigRel) : void 0),
|
|
2036
|
+
handlers: exportOptions?.handlers
|
|
1918
2037
|
});
|
|
1919
2038
|
const routesByKey = toRouteSnapshots(payload);
|
|
1920
2039
|
const sourceObjectsById = toSourceObjectSnapshots(routesByKey);
|
|
@@ -2239,6 +2358,11 @@ var __private = {
|
|
|
2239
2358
|
resolveCommitWindow,
|
|
2240
2359
|
resolveCommitPath,
|
|
2241
2360
|
filterCommits,
|
|
2361
|
+
resolveSnapshotTsconfig,
|
|
2362
|
+
toEmittedModulePath,
|
|
2363
|
+
buildCompileCacheKey,
|
|
2364
|
+
compileSnapshotEntry,
|
|
2365
|
+
loadSnapshotExport,
|
|
2242
2366
|
toRouteSnapshots,
|
|
2243
2367
|
toSourceObjectSnapshots,
|
|
2244
2368
|
diffSnapshots,
|
|
@@ -2249,6 +2373,7 @@ var __private = {
|
|
|
2249
2373
|
import path5 from "path";
|
|
2250
2374
|
function parseFinalizedLeavesChangelogCliArgs(argv) {
|
|
2251
2375
|
const args = /* @__PURE__ */ new Map();
|
|
2376
|
+
let noCache = false;
|
|
2252
2377
|
for (let i = 0; i < argv.length; i += 1) {
|
|
2253
2378
|
const key = argv[i];
|
|
2254
2379
|
if (key === "--") continue;
|
|
@@ -2256,6 +2381,10 @@ function parseFinalizedLeavesChangelogCliArgs(argv) {
|
|
|
2256
2381
|
if (key === "--with-source") {
|
|
2257
2382
|
continue;
|
|
2258
2383
|
}
|
|
2384
|
+
if (key === "--no-cache") {
|
|
2385
|
+
noCache = true;
|
|
2386
|
+
continue;
|
|
2387
|
+
}
|
|
2259
2388
|
const value = argv[i + 1];
|
|
2260
2389
|
if (!value || value.startsWith("--")) {
|
|
2261
2390
|
throw new Error(`Missing value for ${key}`);
|
|
@@ -2274,7 +2403,9 @@ function parseFinalizedLeavesChangelogCliArgs(argv) {
|
|
|
2274
2403
|
htmlFile: args.get("--html") ?? void 0,
|
|
2275
2404
|
tsconfigPath: args.get("--tsconfig") ?? void 0,
|
|
2276
2405
|
from: args.get("--from") ?? void 0,
|
|
2277
|
-
to: args.get("--to") ?? void 0
|
|
2406
|
+
to: args.get("--to") ?? void 0,
|
|
2407
|
+
cacheDir: args.get("--cache-dir") ?? void 0,
|
|
2408
|
+
noCache
|
|
2278
2409
|
};
|
|
2279
2410
|
}
|
|
2280
2411
|
async function runExportFinalizedLeavesChangelogCli(argv) {
|
|
@@ -2292,6 +2423,8 @@ async function runExportFinalizedLeavesChangelogCli(argv) {
|
|
|
2292
2423
|
from: args.from,
|
|
2293
2424
|
to: args.to,
|
|
2294
2425
|
includeSource: true,
|
|
2426
|
+
cacheDir: args.cacheDir,
|
|
2427
|
+
noCache: args.noCache,
|
|
2295
2428
|
log
|
|
2296
2429
|
};
|
|
2297
2430
|
log("[changelog-cli] starting changelog export");
|