Skip to content

Commit

Permalink
Support all CLI options in the gember config file
Browse files Browse the repository at this point in the history
  • Loading branch information
bertdeblock committed Nov 26, 2024
1 parent 635e9de commit 0b44577
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 56 deletions.
85 changes: 62 additions & 23 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { cwd } from "node:process";
import { hideBin } from "yargs/helpers";
import yargs from "yargs/yargs";
import { resolveConfig } from "./config.js";
import { logGemberErrors } from "./errors.js";
import {
generateComponent,
generateHelper,
generateModifier,
generateService,
} from "./generators.js";
import { DocumentName } from "./types.js";

yargs(hideBin(process.argv))
.command({
Expand Down Expand Up @@ -37,12 +39,16 @@ yargs(hideBin(process.argv))
});
},
handler(options) {
logGemberErrors(() =>
generateComponent(options.name, cwd(), {
classBased: options.classBased,
path: options.path,
typescript: options.typescript,
}),
logGemberErrors(async () =>
generateComponent(
options.name,
cwd(),
await applyGeneratorConfig("component", {
classBased: options.classBased,
path: options.path,
typescript: options.typescript,
}),
),
);
},
})
Expand Down Expand Up @@ -73,12 +79,16 @@ yargs(hideBin(process.argv))
});
},
handler(options) {
logGemberErrors(() =>
generateHelper(options.name, cwd(), {
classBased: options.classBased,
path: options.path,
typescript: options.typescript,
}),
logGemberErrors(async () =>
generateHelper(
options.name,
cwd(),
await applyGeneratorConfig("helper", {
classBased: options.classBased,
path: options.path,
typescript: options.typescript,
}),
),
);
},
})
Expand Down Expand Up @@ -109,12 +119,16 @@ yargs(hideBin(process.argv))
});
},
handler(options) {
logGemberErrors(() =>
generateModifier(options.name, cwd(), {
classBased: options.classBased,
path: options.path,
typescript: options.typescript,
}),
logGemberErrors(async () =>
generateModifier(
options.name,
cwd(),
await applyGeneratorConfig("modifier", {
classBased: options.classBased,
path: options.path,
typescript: options.typescript,
}),
),
);
},
})
Expand All @@ -140,15 +154,40 @@ yargs(hideBin(process.argv))
});
},
handler(options) {
logGemberErrors(() =>
generateService(options.name, cwd(), {
path: options.path,
typescript: options.typescript,
}),
logGemberErrors(async () =>
generateService(
options.name,
cwd(),
await applyGeneratorConfig("service", {
path: options.path,
typescript: options.typescript,
}),
),
);
},
})
.demandCommand()
.epilogue("🫚 More info at https://github.com/bertdeblock/gember#usage")
.strict()
.parse();

type Options = Record<string, unknown>;

async function applyGeneratorConfig(
documentName: DocumentName,
options: Options,
): Promise<Options> {
const config = await resolveConfig(cwd());
const generatorConfig: Options = config.generators?.[documentName] ?? {};
const result: Options = { typescript: config.typescript };

for (const key in options) {
if (options[key] !== undefined) {
result[key] = options[key];
} else if (generatorConfig[key] !== undefined) {
result[key] = generatorConfig[key];
}
}

return result;
}
75 changes: 57 additions & 18 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,37 @@ import { GemberError } from "./errors.js";
import { DocumentName, type File } from "./types.js";

export type Config = {
generators?: {
component?: {
classBased?: boolean;
path?: string;
typescript?: boolean;
};
helper?: {
classBased?: boolean;
path?: string;
typescript?: boolean;
};
modifier?: {
classBased?: boolean;
path?: string;
typescript?: boolean;
};
service?: {
path?: string;
typescript?: boolean;
};
};

hooks?: {
postGenerate?: (info: {
documentName: DocumentName;
entityName: string;
files: File[];
}) => Promise<void> | void;
};

typescript?: boolean;
};

