How to use current path in Angular schematics
Asked Answered
W

2

5

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?

Wristlet answered 2/9, 2019 at 7:27 Comment(0)
W
6

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

console.log('DIR', __dirname);
Wristlet answered 4/9, 2019 at 7:9 Comment(2)
How do you use that variable? Could you provide an example? Can I set that in my factory or do I have to provide it as a parameter?Projection
Hi, It was so long ago I don't even remember where I used it ;) But I think it was in the schematics script and it was exposed as global variableWristlet
M
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)
            ]);
        }
    };
}
Marlite answered 9/6, 2020 at 20:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.