角示意图相对路径

时间:2019-04-15 23:49:12

标签: angular angular-cli angular-schematics

我想为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);
  };
}

4 个答案:

答案 0 :(得分:0)

将此添加到您的schema.json

{
 ...,
 "properties": {
  ..
  "path": {
   "type": "string",
   "format": "path",
   "description": "The path to create the simple schematic within.",
   "visible": false
  }

答案 1 :(得分:0)

遵循angular docs

中提到的步骤

您会遇到一些问题。例如

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')

}