我想为Angular创建一个自定义原理图,它将在与执行原理图相同的目录中创建一个文件。我关注了本文,但不确定如何将新文件添加到所需目录中。 (https://developer.okta.com/blog/2019/02/13/angular-schematics#create-your-first-schematic)
例如,如果我具有以下目录结构:
src/app/ !-- Angular Root
|- modules
|_ foo
|- foo.component.ts
|_ foo.component.html
|- app.component.ts
|- app.component.html
|_ app.module.ts
如果要这样做,请执行以下命令:
> cd /src/app/modules/foo
> ng g my-component:my-component
我希望新创建/更新的文件位于/ src / app / modules / foo目录而不是根目录中。想一想ng generate是如何工作的。如果我从目录/ src / app / modules / foo内部执行ng g component bar
,则将在该目录中生成一个新组件。这是我需要复制的行为。
这是我的工厂。现在,它显然是用project.root
定位到根目录,但是我找不到任何替代方法,如果不提供路径,则会出现错误。如何获取要存储在options.path
中的当前路径(src / app / modules / foo)?
export function setupOptions(host: Tree, options: any): Tree {
const workspace = getWorkspace(host);
if (!options.project) {
options.project = Object.keys(workspace.projects)[0];
}
const project = workspace.projects[options.project];
options.path = join(normalize(project.root), 'src');
return host;
}
// You don't have to export the function as default. You can also have more than one rule factory
// per file.
export function myComponent(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
setupOptions(tree, _options);
const movePath = normalize(_options.path + '/');
const templateSource = apply(url('./files/src'), [
template({ ..._options }),
move(movePath),
forEach((fileEntry: FileEntry) => {
if (tree.exists(fileEntry.path)) {
tree.overwrite(fileEntry.path, fileEntry.content);
}
return fileEntry;
})
]);
const rule = mergeWith(templateSource, MergeStrategy.Overwrite);
return rule(tree, _context);
};
}
答案 0 :(得分:0)
将此添加到您的schema.json
{
...,
"properties": {
..
"path": {
"type": "string",
"format": "path",
"description": "The path to create the simple schematic within.",
"visible": false
}
答案 1 :(得分:0)
您会遇到一些问题。例如
1)constworkspaceConfig = tree.read('/ angular.json');
//在使用'schematics'命令时将为null,但在使用'ng g'逗号时将起作用。
2)同样,当使用“ schematics”命令时,“ options.path”将是未定义的,但在使用“ ng g”命令时,将可使用。
以上答复是正确的,您需要将路径添加到schema.json文件,然后在函数中
'导出函数myComponent(_options:any):规则{'
您应该可以使用“ options.path”获取当前位置。但是,正如我提到的那样,在使用“示意图”命令时我无法使其正常工作。我只能在使用'ng g'命令时使其工作。
例如,这是我的文件
1)..schematics / ng-generate / customComponent / schema.json
{
"$schema": "http://json-schema.org/schema",
"id": "GenerateCustomComponent",
"title": "Generate Custom Component",
"type": "object",
"properties": {
"name": {
"description": "The name for the custom component.",
"type": "string",
"x-prompt": "What is the name for the custom component?"
},
"path": {
"type": "string",
"format": "path",
"description": "The path at which to create the component file, relative to the current workspace. Default is a folder with the same name as the component in the project root.",
"visible": false
}
},
"required": [
"name"
]
}
2)..schematics / ng-generate / customComponent / schema.ts
import { Schema as ComponentSChema } from '@schematics/angular/component/schema';
export interface Schema extends ComponentSChema {
// The name of the custom component
name: string;
}
2)..schematics / ng-generate / customComponent / index.ts
import {
Rule, Tree, SchematicsException,
apply, url, applyTemplates, move,
chain, mergeWith
} from '@angular-devkit/schematics';
import { strings, experimental, normalize } from '@angular-devkit/core';
import { Schema as CustomSchema } from './schema';
export function generate(options: CustomSchema): Rule {
return (tree: Tree) => {
const workspaceConfig = tree.read('/angular.json'); // will return null when using schematics command but will work when using ng g
console.log('workspaceConfig::', workspaceConfig);
console.log('path:', options.path); // will be undefined when using schematics command but will work when using ng g
// from now following along with angular docs with slight modifications.
if (workspaceConfig && !options.path) {
const workspaceContent = workspaceConfig.toString();
console.log('workspaceContent::', workspaceContent);
const workspace: experimental.workspace.WorkspaceSchema = JSON.parse(workspaceContent);
console.log('workspace', workspace);
options.project = workspace.defaultProject;
const projectName = options.project as string;
const project = workspace.projects[projectName];
const projectType = project.projectType === 'application' ? 'app' : 'lib';
console.log('projectType::', projectType);
options.path = `${project.sourceRoot}/${projectType}`;
}
if (options.path) {
// this will be used by the ng g command
const templateSource = apply(url('./files'), [
applyTemplates({
classify: strings.classify,
dasherize: strings.dasherize,
name: options.name
}),
move(normalize(options.path as string))
]);
return chain([
mergeWith(templateSource)
]);
} else {
// this will be used by the schematics command
const templateSource = apply(url('./files'), [
applyTemplates({
classify: strings.classify,
dasherize: strings.dasherize,
name: options.name
})
]);
return chain([
mergeWith(templateSource)
]);
}
};
}
答案 2 :(得分:0)
有些让我感到困惑并需要提防的事情。
在角度项目的根目录中执行逻辑示意图命令时,'options.path'将是未定义的。只有将目录更改为根目录的子目录,该路径才可用。
答案 3 :(得分:0)
可能这是一个丑陋的解决方案,但我发现它的唯一方法。
你必须改变树的根目录才能访问当前目录的父目录
const currentPath = (tree as any)['_backend']['_root'] ;
(tree as any)['_backend']['_root'] = '/' ;
const currentDir = tree.getDir(currentPath);
const parent = currentDir.parent ;
知道你可以访问父目录并且可以编写自己的函数来改变一切
查看示例
const rootModelDirectory = 'model-form-request'
export function model(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
const currentPath = (tree as any)['_backend']['_root'] ;
(tree as any)['_backend']['_root'] = '/' ;
console.log(currentPath);
const rootdir = findParentDirectoryPath(tree.getDir(currentPath) , rootModelDirectory);
const templateSource = apply(url('./files'), [
// filter(path => path.endsWith('__name@dasherize__.module.ts.template')),
template({
...strings,
..._options
}),
move(normalize(`/${rootdir}/${dasherize(_options.name)}/`))
]);
return mergeWith(templateSource);
};
}
export function findParentDirectoryPath(location :ReturnType<Tree['getDir']>, directoryName : string): string {
for(const dirPath of location.subdirs){
if(new RegExp(directoryName).test(dirPath)){
return `${location.path}/${dirPath}` ;
}
}
if(location.parent){
return findParentDirectoryPath(location.parent , directoryName);
}
throw new Error('root model directory not found')
}