angularangular-cliangular-schematics

How to overwrite file with angular schematics?


I want to write a Rule that overwrites a file every time. In the following and have MergeStrategy set to 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 {
}

I run schematics .:function --name=test --dry-run=false I get

CREATE /src/app/test.ts (33 bytes)

but then, the second time.

ERROR! /src/app/test.ts already exists.

Should it not overwrite the file test.ts with out error?

Edit:

All of the answers work and are great but it seems they are workarounds and no obvious "right" answer and possibly based on preference / opinionated. So not sure how to mark as answered.


Solution

  • I experienced the same issue. By accident I found that adding a forEach into the apply allowed the files to be deleted and the new files created. This is with @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);
        };
    }