feat(misc): handle artifact generators' path options including file extensions (#29111)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> Artifact generators don't handle consistently receiving a file extension in the `path` option. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Artifact generators should handle receiving a file extension in the `path` option. If the file extension is passed, the file path will be treated as "complete" and used fully as provided. If the `path` provided doesn't contain a file extension, the default extension will be appended to it (or the one provided in a related option, e.g. `--language`, `--js`, etc) together with the suffix for generators that use it. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
3474d7c607
commit
28c53f942b
@ -12,7 +12,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the component file path?"
|
||||
},
|
||||
@ -117,7 +117,7 @@
|
||||
}
|
||||
},
|
||||
"required": ["path"],
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Simple Component\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component\n```\n\n{% /tab %}\n\n{% tab label=\"With Different Symbol Name\" %}\n\nGenerate a component named `CustomComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --name=custom\n```\n\n{% /tab %}\n\n{% tab label=\"Single File Component\" %}\n\nCreate a component named `my-component` with inline styles and inline template:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --inlineStyle --inlineTemplate\n```\n\n{% /tab %}\n\n{% tab label=\"Component with OnPush Change Detection Strategy\" %}\n\nCreate a component named `my-component` with OnPush Change Detection Strategy:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --changeDetection=OnPush\n```\n\n{% /tab %}\n",
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Simple Component\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component.ts\n```\n\n{% /tab %}\n\n{% tab label=\"Without Providing the File Extension\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component\n```\n\n{% /tab %}\n\n{% tab label=\"With Different Symbol Name\" %}\n\nGenerate a component named `CustomComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --name=custom\n```\n\n{% /tab %}\n\n{% tab label=\"Single File Component\" %}\n\nCreate a component named `my-component` with inline styles and inline template:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --inlineStyle --inlineTemplate\n```\n\n{% /tab %}\n\n{% tab label=\"Component with OnPush Change Detection Strategy\" %}\n\nCreate a component named `my-component` with OnPush Change Detection Strategy:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --changeDetection=OnPush\n```\n\n{% /tab %}\n",
|
||||
"presets": []
|
||||
},
|
||||
"aliases": ["c"],
|
||||
|
||||
@ -12,6 +12,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a directive with the exported symbol matching the file name. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:directive mylib/src/lib/foo.directive.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a directive without providing the file extension. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:directive mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -22,7 +26,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the directive without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the directive. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the directive file path?"
|
||||
},
|
||||
|
||||
@ -12,6 +12,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a pipe with the exported symbol matching the file name. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:pipe mylib/src/lib/foo.pipe.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:pipe mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -22,7 +26,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the pipe without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the pipe. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the pipe file path?"
|
||||
},
|
||||
|
||||
@ -10,6 +10,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a directive with the exported symbol matching the file name. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:scam-directive mylib/src/lib/foo.directive.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a directive without providing the file extension. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:scam-directive mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -22,7 +26,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the SCAM directive without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the SCAM directive. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the SCAM directive file path?"
|
||||
},
|
||||
|
||||
@ -10,6 +10,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a pipe with the exported symbol matching the file name. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:scam-pipe mylib/src/lib/foo.pipe.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:scam-pipe mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -22,7 +26,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the SCAM pipe without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the SCAM pipe. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the SCAM pipe file path?"
|
||||
},
|
||||
|
||||
@ -10,6 +10,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a component with the exported symbol matching the file name. It results in the component `FooComponent` at `mylib/src/lib/foo.component.ts`",
|
||||
"command": "nx g @nx/angular:scam mylib/src/lib/foo.component.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component without providing the file extension. It results in the component `FooComponent` at `mylib/src/lib/foo.component.ts`",
|
||||
"command": "nx g @nx/angular:scam mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -22,7 +26,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the SCAM without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the SCAM. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the SCAM file path?"
|
||||
},
|
||||
|
||||
@ -10,11 +10,15 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a component with the exported symbol matching the file name. It results in the component `Foo` at `mylib/src/foo.tsx`",
|
||||
"command": "nx g @nx/expo:component mylib/src/foo"
|
||||
"command": "nx g @nx/expo:component mylib/src/foo.tsx"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component with the exported symbol different from the file name. It results in the component `Custom` at `mylib/src/foo.tsx`",
|
||||
"command": "nx g @nx/expo:component mylib/src/foo --name=custom"
|
||||
"command": "nx g @nx/expo:component mylib/src/foo.tsx --name=custom"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component without the providing the file extension. It results in the component `Foo` at `mylib/src/foo.tsx`",
|
||||
"command": "nx g @nx/expo:component mylib/src/foo"
|
||||
},
|
||||
{
|
||||
"description": "Generate a class component at `mylib/src/foo.tsx`",
|
||||
@ -24,7 +28,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the component file path?"
|
||||
},
|
||||
@ -35,7 +39,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the class `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:class myapp/src/app/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the class without providing the file extension. It results in the class `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:class myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the class without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the class. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the class file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the controller `FooController` at `myapp/src/app/foo.controller.ts`",
|
||||
"command": "nx g @nx/nest:controller myapp/src/app/foo.controller.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the controller without providing the file extension. It results in the controller `FooController` at `myapp/src/app/foo.controller.ts`",
|
||||
"command": "nx g @nx/nest:controller myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the controller without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the controller. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the controller file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the decorator `Foo` at `myapp/src/app/foo.decorator.ts`",
|
||||
"command": "nx g @nx/nest:decorator myapp/src/app/foo.decorator.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the decorator without providing the file extension. It results in the decorator `Foo` at `myapp/src/app/foo.decorator.ts`",
|
||||
"command": "nx g @nx/nest:decorator myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the decorator without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the decorator. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the decorator file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the filter `FooFilter` at `myapp/src/app/foo.filter.ts`",
|
||||
"command": "nx g @nx/nest:filter myapp/src/app/foo.filter.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the filter without providing the file extension. It results in the filter `FooFilter` at `myapp/src/app/foo.filter.ts`",
|
||||
"command": "nx g @nx/nest:filter myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the filter without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the filter. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the filter file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the gateway `FooGateway` at `myapp/src/app/foo.gateway.ts`",
|
||||
"command": "nx g @nx/nest:gateway myapp/src/app/foo.gateway.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the gateway without providing the file extension. It results in the gateway `FooGateway` at `myapp/src/app/foo.gateway.ts`",
|
||||
"command": "nx g @nx/nest:gateway myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the gateway without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the gateway. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the gateway file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the guard `FooGuard` at `myapp/src/app/foo.guard.ts`",
|
||||
"command": "nx g @nx/nest:guard myapp/src/app/foo.guard.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the guard without providing the file extension. It results in the guard `FooGuard` at `myapp/src/app/foo.guard.ts`",
|
||||
"command": "nx g @nx/nest:guard myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the guard without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the guard. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the guard file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the interceptor `FooInterceptor` at `myapp/src/app/foo.interceptor.ts`",
|
||||
"command": "nx g @nx/nest:interceptor myapp/src/app/foo.interceptor.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the interceptor without providing the file extension. It results in the interceptor `FooInterceptor` at `myapp/src/app/foo.interceptor.ts`",
|
||||
"command": "nx g @nx/nest:interceptor myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the interceptor without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the interceptor. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the interceptor file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the interface `Foo` at `myapp/src/app/foo.interface.ts`",
|
||||
"command": "nx g @nx/nest:interface myapp/src/app/foo.interface.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the interface without providing the file extension. It results in the interface `Foo` at `myapp/src/app/foo.interface.ts`",
|
||||
"command": "nx g @nx/nest:interface myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the interface without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the interface. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the interface file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the middleware `FooMiddleware` at `myapp/src/app/foo.middleware.ts`",
|
||||
"command": "nx g @nx/nest:middleware myapp/src/app/foo.middleware.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the middleware without providing the file extension. It results in the middleware `FooMiddleware` at `myapp/src/app/foo.middleware.ts`",
|
||||
"command": "nx g @nx/nest:middleware myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the middleware without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the middleware. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the middleware file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the module `FooModule` at `myapp/src/app/foo.module.ts`",
|
||||
"command": "nx g @nx/nest:module myapp/src/app/foo.module.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the module without providing the file extension. It results in the module `FooModule` at `myapp/src/app/foo.module.ts`",
|
||||
"command": "nx g @nx/nest:module myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the module without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the module. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the module file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the pipe `FooPipe` at `myapp/src/app/foo.pipe.ts`",
|
||||
"command": "nx g @nx/nest:pipe myapp/src/app/foo.pipe.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the pipe without providing the file extension. It results in the pipe `FooPipe` at `myapp/src/app/foo.pipe.ts`",
|
||||
"command": "nx g @nx/nest:pipe myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the pipe without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the pipe. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the pipe file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the provider `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:provider myapp/src/app/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the provider without providing the file extension. It results in the provider `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:provider myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the provider without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the provider. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the provider file path?"
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the resolver `FooResolver` at `myapp/src/app/foo.resolver.ts`",
|
||||
"command": "nx g @nx/nest:resolver myapp/src/app/foo.resolver.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the resolver without providing the file extension. It results in the resolver `FooResolver` at `myapp/src/app/foo.resolver.ts`",
|
||||
"command": "nx g @nx/nest:resolver myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the resolver without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the resolver. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the resolver file path?"
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the resource without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the resource. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the resource file path?"
|
||||
},
|
||||
@ -33,11 +33,6 @@
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"language": {
|
||||
"description": "Nest class language.",
|
||||
"type": "string",
|
||||
"enum": ["js", "ts"]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "The transport layer.",
|
||||
|
||||
@ -11,12 +11,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the service `FooService` at `myapp/src/app/foo.service.ts`",
|
||||
"command": "nx g @nx/nest:service myapp/src/app/foo.service.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the service without providing the file extension. It results in the service `FooService` at `myapp/src/app/foo.service.ts`",
|
||||
"command": "nx g @nx/nest:service myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the service without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the service. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the service file path?"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the component file path?",
|
||||
"x-priority": "important"
|
||||
@ -69,7 +69,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
@ -79,7 +79,7 @@
|
||||
}
|
||||
},
|
||||
"required": ["path"],
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Create a Component\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/app/my-component/my-component.tsx`:\n\n```shell\nnx g component apps/my-app/src/app/my-component/my-component\n```\n\n{% /tab %}\n{% tab label=\"Create a Component with a Different Symbol Name\" %}\n\nGenerate a component named `Custom` at `apps/my-app/src/app/my-component/my-component.tsx`:\n\n```shell\nnx g component apps/my-app/src/app/my-component/my-component --name=custom\n```\n\n{% /tab %}\n{% /tabs %}\n",
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Create a Component\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/app/my-component/my-component.tsx`:\n\n```shell\nnx g component apps/my-app/src/app/my-component/my-component.tsx\n```\n\n{% /tab %}\n{% tab label=\"Create a Component with a Different Symbol Name\" %}\n\nGenerate a component named `Custom` at `apps/my-app/src/app/my-component/my-component.tsx`:\n\n```shell\nnx g component apps/my-app/src/app/my-component/my-component.tsx --name=custom\n```\n\n{% /tab %}\n{% tab label=\"Create a Component Omitting the File Extension\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/app/my-component/my-component.tsx` without specifying the file extension:\n\n```shell\nnx g component apps/my-app/src/app/my-component/my-component\n```\n\n{% /tab %}\n{% /tabs %}\n",
|
||||
"presets": []
|
||||
},
|
||||
"description": "Create a component.",
|
||||
|
||||
@ -7,12 +7,12 @@
|
||||
"$id": "NxPluginExecutor",
|
||||
"title": "Create an Executor for an Nx Plugin",
|
||||
"description": "Create an Executor for an Nx Plugin.",
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Basic executor\" %}\n\nCreate a new executor called `build` at `tools/my-plugin/src/executors/build.ts`:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build\n```\n\n{% /tab %}\n{% tab label=\"With different exported name\" %}\n\nCreate a new executor called `custom` at `tools/my-plugin/src/executors/build.ts`:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build --name=custom\n```\n\n{% /tab %}\n{% tab label=\"With custom hashing\" %}\n\nCreate a new executor called `build` at `tools/my-plugin/src/executors/build.ts`, that uses a custom hashing function:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build --includeHasher\n```\n\n{% /tab %}\n{% /tabs %}\n",
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Basic executor\" %}\n\nCreate a new executor called `build` at `tools/my-plugin/src/executors/build.ts`:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build.ts\n```\n\n{% /tab %}\n{% tab label=\"Without providing the file extension\" %}\n\nCreate a new executor called `build` at `tools/my-plugin/src/executors/build.ts`:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build\n```\n\n{% /tab %}\n{% tab label=\"With different exported name\" %}\n\nCreate a new executor called `custom` at `tools/my-plugin/src/executors/build.ts`:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build.ts --name=custom\n```\n\n{% /tab %}\n{% tab label=\"With custom hashing\" %}\n\nCreate a new executor called `build` at `tools/my-plugin/src/executors/build.ts`, that uses a custom hashing function:\n\n```bash\nnx g @nx/plugin:executor tools/my-plugin/src/executors/build --includeHasher\n```\n\n{% /tab %}\n{% /tabs %}\n",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the executor without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the executor. Relative to the current working directory.",
|
||||
"x-prompt": "What is the executor file path?",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-priority": "important"
|
||||
|
||||
@ -11,6 +11,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a generator exported with the name matching the file name. It results in the generator `foo` at `mylib/src/generators/foo.ts`",
|
||||
"command": "nx g @nx/plugin:generator mylib/src/generators/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a generator without providing the file extension. It results in the generator `foo` at `mylib/src/generators/foo.ts`",
|
||||
"command": "nx g @nx/plugin:generator mylib/src/generators/foo"
|
||||
},
|
||||
{
|
||||
@ -21,7 +25,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the generator without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the generator. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the generator file path?",
|
||||
"x-priority": "important"
|
||||
|
||||
@ -11,6 +11,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a migration exported with the name matching the file name, which will be triggered when migrating to version 1.0.0 or above from a previous version. It results in the migration `foo` at `mylib/src/migrations/foo.ts`",
|
||||
"command": "nx g @nx/plugin:migration mylib/src/migrations/foo.ts -v=1.0.0"
|
||||
},
|
||||
{
|
||||
"description": "Generate a migration without providing the file extension, which will be triggered when migrating to version 1.0.0 or above from a previous version. It results in the migration `foo` at `mylib/src/migrations/foo.ts`",
|
||||
"command": "nx g @nx/plugin:migration mylib/src/migrations/foo -v=1.0.0"
|
||||
},
|
||||
{
|
||||
|
||||
@ -11,11 +11,15 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a component with the exported symbol matching the file name. It results in the component `Foo` at `mylib/src/lib/foo.tsx`",
|
||||
"command": "nx g @nx/react-native:component mylib/src/lib/foo"
|
||||
"command": "nx g @nx/react-native:component mylib/src/lib/foo.tsx"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component with the exported symbol different from the file name. It results in the component `Custom` at `mylib/src/lib/foo.tsx`",
|
||||
"command": "nx g @nx/react-native:component mylib/src/lib/foo --name=custom"
|
||||
"command": "nx g @nx/react-native:component mylib/src/lib/foo.tsx --name=custom"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component without providing the file extension. It results in the component `Foo` at `mylib/src/lib/foo.tsx`",
|
||||
"command": "nx g @nx/react-native:component mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
"description": "Generate a class component at `mylib/src/lib/foo.tsx`",
|
||||
@ -25,7 +29,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the component file path?"
|
||||
},
|
||||
@ -36,7 +40,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipTests": {
|
||||
"type": "boolean",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the component file path?",
|
||||
"x-priority": "important"
|
||||
@ -57,7 +57,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipTests": {
|
||||
"type": "boolean",
|
||||
@ -87,10 +87,6 @@
|
||||
"description": "Default is `false`. When `true`, the component is generated with `*.css`/`*.scss` instead of `*.module.css`/`*.module.scss`.",
|
||||
"default": false
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string",
|
||||
"description": "Create a component with this file name."
|
||||
},
|
||||
"inSourceTests": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
@ -104,7 +100,7 @@
|
||||
}
|
||||
},
|
||||
"required": ["path"],
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Simple Component\" %}\n\nCreate a component named `MyComponent` at `libs/ui/src/my-component.tsx`:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component\n```\n\n{% /tab %}\n\n{% tab label=\"With a Different Symbol Name\" %}\n\nCreate a component named `Custom` at `libs/ui/src/my-component.tsx`:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component --name=custom\n```\n\n{% /tab %}\n\n{% tab label=\"Class Component\" %}\n\nCreate a class component named `MyComponent` at `libs/ui/src/my-component.tsx`:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component --classComponent\n```\n\n{% /tab %}\n",
|
||||
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Simple Component\" %}\n\nCreate a component named `MyComponent` at `libs/ui/src/my-component.tsx`:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component.tsx\n```\n\n{% /tab %}\n\n{% tab label=\"With a Different Symbol Name\" %}\n\nCreate a component named `Custom` at `libs/ui/src/my-component.tsx`:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component.tsx --name=custom\n```\n\n{% /tab %}\n\n{% tab label=\"Omitting the File Extension\" %}\n\nCreate a component named `MyComponent` at `libs/ui/src/my-component.tsx` without specifying the file extension:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component\n```\n\n{% /tab %}\n\n{% tab label=\"Class Component\" %}\n\nCreate a class component named `MyComponent` at `libs/ui/src/my-component.tsx`:\n\n```shell\nnx g @nx/react:component libs/ui/src/my-component --classComponent\n```\n\n{% /tab %}\n",
|
||||
"presets": []
|
||||
},
|
||||
"description": "Create a React component.",
|
||||
|
||||
@ -11,17 +11,21 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a hook with the exported symbol matching the file name. It results in the hook `useFoo` at `mylib/src/lib/foo.ts`",
|
||||
"command": "nx g @nx/react:hook mylib/src/lib/foo"
|
||||
"command": "nx g @nx/react:hook mylib/src/lib/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a hook with the exported symbol different from the file name. It results in the hook `useCustom` at `mylib/src/lib/foo.ts`",
|
||||
"command": "nx g @nx/react:hook mylib/src/lib/foo --name=useCustom"
|
||||
"command": "nx g @nx/react:hook mylib/src/lib/foo.ts --name=useCustom"
|
||||
},
|
||||
{
|
||||
"description": "Generate a hook without providing the file extension. It results in the hook `useFoo` at `mylib/src/lib/foo.ts`",
|
||||
"command": "nx g @nx/react:hook mylib/src/lib/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the hook without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the hook. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the hook file path?",
|
||||
"x-priority": "important"
|
||||
@ -33,7 +37,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipTests": {
|
||||
"type": "boolean",
|
||||
|
||||
@ -11,17 +11,21 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a Redux state slice with the exported symbol matching the file name. It results in the slice `fooSlice` at `mylib/src/lib/foo.slice.ts`",
|
||||
"command": "nx g @nx/react:redux mylib/src/lib/foo"
|
||||
"command": "nx g @nx/react:redux mylib/src/lib/foo.slice.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a Redux state slice with the exported symbol different from the file name. It results in the slice `customSlice` at `mylib/src/lib/foo.slice.ts`",
|
||||
"command": "nx g @nx/react:redux mylib/src/lib/foo --name=custom"
|
||||
"command": "nx g @nx/react:redux mylib/src/lib/foo.slice.ts --name=custom"
|
||||
},
|
||||
{
|
||||
"description": "Generate a Redux state slice without providing the \"slice\" suffix and the file extension. It results in the slice `fooSlice` at `mylib/src/lib/foo.slice.ts`",
|
||||
"command": "nx g @nx/react:redux mylib/src/lib/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the Redux state slice without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the Redux state slice. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the Redux stateslice file path?",
|
||||
"x-priority": "important"
|
||||
@ -38,7 +42,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
}
|
||||
},
|
||||
"required": ["path"],
|
||||
|
||||
@ -9,16 +9,20 @@
|
||||
"description": "Generate a resource route.",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g resource-route 'path/to/page'",
|
||||
"description": "Generate resource route at /path/to/page"
|
||||
"description": "Generate a resource route at `myapp/app/routes/foo.ts`",
|
||||
"command": "nx g resource-route myapp/app/routes/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a resource route without providing the file extension at `myapp/app/routes/foo.tsx`",
|
||||
"command": "nx g resource-route myapp/app/routes/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The route path or path to the filename of the route.",
|
||||
"description": "The file path to the route. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the path of the route? (e.g. 'apps/demo/app/routes/foo/bar')"
|
||||
"x-prompt": "What is the route file path?"
|
||||
},
|
||||
"action": {
|
||||
"type": "boolean",
|
||||
|
||||
@ -9,16 +9,20 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g route 'path/to/page'",
|
||||
"description": "Generate route at /path/to/page"
|
||||
"description": "Generate a route at `myapp/app/routes/foo.tsx`",
|
||||
"command": "nx g resource-route myapp/app/routes/foo.tsx"
|
||||
},
|
||||
{
|
||||
"description": "Generate a route without providing the file extension at `myapp/app/routes/foo.tsx`",
|
||||
"command": "nx g resource-route myapp/app/routes/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The route path or path to the filename of the route.",
|
||||
"description": "The file path to the route. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the path of the route? (e.g. 'apps/demo/app/routes/foo/bar')"
|
||||
"x-prompt": "What is the route file path?"
|
||||
},
|
||||
"style": {
|
||||
"type": "string",
|
||||
|
||||
@ -9,16 +9,16 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g style --path='apps/demo/app/routes/path/to/page.tsx'",
|
||||
"description": "Generate route at apps/demo/app/routes/path/to/page.tsx"
|
||||
"description": "Generate a stylesheet at `myapp/app/styles/foo.css`",
|
||||
"command": "nx g style myapp/app/routes/foo.tsx"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Route path",
|
||||
"description": "The file path to the route. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the path of the route? (e.g. 'apps/demo/app/routes/foo/bar.tsx')"
|
||||
"x-prompt": "What is the route file path?"
|
||||
}
|
||||
},
|
||||
"required": ["path"],
|
||||
|
||||
@ -9,6 +9,14 @@
|
||||
"description": "Create a Vue Component for Nx.",
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a component at `mylib/src/lib/foo.vue`",
|
||||
"command": "nx g @nx/vue:component mylib/src/lib/foo.vue"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component without providing the file extension at `mylib/src/lib/foo.vue`",
|
||||
"command": "nx g @nx/vue:component mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component at `mylib/src/lib/foo.vue` with `vitest` as the unit test runner",
|
||||
"command": "nx g @nx/vue:component mylib/src/lib/foo --unitTestRunner=vitest"
|
||||
@ -17,7 +25,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What is the component file path?"
|
||||
},
|
||||
|
||||
@ -5,6 +5,16 @@
|
||||
|
||||
Generate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:
|
||||
|
||||
```bash
|
||||
nx g @nx/angular:component apps/my-app/src/lib/my-component/my-component.ts
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Without Providing the File Extension" %}
|
||||
|
||||
Generate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:
|
||||
|
||||
```bash
|
||||
nx g @nx/angular:component apps/my-app/src/lib/my-component/my-component
|
||||
```
|
||||
|
||||
@ -179,6 +179,54 @@ export class ExampleComponent {}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should handle path with file extension: component 1`] = `
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'example.component',
|
||||
imports: [CommonModule],
|
||||
templateUrl: './example.component.html',
|
||||
styleUrl: './example.component.css',
|
||||
})
|
||||
export class ExampleComponentComponent {}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should handle path with file extension: component test file 1`] = `
|
||||
"import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ExampleComponentComponent } from './example.component';
|
||||
|
||||
describe('ExampleComponentComponent', () => {
|
||||
let component: ExampleComponentComponent;
|
||||
let fixture: ComponentFixture<ExampleComponentComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ExampleComponentComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ExampleComponentComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should handle path with file extension: entry point file 1`] = `null`;
|
||||
|
||||
exports[`component Generator should handle path with file extension: stylesheet 1`] = `""`;
|
||||
|
||||
exports[`component Generator should handle path with file extension: template 1`] = `
|
||||
"<p>example.component works!</p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should inline styles when --inline-style=true 1`] = `
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
|
||||
@ -77,6 +77,35 @@ describe('component Generator', () => {
|
||||
).toContain(`import ExampleComponent from './example.component';`);
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
addProjectConfiguration(tree, 'lib1', {
|
||||
projectType: 'library',
|
||||
sourceRoot: 'lib1/src',
|
||||
root: 'lib1',
|
||||
});
|
||||
|
||||
await componentGenerator(tree, {
|
||||
path: 'lib1/src/lib/example/example.component.ts',
|
||||
});
|
||||
|
||||
expect(
|
||||
tree.read('lib1/src/lib/example/example.component.ts', 'utf-8')
|
||||
).toMatchSnapshot('component');
|
||||
expect(
|
||||
tree.read('lib1/src/lib/example/example.component.html', 'utf-8')
|
||||
).toMatchSnapshot('template');
|
||||
expect(
|
||||
tree.read('lib1/src/lib/example/example.component.css', 'utf-8')
|
||||
).toMatchSnapshot('stylesheet');
|
||||
expect(
|
||||
tree.read('lib1/src/lib/example/example.component.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot('component test file');
|
||||
expect(tree.read('lib1/src/index.ts', 'utf-8')).toMatchSnapshot(
|
||||
'entry point file'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not generate test file when --skip-tests=true', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
|
||||
@ -21,6 +21,8 @@ export async function normalizeOptions(
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
suffix: options.type ?? 'component',
|
||||
allowedFileExtensions: ['ts'],
|
||||
fileExtension: 'ts',
|
||||
});
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
|
||||
@ -125,3 +125,27 @@ describe('TestDirective', () => {
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`directive generator should handle path with file extension 1`] = `
|
||||
"import { Directive } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[test]',
|
||||
})
|
||||
export class TestDirective {
|
||||
constructor() {}
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`directive generator should handle path with file extension 2`] = `
|
||||
"import { TestDirective } from './test.directive';
|
||||
|
||||
describe('TestDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
const directive = new TestDirective();
|
||||
expect(directive).toBeTruthy();
|
||||
});
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
@ -35,6 +35,20 @@ describe('directive generator', () => {
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
await generateDirectiveWithDefaultOptions(tree, {
|
||||
path: 'test/src/app/test.directive.ts',
|
||||
skipFormat: false,
|
||||
});
|
||||
|
||||
expect(
|
||||
tree.read('test/src/app/test.directive.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
tree.read('test/src/app/test.directive.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not import the directive into an existing module', async () => {
|
||||
// ARRANGE
|
||||
addModule(tree);
|
||||
|
||||
@ -20,6 +20,8 @@ export async function normalizeOptions(
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
suffix: 'directive',
|
||||
allowedFileExtensions: ['ts'],
|
||||
fileExtension: 'ts',
|
||||
});
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
@ -9,6 +9,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a directive with the exported symbol matching the file name. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:directive mylib/src/lib/foo.directive.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a directive without providing the file extension. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:directive mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -19,7 +23,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the directive without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the directive. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
|
||||
@ -154,3 +154,29 @@ describe('TestPipe', () => {
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`pipe generator should handle path with file extension 1`] = `
|
||||
"import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'test',
|
||||
})
|
||||
export class TestPipe implements PipeTransform {
|
||||
transform(value: unknown, ...args: unknown[]): unknown {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`pipe generator should handle path with file extension 2`] = `
|
||||
"import { TestPipe } from './test.pipe';
|
||||
|
||||
describe('TestPipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new TestPipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
@ -18,6 +18,8 @@ export async function normalizeOptions(
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
suffix: 'pipe',
|
||||
allowedFileExtensions: ['ts'],
|
||||
fileExtension: 'ts',
|
||||
});
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
@ -27,6 +27,18 @@ describe('pipe generator', () => {
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
await generatePipeWithDefaultOptions(tree, {
|
||||
path: 'test/src/app/test.pipe.ts',
|
||||
skipFormat: false,
|
||||
});
|
||||
|
||||
expect(tree.read('test/src/app/test.pipe.ts', 'utf-8')).toMatchSnapshot();
|
||||
expect(
|
||||
tree.read('test/src/app/test.pipe.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not import the pipe into an existing module', async () => {
|
||||
// ARRANGE
|
||||
addModule(tree);
|
||||
|
||||
@ -9,6 +9,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a pipe with the exported symbol matching the file name. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:pipe mylib/src/lib/foo.pipe.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:pipe mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -19,7 +23,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the pipe without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the pipe. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
|
||||
@ -18,6 +18,8 @@ export async function normalizeOptions(
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
suffix: 'directive',
|
||||
allowedFileExtensions: ['ts'],
|
||||
fileExtension: 'ts',
|
||||
});
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
@ -84,6 +84,47 @@ describe('SCAM Directive Generator', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
projectType: 'application',
|
||||
sourceRoot: 'apps/app1/src',
|
||||
root: 'apps/app1',
|
||||
});
|
||||
|
||||
await scamDirectiveGenerator(tree, {
|
||||
name: 'example',
|
||||
path: 'apps/app1/src/app/example.directive.ts',
|
||||
inlineScam: true,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const directiveSource = tree.read(
|
||||
'apps/app1/src/app/example.directive.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(directiveSource).toMatchInlineSnapshot(`
|
||||
"import { Directive, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Directive({
|
||||
selector: '[example]',
|
||||
standalone: false
|
||||
})
|
||||
export class ExampleDirective {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [ExampleDirective],
|
||||
exports: [ExampleDirective],
|
||||
})
|
||||
export class ExampleDirectiveModule {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create the scam directive correctly and export it for a secondary entrypoint', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
|
||||
@ -7,6 +7,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a directive with the exported symbol matching the file name. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:scam-directive mylib/src/lib/foo.directive.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a directive without providing the file extension. It results in the directive `FooDirective` at `mylib/src/lib/foo.directive.ts`",
|
||||
"command": "nx g @nx/angular:scam-directive mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -19,7 +23,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the SCAM directive without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the SCAM directive. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
|
||||
@ -18,6 +18,8 @@ export async function normalizeOptions(
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
suffix: 'pipe',
|
||||
allowedFileExtensions: ['ts'],
|
||||
fileExtension: 'ts',
|
||||
});
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
@ -86,6 +86,49 @@ describe('SCAM Pipe Generator', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
projectType: 'application',
|
||||
sourceRoot: 'apps/app1/src',
|
||||
root: 'apps/app1',
|
||||
});
|
||||
|
||||
await scamPipeGenerator(tree, {
|
||||
name: 'example',
|
||||
path: 'apps/app1/src/app/example/example.pipe.ts',
|
||||
inlineScam: true,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const pipeSource = tree.read(
|
||||
'apps/app1/src/app/example/example.pipe.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(pipeSource).toMatchInlineSnapshot(`
|
||||
"import { Pipe, PipeTransform, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Pipe({
|
||||
name: 'example',
|
||||
standalone: false
|
||||
})
|
||||
export class ExamplePipe implements PipeTransform {
|
||||
transform(value: unknown, ...args: unknown[]): unknown {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [ExamplePipe],
|
||||
exports: [ExamplePipe],
|
||||
})
|
||||
export class ExamplePipeModule {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create the scam pipe correctly and export it for a secondary entrypoint', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
|
||||
@ -7,6 +7,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a pipe with the exported symbol matching the file name. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:scam-pipe mylib/src/lib/foo.pipe.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
|
||||
"command": "nx g @nx/angular:scam-pipe mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -19,7 +23,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the SCAM pipe without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the SCAM pipe. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
|
||||
@ -19,6 +19,8 @@ export async function normalizeOptions(
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
suffix: options.type ?? 'component',
|
||||
allowedFileExtensions: ['ts'],
|
||||
fileExtension: 'ts',
|
||||
});
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
@ -84,6 +84,47 @@ describe('SCAM Generator', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
projectType: 'application',
|
||||
sourceRoot: 'apps/app1/src',
|
||||
root: 'apps/app1',
|
||||
});
|
||||
|
||||
await scamGenerator(tree, {
|
||||
name: 'example',
|
||||
path: 'apps/app1/src/app/example/example.component.ts',
|
||||
inlineScam: true,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const componentSource = tree.read(
|
||||
'apps/app1/src/app/example/example.component.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
standalone: false,
|
||||
templateUrl: './example.component.html',
|
||||
styleUrl: './example.component.css'
|
||||
})
|
||||
export class ExampleComponent {}
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [ExampleComponent],
|
||||
exports: [ExampleComponent],
|
||||
})
|
||||
export class ExampleComponentModule {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create the scam correctly and export it for a secondary entrypoint', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
|
||||
@ -7,6 +7,10 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a component with the exported symbol matching the file name. It results in the component `FooComponent` at `mylib/src/lib/foo.component.ts`",
|
||||
"command": "nx g @nx/angular:scam mylib/src/lib/foo.component.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component without providing the file extension. It results in the component `FooComponent` at `mylib/src/lib/foo.component.ts`",
|
||||
"command": "nx g @nx/angular:scam mylib/src/lib/foo"
|
||||
},
|
||||
{
|
||||
@ -19,7 +23,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the SCAM without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the SCAM. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
|
||||
@ -26,7 +26,7 @@ describe('determineArtifactNameAndDirectoryOptions', () => {
|
||||
originalInitCwd = process.env.INIT_CWD;
|
||||
});
|
||||
|
||||
it('should throw an error when the resolver directory is not under any project root', async () => {
|
||||
it('should throw an error when the resolved directory is not under any project root', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
@ -44,7 +44,31 @@ describe('determineArtifactNameAndDirectoryOptions', () => {
|
||||
restoreCwd();
|
||||
});
|
||||
|
||||
it('should return options as provided when there is a project at the cwd', async () => {
|
||||
it('should return the normalized options when there is a project at the cwd', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
setCwd('apps/app1');
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'myComponent',
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
fileExtension: 'ts',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
|
||||
restoreCwd();
|
||||
});
|
||||
|
||||
it('should not duplicate the cwd when the provided directory starts with the cwd', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
@ -60,53 +84,14 @@ describe('determineArtifactNameAndDirectoryOptions', () => {
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
fileExtension: 'ts',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
|
||||
restoreCwd();
|
||||
});
|
||||
|
||||
it('should not duplicate the cwd when the provided directory starts with the cwd and format is "as-provided"', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
setCwd('apps/app1');
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent',
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
project: 'app1',
|
||||
});
|
||||
|
||||
restoreCwd();
|
||||
});
|
||||
|
||||
it('should return the options as provided when directory is provided', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent',
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
|
||||
it(`should handle window's style paths correctly`, async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
@ -122,25 +107,8 @@ describe('determineArtifactNameAndDirectoryOptions', () => {
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should support receiving a path as the name', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/foo/bar/myComponent',
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1/foo/bar',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/foo/bar/myComponent.ts',
|
||||
fileExtension: 'ts',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
@ -161,26 +129,51 @@ describe('determineArtifactNameAndDirectoryOptions', () => {
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent.component',
|
||||
filePath: 'apps/app1/myComponent.component.ts',
|
||||
fileExtension: 'ts',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should support receiving a fileName', async () => {
|
||||
it('should support receiving the full file path including the file extension', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
fileName: 'myComponent.component',
|
||||
path: 'apps/app1/myComponent',
|
||||
path: 'apps/app1/myComponent.ts',
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent.component',
|
||||
filePath: 'apps/app1/myComponent.component.ts',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
fileExtension: 'ts',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore specified suffix when receiving the full file path including the file extension', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent.ts',
|
||||
suffix: 'component',
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.ts',
|
||||
fileExtension: 'ts',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
@ -201,7 +194,97 @@ describe('determineArtifactNameAndDirectoryOptions', () => {
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.tsx',
|
||||
fileExtension: 'tsx',
|
||||
fileExtensionType: 'ts',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should support receiving a file path with a non-default file extension', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
const result = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent.astro',
|
||||
allowedFileExtensions: ['astro'],
|
||||
});
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
artifactName: 'myComponent',
|
||||
directory: 'apps/app1',
|
||||
fileName: 'myComponent',
|
||||
filePath: 'apps/app1/myComponent.astro',
|
||||
fileExtension: 'astro',
|
||||
fileExtensionType: 'other',
|
||||
project: 'app1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error when the file extension is not supported', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
await expect(
|
||||
determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent.ts',
|
||||
allowedFileExtensions: ['jsx', 'tsx'],
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||
"The provided file path has an extension (.ts) that is not supported by this generator.
|
||||
The supported extensions are: .jsx, .tsx."
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw an error when having a TypeScript file extension and the --js option is used', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
await expect(
|
||||
determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent.tsx',
|
||||
js: true,
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"The provided file path has an extension (.tsx) that conflicts with the provided "--js" option."`
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error when having a JavaScript file extension and the --js=false option is used', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
await expect(
|
||||
determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent.jsx',
|
||||
js: false,
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"The provided file path has an extension (.jsx) that conflicts with the provided "--js" option."`
|
||||
);
|
||||
});
|
||||
|
||||
it('should support customizing the --js option name', async () => {
|
||||
addProjectConfiguration(tree, 'app1', {
|
||||
root: 'apps/app1',
|
||||
projectType: 'application',
|
||||
});
|
||||
|
||||
await expect(
|
||||
determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: 'apps/app1/myComponent.tsx',
|
||||
js: true,
|
||||
jsOptionName: 'language',
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"The provided file path has an extension (.tsx) that conflicts with the provided "--language" option."`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -12,14 +12,32 @@ import {
|
||||
} from 'nx/src/devkit-internals';
|
||||
import { join, relative } from 'path';
|
||||
|
||||
const DEFAULT_ALLOWED_JS_FILE_EXTENSIONS = ['js', 'cjs', 'mjs', 'jsx'];
|
||||
const DEFAULT_ALLOWED_TS_FILE_EXTENSIONS = ['ts', 'cts', 'mts', 'tsx'];
|
||||
const DEFAULT_ALLOWED_FILE_EXTENSIONS = [
|
||||
...DEFAULT_ALLOWED_JS_FILE_EXTENSIONS,
|
||||
...DEFAULT_ALLOWED_TS_FILE_EXTENSIONS,
|
||||
'vue',
|
||||
];
|
||||
|
||||
export type ArtifactGenerationOptions = {
|
||||
path: string;
|
||||
name?: string;
|
||||
fileExtension?: 'js' | 'jsx' | 'ts' | 'tsx' | 'vue';
|
||||
fileName?: string;
|
||||
fileExtension?: string;
|
||||
suffix?: string;
|
||||
allowedFileExtensions?: string[];
|
||||
|
||||
/**
|
||||
* @deprecated Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21.
|
||||
*/
|
||||
js?: boolean;
|
||||
/**
|
||||
* @deprecated Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21.
|
||||
*/
|
||||
jsOptionName?: string;
|
||||
};
|
||||
|
||||
export type FileExtensionType = 'js' | 'ts' | 'other';
|
||||
export type NameAndDirectoryOptions = {
|
||||
/**
|
||||
* Normalized artifact name.
|
||||
@ -33,6 +51,14 @@ export type NameAndDirectoryOptions = {
|
||||
* Normalized file name of the artifact without the extension.
|
||||
*/
|
||||
fileName: string;
|
||||
/**
|
||||
* Normalized file extension.
|
||||
*/
|
||||
fileExtension: string;
|
||||
/**
|
||||
* Normalized file extension type.
|
||||
*/
|
||||
fileExtensionType: FileExtensionType;
|
||||
/**
|
||||
* Normalized full file path of the artifact.
|
||||
*/
|
||||
@ -60,11 +86,10 @@ export async function determineArtifactNameAndDirectoryOptions(
|
||||
function getNameAndDirectoryOptions(
|
||||
tree: Tree,
|
||||
options: ArtifactGenerationOptions
|
||||
) {
|
||||
): NameAndDirectoryOptions {
|
||||
const path = options.path
|
||||
? normalizePath(options.path.replace(/^\.?\//, ''))
|
||||
: undefined;
|
||||
const fileExtension = options.fileExtension ?? 'ts';
|
||||
let { name: extractedName, directory } =
|
||||
extractNameAndDirectoryFromPath(path);
|
||||
const relativeCwd = getRelativeCwd();
|
||||
@ -75,17 +100,43 @@ function getNameAndDirectoryOptions(
|
||||
}
|
||||
|
||||
const project = findProjectFromPath(tree, directory);
|
||||
const name =
|
||||
options.fileName ??
|
||||
(options.suffix ? `${extractedName}.${options.suffix}` : extractedName);
|
||||
const filePath = joinPathFragments(directory, `${name}.${fileExtension}`);
|
||||
|
||||
let fileName = extractedName;
|
||||
let fileExtension: string = options.fileExtension ?? 'ts';
|
||||
|
||||
const allowedFileExtensions =
|
||||
options.allowedFileExtensions ?? DEFAULT_ALLOWED_FILE_EXTENSIONS;
|
||||
const fileExtensionRegex = new RegExp(
|
||||
`\\.(${allowedFileExtensions.join('|')})$`
|
||||
);
|
||||
const fileExtensionMatch = fileName.match(fileExtensionRegex);
|
||||
|
||||
if (fileExtensionMatch) {
|
||||
fileExtension = fileExtensionMatch[1];
|
||||
fileName = fileName.replace(fileExtensionRegex, '');
|
||||
extractedName = fileName;
|
||||
} else if (options.suffix) {
|
||||
fileName = `${fileName}.${options.suffix}`;
|
||||
}
|
||||
|
||||
const filePath = joinPathFragments(directory, `${fileName}.${fileExtension}`);
|
||||
const fileExtensionType = getFileExtensionType(fileExtension);
|
||||
|
||||
validateFileExtension(
|
||||
fileExtension,
|
||||
allowedFileExtensions,
|
||||
options.js,
|
||||
options.jsOptionName
|
||||
);
|
||||
|
||||
return {
|
||||
artifactName: options.name ?? extractedName,
|
||||
directory: directory,
|
||||
fileName: name,
|
||||
filePath: filePath,
|
||||
project: project,
|
||||
directory,
|
||||
fileName,
|
||||
fileExtension,
|
||||
fileExtensionType,
|
||||
filePath,
|
||||
project,
|
||||
};
|
||||
}
|
||||
|
||||
@ -145,3 +196,50 @@ function extractNameAndDirectoryFromPath(path: string): {
|
||||
|
||||
return { name, directory };
|
||||
}
|
||||
|
||||
function getFileExtensionType(fileExtension: string): FileExtensionType {
|
||||
if (DEFAULT_ALLOWED_JS_FILE_EXTENSIONS.includes(fileExtension)) {
|
||||
return 'js';
|
||||
}
|
||||
|
||||
if (DEFAULT_ALLOWED_TS_FILE_EXTENSIONS.includes(fileExtension)) {
|
||||
return 'ts';
|
||||
}
|
||||
|
||||
return 'other';
|
||||
}
|
||||
|
||||
function validateFileExtension(
|
||||
fileExtension: string,
|
||||
allowedFileExtensions: string[],
|
||||
js: boolean | undefined,
|
||||
jsOptionName: string | undefined
|
||||
): FileExtensionType {
|
||||
const fileExtensionType = getFileExtensionType(fileExtension);
|
||||
|
||||
if (!allowedFileExtensions.includes(fileExtension)) {
|
||||
throw new Error(
|
||||
`The provided file path has an extension (.${fileExtension}) that is not supported by this generator.
|
||||
The supported extensions are: ${allowedFileExtensions
|
||||
.map((ext) => `.${ext}`)
|
||||
.join(', ')}.`
|
||||
);
|
||||
}
|
||||
|
||||
if (js !== undefined) {
|
||||
jsOptionName = jsOptionName ?? 'js';
|
||||
|
||||
if (js && fileExtensionType === 'ts') {
|
||||
throw new Error(
|
||||
`The provided file path has an extension (.${fileExtension}) that conflicts with the provided "--${jsOptionName}" option.`
|
||||
);
|
||||
}
|
||||
if (!js && fileExtensionType === 'js') {
|
||||
throw new Error(
|
||||
`The provided file path has an extension (.${fileExtension}) that conflicts with the provided "--${jsOptionName}" option.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return fileExtensionType;
|
||||
}
|
||||
|
||||
@ -59,6 +59,16 @@ describe('component', () => {
|
||||
expect(appTree.exists('my-lib/src/lib/hello/hello.spec.tsx')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
await expoComponentGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
path: 'my-lib/src/lib/hello/hello.tsx',
|
||||
});
|
||||
|
||||
expect(appTree.exists('my-lib/src/lib/hello/hello.tsx')).toBeTruthy();
|
||||
expect(appTree.exists('my-lib/src/lib/hello/hello.spec.tsx')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should generate files for an app', async () => {
|
||||
await expoComponentGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
generateFiles,
|
||||
getProjects,
|
||||
joinPathFragments,
|
||||
toJS,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
||||
@ -25,25 +24,23 @@ export async function expoComponentGenerator(host: Tree, schema: Schema) {
|
||||
}
|
||||
|
||||
function createComponentFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(host, join(__dirname, './files'), options.directory, {
|
||||
...options,
|
||||
tmpl: '',
|
||||
});
|
||||
|
||||
for (const c of host.listChanges()) {
|
||||
let deleteFile = false;
|
||||
|
||||
if (options.skipTests && /.*spec.tsx/.test(c.path)) {
|
||||
deleteFile = true;
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, './files', options.fileExtensionType),
|
||||
options.directory,
|
||||
{
|
||||
...options,
|
||||
ext: options.fileExtension,
|
||||
}
|
||||
);
|
||||
|
||||
if (deleteFile) {
|
||||
host.delete(c.path);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.js) {
|
||||
toJS(host);
|
||||
if (options.skipTests) {
|
||||
host.delete(
|
||||
joinPathFragments(
|
||||
options.directory,
|
||||
`${options.fileName}.spec.${options.fileExtension}`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,26 +52,29 @@ function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
|
||||
if (options.export && !isApp) {
|
||||
const indexFilePath = joinPathFragments(
|
||||
options.projectSourceRoot,
|
||||
options.js ? 'index.js' : 'index.ts'
|
||||
options.fileExtensionType === 'js' ? 'index.js' : 'index.ts'
|
||||
);
|
||||
const indexSource = host.read(indexFilePath, 'utf-8');
|
||||
if (indexSource !== null) {
|
||||
const indexSourceFile = ts.createSourceFile(
|
||||
indexFilePath,
|
||||
indexSource,
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
const relativePathFromIndex = getRelativeImportToFile(
|
||||
indexFilePath,
|
||||
options.filePath
|
||||
);
|
||||
const changes = applyChangesToString(
|
||||
indexSource,
|
||||
addImport(indexSourceFile, `export * from '${relativePathFromIndex}';`)
|
||||
);
|
||||
host.write(indexFilePath, changes);
|
||||
|
||||
if (!host.exists(indexFilePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const indexSource = host.read(indexFilePath, 'utf-8');
|
||||
const indexSourceFile = ts.createSourceFile(
|
||||
indexFilePath,
|
||||
indexSource,
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
const relativePathFromIndex = getRelativeImportToFile(
|
||||
indexFilePath,
|
||||
options.filePath
|
||||
);
|
||||
const changes = applyChangesToString(
|
||||
indexSource,
|
||||
addImport(indexSourceFile, `export * from '${relativePathFromIndex}';`)
|
||||
);
|
||||
host.write(indexFilePath, changes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
<%_ if (classComponent) { _%>
|
||||
import { Component } from 'react';
|
||||
<%_ } else { _%>
|
||||
import React from 'react';
|
||||
<%_ } _%>
|
||||
import { View, Text } from 'react-native';
|
||||
|
||||
<%_ if (classComponent) { _%>
|
||||
export class <%= className %> extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text>Welcome to <%= name %>!</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
<%_ } else { _%>
|
||||
export function <%= className %>(props) {
|
||||
return (
|
||||
<View>
|
||||
<Text>Welcome to <%= name %>!</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
<%_ } _%>
|
||||
|
||||
export default <%= className %>;
|
||||
@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react-native';
|
||||
import <%= className %> from './<%= fileName %>';
|
||||
|
||||
describe('<%= className %>', () => {
|
||||
it('should render successfully', () => {
|
||||
const { root } = render(< <%= className %> />);
|
||||
expect(root).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -1,15 +1,15 @@
|
||||
<% if (classComponent) { %>
|
||||
<%_ if (classComponent) { _%>
|
||||
import { Component } from 'react';
|
||||
<% } else { %>
|
||||
<%_ } else { _%>
|
||||
import React from 'react';
|
||||
<% } %>
|
||||
<%_ } _%>
|
||||
import { View, Text } from 'react-native';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface <%= className %>Props {
|
||||
}
|
||||
|
||||
<% if (classComponent) { %>
|
||||
<%_ if (classComponent) { _%>
|
||||
export class <%= className %> extends Component<<%= className %>Props> {
|
||||
render() {
|
||||
return (
|
||||
@ -19,7 +19,7 @@ export class <%= className %> extends Component<<%= className %>Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
<% } else { %>
|
||||
<%_ } else { _%>
|
||||
export function <%= className %>(props: <%= className %>Props) {
|
||||
return (
|
||||
<View>
|
||||
@ -27,6 +27,6 @@ export function <%= className %>(props: <%= className %>Props) {
|
||||
</View>
|
||||
);
|
||||
}
|
||||
<% } %>
|
||||
<%_ } _%>
|
||||
|
||||
export default <%= className %>;
|
||||
@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react-native';
|
||||
import <%= className %> from './<%= fileName %>';
|
||||
|
||||
describe('<%= className %>', () => {
|
||||
it('should render successfully', () => {
|
||||
const { root } = render(< <%= className %> />);
|
||||
expect(root).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -1,11 +1,16 @@
|
||||
import { getProjects, logger, names, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineArtifactNameAndDirectoryOptions,
|
||||
type FileExtensionType,
|
||||
} from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema extends Omit<Schema, 'js'> {
|
||||
directory: string;
|
||||
projectSourceRoot: string;
|
||||
fileName: string;
|
||||
fileExtension: string;
|
||||
fileExtensionType: FileExtensionType;
|
||||
className: string;
|
||||
filePath: string;
|
||||
projectName: string;
|
||||
@ -18,19 +23,21 @@ export async function normalizeOptions(
|
||||
const {
|
||||
artifactName: name,
|
||||
fileName,
|
||||
fileExtension,
|
||||
fileExtensionType,
|
||||
filePath,
|
||||
directory,
|
||||
project: projectName,
|
||||
} = await determineArtifactNameAndDirectoryOptions(host, {
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
fileExtension: 'tsx',
|
||||
allowedFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
|
||||
fileExtension: options.js ? 'js' : 'tsx',
|
||||
js: options.js,
|
||||
});
|
||||
|
||||
const project = getProjects(host).get(projectName);
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
const project = getProjects(host).get(projectName);
|
||||
const { sourceRoot: projectSourceRoot, projectType } = project;
|
||||
|
||||
if (options.export && projectType === 'application') {
|
||||
@ -47,6 +54,8 @@ export async function normalizeOptions(
|
||||
directory,
|
||||
className,
|
||||
fileName,
|
||||
fileExtension,
|
||||
fileExtensionType,
|
||||
filePath,
|
||||
projectSourceRoot,
|
||||
projectName,
|
||||
|
||||
@ -4,9 +4,13 @@
|
||||
export interface Schema {
|
||||
path: string;
|
||||
name?: string;
|
||||
skipFormat: boolean; // default is false
|
||||
skipTests: boolean; // default is false
|
||||
export: boolean; // default is false
|
||||
classComponent: boolean; // default is false
|
||||
js: boolean; // default is false
|
||||
skipFormat?: boolean;
|
||||
skipTests?: boolean;
|
||||
export?: boolean;
|
||||
classComponent?: boolean;
|
||||
|
||||
/**
|
||||
* @deprecated Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21.
|
||||
*/
|
||||
js?: boolean;
|
||||
}
|
||||
|
||||
@ -7,11 +7,15 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate a component with the exported symbol matching the file name. It results in the component `Foo` at `mylib/src/foo.tsx`",
|
||||
"command": "nx g @nx/expo:component mylib/src/foo"
|
||||
"command": "nx g @nx/expo:component mylib/src/foo.tsx"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component with the exported symbol different from the file name. It results in the component `Custom` at `mylib/src/foo.tsx`",
|
||||
"command": "nx g @nx/expo:component mylib/src/foo --name=custom"
|
||||
"command": "nx g @nx/expo:component mylib/src/foo.tsx --name=custom"
|
||||
},
|
||||
{
|
||||
"description": "Generate a component without the providing the file extension. It results in the component `Foo` at `mylib/src/foo.tsx`",
|
||||
"command": "nx g @nx/expo:component mylib/src/foo"
|
||||
},
|
||||
{
|
||||
"description": "Generate a class component at `mylib/src/foo.tsx`",
|
||||
@ -21,7 +25,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
@ -35,7 +39,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the class `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:class myapp/src/app/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the class without providing the file extension. It results in the class `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:class myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the class without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the class. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -31,7 +31,9 @@ async function normalizeControllerOptions(
|
||||
tree: Tree,
|
||||
options: ControllerGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'controller',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the controller `FooController` at `myapp/src/app/foo.controller.ts`",
|
||||
"command": "nx g @nx/nest:controller myapp/src/app/foo.controller.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the controller without providing the file extension. It results in the controller `FooController` at `myapp/src/app/foo.controller.ts`",
|
||||
"command": "nx g @nx/nest:controller myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the controller without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the controller. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -22,7 +22,9 @@ async function normalizeDecoratorOptions(
|
||||
tree: Tree,
|
||||
options: DecoratorGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'decorator',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the decorator `Foo` at `myapp/src/app/foo.decorator.ts`",
|
||||
"command": "nx g @nx/nest:decorator myapp/src/app/foo.decorator.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the decorator without providing the file extension. It results in the decorator `Foo` at `myapp/src/app/foo.decorator.ts`",
|
||||
"command": "nx g @nx/nest:decorator myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the decorator without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the decorator. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeFilterOptions(
|
||||
tree: Tree,
|
||||
options: FilterGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'filter',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the filter `FooFilter` at `myapp/src/app/foo.filter.ts`",
|
||||
"command": "nx g @nx/nest:filter myapp/src/app/foo.filter.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the filter without providing the file extension. It results in the filter `FooFilter` at `myapp/src/app/foo.filter.ts`",
|
||||
"command": "nx g @nx/nest:filter myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the filter without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the filter. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeGatewayOptions(
|
||||
tree: Tree,
|
||||
options: GatewayGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'gateway',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the gateway `FooGateway` at `myapp/src/app/foo.gateway.ts`",
|
||||
"command": "nx g @nx/nest:gateway myapp/src/app/foo.gateway.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the gateway without providing the file extension. It results in the gateway `FooGateway` at `myapp/src/app/foo.gateway.ts`",
|
||||
"command": "nx g @nx/nest:gateway myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the gateway without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the gateway. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeGuardOptions(
|
||||
tree: Tree,
|
||||
options: GuardGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'guard',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the guard `FooGuard` at `myapp/src/app/foo.guard.ts`",
|
||||
"command": "nx g @nx/nest:guard myapp/src/app/foo.guard.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the guard without providing the file extension. It results in the guard `FooGuard` at `myapp/src/app/foo.guard.ts`",
|
||||
"command": "nx g @nx/nest:guard myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the guard without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the guard. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeInterceptorOptions(
|
||||
tree: Tree,
|
||||
options: InterceptorGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'interceptor',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the interceptor `FooInterceptor` at `myapp/src/app/foo.interceptor.ts`",
|
||||
"command": "nx g @nx/nest:interceptor myapp/src/app/foo.interceptor.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the interceptor without providing the file extension. It results in the interceptor `FooInterceptor` at `myapp/src/app/foo.interceptor.ts`",
|
||||
"command": "nx g @nx/nest:interceptor myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the interceptor without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the interceptor. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -8,7 +8,11 @@ export async function interfaceGenerator(
|
||||
tree: Tree,
|
||||
rawOptions: InterfaceGeneratorOptions
|
||||
): Promise<any> {
|
||||
const options = await normalizeOptions(tree, rawOptions);
|
||||
const options = await normalizeOptions(tree, rawOptions, {
|
||||
allowedFileExtensions: ['ts'],
|
||||
skipLanguageOption: true,
|
||||
suffix: 'interface',
|
||||
});
|
||||
|
||||
return runNestSchematic(tree, 'interface', options);
|
||||
}
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the interface `Foo` at `myapp/src/app/foo.interface.ts`",
|
||||
"command": "nx g @nx/nest:interface myapp/src/app/foo.interface.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the interface without providing the file extension. It results in the interface `Foo` at `myapp/src/app/foo.interface.ts`",
|
||||
"command": "nx g @nx/nest:interface myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the interface without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the interface. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeMiddlewareOptions(
|
||||
tree: Tree,
|
||||
options: MiddlewareGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'middleware',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the middleware `FooMiddleware` at `myapp/src/app/foo.middleware.ts`",
|
||||
"command": "nx g @nx/nest:middleware myapp/src/app/foo.middleware.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the middleware without providing the file extension. It results in the middleware `FooMiddleware` at `myapp/src/app/foo.middleware.ts`",
|
||||
"command": "nx g @nx/nest:middleware myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the middleware without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the middleware. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -25,7 +25,9 @@ async function normalizeModuleOptions(
|
||||
tree: Tree,
|
||||
options: ModuleGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOption = await normalizeOptions(tree, options);
|
||||
const normalizedOption = await normalizeOptions(tree, options, {
|
||||
suffix: 'module',
|
||||
});
|
||||
return {
|
||||
...normalizedOption,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the module `FooModule` at `myapp/src/app/foo.module.ts`",
|
||||
"command": "nx g @nx/nest:module myapp/src/app/foo.module.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the module without providing the file extension. It results in the module `FooModule` at `myapp/src/app/foo.module.ts`",
|
||||
"command": "nx g @nx/nest:module myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the module without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the module. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizePipeOptions(
|
||||
tree: Tree,
|
||||
options: PipeGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'pipe',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the pipe `FooPipe` at `myapp/src/app/foo.pipe.ts`",
|
||||
"command": "nx g @nx/nest:pipe myapp/src/app/foo.pipe.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the pipe without providing the file extension. It results in the pipe `FooPipe` at `myapp/src/app/foo.pipe.ts`",
|
||||
"command": "nx g @nx/nest:pipe myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the pipe without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the pipe. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the provider `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:provider myapp/src/app/foo.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the provider without providing the file extension. It results in the provider `Foo` at `myapp/src/app/foo.ts`",
|
||||
"command": "nx g @nx/nest:provider myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the provider without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the provider. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeResolverOptions(
|
||||
tree: Tree,
|
||||
options: ResolverGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'resolver',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the resolver `FooResolver` at `myapp/src/app/foo.resolver.ts`",
|
||||
"command": "nx g @nx/nest:resolver myapp/src/app/foo.resolver.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the resolver without providing the file extension. It results in the resolver `FooResolver` at `myapp/src/app/foo.resolver.ts`",
|
||||
"command": "nx g @nx/nest:resolver myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the resolver without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the resolver. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import type {
|
||||
NestGeneratorWithLanguageOption,
|
||||
NestGeneratorWithResourceOption,
|
||||
NestGeneratorWithTestOption,
|
||||
NormalizedOptions,
|
||||
@ -11,8 +10,7 @@ import {
|
||||
unitTestRunnerToSpec,
|
||||
} from '../utils';
|
||||
|
||||
export type ResourceGeneratorOptions = NestGeneratorWithLanguageOption &
|
||||
NestGeneratorWithTestOption &
|
||||
export type ResourceGeneratorOptions = NestGeneratorWithTestOption &
|
||||
NestGeneratorWithResourceOption;
|
||||
|
||||
export async function resourceGenerator(
|
||||
@ -30,10 +28,11 @@ async function normalizeResourceOptions(
|
||||
tree: Tree,
|
||||
options: ResourceGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
skipLanguageOption: true,
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
spec: unitTestRunnerToSpec(options.unitTestRunner),
|
||||
};
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the resource without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the resource. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
@ -33,11 +33,6 @@
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"language": {
|
||||
"description": "Nest class language.",
|
||||
"type": "string",
|
||||
"enum": ["js", "ts"]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "The transport layer.",
|
||||
|
||||
@ -8,12 +8,16 @@
|
||||
"examples": [
|
||||
{
|
||||
"description": "Generate the service `FooService` at `myapp/src/app/foo.service.ts`",
|
||||
"command": "nx g @nx/nest:service myapp/src/app/foo.service.ts"
|
||||
},
|
||||
{
|
||||
"description": "Generate the service without providing the file extension. It results in the service `FooService` at `myapp/src/app/foo.service.ts`",
|
||||
"command": "nx g @nx/nest:service myapp/src/app/foo"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The file path to the service without the file extension and suffix. Relative to the current working directory.",
|
||||
"description": "The file path to the service. Relative to the current working directory.",
|
||||
"type": "string",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
|
||||
@ -28,7 +28,9 @@ async function normalizeServiceOptions(
|
||||
tree: Tree,
|
||||
options: ServiceGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
const normalizedOptions = await normalizeOptions(tree, options);
|
||||
const normalizedOptions = await normalizeOptions(tree, options, {
|
||||
suffix: 'service',
|
||||
});
|
||||
return {
|
||||
...normalizedOptions,
|
||||
language: options.language,
|
||||
|
||||
@ -1,27 +1,53 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import type {
|
||||
NestGeneratorOptions,
|
||||
Language,
|
||||
NestGeneratorWithLanguageOption,
|
||||
NormalizedOptions,
|
||||
UnitTestRunner,
|
||||
} from './types';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
|
||||
export async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: NestGeneratorOptions
|
||||
options: NestGeneratorWithLanguageOption,
|
||||
normalizationOptions: {
|
||||
allowedFileExtensions?: Array<'js' | 'ts'>;
|
||||
skipLanguageOption?: boolean;
|
||||
suffix?: string;
|
||||
} = {}
|
||||
): Promise<NormalizedOptions> {
|
||||
const { directory, artifactName } =
|
||||
const {
|
||||
allowedFileExtensions = ['js', 'ts'],
|
||||
skipLanguageOption = false,
|
||||
suffix,
|
||||
} = normalizationOptions;
|
||||
|
||||
const { directory, artifactName, fileExtension } =
|
||||
await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: options.path,
|
||||
allowedFileExtensions,
|
||||
fileExtension: options.language === 'js' ? 'js' : 'ts',
|
||||
js: options.language ? options.language === 'js' : undefined,
|
||||
jsOptionName: 'language',
|
||||
});
|
||||
|
||||
options.path = undefined; // Now that we have `directory` we don't need `path`
|
||||
|
||||
if (!skipLanguageOption) {
|
||||
// we assign the language based on the normalized file extension
|
||||
options.language = fileExtension as Language;
|
||||
}
|
||||
|
||||
let name = artifactName;
|
||||
if (suffix && artifactName.endsWith(`.${suffix}`)) {
|
||||
// strip the suffix if it exists, the nestjs schematic will always add it
|
||||
name = artifactName.replace(`.${suffix}`, '');
|
||||
}
|
||||
|
||||
return {
|
||||
...options,
|
||||
flat: true,
|
||||
name: artifactName,
|
||||
skipFormat: options.skipFormat,
|
||||
name,
|
||||
sourceRoot: directory,
|
||||
};
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
Generate a component named `MyComponent` at `apps/my-app/src/app/my-component/my-component.tsx`:
|
||||
|
||||
```shell
|
||||
nx g component apps/my-app/src/app/my-component/my-component
|
||||
nx g component apps/my-app/src/app/my-component/my-component.tsx
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
@ -15,7 +15,16 @@ nx g component apps/my-app/src/app/my-component/my-component
|
||||
Generate a component named `Custom` at `apps/my-app/src/app/my-component/my-component.tsx`:
|
||||
|
||||
```shell
|
||||
nx g component apps/my-app/src/app/my-component/my-component --name=custom
|
||||
nx g component apps/my-app/src/app/my-component/my-component.tsx --name=custom
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="Create a Component Omitting the File Extension" %}
|
||||
|
||||
Generate a component named `MyComponent` at `apps/my-app/src/app/my-component/my-component.tsx` without specifying the file extension:
|
||||
|
||||
```shell
|
||||
nx g component apps/my-app/src/app/my-component/my-component
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
|
||||
@ -40,6 +40,19 @@ describe('component', () => {
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should handle path with file extension', async () => {
|
||||
await componentGenerator(tree, {
|
||||
path: `${appName}/components/hello/hello.tsx`,
|
||||
style: 'css',
|
||||
});
|
||||
|
||||
expect(tree.exists('my-app/components/hello/hello.tsx')).toBeTruthy();
|
||||
expect(tree.exists('my-app/components/hello/hello.spec.tsx')).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('my-app/components/hello/hello.module.css')
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should generate component in default directory for library', async () => {
|
||||
await componentGenerator(tree, {
|
||||
name: 'hello',
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
import {
|
||||
formatFiles,
|
||||
getProjects,
|
||||
joinPathFragments,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import type { SupportedStyles } from '@nx/react';
|
||||
import { componentGenerator as reactComponentGenerator } from '@nx/react';
|
||||
|
||||
import { addStyleDependencies } from '../../utils/styles';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
|
||||
interface Schema {
|
||||
path: string;
|
||||
@ -24,19 +22,15 @@ interface Schema {
|
||||
* extra dependencies for css, sass, less style options.
|
||||
*/
|
||||
export async function componentGenerator(host: Tree, options: Schema) {
|
||||
const {
|
||||
artifactName: name,
|
||||
directory,
|
||||
project: projectName,
|
||||
} = await determineArtifactNameAndDirectoryOptions(host, {
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
fileExtension: 'tsx',
|
||||
});
|
||||
// we only need to provide the path to get the project, we let the react
|
||||
// generator handle the rest
|
||||
const { project: projectName } =
|
||||
await determineArtifactNameAndDirectoryOptions(host, {
|
||||
path: options.path,
|
||||
});
|
||||
|
||||
const componentInstall = await reactComponentGenerator(host, {
|
||||
...options,
|
||||
name,
|
||||
classComponent: false,
|
||||
routing: false,
|
||||
skipFormat: true,
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The file path to the component without the file extension. Relative to the current working directory.",
|
||||
"description": "The file path to the component. Relative to the current working directory.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
@ -75,7 +75,7 @@
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||
"default": false
|
||||
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user