const CONFIG_FILES = [
Expand All @@ -19,30 +43,45 @@ const CONFIG_FILES = [
"gember.config.mjs",
];

const DEFAULT_CONFIG: Config = {};
const RESOLVED_CONFIGS: Map<string, Config> = new Map();

export async function getConfig(cwd: string): Promise<Config> {
const path = await findUp(CONFIG_FILES, { cwd });
export async function resolveConfig(cwd: string): Promise<Config> {
let resolvedConfig = RESOLVED_CONFIGS.get(cwd);

if (path === undefined) {
return DEFAULT_CONFIG;
if (resolvedConfig) {
return resolvedConfig;
}

let config;
const path = await findUp(CONFIG_FILES, { cwd });

try {
config = (await import(pathToFileURL(path).toString())).default;
} catch (cause) {
throw new GemberError(`Could not import gember config file at "${path}".`, {
cause,
});
}
if (path) {
let config;

try {
config = (await import(pathToFileURL(path).toString())).default;
} catch (cause) {
throw new GemberError(
`Could not import gember config file at \`${path}\`.`,
{
cause,
},
);
}

if (config === undefined) {
throw new GemberError(
`gember config file at "${path}" must have a "default" export.`,
);
if (config === undefined) {
throw new GemberError(
`gember config file at \`${path}\` must have a \`default\` export.`,
);
}

resolvedConfig = (
typeof config === "function" ? await config() : config
) as Config;
} else {
resolvedConfig = {};
}

return typeof config === "function" ? await config() : config;
RESOLVED_CONFIGS.set(cwd, resolvedConfig);

return resolvedConfig;
}
13 changes: 9 additions & 4 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { dirname, isAbsolute, join, parse, relative } from "node:path";
import { cwd } from "node:process";
import { fileURLToPath } from "node:url";
import { type GenerateInputs, loadScaffdog } from "scaffdog";
import { getConfig } from "./config.js";
import { resolveConfig } from "./config.js";
import { GemberError } from "./errors.js";
import { isAddon, isV2Addon } from "./helpers.js";
import { type DocumentName } from "./types.js";
Expand Down Expand Up @@ -34,7 +34,12 @@ export async function generate(
throw new GemberError(`[BUG] Document \`${documentName}\` not found.`);
}

const generatePath = await getGeneratePath(documentName, packagePath, path);
const generatePath = await resolveGeneratePath(
documentName,
packagePath,
path,
);

const files = await scaffdog.generate(document, generatePath, {
inputs: {
...inputs,
Expand Down Expand Up @@ -63,7 +68,7 @@ export async function generate(
);
}

const config = await getConfig(packagePath);
const config = await resolveConfig(packagePath);

await config.hooks?.postGenerate?.({
documentName,
Expand All @@ -89,7 +94,7 @@ const SRC_DIRECTORY: Record<string, string> = {
V2_ADDON: "src",
};

export async function getGeneratePath(
export async function resolveGeneratePath(
documentName: DocumentName,
packagePath: string,
path?: string,
Expand Down
10 changes: 5 additions & 5 deletions test/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Project } from "fixturify-project";
import { it } from "vitest";
import { getConfig } from "../src/config.js";
import { resolveConfig } from "../src/config.js";
import { generateComponent } from "../src/generators.ts";
import { Package } from "./helpers.js";

Expand All @@ -14,7 +14,7 @@ it("supports a `gember.config.js` file", async (ctx) => {

await project.write();

const config = await getConfig(project.baseDir);
const config = await resolveConfig(project.baseDir);

ctx.expect(config).to.deep.equal({ hooks: {} });
});
Expand All @@ -29,7 +29,7 @@ it("supports a `gember.config.cjs` file", async (ctx) => {

await project.write();

const config = await getConfig(project.baseDir);
const config = await resolveConfig(project.baseDir);

ctx.expect(config).to.deep.equal({ hooks: {} });
});
Expand All @@ -44,13 +44,13 @@ it("supports a `gember.config.mjs` file", async (ctx) => {

await project.write();

const config = await getConfig(project.baseDir);
const config = await resolveConfig(project.baseDir);

ctx.expect(config).to.deep.equal({ hooks: {} });
});

it("runs the `postGenerate` hook", async (ctx) => {
const pkg = await Package.create("v2-addon-hooks", "post-generate-info");
const pkg = await Package.create("v2-addon-config", "post-generate-info");

await generateComponent("foo", pkg.path);

Expand Down
8 changes: 4 additions & 4 deletions test/generate-document.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { join } from "node:path";
import { it } from "vitest";
import { getGeneratePath } from "../src/generate.ts";
import { resolveGeneratePath } from "../src/generate.ts";
import { Package } from "./helpers.ts";

it("supports v1 apps", async (ctx) => {
const name = "v1-app";
const generatePath = await getGeneratePath(
const generatePath = await resolveGeneratePath(
"component",
Package.createPath(name),
);
Expand All @@ -17,7 +17,7 @@ it("supports v1 apps", async (ctx) => {

it("supports v1 addons", async (ctx) => {
const name = "v1-addon";
const generatePath = await getGeneratePath(
const generatePath = await resolveGeneratePath(
"component",
Package.createPath(name),
);
Expand All @@ -29,7 +29,7 @@ it("supports v1 addons", async (ctx) => {

it("supports v2 addons", async (ctx) => {
const name = "v2-addon";
const generatePath = await getGeneratePath(
const generatePath = await resolveGeneratePath(
"component",
Package.createPath(name),
);
Expand Down
2 changes: 1 addition & 1 deletion test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { join } from "node:path";
import recursiveCopy from "recursive-copy";
import { v4 as uuidv4 } from "uuid";

type PackageName = "v1-app" | "v1-addon" | "v2-addon" | "v2-addon-hooks";
type PackageName = "v1-app" | "v1-addon" | "v2-addon" | "v2-addon-config";

export class Package {
path: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { fileURLToPath } from "node:url";

/** @type {import('../../../src/config.ts').Config} */
export default {
generators: {
component: {
classBased: true,
},
},

hooks: {
postGenerate: async (info) => {
const file = join(
Expand All @@ -23,4 +29,6 @@ export default {
await writeFile(file, JSON.stringify(info, null, 2));
},
},

typescript: true,
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "v2-addon-hooks",
"name": "v2-addon-config",
"private": true,
"volta": {
"extends": "../../../package.json"
Expand Down

0 comments on commit 0b44577

Please sign in to comment.