Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overriding the output root with a command line flag #1390

Closed
wants to merge 1 commit into from
Closed
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
11 changes: 7 additions & 4 deletions src/bin/observable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const CONFIG_OPTION = {
root: {
type: "string"
},
output: {
type: "string"
},
config: {
type: "string",
short: "c"
Expand Down Expand Up @@ -94,11 +97,11 @@ try {
}
case "build": {
const {
values: {config, root}
values: {config, root, output}
} = helpArgs(command, {
options: {...CONFIG_OPTION}
});
await import("../build.js").then(async (build) => build.build({config: await readConfig(config, root)}));
await import("../build.js").then(async (build) => build.build({config: await readConfig(config, root, output)}));
break;
}
case "create": {
Expand All @@ -108,7 +111,7 @@ try {
}
case "deploy": {
const {
values: {config, root, message, build}
values: {config, root, output, message, build}
} = helpArgs(command, {
options: {
...CONFIG_OPTION,
Expand All @@ -128,7 +131,7 @@ try {
});
await import("../deploy.js").then(async (deploy) =>
deploy.deploy({
config: await readConfig(config, root),
config: await readConfig(config, root, output),
message,
force: build === true ? "build" : build === false ? "deploy" : null
})
Expand Down
13 changes: 8 additions & 5 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ async function importConfig(path: string): Promise<ConfigSpec> {
return (await import(`${pathToFileURL(path).href}?${mtimeMs}`)).default;
}

export async function readConfig(configPath?: string, root?: string): Promise<Config> {
export async function readConfig(configPath?: string, root?: string, outputRoot?: string): Promise<Config> {
if (configPath === undefined) configPath = await resolveDefaultConfig(root);
if (configPath === undefined) return normalizeConfig(undefined, root);
return normalizeConfig(await importConfig(configPath), root, configPath);
if (configPath === undefined) return normalizeConfig(undefined, {defaultRoot: root, outputRoot});
return normalizeConfig(await importConfig(configPath), {defaultRoot: root, watchPath: configPath, outputRoot});
}

async function resolveDefaultConfig(root?: string): Promise<string | undefined> {
Expand Down Expand Up @@ -199,11 +199,14 @@ export function setCurrentDate(date: Date | null): void {
// module), we want to return the same Config instance.
const configCache = new WeakMap<ConfigSpec, Config>();

export function normalizeConfig(spec: ConfigSpec = {}, defaultRoot?: string, watchPath?: string): Config {
export function normalizeConfig(
spec: ConfigSpec = {},
{defaultRoot, watchPath, outputRoot}: {defaultRoot?: string; watchPath?: string; outputRoot?: string} = {}
): Config {
const cachedConfig = configCache.get(spec);
if (cachedConfig) return cachedConfig;
const root = spec.root === undefined ? findDefaultRoot(defaultRoot) : String(spec.root);
const output = spec.output === undefined ? "dist" : String(spec.output);
const output = outputRoot ?? (spec.output === undefined ? "dist" : String(spec.output));
const base = spec.base === undefined ? "/" : normalizeBase(spec.base);
const style =
spec.style === null
Expand Down
2 changes: 1 addition & 1 deletion test/build-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe("build", () => {
const outputDir = await mkdtemp(tmpPrefix + "output-");
const cacheDir = await mkdtemp(tmpPrefix + "output-");

const config = normalizeConfig({root: inputDir, output: outputDir}, inputDir);
const config = normalizeConfig({root: inputDir, output: outputDir}, {defaultRoot: inputDir});
const effects = new LoggingBuildEffects(outputDir, cacheDir);
await build({config}, effects);
assert.deepEqual(effects.buildManifest, {
Expand Down
58 changes: 31 additions & 27 deletions test/config-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,24 @@ describe("readConfig(undefined, root)", () => {
watchPath: undefined
});
});
it("overrides the file's output path with a passed one", async () => {
const config = await readConfig(undefined, "test/input/build/simple", "override");
assert.equal(config.output, "override");
});
});

describe("normalizeConfig(spec, root)", () => {
const root = "test/input/build/config";
const defaultRoot = "test/input/build/config";
it("coerces the title to a string", () => {
assert.strictEqual(config({title: 42, pages: []}, root).title, "42");
assert.strictEqual(config({title: null, pages: []}, root).title, "null");
assert.strictEqual(config({title: 42, pages: []}, {defaultRoot}).title, "42");
assert.strictEqual(config({title: null, pages: []}, {defaultRoot}).title, "null");
});
it("considers the title optional", () => {
assert.strictEqual(config({pages: []}, root).title, undefined);
assert.strictEqual(config({title: undefined, pages: []}, root).title, undefined);
assert.strictEqual(config({pages: []}, {defaultRoot}).title, undefined);
assert.strictEqual(config({title: undefined, pages: []}, {defaultRoot}).title, undefined);
});
it("populates default pages", () => {
assert.deepStrictEqual(config({}, root).pages, [
assert.deepStrictEqual(config({}, {defaultRoot}).pages, [
{name: "One", path: "/one", pager: "main"},
{name: "H1: Section", path: "/toc-override", pager: "main"},
{name: "H1: Section", path: "/toc", pager: "main"},
Expand All @@ -88,7 +92,7 @@ describe("normalizeConfig(spec, root)", () => {
]);
});
it("coerces pages to an array", () => {
assert.deepStrictEqual(config({pages: new Set()}, root).pages, []);
assert.deepStrictEqual(config({pages: new Set()}, {defaultRoot}).pages, []);
});
it("coerces and normalizes page paths", () => {
const inpages = [
Expand All @@ -105,11 +109,11 @@ describe("normalizeConfig(spec, root)", () => {
{name: "Index.html", path: "/foo/index", pager: "main"},
{name: "Page.html", path: "/foo", pager: "main"}
];
assert.deepStrictEqual(config({pages: inpages}, root).pages, outpages);
assert.deepStrictEqual(config({pages: inpages}, {defaultRoot}).pages, outpages);
});
it("allows external page paths", () => {
const pages = [{name: "Example.com", path: "https://example.com", pager: null}];
assert.deepStrictEqual(config({pages}, root).pages, pages);
assert.deepStrictEqual(config({pages}, {defaultRoot}).pages, pages);
});
it("allows page paths to have query strings and anchor fragments", () => {
const inpages = [
Expand All @@ -136,7 +140,7 @@ describe("normalizeConfig(spec, root)", () => {
{name: "Query string on slash", path: "/test/index?foo=bar", pager: "main"},
{name: "Query string", path: "/test?foo=bar", pager: "main"}
];
assert.deepStrictEqual(config({pages: inpages}, root).pages, outpages);
assert.deepStrictEqual(config({pages: inpages}, {defaultRoot}).pages, outpages);
});
it("coerces sections", () => {
const inpages = [{name: 42, pages: new Set([{name: null, path: {toString: () => "yes"}}])}];
Expand All @@ -150,33 +154,33 @@ describe("normalizeConfig(spec, root)", () => {
pages: [{name: "null", path: "/yes", pager: "main"}]
}
];
assert.deepStrictEqual(config({pages: inpages}, root).pages, outpages);
assert.deepStrictEqual(config({pages: inpages}, {defaultRoot}).pages, outpages);
});
it("coerces toc", () => {
assert.deepStrictEqual(config({pages: [], toc: {}}, root).toc, {label: "Contents", show: true});
assert.deepStrictEqual(config({pages: [], toc: {label: null}}, root).toc, {label: "null", show: true});
assert.deepStrictEqual(config({pages: [], toc: {}}, {defaultRoot}).toc, {label: "Contents", show: true});
assert.deepStrictEqual(config({pages: [], toc: {label: null}}, {defaultRoot}).toc, {label: "null", show: true});
});
it("populates default toc", () => {
assert.deepStrictEqual(config({pages: []}, root).toc, {label: "Contents", show: true});
assert.deepStrictEqual(config({pages: []}, {defaultRoot}).toc, {label: "Contents", show: true});
});
it("promotes boolean toc to toc.show", () => {
assert.deepStrictEqual(config({pages: [], toc: true}, root).toc, {label: "Contents", show: true});
assert.deepStrictEqual(config({pages: [], toc: false}, root).toc, {label: "Contents", show: false});
assert.deepStrictEqual(config({pages: [], toc: true}, {defaultRoot}).toc, {label: "Contents", show: true});
assert.deepStrictEqual(config({pages: [], toc: false}, {defaultRoot}).toc, {label: "Contents", show: false});
});
it("coerces pager", () => {
assert.strictEqual(config({pages: [], pager: 0}, root).pager, false);
assert.strictEqual(config({pages: [], pager: 1}, root).pager, true);
assert.strictEqual(config({pages: [], pager: ""}, root).pager, false);
assert.strictEqual(config({pages: [], pager: "0"}, root).pager, true);
assert.strictEqual(config({pages: [], pager: 0}, {defaultRoot}).pager, false);
assert.strictEqual(config({pages: [], pager: 1}, {defaultRoot}).pager, true);
assert.strictEqual(config({pages: [], pager: ""}, {defaultRoot}).pager, false);
assert.strictEqual(config({pages: [], pager: "0"}, {defaultRoot}).pager, true);
});
it("populates default pager", () => {
assert.strictEqual(config({pages: []}, root).pager, true);
assert.strictEqual(config({pages: []}, {defaultRoot}).pager, true);
});
});

describe("normalizePath(path) with {cleanUrls: false}", () => {
const root = "test/input";
const normalize = config({cleanUrls: false}, root).normalizePath;
const defaultRoot = "test/input";
const normalize = config({cleanUrls: false}, {defaultRoot}).normalizePath;
it("appends .html to extension-less links", () => {
assert.strictEqual(normalize("foo"), "foo.html");
});
Expand Down Expand Up @@ -222,8 +226,8 @@ describe("normalizePath(path) with {cleanUrls: false}", () => {
});

describe("normalizePath(path) with {cleanUrls: true}", () => {
const root = "test/input";
const normalize = config({cleanUrls: true}, root).normalizePath;
const defaultRoot = "test/input";
const normalize = config({cleanUrls: true}, {defaultRoot}).normalizePath;
it("does not append .html to extension-less links", () => {
assert.strictEqual(normalize("foo"), "foo");
});
Expand Down Expand Up @@ -271,9 +275,9 @@ describe("normalizePath(path) with {cleanUrls: true}", () => {
});

describe("mergeToc(spec, toc)", () => {
const root = "test/input/build/config";
const defaultRoot = "test/input/build/config";
it("merges page- and project-level toc config", async () => {
const toc = config({pages: [], toc: true}, root).toc;
const toc = config({pages: [], toc: true}, {defaultRoot}).toc;
assert.deepStrictEqual(mergeToc({show: false}, toc), {label: "Contents", show: false});
assert.deepStrictEqual(mergeToc({label: "On this page"}, toc), {label: "On this page", show: true});
assert.deepStrictEqual(mergeToc({label: undefined}, toc), {label: "Contents", show: true});
Expand Down