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> = {{yield}};
+const [[name]]: TOC<[[signature]]> = {{yield}};
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]]> {
{{yield}}
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;
}