From f2ac27cd12be6bd14c9a78bdd3e3c17de6d02d2a Mon Sep 17 00:00:00 2001 From: Baroshem Date: Tue, 22 Mar 2022 18:41:33 +0100 Subject: [PATCH 01/16] feat: add cli schematic --- packages/nuxi/src/commands/add.ts | 43 +++++++++++++++++++++++++++++ packages/nuxi/src/commands/index.ts | 3 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 packages/nuxi/src/commands/add.ts diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts new file mode 100644 index 00000000000..c9d005c5b99 --- /dev/null +++ b/packages/nuxi/src/commands/add.ts @@ -0,0 +1,43 @@ +import { defineNuxtCommand } from "./index"; +import { existsSync, promises as fsp, readdirSync } from 'fs' +import { resolve } from 'pathe' +import { loadKit } from '../utils/kit' + +export default defineNuxtCommand({ + meta: { + name: 'add', + usage: 'npx nuxi add endpoint test', + description: '' + }, + async invoke(args) { + const rootDir = resolve('.') + const schematic = args._[0] + const name = args._[1]; + + const { loadNuxt } = await loadKit(rootDir) + const nuxt = await loadNuxt({ rootDir, config: { _export: true } }) + + const rootDirPath = nuxt.options.rootDir + + switch (schematic) { + case 'endpoint': + const endpointPath = `${rootDirPath}/server/api` + const newEndpointPath = resolve(endpointPath, `${name.toLowerCase()}.ts`) + + if(!(existsSync(endpointPath) && readdirSync(endpointPath).length)) { + await fsp.mkdir(endpointPath, { recursive: true }) + } + await fsp.writeFile(newEndpointPath, `export default (req, res) => 'Hello ${name}'`) + break + case 'plugin': + const pluginPath = `${rootDirPath}/plugins` + const newPluginPath = resolve(pluginPath, `${name.toLowerCase()}.ts`) + + if(!(existsSync(pluginPath) && readdirSync(pluginPath).length)) { + await fsp.mkdir(pluginPath, { recursive: true }) + } + await fsp.writeFile(newPluginPath, 'export default defineNuxtPlugin(nuxtApp => {})') + break + } + } +}) diff --git a/packages/nuxi/src/commands/index.ts b/packages/nuxi/src/commands/index.ts index 652a613cf77..a040e0cd470 100644 --- a/packages/nuxi/src/commands/index.ts +++ b/packages/nuxi/src/commands/index.ts @@ -16,7 +16,8 @@ export const commands = { init: () => import('./init').then(_rDefault), create: () => import('./init').then(_rDefault), upgrade: () => import('./upgrade').then(_rDefault), - test: () => import('./test').then(_rDefault) + test: () => import('./test').then(_rDefault), + add: () => import('./add').then(_rDefault) } export type Command = keyof typeof commands From a0a1ea73318bb13784feb41e9647640a75ebdb47 Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Tue, 22 Mar 2022 19:18:51 +0100 Subject: [PATCH 02/16] Update packages/nuxi/src/commands/add.ts --- packages/nuxi/src/commands/add.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index c9d005c5b99..d3910923661 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -6,7 +6,7 @@ import { loadKit } from '../utils/kit' export default defineNuxtCommand({ meta: { name: 'add', - usage: 'npx nuxi add endpoint test', + usage: 'npx nuxi add endpoint|plugin ', description: '' }, async invoke(args) { From 0879b401bc5e286f3c72040e530b745505a58206 Mon Sep 17 00:00:00 2001 From: Baroshem Date: Wed, 23 Mar 2022 11:48:00 +0100 Subject: [PATCH 03/16] feat: refactor after CR --- packages/nuxi/src/commands/add.ts | 99 ++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 22 deletions(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index d3910923661..5fb1681c15c 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -6,11 +6,11 @@ import { loadKit } from '../utils/kit' export default defineNuxtCommand({ meta: { name: 'add', - usage: 'npx nuxi add endpoint|plugin ', - description: '' + usage: 'npx nuxi add api|plugin|component|composable|middleware|layout|page [rootDir]', + description: 'Create new components, plugins, composables by using handy CLI commands' }, async invoke(args) { - const rootDir = resolve('.') + const rootDir = resolve(args.rootDir || '.') const schematic = args._[0] const name = args._[1]; @@ -19,25 +19,80 @@ export default defineNuxtCommand({ const rootDirPath = nuxt.options.rootDir - switch (schematic) { - case 'endpoint': - const endpointPath = `${rootDirPath}/server/api` - const newEndpointPath = resolve(endpointPath, `${name.toLowerCase()}.ts`) - - if(!(existsSync(endpointPath) && readdirSync(endpointPath).length)) { - await fsp.mkdir(endpointPath, { recursive: true }) - } - await fsp.writeFile(newEndpointPath, `export default (req, res) => 'Hello ${name}'`) - break - case 'plugin': - const pluginPath = `${rootDirPath}/plugins` - const newPluginPath = resolve(pluginPath, `${name.toLowerCase()}.ts`) - - if(!(existsSync(pluginPath) && readdirSync(pluginPath).length)) { - await fsp.mkdir(pluginPath, { recursive: true }) - } - await fsp.writeFile(newPluginPath, 'export default defineNuxtPlugin(nuxtApp => {})') - break + const templates = { + api: { + path: `${rootDirPath}/server/api`, + template: `export default (req, res) => 'Hello ${name}'`, + fileName: name, + fileExtension: 'ts' + }, + plugin: { + path: `${rootDirPath}/plugins`, + template: 'export default defineNuxtPlugin(nuxtApp => {})', + fileName: name, + fileExtension: 'ts' + }, + component: { + path: `${rootDirPath}/components`, + template: ` + +`, + fileName: name, + fileExtension: 'vue' + }, + composable: { + path: `${rootDirPath}/composables`, + template: `export const ${name} = () => { + return useState(${name}, () => 'bar') +}`, + fileName: !name.includes('use') ? `use${name.charAt(0).toUpperCase() + name.slice(1)}` : name, + fileExtension: 'ts' + }, + middleware: { + path: `${rootDirPath}/middleware`, + template: 'export default defineNuxtRouteMiddleware((to, from) => {})', + fileName: name, + fileExtension: 'ts' + }, + layout: { + path: `${rootDirPath}/layouts`, + template: ` + +`, + fileName: name, + fileExtension: 'vue' + }, + page: { + path: name.includes('/') ? `${rootDirPath}/pages/${name.split('/')[0]}` : `${rootDirPath}/pages`, + template: ` + +`, + fileName: name.includes('/') ? name.split('/')[1] : name, + fileExtension: 'vue' + } } + + const { path, template, fileExtension, fileName } = templates[schematic] + + await writeTemplate(path, template, fileExtension, fileName) } }) + +async function writeTemplate(path: string, template: string, fileExtension: string, fileName: string) { + if(!(existsSync(path) && readdirSync(path).length)) { + await fsp.mkdir(path, { recursive: true }) + } + + const newFilePath = resolve(path, `${fileName}.${fileExtension}`) + + await fsp.writeFile(newFilePath, template) +} From bb0a4228291ca39ceb6e31ac245090761b4ece11 Mon Sep 17 00:00:00 2001 From: Baroshem Date: Wed, 23 Mar 2022 11:51:53 +0100 Subject: [PATCH 04/16] feat: add basic error handling --- packages/nuxi/src/commands/add.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index 5fb1681c15c..0eba02ee8b1 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -81,7 +81,11 @@ export default defineNuxtCommand({ } } - const { path, template, fileExtension, fileName } = templates[schematic] + const schema = templates[schematic] + + if (!schema) throw new Error('Schematic was not found. Pleasy try one of the schematics described in the docs') + + const { path, template, fileExtension, fileName } = schema; await writeTemplate(path, template, fileExtension, fileName) } From 8e3661dc280516915881c3813c3ff50d94b91048 Mon Sep 17 00:00:00 2001 From: Baroshem Date: Wed, 23 Mar 2022 11:53:46 +0100 Subject: [PATCH 05/16] feat: lint --- packages/nuxi/src/commands/add.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index 0eba02ee8b1..be6ee1b9edc 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -1,7 +1,7 @@ -import { defineNuxtCommand } from "./index"; import { existsSync, promises as fsp, readdirSync } from 'fs' import { resolve } from 'pathe' import { loadKit } from '../utils/kit' +import { defineNuxtCommand } from './index' export default defineNuxtCommand({ meta: { @@ -9,10 +9,10 @@ export default defineNuxtCommand({ usage: 'npx nuxi add api|plugin|component|composable|middleware|layout|page [rootDir]', description: 'Create new components, plugins, composables by using handy CLI commands' }, - async invoke(args) { + async invoke (args) { const rootDir = resolve(args.rootDir || '.') const schematic = args._[0] - const name = args._[1]; + const name = args._[1] const { loadNuxt } = await loadKit(rootDir) const nuxt = await loadNuxt({ rootDir, config: { _export: true } }) @@ -83,16 +83,16 @@ export default defineNuxtCommand({ const schema = templates[schematic] - if (!schema) throw new Error('Schematic was not found. Pleasy try one of the schematics described in the docs') + if (!schema) { throw new Error('Schematic was not found. Pleasy try one of the schematics described in the docs') } - const { path, template, fileExtension, fileName } = schema; + const { path, template, fileExtension, fileName } = schema await writeTemplate(path, template, fileExtension, fileName) } }) -async function writeTemplate(path: string, template: string, fileExtension: string, fileName: string) { - if(!(existsSync(path) && readdirSync(path).length)) { +async function writeTemplate (path: string, template: string, fileExtension: string, fileName: string) { + if (!(existsSync(path) && readdirSync(path).length)) { await fsp.mkdir(path, { recursive: true }) } From 3961c42018e19166a7cdf791e2f61a52a65ba3a8 Mon Sep 17 00:00:00 2001 From: Baroshem Date: Wed, 23 Mar 2022 14:43:45 +0100 Subject: [PATCH 06/16] feat: add docs --- docs/content/3.docs/1.usage/8.cli.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/content/3.docs/1.usage/8.cli.md b/docs/content/3.docs/1.usage/8.cli.md index c2409e889e1..ca3c77bd563 100644 --- a/docs/content/3.docs/1.usage/8.cli.md +++ b/docs/content/3.docs/1.usage/8.cli.md @@ -102,3 +102,17 @@ The `upgrade` command upgrades Nuxt 3 to the latest version. Option | Default | Description -------------------------|-----------------|------------------ `--force, -f` | `false` | Removes `node_modules` and lock files before upgrade. + +## Add + +```{bash} +npx nuxi add [TEMPLATE] [NAME] [--rootDir] +``` + +The `add` command can be used to generate new elements like components, composables, layouts, plugins and many more. + +Option | Default | Description +-------------------------|-----------------|------------------ +`TEMPLATE` | `false` | Specify a template of the file to be generated. Choose from component, composable, layout, plugin, page, middleware, api. +`NAME` | `test` | Specify a name of the file that will be created. +`rootDir` | `.` | The directory of the target application. From a06159c60fb9223953fac908ae92b877e7151e1b Mon Sep 17 00:00:00 2001 From: Baroshem Date: Wed, 23 Mar 2022 17:16:06 +0100 Subject: [PATCH 07/16] feat: add docs --- docs/content/3.docs/1.usage/8.cli.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/content/3.docs/1.usage/8.cli.md b/docs/content/3.docs/1.usage/8.cli.md index ca3c77bd563..4ec05976118 100644 --- a/docs/content/3.docs/1.usage/8.cli.md +++ b/docs/content/3.docs/1.usage/8.cli.md @@ -109,10 +109,18 @@ Option | Default | Description npx nuxi add [TEMPLATE] [NAME] [--rootDir] ``` -The `add` command can be used to generate new elements like components, composables, layouts, plugins and many more. +The `add` command can be used to generate new elements like: + +* components -> `npx nuxi add component TheHeader` +* composables -> `npx nuxi add composable useFoo|foo` (CLI will tranform the name to `useSomething`) +* layouts -> `npx nuxi add layout custom` +* plugins -> `npx nuxi add plugin analytics` +* pages -> `npx nuxi add page about|"category/[id]"` (CLI will generate dynamic pages as well) +* middlewares -> `npx nuxi add middleware auth` +* api -> `npx nuxi add api hello` (CLI will generate file under `/server/api`) Option | Default | Description -------------------------|-----------------|------------------ -`TEMPLATE` | `false` | Specify a template of the file to be generated. Choose from component, composable, layout, plugin, page, middleware, api. -`NAME` | `test` | Specify a name of the file that will be created. +`TEMPLATE` | - | Specify a template of the file to be generated. Choose from component, composable, layout, plugin, page, middleware, api. +`NAME` | - | Specify a name of the file that will be created. `rootDir` | `.` | The directory of the target application. From 152f6b5c5c7b1b2d32b56fa33393f1cbc1671b14 Mon Sep 17 00:00:00 2001 From: Baroshem Date: Wed, 23 Mar 2022 17:16:18 +0100 Subject: [PATCH 08/16] feat: refactor with CR fixes --- packages/nuxi/src/commands/add.ts | 88 +++++----------------------- packages/nuxi/src/utils/templates.ts | 55 +++++++++++++++++ 2 files changed, 70 insertions(+), 73 deletions(-) create mode 100644 packages/nuxi/src/utils/templates.ts diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index be6ee1b9edc..1e375e0f942 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -1,17 +1,18 @@ import { existsSync, promises as fsp, readdirSync } from 'fs' import { resolve } from 'pathe' import { loadKit } from '../utils/kit' +import { templates } from '../utils/templates' import { defineNuxtCommand } from './index' export default defineNuxtCommand({ meta: { name: 'add', - usage: 'npx nuxi add api|plugin|component|composable|middleware|layout|page [rootDir]', + usage: `npx nuxi add ${Object.keys(templates).join('|')} [rootDir]`, description: 'Create new components, plugins, composables by using handy CLI commands' }, async invoke (args) { const rootDir = resolve(args.rootDir || '.') - const schematic = args._[0] + const element = args._[0] const name = args._[1] const { loadNuxt } = await loadKit(rootDir) @@ -19,84 +20,25 @@ export default defineNuxtCommand({ const rootDirPath = nuxt.options.rootDir - const templates = { - api: { - path: `${rootDirPath}/server/api`, - template: `export default (req, res) => 'Hello ${name}'`, - fileName: name, - fileExtension: 'ts' - }, - plugin: { - path: `${rootDirPath}/plugins`, - template: 'export default defineNuxtPlugin(nuxtApp => {})', - fileName: name, - fileExtension: 'ts' - }, - component: { - path: `${rootDirPath}/components`, - template: ` + const schema = templates[element](name) -`, - fileName: name, - fileExtension: 'vue' - }, - composable: { - path: `${rootDirPath}/composables`, - template: `export const ${name} = () => { - return useState(${name}, () => 'bar') -}`, - fileName: !name.includes('use') ? `use${name.charAt(0).toUpperCase() + name.slice(1)}` : name, - fileExtension: 'ts' - }, - middleware: { - path: `${rootDirPath}/middleware`, - template: 'export default defineNuxtRouteMiddleware((to, from) => {})', - fileName: name, - fileExtension: 'ts' - }, - layout: { - path: `${rootDirPath}/layouts`, - template: ` + if (!schema) { throw new Error('Template was not found. Pleasy try one of the templates described in the docs') } -`, - fileName: name, - fileExtension: 'vue' - }, - page: { - path: name.includes('/') ? `${rootDirPath}/pages/${name.split('/')[0]}` : `${rootDirPath}/pages`, - template: ` + const { path, template } = schema -`, - fileName: name.includes('/') ? name.split('/')[1] : name, - fileExtension: 'vue' - } - } + const pathWithRootDir = rootDirPath + path - const schema = templates[schematic] - - if (!schema) { throw new Error('Schematic was not found. Pleasy try one of the schematics described in the docs') } - - const { path, template, fileExtension, fileName } = schema - - await writeTemplate(path, template, fileExtension, fileName) + await writeTemplate(pathWithRootDir, template) } }) -async function writeTemplate (path: string, template: string, fileExtension: string, fileName: string) { - if (!(existsSync(path) && readdirSync(path).length)) { - await fsp.mkdir(path, { recursive: true }) - } +async function writeTemplate (path: string, template: string) { + const pathElements = path.split('/') + const pathWithoutFile = pathElements.filter((element, index) => index < pathElements.length - 1).join('/') - const newFilePath = resolve(path, `${fileName}.${fileExtension}`) + if (!(existsSync(pathWithoutFile) && readdirSync(pathWithoutFile).length)) { + await fsp.mkdir(pathWithoutFile, { recursive: true }) + } - await fsp.writeFile(newFilePath, template) + await fsp.writeFile(path, template) } diff --git a/packages/nuxi/src/utils/templates.ts b/packages/nuxi/src/utils/templates.ts new file mode 100644 index 00000000000..5f558753ccf --- /dev/null +++ b/packages/nuxi/src/utils/templates.ts @@ -0,0 +1,55 @@ +import { upperFirst } from 'scule' + +export const templates = { + api: (name: string) => ({ + path: `/server/api/${name}.ts`, + template: `export default (req, res) => 'Hello ${name}'` + }), + plugin: (name: string) => ({ + path: `/plugins/${name}.ts`, + template: 'export default defineNuxtPlugin(nuxtApp => {})' + }), + component: (name: string) => ({ + path: `/components/${name}.vue`, + template: ` + + + +` + }), + composable: (name: string) => ({ + path: `/composables/${!name.includes('use') ? `use${upperFirst(name)}` : name}.ts`, + template: `export const ${name} = () => { +return useState(${name}, () => 'bar') +}` + }), + middleware: (name: string) => ({ + path: `/middleware/${name}.ts`, + template: 'export default defineNuxtRouteMiddleware((to, from) => {})' + }), + layout: (name: string) => ({ + path: `/layouts/${name}.vue`, + template: ` + + + +` + }), + page: (name: string) => ({ + path: `/pages/${name}.vue`, + template: ` + + + +` + }) +} From f4a2dced832acde6492b69e69d4aed65dd0dc223 Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Thu, 24 Mar 2022 16:59:58 +0100 Subject: [PATCH 09/16] Update docs/content/3.docs/1.usage/8.cli.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Ollivier --- docs/content/3.docs/1.usage/8.cli.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/content/3.docs/1.usage/8.cli.md b/docs/content/3.docs/1.usage/8.cli.md index 4ec05976118..51eafd1f1b0 100644 --- a/docs/content/3.docs/1.usage/8.cli.md +++ b/docs/content/3.docs/1.usage/8.cli.md @@ -111,13 +111,13 @@ npx nuxi add [TEMPLATE] [NAME] [--rootDir] The `add` command can be used to generate new elements like: -* components -> `npx nuxi add component TheHeader` -* composables -> `npx nuxi add composable useFoo|foo` (CLI will tranform the name to `useSomething`) -* layouts -> `npx nuxi add layout custom` -* plugins -> `npx nuxi add plugin analytics` -* pages -> `npx nuxi add page about|"category/[id]"` (CLI will generate dynamic pages as well) -* middlewares -> `npx nuxi add middleware auth` -* api -> `npx nuxi add api hello` (CLI will generate file under `/server/api`) +* **components**: `npx nuxi add component TheHeader` +* **composables**: `npx nuxi add composable useFoo|foo` (CLI will tranform the name to `useSomething`) +* **layouts**: `npx nuxi add layout custom` +* **plugins**: `npx nuxi add plugin analytics` +* **pages**: `npx nuxi add page about|"category/[id]"` (CLI will generate dynamic pages as well) +* **middlewares**: `npx nuxi add middleware auth` +* **api**: `npx nuxi add api hello` (CLI will generate file under `/server/api`) Option | Default | Description -------------------------|-----------------|------------------ From 1d1ac2ef341e7da276116826c2690e761375a260 Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Thu, 24 Mar 2022 17:00:14 +0100 Subject: [PATCH 10/16] Update docs/content/3.docs/1.usage/8.cli.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Ollivier --- docs/content/3.docs/1.usage/8.cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.docs/1.usage/8.cli.md b/docs/content/3.docs/1.usage/8.cli.md index 51eafd1f1b0..47f15e44eda 100644 --- a/docs/content/3.docs/1.usage/8.cli.md +++ b/docs/content/3.docs/1.usage/8.cli.md @@ -109,7 +109,7 @@ Option | Default | Description npx nuxi add [TEMPLATE] [NAME] [--rootDir] ``` -The `add` command can be used to generate new elements like: +The `add` command generates new elements like: * **components**: `npx nuxi add component TheHeader` * **composables**: `npx nuxi add composable useFoo|foo` (CLI will tranform the name to `useSomething`) From 00e37cc1d8b40df047fcb2a0c45b0d961d80814e Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Mar 2022 14:20:44 +0100 Subject: [PATCH 11/16] refactor: update templates --- packages/nuxi/src/utils/templates.ts | 115 ++++++++++++++++++--------- 1 file changed, 76 insertions(+), 39 deletions(-) diff --git a/packages/nuxi/src/utils/templates.ts b/packages/nuxi/src/utils/templates.ts index 5f558753ccf..bd88064ddbf 100644 --- a/packages/nuxi/src/utils/templates.ts +++ b/packages/nuxi/src/utils/templates.ts @@ -1,55 +1,92 @@ import { upperFirst } from 'scule' -export const templates = { - api: (name: string) => ({ - path: `/server/api/${name}.ts`, - template: `export default (req, res) => 'Hello ${name}'` - }), - plugin: (name: string) => ({ - path: `/plugins/${name}.ts`, - template: 'export default defineNuxtPlugin(nuxtApp => {})' - }), - component: (name: string) => ({ - path: `/components/${name}.vue`, - template: ` +interface Template { + (options: { name: string }): { path: string, template: string } +} + +const api: Template = ({ name }) => ({ + path: `/server/api/${name}.ts`, + template: ` +import { defineHandle } from 'h3' +export default defineHandle((req, res) => { + return 'Hello ${name}' +}) +` +}) + +const plugin: Template = ({ name }) => ({ + path: `/plugins/${name}.ts`, + template: ` +export default defineNuxtPlugin(nuxtApp => {}) + ` +}) + +const component: Template = ({ name }) => ({ + path: `/components/${name}.vue`, + template: ` + -` - }), - composable: (name: string) => ({ - path: `/composables/${!name.includes('use') ? `use${upperFirst(name)}` : name}.ts`, - template: `export const ${name} = () => { + +` +}) + +const composable: Template = ({ name }) => ({ + path: `/composables/${!name.includes('use') ? `use${upperFirst(name)}` : name}.ts`, + template: ` +export const ${name} = () => { return useState(${name}, () => 'bar') -}` - }), - middleware: (name: string) => ({ - path: `/middleware/${name}.ts`, - template: 'export default defineNuxtRouteMiddleware((to, from) => {})' - }), - layout: (name: string) => ({ - path: `/layouts/${name}.vue`, - template: ` +} +` +}) + +const middleware: Template = ({ name }) => ({ + path: `/middleware/${name}.ts`, + template: ` +export default defineNuxtRouteMiddleware((to, from) => {}) +` +}) + +const layout: Template = ({ name }) => ({ + path: `/layouts/${name}.vue`, + template: ` + -` - }), - page: (name: string) => ({ - path: `/pages/${name}.vue`, - template: ` + +` +}) + +const page: Template = ({ name }) => ({ + path: `/pages/${name}.vue`, + template: ` + -` - }) + +` +}) + +export const templates = { + api, + plugin, + component, + composable, + middleware, + layout, + page } From 2fff4efea86ea8082173fe778b1d33290766fd28 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Mar 2022 14:48:11 +0100 Subject: [PATCH 12/16] improve add behavior --- packages/nuxi/src/commands/add.ts | 77 ++++++++++++++++------------ packages/nuxi/src/utils/templates.ts | 66 +++++++++++++----------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index 1e375e0f942..ed7fdf6fe59 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -1,44 +1,57 @@ -import { existsSync, promises as fsp, readdirSync } from 'fs' -import { resolve } from 'pathe' -import { loadKit } from '../utils/kit' +import { existsSync, promises as fsp } from 'fs' +import { resolve, dirname } from 'pathe' +import consola from 'consola' import { templates } from '../utils/templates' import { defineNuxtCommand } from './index' export default defineNuxtCommand({ meta: { - name: 'add', - usage: `npx nuxi add ${Object.keys(templates).join('|')} [rootDir]`, + name: 'create', + usage: `npx nuxi create [--cwd] [--force] ${Object.keys(templates).join('|')} `, description: 'Create new components, plugins, composables by using handy CLI commands' }, async invoke (args) { - const rootDir = resolve(args.rootDir || '.') - const element = args._[0] - const name = args._[1] - - const { loadNuxt } = await loadKit(rootDir) - const nuxt = await loadNuxt({ rootDir, config: { _export: true } }) - - const rootDirPath = nuxt.options.rootDir - - const schema = templates[element](name) - - if (!schema) { throw new Error('Template was not found. Pleasy try one of the templates described in the docs') } - - const { path, template } = schema + const cwd = resolve(args.cwd || '.') - const pathWithRootDir = rootDirPath + path + const template = args._[0] + const name = args._[1] - await writeTemplate(pathWithRootDir, template) + // Validate template name + if (!templates[template]) { + consola.error(`Template ${template} is not supported. Possible values: ${Object.keys(templates).join(', ')}`) + process.exit(1) + } + + // Validate options + if (!name) { + consola.error('name argument is missing!') + process.exit(1) + } + + // Resolve template + const res = templates[template]({ name }) + + // Resolve full path to generated file + const path = resolve(cwd, res.path) + + // Ensure not overriding user code + if (!args.force && existsSync(path)) { + consola.error(`File exists: ${path} . Use --force to override or use a different name.`) + process.exit(1) + } + + // Ensure parent directory exists + const parentDir = dirname(path) + if (!existsSync(parentDir)) { + consola.info('Creating directory', parentDir) + if (template === 'page') { + consola.info('This enables vue-router functionality!') + } + await fsp.mkdir(parentDir, { recursive: true }) + } + + // Write file + await fsp.writeFile(path, res.contents.trim() + '\n') + consola.info(`🪄 Generated a new ${template} in ${path}`) } }) - -async function writeTemplate (path: string, template: string) { - const pathElements = path.split('/') - const pathWithoutFile = pathElements.filter((element, index) => index < pathElements.length - 1).join('/') - - if (!(existsSync(pathWithoutFile) && readdirSync(pathWithoutFile).length)) { - await fsp.mkdir(pathWithoutFile, { recursive: true }) - } - - await fsp.writeFile(path, template) -} diff --git a/packages/nuxi/src/utils/templates.ts b/packages/nuxi/src/utils/templates.ts index bd88064ddbf..24c58db9e38 100644 --- a/packages/nuxi/src/utils/templates.ts +++ b/packages/nuxi/src/utils/templates.ts @@ -1,13 +1,14 @@ import { upperFirst } from 'scule' interface Template { - (options: { name: string }): { path: string, template: string } + (options: { name: string }): { path: string, contents: string } } const api: Template = ({ name }) => ({ - path: `/server/api/${name}.ts`, - template: ` + path: `server/api/${name}.ts`, + contents: ` import { defineHandle } from 'h3' + export default defineHandle((req, res) => { return 'Hello ${name}' }) @@ -15,51 +16,56 @@ export default defineHandle((req, res) => { }) const plugin: Template = ({ name }) => ({ - path: `/plugins/${name}.ts`, - template: ` -export default defineNuxtPlugin(nuxtApp => {}) + path: `plugins/${name}.ts`, + contents: ` +export default defineNuxtPlugin((nuxtApp) => {}) ` }) const component: Template = ({ name }) => ({ - path: `/components/${name}.vue`, - template: ` + path: `components/${name}.vue`, + contents: ` ` }) -const composable: Template = ({ name }) => ({ - path: `/composables/${!name.includes('use') ? `use${upperFirst(name)}` : name}.ts`, - template: ` -export const ${name} = () => { -return useState(${name}, () => 'bar') +const composable: Template = ({ name }) => { + const nameWithUsePrefix = name.startsWith('use') ? name : `use${upperFirst(name)}` + return { + path: `composables/${name}.ts`, + contents: ` +export const ${nameWithUsePrefix} = () => { + return ref() +} + ` + } } -` -}) const middleware: Template = ({ name }) => ({ - path: `/middleware/${name}.ts`, - template: ` + path: `middleware/${name}.ts`, + contents: ` export default defineNuxtRouteMiddleware((to, from) => {}) ` }) const layout: Template = ({ name }) => ({ - path: `/layouts/${name}.vue`, - template: ` + path: `layouts/${name}.vue`, + contents: ` @@ -67,14 +73,14 @@ const layout: Template = ({ name }) => ({ }) const page: Template = ({ name }) => ({ - path: `/pages/${name}.vue`, - template: ` + path: `pages/${name}.vue`, + contents: ` @@ -89,4 +95,4 @@ export const templates = { middleware, layout, page -} +} as Record From aa507b263f961ed3fcd4edc813ddb6f16edc7acb Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Mar 2022 15:06:52 +0100 Subject: [PATCH 13/16] respect srcDir --- packages/nuxi/src/commands/add.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index ed7fdf6fe59..c6f8761744e 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -1,6 +1,7 @@ import { existsSync, promises as fsp } from 'fs' import { resolve, dirname } from 'pathe' import consola from 'consola' +import { loadKit } from '../utils/kit' import { templates } from '../utils/templates' import { defineNuxtCommand } from './index' @@ -28,11 +29,15 @@ export default defineNuxtCommand({ process.exit(1) } + // Load config in order to respect srcDir + const kit = await loadKit(cwd) + const config = await kit.loadNuxtConfig({ cwd }) + // Resolve template const res = templates[template]({ name }) // Resolve full path to generated file - const path = resolve(cwd, res.path) + const path = resolve(config.srcDir, res.path) // Ensure not overriding user code if (!args.force && existsSync(path)) { From dbd0d4a9362b8ff5b7488a8458b5d1f9f64b97d3 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Mar 2022 15:12:58 +0100 Subject: [PATCH 14/16] update cli description and add new alias --- packages/nuxi/src/commands/add.ts | 6 +++--- packages/nuxi/src/commands/index.ts | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/nuxi/src/commands/add.ts b/packages/nuxi/src/commands/add.ts index c6f8761744e..ca8994f526d 100644 --- a/packages/nuxi/src/commands/add.ts +++ b/packages/nuxi/src/commands/add.ts @@ -7,9 +7,9 @@ import { defineNuxtCommand } from './index' export default defineNuxtCommand({ meta: { - name: 'create', - usage: `npx nuxi create [--cwd] [--force] ${Object.keys(templates).join('|')} `, - description: 'Create new components, plugins, composables by using handy CLI commands' + name: 'new', + usage: `npx nuxi add [--cwd] [--force] ${Object.keys(templates).join('|')} `, + description: 'Create a new template file.' }, async invoke (args) { const cwd = resolve(args.cwd || '.') diff --git a/packages/nuxi/src/commands/index.ts b/packages/nuxi/src/commands/index.ts index a040e0cd470..92494977f4c 100644 --- a/packages/nuxi/src/commands/index.ts +++ b/packages/nuxi/src/commands/index.ts @@ -17,7 +17,8 @@ export const commands = { create: () => import('./init').then(_rDefault), upgrade: () => import('./upgrade').then(_rDefault), test: () => import('./test').then(_rDefault), - add: () => import('./add').then(_rDefault) + add: () => import('./add').then(_rDefault), + new: () => import('./add').then(_rDefault) } export type Command = keyof typeof commands From ac36d808c06235059552f4f45eb77e48dbfa7c02 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Mar 2022 15:53:59 +0100 Subject: [PATCH 15/16] update docs --- docs/content/3.docs/1.usage/8.cli.md | 33 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/content/3.docs/1.usage/8.cli.md b/docs/content/3.docs/1.usage/8.cli.md index 47f15e44eda..9db5ad83d30 100644 --- a/docs/content/3.docs/1.usage/8.cli.md +++ b/docs/content/3.docs/1.usage/8.cli.md @@ -106,21 +106,28 @@ Option | Default | Description ## Add ```{bash} -npx nuxi add [TEMPLATE] [NAME] [--rootDir] +npx nuxi add [--cwd] [--force]