Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DEFAULT_CONFIG,
type DocsCacheConfig,
resolveConfigPath,
stripDefaultConfigValues,
validateConfig,
writeConfig,
} from "./config";
Expand Down Expand Up @@ -132,7 +133,7 @@ export const addSources = async (params: {

if (target.mode === "package") {
const pkg = rawPackage ?? {};
pkg["docs-cache"] = nextConfig;
pkg["docs-cache"] = stripDefaultConfigValues(nextConfig);
await writeFile(resolvedPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
} else {
await writeConfig(resolvedPath, nextConfig);
Expand Down
69 changes: 69 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,75 @@ export const DEFAULT_CONFIG: DocsCacheConfig = {
sources: [],
};

const isEqualStringArray = (left?: string[], right?: string[]) => {
if (!left || !right) {
return left === right;
}
if (left.length !== right.length) {
return false;
}
return left.every((value, index) => value === right[index]);
};

const isObject = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);

const pruneDefaults = (
value: Record<string, unknown>,
baseline: Record<string, unknown>,
): Record<string, unknown> => {
const result: Record<string, unknown> = {};
for (const [key, entry] of Object.entries(value)) {
Comment thread
fbosch marked this conversation as resolved.
const base = baseline[key];
if (Array.isArray(entry) && Array.isArray(base)) {
if (!isEqualStringArray(entry, base)) {
result[key] = entry;
}
continue;
}
if (isObject(entry) && isObject(base)) {
const pruned = pruneDefaults(entry, base);
if (Object.keys(pruned).length > 0) {
result[key] = pruned;
}
continue;
}
if (entry !== base) {
result[key] = entry;
}
}
return result;
};

export const stripDefaultConfigValues = (
config: DocsCacheConfig,
): DocsCacheConfig => {
const baseline: DocsCacheConfig = {
...DEFAULT_CONFIG,
$schema: config.$schema,
defaults: {
...DEFAULT_CONFIG.defaults,
...(config.targetMode ? { targetMode: config.targetMode } : undefined),
},
};
const pruned = pruneDefaults(
config as unknown as Record<string, unknown>,
baseline as unknown as Record<string, unknown>,
);
const next: DocsCacheConfig = {
$schema: pruned.$schema as DocsCacheConfig["$schema"],
cacheDir: pruned.cacheDir as DocsCacheConfig["cacheDir"],
index: pruned.index as DocsCacheConfig["index"],
targetMode: pruned.targetMode as DocsCacheConfig["targetMode"],
defaults: pruned.defaults as DocsCacheConfig["defaults"],
sources: config.sources,
};
if (!next.defaults || Object.keys(next.defaults).length === 0) {
delete next.defaults;
}
return next;
};

const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);

Expand Down
3 changes: 2 additions & 1 deletion src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
DEFAULT_CACHE_DIR,
DEFAULT_CONFIG_FILENAME,
type DocsCacheConfig,
stripDefaultConfigValues,
writeConfig,
} from "./config";

Expand Down Expand Up @@ -130,7 +131,7 @@ export const initConfig = async (
if (answers.index) {
baseConfig.index = true;
}
pkg["docs-cache"] = baseConfig;
pkg["docs-cache"] = stripDefaultConfigValues(baseConfig);
await writeFile(
resolvedConfigPath,
`${JSON.stringify(pkg, null, 2)}\n`,
Expand Down
3 changes: 2 additions & 1 deletion src/remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
DEFAULT_CONFIG,
type DocsCacheConfig,
resolveConfigPath,
stripDefaultConfigValues,
validateConfig,
writeConfig,
} from "./config";
Expand Down Expand Up @@ -148,7 +149,7 @@ export const removeSources = async (params: {

if (target.mode === "package") {
const pkg = rawPackage ?? {};
pkg["docs-cache"] = nextConfig;
pkg["docs-cache"] = stripDefaultConfigValues(nextConfig);
await writeFile(resolvedPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
} else {
await writeConfig(resolvedPath, nextConfig);
Expand Down
10 changes: 10 additions & 0 deletions src/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ const loadToolVersion = async () => {
);
const pkg = JSON.parse(raw.toString());
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
} catch {
// fallback to dist/chunks relative location
}
try {
const raw = await readFile(
new URL("../../package.json", import.meta.url),
"utf8",
);
const pkg = JSON.parse(raw.toString());
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
} catch {
return "0.0.0";
}
Expand Down
30 changes: 29 additions & 1 deletion tests/cli-add.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { readFile } from "node:fs/promises";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { test } from "node:test";
Expand Down Expand Up @@ -113,3 +113,31 @@ test("add supports full https gitlab url", async () => {
const config = JSON.parse(raw);
assert.equal(config.sources[0].repo, "https://gitlab.com/acme/docs.git");
});

test("add writes package.json without default fields", async () => {
const tmpRoot = path.join(tmpdir(), `docs-cache-add-package-${Date.now()}`);
await mkdir(tmpRoot, { recursive: true });
const packagePath = path.join(tmpRoot, "package.json");
await writeFile(
packagePath,
JSON.stringify({ name: "x", version: "0.0.0" }),
"utf8",
);

await execFileAsync("node", [
"bin/docs-cache.mjs",
"add",
"--offline",
"https://github.com/fbosch/docs-cache.git",
"--config",
packagePath,
]);

const raw = await readFile(packagePath, "utf8");
const pkg = JSON.parse(raw);
assert.ok(pkg["docs-cache"]);
assert.equal(pkg["docs-cache"].cacheDir, undefined);
assert.equal(pkg["docs-cache"].index, undefined);
assert.equal(pkg["docs-cache"].defaults, undefined);
assert.equal(pkg["docs-cache"].targetMode, undefined);
});
Comment thread
fbosch marked this conversation as resolved.
54 changes: 54 additions & 0 deletions tests/sync-tool-version.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import assert from "node:assert/strict";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { test } from "node:test";

import { runSync } from "../dist/api.mjs";

test("sync writes lock toolVersion from package.json", async () => {
const tmpRoot = path.join(
tmpdir(),
`docs-cache-tool-version-${Date.now().toString(36)}`,
);
await mkdir(tmpRoot, { recursive: true });
const configPath = path.join(tmpRoot, "docs.config.json");
const cacheDir = path.join(tmpRoot, ".docs");

await writeFile(
configPath,
JSON.stringify(
{
$schema:
"https://raw.githubusercontent.com/fbosch/docs-cache/main/docs.config.schema.json",
sources: [
{
id: "local",
repo: "https://example.com/repo.git",
},
],
},
null,
2,
),
"utf8",
);

await runSync({
configPath,
cacheDirOverride: cacheDir,
json: true,
lockOnly: true,
offline: true,
failOnMiss: false,
});

const lockRaw = await readFile(path.join(tmpRoot, "docs.lock"), "utf8");
const lock = JSON.parse(lockRaw);
const pkgRaw = await readFile(
path.resolve(process.cwd(), "package.json"),
"utf8",
);
const pkg = JSON.parse(pkgRaw);
assert.equal(lock.toolVersion, pkg.version);
});
Loading