diff --git a/src/cli.ts b/src/cli.ts
index 5121fc7..4e3dc69 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -9,6 +9,7 @@ import { GemberError, logGemberErrors } from "./errors.js";
import {
generators,
getGenerator,
+ getTemplateGenerator,
getTestGenerator,
} from "./generators/generators.js";
import { readOwnPackageJsonSync } from "./internal.js";
@@ -135,6 +136,16 @@ function generatorCommands(deprecated?: boolean): SubCommandsDef {
);
}
}
+
+ if (context.args.template) {
+ if (generator.args.find((arg) => arg.name === "template")) {
+ await getTemplateGenerator().run(context.args);
+ } else {
+ logger.warn(
+ `You passed the \`--template\` option, but the \`${generator.name}\` generator does not support generating a template.`,
+ );
+ }
+ }
});
},
};
diff --git a/src/config.ts b/src/config.ts
index af2bf06..fda8b34 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -159,6 +159,8 @@ export type Config = {
log?: boolean;
// Generate a route at a custom path, e.g. `--path=src/-private`:
path?: string;
+ // Generate a corresponding template:
+ template?: boolean;
// Generate a corresponding route-test:
test?: boolean;
// Generate a `.ts` route, instead of a `.js` route:
@@ -178,6 +180,22 @@ export type Config = {
// Generate a `.ts` route-test, instead of a `.js` route-test:
typescript?: boolean;
};
+ template?: {
+ // Generate a `class-based` template, instead of a `template-only` template:
+ classBased?: boolean;
+ // Copy the generated template to the clipboard, instead of writing it to disk:
+ copy?: boolean;
+ // The current working directory to run the template generator in:
+ cwd?: string;
+ // Destroy a template by name:
+ destroy?: boolean;
+ // Log the generated template to the console, instead of writing it to disk:
+ log?: boolean;
+ // Generate a template at a custom path, e.g. `--path=src/-private`:
+ path?: string;
+ // Generate a `.gts` template, instead of a `.gjs` template:
+ typescript?: boolean;
+ };
service?: {
// Copy the generated service to the clipboard, instead of writing it to disk:
copy?: boolean;
diff --git a/src/generators/generator.ts b/src/generators/generator.ts
index 65f6515..9a4dc6f 100644
--- a/src/generators/generator.ts
+++ b/src/generators/generator.ts
@@ -358,6 +358,14 @@ export function path(): GeneratorArgFactory {
});
}
+export function template(): GeneratorArgFactory {
+ return () => ({
+ description: `Generate a corresponding template`,
+ name: "template",
+ type: "boolean",
+ });
+}
+
export function test(): GeneratorArgFactory {
return (generatorName) => ({
description: `Generate a corresponding ${testGeneratorName(generatorName)}`,
diff --git a/src/generators/generators.ts b/src/generators/generators.ts
index bcfafa8..1672515 100644
--- a/src/generators/generators.ts
+++ b/src/generators/generators.ts
@@ -5,6 +5,7 @@ import {
defineTestGenerator,
namedExport,
nested,
+ template,
test,
testGeneratorName,
typescript,
@@ -73,7 +74,7 @@ export const generators: Generator[] = [
}),
defineGenerator({
- args: [test(), typescript()],
+ args: [template(), test(), typescript()],
name: "route",
}),
@@ -94,6 +95,17 @@ export const generators: Generator[] = [
testsDir: "unit",
}),
+ defineGenerator({
+ args: [
+ classBased({ functionBasedName: "template-only" }),
+ typescript({ gts: true }),
+ ],
+ modifyTemplateFile: (templateFile) => {
+ templateFile.name = "component";
+ },
+ name: "template",
+ }),
+
defineGenerator({
args: [namedExport(), test(), typescript()],
name: "util",
@@ -121,3 +133,7 @@ export function getGenerator(generatorName: string): Generator {
export function getTestGenerator(generatorName: string): Generator {
return getGenerator(testGeneratorName(generatorName));
}
+
+export function getTemplateGenerator(): Generator {
+ return getGenerator("template");
+}
diff --git a/templates/template/component.class-based.gjs b/templates/template/component.class-based.gjs
new file mode 100644
index 0000000..efbc0ff
--- /dev/null
+++ b/templates/template/component.class-based.gjs
@@ -0,0 +1,5 @@
+import Component from '@glimmer/component';
+
+export default class {{name.pascal}} extends Component {
+ \{{yield}}
+}
diff --git a/templates/template/component.class-based.gts b/templates/template/component.class-based.gts
new file mode 100644
index 0000000..5c0abb3
--- /dev/null
+++ b/templates/template/component.class-based.gts
@@ -0,0 +1,18 @@
+import Component from '@glimmer/component';
+
+export interface {{name.signature}} {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+export default class {{name.pascal}} extends Component<{{name.signature}}> {
+
+ \{{yield}}
+
+}
diff --git a/templates/template/component.template-only.gjs b/templates/template/component.template-only.gjs
new file mode 100644
index 0000000..181ad27
--- /dev/null
+++ b/templates/template/component.template-only.gjs
@@ -0,0 +1 @@
+\{{yield}}
diff --git a/templates/template/component.template-only.gts b/templates/template/component.template-only.gts
new file mode 100644
index 0000000..3274873
--- /dev/null
+++ b/templates/template/component.template-only.gts
@@ -0,0 +1,16 @@
+import type { TOC } from '@ember/component/template-only';
+
+export interface {{name.signature}} {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const {{name.pascal}}: TOC<{{name.signature}}> = \{{yield}};
+
+export default {{name.pascal}};
diff --git a/test/__snapshots__/generators.test.ts.snap b/test/__snapshots__/generators.test.ts.snap
index 0ed2524..53e1087 100644
--- a/test/__snapshots__/generators.test.ts.snap
+++ b/test/__snapshots__/generators.test.ts.snap
@@ -1980,6 +1980,98 @@ module('Integration | Modifier | fooBarBaz', function (hooks) {
exports[`package-type: v1-addon > generator: modifier-test > args: --typescript 1`] = `"[success] Generated modifier-test \`foo/bar-baz\` at \`tests/integration/modifiers/foo/bar-baz-test.gts\`."`;
+exports[`package-type: v1-addon > generator: route > args: --log --template --test --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v1-addon > generator: route > args: --log --template --test 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] {{yield}}
+"
+`;
+
+exports[`package-type: v1-addon > generator: route > args: --log --template --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v1-addon > generator: route > args: --log --template 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] {{yield}}
+"
+`;
+
exports[`package-type: v1-addon > generator: route > args: --log --test --typescript 1`] = `
"[log] import Route from '@ember/routing/route';
@@ -2034,6 +2126,28 @@ export default class FooBarBazRoute extends Route {}
"
`;
+exports[`package-type: v1-addon > generator: route > args: --template --test --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`addon/routes/foo/bar-baz.ts\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v1-addon > generator: route > args: --template --test 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`addon/routes/foo/bar-baz.js\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.js\`.
+[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gjs\`."
+`;
+
+exports[`package-type: v1-addon > generator: route > args: --template --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`addon/routes/foo/bar-baz.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v1-addon > generator: route > args: --template 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`addon/routes/foo/bar-baz.js\`.
+[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gjs\`."
+`;
+
exports[`package-type: v1-addon > generator: route > args: --test --typescript 1`] = `
"[success] Generated route \`foo/bar-baz\` at \`addon/routes/foo/bar-baz.ts\`.
[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`."
@@ -2192,6 +2306,68 @@ module('Unit | Service | FooBarBaz', function (hooks) {
exports[`package-type: v1-addon > generator: service-test > args: --typescript 1`] = `"[success] Generated service-test \`foo/bar-baz\` at \`tests/unit/services/foo/bar-baz-test.ts\`."`;
+exports[`package-type: v1-addon > generator: template > args: --classBased --log --typescript 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+export default class FooBarBaz extends Component {
+
+ {{yield}}
+
+}
+"
+`;
+
+exports[`package-type: v1-addon > generator: template > args: --classBased --log 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export default class FooBarBaz extends Component {
+ {{yield}}
+}
+"
+`;
+
+exports[`package-type: v1-addon > generator: template > args: --classBased --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gts\`."`;
+
+exports[`package-type: v1-addon > generator: template > args: --classBased 1`] = `"[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gjs\`."`;
+
+exports[`package-type: v1-addon > generator: template > args: --log --typescript 1`] = `
+"[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v1-addon > generator: template > args: --log 1`] = `
+"[log] {{yield}}
+"
+`;
+
+exports[`package-type: v1-addon > generator: template > args: --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`addon/templates/foo/bar-baz.gts\`."`;
+
exports[`package-type: v1-addon > generator: util > args: --log --namedExport --test --typescript 1`] = `
"[log] export function fooBarBaz() {
return true;
@@ -4328,6 +4504,98 @@ module('Integration | Modifier | fooBarBaz', function (hooks) {
exports[`package-type: v1-app > generator: modifier-test > args: --typescript 1`] = `"[success] Generated modifier-test \`foo/bar-baz\` at \`tests/integration/modifiers/foo/bar-baz-test.gts\`."`;
+exports[`package-type: v1-app > generator: route > args: --log --template --test --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v1-app > generator: route > args: --log --template --test 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] {{yield}}
+"
+`;
+
+exports[`package-type: v1-app > generator: route > args: --log --template --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v1-app > generator: route > args: --log --template 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] {{yield}}
+"
+`;
+
exports[`package-type: v1-app > generator: route > args: --log --test --typescript 1`] = `
"[log] import Route from '@ember/routing/route';
@@ -4382,6 +4650,28 @@ export default class FooBarBazRoute extends Route {}
"
`;
+exports[`package-type: v1-app > generator: route > args: --template --test --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.ts\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v1-app > generator: route > args: --template --test 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.js\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.js\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gjs\`."
+`;
+
+exports[`package-type: v1-app > generator: route > args: --template --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v1-app > generator: route > args: --template 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.js\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gjs\`."
+`;
+
exports[`package-type: v1-app > generator: route > args: --test --typescript 1`] = `
"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.ts\`.
[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`."
@@ -4540,6 +4830,68 @@ module('Unit | Service | FooBarBaz', function (hooks) {
exports[`package-type: v1-app > generator: service-test > args: --typescript 1`] = `"[success] Generated service-test \`foo/bar-baz\` at \`tests/unit/services/foo/bar-baz-test.ts\`."`;
+exports[`package-type: v1-app > generator: template > args: --classBased --log --typescript 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+export default class FooBarBaz extends Component {
+
+ {{yield}}
+
+}
+"
+`;
+
+exports[`package-type: v1-app > generator: template > args: --classBased --log 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export default class FooBarBaz extends Component {
+ {{yield}}
+}
+"
+`;
+
+exports[`package-type: v1-app > generator: template > args: --classBased --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."`;
+
+exports[`package-type: v1-app > generator: template > args: --classBased 1`] = `"[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gjs\`."`;
+
+exports[`package-type: v1-app > generator: template > args: --log --typescript 1`] = `
+"[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v1-app > generator: template > args: --log 1`] = `
+"[log] {{yield}}
+"
+`;
+
+exports[`package-type: v1-app > generator: template > args: --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."`;
+
exports[`package-type: v1-app > generator: util > args: --log --namedExport --test --typescript 1`] = `
"[log] export function fooBarBaz() {
return true;
@@ -6639,42 +6991,134 @@ import { setupRenderingTest } from 'v2-addon/tests/helpers';
module('Integration | Modifier | fooBarBaz', function (hooks) {
setupRenderingTest(hooks);
- test('it renders', async function (assert) {
- await render(
-
-
-
- );
+ test('it renders', async function (assert) {
+ await render(
+
+
+
+ );
+
+ assert.ok(true);
+ });
+});
+"
+`;
+
+exports[`package-type: v2-addon > generator: modifier-test > args: --log 1`] = `
+"[log] import { render } from '@ember/test-helpers';
+import { module, test } from 'qunit';
+import fooBarBaz from 'v2-addon/modifiers/foo/bar-baz';
+import { setupRenderingTest } from 'v2-addon/tests/helpers';
+
+module('Integration | Modifier | fooBarBaz', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(
+
+
+
+ );
+
+ assert.ok(true);
+ });
+});
+"
+`;
+
+exports[`package-type: v2-addon > generator: modifier-test > args: --typescript 1`] = `"[success] Generated modifier-test \`foo/bar-baz\` at \`tests/integration/modifiers/foo/bar-baz-test.gts\`."`;
+
+exports[`package-type: v2-addon > generator: route > args: --log --template --test --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'v2-addon/tests/helpers';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v2-addon > generator: route > args: --log --template --test 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'v2-addon/tests/helpers';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
- assert.ok(true);
+ assert.ok(route);
});
});
+
+[log] {{yield}}
"
`;
-exports[`package-type: v2-addon > generator: modifier-test > args: --log 1`] = `
-"[log] import { render } from '@ember/test-helpers';
-import { module, test } from 'qunit';
-import fooBarBaz from 'v2-addon/modifiers/foo/bar-baz';
-import { setupRenderingTest } from 'v2-addon/tests/helpers';
+exports[`package-type: v2-addon > generator: route > args: --log --template --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
-module('Integration | Modifier | fooBarBaz', function (hooks) {
- setupRenderingTest(hooks);
+export default class FooBarBazRoute extends Route {}
- test('it renders', async function (assert) {
- await render(
-
-
-
- );
+[log] import type { TOC } from '@ember/component/template-only';
- assert.ok(true);
- });
-});
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
"
`;
-exports[`package-type: v2-addon > generator: modifier-test > args: --typescript 1`] = `"[success] Generated modifier-test \`foo/bar-baz\` at \`tests/integration/modifiers/foo/bar-baz-test.gts\`."`;
+exports[`package-type: v2-addon > generator: route > args: --log --template 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] {{yield}}
+"
+`;
exports[`package-type: v2-addon > generator: route > args: --log --test --typescript 1`] = `
"[log] import Route from '@ember/routing/route';
@@ -6730,6 +7174,28 @@ export default class FooBarBazRoute extends Route {}
"
`;
+exports[`package-type: v2-addon > generator: route > args: --template --test --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`src/routes/foo/bar-baz.ts\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v2-addon > generator: route > args: --template --test 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`src/routes/foo/bar-baz.js\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.js\`.
+[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gjs\`."
+`;
+
+exports[`package-type: v2-addon > generator: route > args: --template --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`src/routes/foo/bar-baz.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v2-addon > generator: route > args: --template 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`src/routes/foo/bar-baz.js\`.
+[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gjs\`."
+`;
+
exports[`package-type: v2-addon > generator: route > args: --test --typescript 1`] = `
"[success] Generated route \`foo/bar-baz\` at \`src/routes/foo/bar-baz.ts\`.
[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`."
@@ -6888,6 +7354,68 @@ module('Unit | Service | FooBarBaz', function (hooks) {
exports[`package-type: v2-addon > generator: service-test > args: --typescript 1`] = `"[success] Generated service-test \`foo/bar-baz\` at \`tests/unit/services/foo/bar-baz-test.ts\`."`;
+exports[`package-type: v2-addon > generator: template > args: --classBased --log --typescript 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+export default class FooBarBaz extends Component {
+
+ {{yield}}
+
+}
+"
+`;
+
+exports[`package-type: v2-addon > generator: template > args: --classBased --log 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export default class FooBarBaz extends Component {
+ {{yield}}
+}
+"
+`;
+
+exports[`package-type: v2-addon > generator: template > args: --classBased --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gts\`."`;
+
+exports[`package-type: v2-addon > generator: template > args: --classBased 1`] = `"[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gjs\`."`;
+
+exports[`package-type: v2-addon > generator: template > args: --log --typescript 1`] = `
+"[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v2-addon > generator: template > args: --log 1`] = `
+"[log] {{yield}}
+"
+`;
+
+exports[`package-type: v2-addon > generator: template > args: --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`src/templates/foo/bar-baz.gts\`."`;
+
exports[`package-type: v2-addon > generator: util > args: --log --namedExport --test --typescript 1`] = `
"[log] export function fooBarBaz() {
return true;
@@ -9024,6 +9552,98 @@ module('Integration | Modifier | fooBarBaz', function (hooks) {
exports[`package-type: v2-app > generator: modifier-test > args: --typescript 1`] = `"[success] Generated modifier-test \`foo/bar-baz\` at \`tests/integration/modifiers/foo/bar-baz-test.gts\`."`;
+exports[`package-type: v2-app > generator: route > args: --log --template --test --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v2-app > generator: route > args: --log --template --test 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | FooBarBaz', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ const route = this.owner.lookup('route:foo/bar-baz');
+
+ assert.ok(route);
+ });
+});
+
+[log] {{yield}}
+"
+`;
+
+exports[`package-type: v2-app > generator: route > args: --log --template --typescript 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v2-app > generator: route > args: --log --template 1`] = `
+"[log] import Route from '@ember/routing/route';
+
+export default class FooBarBazRoute extends Route {}
+
+[log] {{yield}}
+"
+`;
+
exports[`package-type: v2-app > generator: route > args: --log --test --typescript 1`] = `
"[log] import Route from '@ember/routing/route';
@@ -9078,6 +9698,28 @@ export default class FooBarBazRoute extends Route {}
"
`;
+exports[`package-type: v2-app > generator: route > args: --template --test --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.ts\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v2-app > generator: route > args: --template --test 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.js\`.
+[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.js\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gjs\`."
+`;
+
+exports[`package-type: v2-app > generator: route > args: --template --typescript 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.ts\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."
+`;
+
+exports[`package-type: v2-app > generator: route > args: --template 1`] = `
+"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.js\`.
+[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gjs\`."
+`;
+
exports[`package-type: v2-app > generator: route > args: --test --typescript 1`] = `
"[success] Generated route \`foo/bar-baz\` at \`app/routes/foo/bar-baz.ts\`.
[success] Generated route-test \`foo/bar-baz\` at \`tests/unit/routes/foo/bar-baz-test.ts\`."
@@ -9236,6 +9878,68 @@ module('Unit | Service | FooBarBaz', function (hooks) {
exports[`package-type: v2-app > generator: service-test > args: --typescript 1`] = `"[success] Generated service-test \`foo/bar-baz\` at \`tests/unit/services/foo/bar-baz-test.ts\`."`;
+exports[`package-type: v2-app > generator: template > args: --classBased --log --typescript 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+export default class FooBarBaz extends Component {
+
+ {{yield}}
+
+}
+"
+`;
+
+exports[`package-type: v2-app > generator: template > args: --classBased --log 1`] = `
+"[log] import Component from '@glimmer/component';
+
+export default class FooBarBaz extends Component {
+ {{yield}}
+}
+"
+`;
+
+exports[`package-type: v2-app > generator: template > args: --classBased --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."`;
+
+exports[`package-type: v2-app > generator: template > args: --classBased 1`] = `"[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gjs\`."`;
+
+exports[`package-type: v2-app > generator: template > args: --log --typescript 1`] = `
+"[log] import type { TOC } from '@ember/component/template-only';
+
+export interface FooBarBazSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const FooBarBaz: TOC = {{yield}};
+
+export default FooBarBaz;
+"
+`;
+
+exports[`package-type: v2-app > generator: template > args: --log 1`] = `
+"[log] {{yield}}
+"
+`;
+
+exports[`package-type: v2-app > generator: template > args: --typescript 1`] = `"[success] Generated template \`foo/bar-baz\` at \`app/templates/foo/bar-baz.gts\`."`;
+
exports[`package-type: v2-app > generator: util > args: --log --namedExport --test --typescript 1`] = `
"[log] export function fooBarBaz() {
return true;
diff --git a/test/generators/__snapshots__/template.test.ts.snap b/test/generators/__snapshots__/template.test.ts.snap
new file mode 100644
index 0000000..2a4ec0c
--- /dev/null
+++ b/test/generators/__snapshots__/template.test.ts.snap
@@ -0,0 +1,92 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`creates nested route templates 1`] = `
+"{{yield}}
+"
+`;
+
+exports[`generates a class-based \`.gjs\` template 1`] = `
+"import Component from '@glimmer/component';
+
+export default class Foo extends Component {
+ {{yield}}
+}
+"
+`;
+
+exports[`generates a class-based \`.gts\` template 1`] = `
+"import Component from '@glimmer/component';
+
+export interface FooSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+export default class Foo extends Component {
+
+ {{yield}}
+
+}
+"
+`;
+
+exports[`generates a nested \`.gjs\` template 1`] = `
+"{{yield}}
+"
+`;
+
+exports[`generates a template-only \`.gjs\` template 1`] = `
+"{{yield}}
+"
+`;
+
+exports[`generates a template-only \`.gjs\` template at a custom path 1`] = `
+"{{yield}}
+"
+`;
+
+exports[`generates a template-only \`.gts\` template 1`] = `
+"import type { TOC } from '@ember/component/template-only';
+
+export interface FooSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const Foo: TOC = {{yield}};
+
+export default Foo;
+"
+`;
+
+exports[`generates a template-only \`.gts\` template at a custom path 1`] = `
+"import type { TOC } from '@ember/component/template-only';
+
+export interface FooSignature {
+ Args: {
+ model: unknown;
+ controller: unknown;
+ };
+ Blocks: {
+ default: [];
+ };
+ Element: null;
+}
+
+const Foo: TOC = {{yield}};
+
+export default Foo;
+"
+`;
diff --git a/test/generators/route.test.ts b/test/generators/route.test.ts
index 122993f..162d1f5 100644
--- a/test/generators/route.test.ts
+++ b/test/generators/route.test.ts
@@ -76,6 +76,15 @@ it("generates a corresponding route-test", async (ctx) => {
.to.equal(true);
});
+it("generates a corresponding template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("route", "foo", "--template");
+
+ ctx.expect(await pkg.pathExists("src/routes/foo.js")).to.equal(true);
+ ctx.expect(await pkg.pathExists("src/templates/foo.gjs")).to.equal(true);
+});
+
it("destroys a route", async (ctx) => {
pkg = await Package.create("v2-addon");
diff --git a/test/generators/template.test.ts b/test/generators/template.test.ts
new file mode 100644
index 0000000..8e845da
--- /dev/null
+++ b/test/generators/template.test.ts
@@ -0,0 +1,98 @@
+import { afterEach, it } from "vitest";
+import { Package } from "../helpers.ts";
+
+let pkg: Package;
+
+afterEach(() => pkg.cleanUp());
+
+it("generates a template-only `.gjs` template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo");
+
+ const content = await pkg.readFile("src/templates/foo.gjs");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("generates a class-based `.gjs` template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo", "--classBased");
+
+ const content = await pkg.readFile("src/templates/foo.gjs");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("generates a template-only `.gjs` template at a custom path", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo", "--path=src/-private");
+
+ const content = await pkg.readFile("src/-private/foo.gjs");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("generates a template-only `.gts` template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo", "--typescript");
+
+ const content = await pkg.readFile("src/templates/foo.gts");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("generates a class-based `.gts` template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo", "--classBased", "--typescript");
+
+ const content = await pkg.readFile("src/templates/foo.gts");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("generates a template-only `.gts` template at a custom path", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo", "--path=src/-private", "--typescript");
+
+ const content = await pkg.readFile("src/-private/foo.gts");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("generates a nested `.gjs` template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo/bar");
+
+ const content = await pkg.readFile("src/templates/foo/bar.gjs");
+
+ ctx.expect(content).toMatchSnapshot();
+});
+
+it("destroys a template", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo");
+
+ ctx.expect(await pkg.pathExists("src/templates/foo.gjs")).to.equal(true);
+
+ await pkg.gember("template", "foo", "--destroy");
+
+ ctx.expect(await pkg.pathExists("src/templates/foo.gjs")).to.equal(false);
+});
+
+it("creates nested route templates", async (ctx) => {
+ pkg = await Package.create("v2-addon");
+
+ await pkg.gember("template", "foo/bar/baz");
+
+ const content = await pkg.readFile("src/templates/foo/bar/baz.gjs");
+
+ ctx.expect(content).toMatchSnapshot();
+});