3

I'm developing a schematic which produces some files. I'd like to have new files in current directory, i.e.

My project root is /src/app. When I am in folder /src/app/features/f1, and type

ng g my:some-schemaitc --name=name

I am expecting new file

/src/app/features/f1/name.ts

instead, the result is

/src/app/name.ts

I'd like to achieve same behavior as ng g class --name=name. When I type ng g class --name=class in directory /src/app/features/f1, the result will be

/src/app/features/f1/class.ts

I tried to mimic Angular ng g class behavior schematics source code, but without satisfying result. My code is almost same.

Have someone made use of current path?

Walter Luszczyk
  • 1,369
  • 2
  • 19
  • 36

2 Answers2

5

Accidentally I found out a global variable __dirname which stores current path. For exapmple:

console.log('DIR', __dirname);
Walter Luszczyk
  • 1,369
  • 2
  • 19
  • 36
0

Follow the steps mentioned in the angular docs

You will run into a bit of issues. For example

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

// will be null when using the 'schematics' command but will work when using the 'ng g' commad.

2) Similarly 'options.path' will be undefined when using the 'schematics' command but will work when using the 'ng g' command.

You need to add path to schema.json file and then in your function, you should be able to use 'options.path' to get the current location. However as I mentioned I was not able to get it to work when using the 'schematics' command. I was only able to get it to work when using the 'ng g' command.

So as an example here are my files

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)
            ]);
        }
    };
}
ecosystem31
  • 276
  • 2
  • 4