15

我想写一个Rule每次都覆盖一个文件。在下面并已MergeStrategy设置为Overwrite

collection.json

{
  "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
  "schematics": {
    "function": {
      "aliases": [ "fn" ],
      "factory": "./function",
      "description": "Create a function.",
      "schema": "./function/schema.json"
    }
  }
}

function/index.ts

export default function(options: FunctionOptions): Rule {
  options.path = options.path ? normalize(options.path) : options.path;
  const sourceDir = options.sourceDir;
  if (!sourceDir) {
    throw new SchematicsException(`sourceDir option is required.`);
  }

  const templateSource: Source = apply(
    url('./files'),
    [
      template({
        ...strings,
        ...options,
      }),
      move(sourceDir),
    ]
  )

  return mergeWith(templateSource, MergeStrategy.Overwrite);

}

files/__path__/__name@dasherize__.ts

export function <%= camelize(name) %>(): void {
}

我跑schematics .:function --name=test --dry-run=false我得到

创建 /src/app/test.ts(33 字节)

但是,第二次。

错误!/src/app/test.ts 已经存在。

它不应该在没有错误的情况下覆盖文件 test.ts 吗?

编辑:

所有答案都有效并且很棒,但似乎它们是变通方法,没有明显的“正确”答案,并且可能基于偏好/自以为是。所以不知道如何标记为已回答。

4

5 回答 5

12

修改克里斯的回答我能够想出以下解决方案:

export function applyWithOverwrite(source: Source, rules: Rule[]): Rule {
  return (tree: Tree, _context: SchematicContext) => {
    const rule = mergeWith(
      apply(source, [
        ...rules,
        forEach((fileEntry) => {
          if (tree.exists(fileEntry.path)) {
            tree.overwrite(fileEntry.path, fileEntry.content);
            return null;
          }
          return fileEntry;
        }),

      ]),
    );

    return rule(tree, _context);
  };
}

apply用调用这个函数替换你的用法。

 applyWithOverwrite(url('./files/stylelint'), [
        template({
          dot: '.',
        }),
      ]),
于 2018-11-09T16:49:41.543 回答
6

我遇到了同样的问题。偶然我发现添加一个forEach允许apply删除文件并创建新文件。这是@angular-devkit/schematics-cli@0.6.8。

export function indexPage(options: any): Rule {
    return (tree: Tree, _context: SchematicContext) => {
        const rule = mergeWith(
            apply(url('./files'), [
                template({ ...options }),
                forEach((fileEntry: FileEntry) => {
                    // Just by adding this is allows the file to be overwritten if it already exists
                    if (tree.exists(fileEntry.path)) return null;
                    return fileEntry;
                })

            ])
        );

        return rule(tree, _context);
    };
}
于 2018-07-07T00:03:58.400 回答
3

如果您要替换许多文件,这可能并不理想。我在向项目添加样板时遇到了替换 favicon.ico 的问题。我使用的解决方案是先显式删除它。

export function scaffold(options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
  
    tree.delete('src/favicon.ico');

    const templateSource = apply(url('./files'), [
      template({
        ...options,
      }),
      move('.'),
    ]);

    return chain([
      branchAndMerge(chain([
        mergeWith(templateSource, MergeStrategy.Overwrite),
      ]), MergeStrategy.AllowOverwriteConflict),
    ])(tree, _context);
  };
}

注意:此方法不再适用于当前版本的 Schematics。

以下似乎适用于 0.6.8 原理图。

export function scaffold(options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
  
    const templateSource = apply(url('./files'), [
      template({
        ...options,
      }),
      move('.'),
    ]);

    return chain([
      branchAndMerge(chain([
        mergeWith(templateSource, MergeStrategy.Overwrite),
      ]), MergeStrategy.Overwrite),
    ])(tree, _context);
  };
}

作为奖励,我不再需要明确删除该文件。

于 2018-04-11T15:15:11.230 回答
0

感谢@cgatian 的提示!
不幸的是,它不适move用于某个位置的模板,所以我不得不添加:

forEach(fileEntry => {
  const destPath = join(options.output, fileEntry.path);
  if (tree.exists(destPath)) {
    tree.overwrite(destPath, fileEntry.content);
  } else {
    tree.create(destPath, fileEntry.content);
  }
  return null;
})

直到MergeStrategy按预期工作,
这将完成传递目标路径的技巧options.output

再次感谢!

于 2019-02-11T05:20:39.263 回答
-1

使用--force论据: ng g c component-name --force

于 2020-10-28T22:01:41.440 回答