Skip to content

Commit

Permalink
feat(nuxt): component and page generators
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Oct 9, 2023
1 parent 91bbfae commit 2f444d2
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 2 deletions.
13 changes: 13 additions & 0 deletions packages/nuxt/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@
"schema": "./src/generators/application/schema.json",
"aliases": ["app"],
"description": "Create a Nuxt application."
},
"component": {
"factory": "./src/generators/component/component",
"schema": "./src/generators/component/schema.json",
"aliases": ["c"],
"x-type": "component",
"description": "Create a Vue component for your Nuxt application."
},
"page": {
"factory": "./src/generators/page/page",
"schema": "./src/generators/page/schema.json",
"x-type": "page",
"description": "Create a new page for your Nuxt application."
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exports[`app generated files content - as-provided should configure tsconfig and
"name": "my-app",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "my-app/src",
"sourceRoot": "my-app",
"targets": {
"serve": {
"executor": "nx:run-commands",
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
addProjectConfiguration(tree, options.name, {
root: options.appProjectRoot,
projectType: 'application',
sourceRoot: `${options.appProjectRoot}/src`,
sourceRoot: `${options.appProjectRoot}`,
targets: {},
});

Expand Down
27 changes: 27 additions & 0 deletions packages/nuxt/src/generators/component/component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Tree } from '@nx/devkit';
import { applicationGenerator } from '../application/application';
import { componentGenerator } from './component';

describe('app', () => {
let tree: Tree;
const name = 'my-app';

describe('generated files content - as-provided', () => {
beforeAll(async () => {
tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, {
name,
projectNameAndRootFormat: 'as-provided',
});
});
it('should create a new vue component in the correct location', async () => {
await componentGenerator(tree, {
name: 'hello',
project: name,
});

expect(tree.exists('my-app/components/hello/hello.vue')).toBeTruthy();
});
});
});
23 changes: 23 additions & 0 deletions packages/nuxt/src/generators/component/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { formatFiles, runTasksInSerial, Tree } from '@nx/devkit';
import { componentGenerator as vueComponentGenerator } from '@nx/vue';
import { Schema } from './schema';

/*
* This generator is basically the Vue one, but for Nuxt we
* are just adjusting some options
*/
export async function componentGenerator(host: Tree, options: Schema) {
const componentGenerator = await vueComponentGenerator(host, {
...options,
routing: false,
skipFormat: true,
});

if (!options.skipFormat) {
await formatFiles(host);
}

return runTasksInSerial(componentGenerator);
}

export default componentGenerator;
13 changes: 13 additions & 0 deletions packages/nuxt/src/generators/component/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export interface Schema {
project: string;
name: string;
skipTests?: boolean;
flat?: boolean;
pascalCaseFiles?: boolean;
pascalCaseDirectory?: boolean;
fileName?: string;
inSourceTests?: boolean;
skipFormat?: boolean;
directory?: string;
unitTestRunner?: 'jest' | 'vitest' | 'none';
}
91 changes: 91 additions & 0 deletions packages/nuxt/src/generators/component/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"$schema": "http://json-schema.org/schema",
"cli": "nx",
"$id": "NxNuxtComponent",
"title": "Create a Nuxt Component",
"description": "Create a Nuxt Component for Nx.",
"type": "object",
"examples": [
{
"command": "nx g component my-component --project=myapp",
"description": "Generate a component in the `myapp` application"
},
{
"command": "nx g component my-component --project=myapp --classComponent",
"description": "Generate a class component in the `myapp` application"
}
],
"properties": {
"project": {
"type": "string",
"description": "The name of the project.",
"alias": "p",
"$default": {
"$source": "projectName"
},
"x-prompt": "What is the name of the project for this component?",
"x-priority": "important"
},
"name": {
"type": "string",
"description": "The name of the component.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use for the component?",
"x-priority": "important"
},
"skipTests": {
"type": "boolean",
"description": "When true, does not create `spec.ts` test files for the new component.",
"default": false,
"x-priority": "internal"
},
"flat": {
"type": "boolean",
"description": "Create component at the source root rather than its own directory.",
"default": false
},
"directory": {
"type": "string",
"description": "Create the component under this directory (can be nested).",
"alias": "dir",
"x-priority": "important"
},
"pascalCaseFiles": {
"type": "boolean",
"description": "Use pascal case component file name (e.g. `App.vue`).",
"alias": "P",
"default": false
},
"pascalCaseDirectory": {
"type": "boolean",
"description": "Use pascal case directory name (e.g. `App/App.vue`).",
"alias": "R",
"default": false
},
"fileName": {
"type": "string",
"description": "Create a component with this file name."
},
"inSourceTests": {
"type": "boolean",
"default": false,
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files. Read more on the Vitest docs site: https://vitest.dev/guide/in-source.html"
},
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
"default": false,
"x-priority": "internal"
},
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "jest", "none"],
"description": "Test runner to use for unit tests.",
"x-prompt": "What unit test runner should be used?"
}
},
"required": ["name", "project"]
}
57 changes: 57 additions & 0 deletions packages/nuxt/src/generators/page/page.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Tree } from '@nx/devkit';
import { applicationGenerator } from '../application/application';
import { getDirectory, pageGenerator } from './page';

describe('app', () => {
let tree: Tree;
const name = 'my-app';

describe('getDirectory', () => {
it('should return "pages" if no directory is provided', () => {
expect(getDirectory(undefined)).toEqual('pages');
});

it('should return the directory unchanged if it already starts with "pages/"', () => {
expect(getDirectory('pages/someDir')).toEqual('pages/someDir');
});

it('should append "/pages" to the directory if it does not start with "pages/" 2', () => {
expect(getDirectory('someDir/')).toEqual('someDir/pages');
});

it('should append "/pages" to the directory if it does not start with "pages/"', () => {
expect(getDirectory('someDir')).toEqual('someDir/pages');
});

it('should work with an empty string', () => {
expect(getDirectory('')).toEqual('pages');
});
});
describe('generated files content - as-provided', () => {
beforeAll(async () => {
tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, {
name,
projectNameAndRootFormat: 'as-provided',
});
});
it('should create a new page in the correct location', async () => {
await pageGenerator(tree, {
name: 'about',
project: name,
});

expect(tree.exists('my-app/pages/About.vue')).toBeTruthy();
});

it('should create a new page in the correct location for nested directory', async () => {
await pageGenerator(tree, {
name: 'about',
project: name,
});

expect(tree.exists('my-app/pages/About.vue')).toBeTruthy();
});
});
});
36 changes: 36 additions & 0 deletions packages/nuxt/src/generators/page/page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
formatFiles,
joinPathFragments,
runTasksInSerial,
Tree,
} from '@nx/devkit';
import { componentGenerator } from '../component/component';
import { Schema } from './schema';

export async function pageGenerator(host: Tree, options: Schema) {
const pageGenerator = await componentGenerator(host, {
...options,
directory: getDirectory(options.directory),
skipTests: true,
flat: true,
pascalCaseFiles: options.pascalCaseFiles ?? true,
pascalCaseDirectory: options.pascalCaseDirectory ?? true,
skipFormat: true,
});

if (!options.skipFormat) {
await formatFiles(host);
}

return runTasksInSerial(pageGenerator);
}

export function getDirectory(directory: string) {
return directory?.length > 0
? directory.startsWith('pages/')
? directory
: joinPathFragments(directory + '/pages')
: 'pages';
}

export default pageGenerator;
9 changes: 9 additions & 0 deletions packages/nuxt/src/generators/page/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface Schema {
project: string;
name: string;
pascalCaseFiles?: boolean;
pascalCaseDirectory?: boolean;
directory?: string;
fileName?: string;
skipFormat?: boolean;
}
62 changes: 62 additions & 0 deletions packages/nuxt/src/generators/page/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"$schema": "http://json-schema.org/schema",
"cli": "nx",
"$id": "NxNuxtPage",
"title": "Create a Nuxt page",
"description": "Create a Nuxt page for Nx.",
"type": "object",
"examples": [
{
"command": "nx g page new-page --project=myapp",
"description": "Generate a page in the `myapp` application"
}
],
"properties": {
"project": {
"type": "string",
"description": "The name of the project.",
"alias": "p",
"$default": {
"$source": "projectName"
},
"x-prompt": "What is the name of the project for this page?",
"x-priority": "important"
},
"name": {
"type": "string",
"description": "The name of the page.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use for the page?",
"x-priority": "important"
},
"directory": {
"type": "string",
"description": "Create the page under this directory - all nested directories will be created under the pages directory.",
"alias": "dir"
},
"pascalCaseFiles": {
"type": "boolean",
"description": "Use pascal case component file name (e.g. `App.vue`).",
"alias": "P"
},
"pascalCaseDirectory": {
"type": "boolean",
"description": "Use pascal case directory name (e.g. `App/App.vue`).",
"alias": "R"
},
"fileName": {
"type": "string",
"description": "Create a component with this file name."
},
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
"default": false,
"x-priority": "internal"
}
},
"required": ["name", "project"]
}

0 comments on commit 2f444d2

Please sign in to comment.