diff --git a/.prettierignore b/.prettierignore index 583cfad..572673a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,6 @@ -/.scaffdog/documents/ /coverage/ /dist/ +/documents/ /test/output/ /CHANGELOG.md /pnpm-lock.yaml diff --git a/.scaffdog/documents/modifier.md b/.scaffdog/documents/modifier.md deleted file mode 100644 index 6f07c35..0000000 --- a/.scaffdog/documents/modifier.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: "modifier" -root: "." -output: "**/*" ---- - -# [[inputs.name]].[[inputs.authoringFormat]] - -```ts -[[name := camel(inputs.name)-]] - -import { modifier } from "ember-modifier"; - -export default modifier(function [[name]](element /*, positional, named*/) {}); - -``` diff --git a/README.md b/README.md index 7d8d107..2996f59 100644 --- a/README.md +++ b/README.md @@ -7,46 +7,93 @@ Generate components, helpers, modifiers and services in v2 addons. Uses [scaffdog](https://scaff.dog/) underneath. +## Notes + +- Only supports `.gjs` (default) and `.gts` files for components + ## Installation +
+ npm + ```shell -bun add -D @bertdeblock/gember +npm install -D @bertdeblock/gember ``` +
+ +
+ bun + ```shell -npm install -D @bertdeblock/gember +bun add -D @bertdeblock/gember ``` +
+ +
+ pnpm + ```shell pnpm add -D @bertdeblock/gember ``` +
+ +
+ yarn + ```shell yarn add -D @bertdeblock/gember ``` +
+ ## Usage +
+ Generating components + ```shell pnpm gember component foo pnpm gember component foo --class pnpm gember component foo --gts pnpm gember component foo --path="src/-private" +``` + +
+ +
+ Generating helpers +```shell pnpm gember helper foo pnpm gember helper foo --class pnpm gember helper foo --ts pnpm gember helper foo --path="src/-private" +``` + +
+ +
+ Generating modifiers +```shell pnpm gember modifier foo +pnpm gember modifier foo --class pnpm gember modifier foo --ts pnpm gember modifier foo --path="src/-private" +``` + +
+ +
+ Generating services +```shell pnpm gember service foo pnpm gember service foo --ts pnpm gember service foo --path="src/-private" ``` -## Notes - -- Only supports `.gjs` (default) and `.gts` files for components +
diff --git a/.scaffdog/documents/component.md b/documents/component.md similarity index 79% rename from .scaffdog/documents/component.md rename to documents/component.md index ede270d..8af743c 100644 --- a/.scaffdog/documents/component.md +++ b/documents/component.md @@ -28,10 +28,11 @@ export default class [[name]] extends Component { ```gts [[name := pascal(inputs.name)-]] +[[signature := (name + "Signature")-]] import type { TOC } from '@ember/component/template-only'; -export interface [[name]]Signature { +export interface [[signature]] { Args: {}; Blocks: { default: []; @@ -39,7 +40,7 @@ export interface [[name]]Signature { Element: null; } -const [[name]]: TOC<[[name]]Signature> = ; +const [[name]]: TOC<[[signature]]> = ; export default [[name]]; @@ -49,10 +50,11 @@ export default [[name]]; ```gts [[name := pascal(inputs.name)-]] +[[signature := (name + "Signature")-]] import Component from "@glimmer/component"; -export interface [[name]]Signature { +export interface [[signature]] { Args: {}; Blocks: { default: []; @@ -60,7 +62,7 @@ export interface [[name]]Signature { Element: null; } -export default class [[name]] extends Component<[[name]]Signature> { +export default class [[name]] extends Component<[[signature]]> { diff --git a/.scaffdog/config.js b/documents/config.ts similarity index 59% rename from .scaffdog/config.js rename to documents/config.ts index f5c0bc1..23750b5 100644 --- a/.scaffdog/config.js +++ b/documents/config.ts @@ -1,4 +1,4 @@ export default { - files: ["documents/*.md"], + files: ["*.md"], tags: ["[[", "]]"], }; diff --git a/.scaffdog/documents/helper.md b/documents/helper.md similarity index 100% rename from .scaffdog/documents/helper.md rename to documents/helper.md diff --git a/documents/modifier.md b/documents/modifier.md new file mode 100644 index 0000000..a75a2d2 --- /dev/null +++ b/documents/modifier.md @@ -0,0 +1,75 @@ +--- +name: "modifier" +root: "." +output: "**/*" +--- + +# [[inputs.authoringFormat == "js" ? (inputs.classBased ? "!" : "") : "!"]][[inputs.name]].js + +```js +[[name := camel(inputs.name)-]] + +import { modifier } from "ember-modifier"; + +export default modifier(function [[name]](element, positional, named) {}); + +``` + +# [[inputs.authoringFormat == "js" ? (inputs.classBased ? "" : "!") : "!"]][[inputs.name]].js + +```js +[[name := pascal(inputs.name)-]] + +import Modifier from "ember-modifier"; + +export default class [[name]] extends Modifier { + modify(element, positional, named) {} +} + +``` + +# [[inputs.authoringFormat == "ts" ? (inputs.classBased ? "!" : "") : "!"]][[inputs.name]].ts + +```ts +[[name := camel(inputs.name)-]] +[[signature := (pascal(inputs.name) + "Signature")-]] + +import { modifier, type NamedArgs, type PositionalArgs } from "ember-modifier"; + +export interface [[signature]] { + Args: { + Named: {}; + Positional: []; + }; + Element: null; +} + +export default modifier<[[signature]]>(function [[name]](element, positional, named) {}); + +``` + +# [[inputs.authoringFormat == "ts" ? (inputs.classBased ? "" : "!") : "!"]][[inputs.name]].ts + +```ts +[[name := pascal(inputs.name)-]] +[[signature := (pascal(inputs.name) + "Signature")-]] + +import Modifier, { type NamedArgs, type PositionalArgs } from "ember-modifier"; + +export interface [[signature]] { + Args: { + Named: {}; + Positional: []; + }; + Element: null; +} + +export default class [[name]] extends Modifier<[[signature]]> { + modify( + element: [[signature]]["Element"], + positional: PositionalArgs<[[signature]]>, + named: NamedArgs<[[signature]]>, + ) {} +} + +``` diff --git a/.scaffdog/documents/service.md b/documents/service.md similarity index 100% rename from .scaffdog/documents/service.md rename to documents/service.md diff --git a/package.json b/package.json index 681265f..e808ca5 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ "gember": "bin/gember.js" }, "files": [ - ".scaffdog/", "bin/", "dist/", + "documents/", "CHANGELOG.md" ], "scripts": { diff --git a/src/cli.ts b/src/cli.ts index 8bd4698..3c3f980 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -91,6 +91,12 @@ yargs(hideBin(process.argv)) description: "The modifier's name", type: "string", }) + .option("class-based", { + alias: ["class"], + default: false, + description: "Generate a class-based modifier", + type: "boolean", + }) .option("path", { default: "", description: "Generate a modifier at a custom path", @@ -105,6 +111,7 @@ yargs(hideBin(process.argv)) handler(options) { generateModifier(options.name, { authoringFormat: options.ts ? "ts" : "js", + classBased: options.classBased, path: options.path, }); }, diff --git a/src/generate-document.ts b/src/generate-document.ts index 58bd86d..36e72a7 100644 --- a/src/generate-document.ts +++ b/src/generate-document.ts @@ -21,7 +21,7 @@ export async function generateDocument( } = {}, ) { const directory = dirname(fileURLToPath(import.meta.url)); - const scaffdog = await loadScaffdog(join(directory, "..", ".scaffdog")); + const scaffdog = await loadScaffdog(join(directory, "../documents")); const documents = await scaffdog.list(); const document = documents.find((document) => document.name === documentName); diff --git a/src/generators.ts b/src/generators.ts index 2c50bc7..23653c8 100644 --- a/src/generators.ts +++ b/src/generators.ts @@ -46,17 +46,19 @@ export function generateModifier( name: string, { authoringFormat = "js", + classBased = false, cwd = "", path = "", }: { authoringFormat?: "js" | "ts"; + classBased?: boolean; cwd?: string; path?: string; } = {}, ) { return generateDocument("modifier", name, { cwd, - inputs: { authoringFormat }, + inputs: { authoringFormat, classBased }, path, }); } diff --git a/test/__snapshots__/generate-modifier.test.ts.snap b/test/__snapshots__/generate-modifier.test.ts.snap index b0a529a..25d517e 100644 --- a/test/__snapshots__/generate-modifier.test.ts.snap +++ b/test/__snapshots__/generate-modifier.test.ts.snap @@ -1,29 +1,75 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`generates a \`.js\` modifier 1`] = ` -"import { modifier } from "ember-modifier"; +exports[`generates a class-based \`.js\` modifier 1`] = ` +"import Modifier from "ember-modifier"; -export default modifier(function foo(element /*, positional, named*/) {}); +export default class Foo extends Modifier { + modify(element, positional, named) {} +} " `; -exports[`generates a \`.js\` modifier at a custom path 1`] = ` -"import { modifier } from "ember-modifier"; +exports[`generates a class-based \`.ts\` modifier 1`] = ` +"import Modifier, { type NamedArgs, type PositionalArgs } from "ember-modifier"; -export default modifier(function foo(element /*, positional, named*/) {}); +export interface FooSignature { + Args: { + Named: {}; + Positional: []; + }; + Element: null; +} + +export default class Foo extends Modifier { + modify( + element: FooSignature["Element"], + positional: PositionalArgs, + named: NamedArgs, + ) {} +} " `; -exports[`generates a \`.ts\` modifier 1`] = ` +exports[`generates a function-based \`.js\` modifier 1`] = ` "import { modifier } from "ember-modifier"; -export default modifier(function foo(element /*, positional, named*/) {}); +export default modifier(function foo(element, positional, named) {}); " `; -exports[`generates a \`.ts\` modifier at a custom path 1`] = ` +exports[`generates a function-based \`.js\` modifier at a custom path 1`] = ` "import { modifier } from "ember-modifier"; -export default modifier(function foo(element /*, positional, named*/) {}); +export default modifier(function foo(element, positional, named) {}); +" +`; + +exports[`generates a function-based \`.ts\` modifier 1`] = ` +"import { modifier, type NamedArgs, type PositionalArgs } from "ember-modifier"; + +export interface FooSignature { + Args: { + Named: {}; + Positional: []; + }; + Element: null; +} + +export default modifier(function foo(element, positional, named) {}); +" +`; + +exports[`generates a function-based \`.ts\` modifier at a custom path 1`] = ` +"import { modifier, type NamedArgs, type PositionalArgs } from "ember-modifier"; + +export interface FooSignature { + Args: { + Named: {}; + Positional: []; + }; + Element: null; +} + +export default modifier(function foo(element, positional, named) {}); " `; diff --git a/test/generate-modifier.test.ts b/test/generate-modifier.test.ts index 7f81af6..cfd830e 100644 --- a/test/generate-modifier.test.ts +++ b/test/generate-modifier.test.ts @@ -9,7 +9,7 @@ let cwd: string; afterEach(() => fsExtra.remove(cwd)); -it("generates a `.js` modifier", async (ctx) => { +it("generates a function-based `.js` modifier", async (ctx) => { cwd = await copyBlueprint("v2-addon"); await generateModifier("foo", { cwd }); @@ -19,17 +19,17 @@ it("generates a `.js` modifier", async (ctx) => { ctx.expect(content).toMatchSnapshot(); }); -it("generates a `.ts` modifier", async (ctx) => { +it("generates a class-based `.js` modifier", async (ctx) => { cwd = await copyBlueprint("v2-addon"); - await generateModifier("foo", { authoringFormat: "ts", cwd }); + await generateModifier("foo", { classBased: true, cwd }); - const content = await readFile(join(cwd, "src/modifiers/foo.ts"), "utf-8"); + const content = await readFile(join(cwd, "src/modifiers/foo.js"), "utf-8"); ctx.expect(content).toMatchSnapshot(); }); -it("generates a `.js` modifier at a custom path", async (ctx) => { +it("generates a function-based `.js` modifier at a custom path", async (ctx) => { cwd = await copyBlueprint("v2-addon"); await generateModifier("foo", { cwd, path: "src/-private" }); @@ -39,7 +39,31 @@ it("generates a `.js` modifier at a custom path", async (ctx) => { ctx.expect(content).toMatchSnapshot(); }); -it("generates a `.ts` modifier at a custom path", async (ctx) => { +it("generates a function-based `.ts` modifier", async (ctx) => { + cwd = await copyBlueprint("v2-addon"); + + await generateModifier("foo", { authoringFormat: "ts", cwd }); + + const content = await readFile(join(cwd, "src/modifiers/foo.ts"), "utf-8"); + + ctx.expect(content).toMatchSnapshot(); +}); + +it("generates a class-based `.ts` modifier", async (ctx) => { + cwd = await copyBlueprint("v2-addon"); + + await generateModifier("foo", { + authoringFormat: "ts", + classBased: true, + cwd, + }); + + const content = await readFile(join(cwd, "src/modifiers/foo.ts"), "utf-8"); + + ctx.expect(content).toMatchSnapshot(); +}); + +it("generates a function-based `.ts` modifier at a custom path", async (ctx) => { cwd = await copyBlueprint("v2-addon"); await generateModifier("foo", { diff --git a/test/helpers.ts b/test/helpers.ts index 288e397..144e096 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -5,7 +5,7 @@ import { v4 as uuidv4 } from "uuid"; export async function copyBlueprint(name: "v2-addon") { const cwd = join("test/output", uuidv4()); - await recursiveCopy(join("test", "blueprints", name), cwd); + await recursiveCopy(join("test/blueprints", name), cwd); return cwd; }