【问题标题】:Angular Schematics relative pathAngular Schematics 相对路径
【发布时间】:2019-09-05 23:54:36
【问题描述】:

我想为 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 定位根目录但是我没有找到任何替代方案,如果我不提供路径,那么我会收到错误消息。如何获取当前路径(src/app/modules/foo)以存储在options.path

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);
  };
}

【问题讨论】:

  • 这应该默认使用ng cli。你能发布你的工厂吗?
  • 我在上面加了工厂。

标签: angular angular-cli angular-schematics


【解决方案1】:

可能这是一个丑陋的解决方案,但我找到它的唯一方法。

你必须改变树的根目录才能访问当前目录的父目录

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

}

【讨论】:

    【解决方案2】:

    有些事情让我困惑了一段时间,需要提防。

    'options.path' 在角度项目的根目录中执行原理图命令时将未定义。只有将目录更改为根目录的子目录,路径才可用。

    【讨论】:

      【解决方案3】:

      按照angular docs中提到的步骤进行

      你会遇到一些问题。例如

      1) const workspaceConfig = tree.read('/angular.json');

      // 使用 'schematics' 命令时将为空,但使用 'ng g' 命令时会起作用。

      2) 同样,在使用“schematics”命令时,“options.path”将是未定义的,但在使用“ng g”命令时会起作用。

      上面的回复是正确的,你需要添加schema.json文件的路径,然后在你的函数中

      '导出函数myComponent(_options: any): Rule {'

      您应该能够使用“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)
                  ]);
              }
          };
      }

      【讨论】:

        【解决方案4】:

        将此添加到您的 schema.json

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

        【讨论】:

          猜你喜欢
          • 2016-10-10
          • 2020-01-18
          • 2018-12-15
          • 2016-07-17
          • 2017-05-18
          • 2017-02-19
          • 2019-06-21
          • 2012-01-11
          相关资源
          最近更新 更多