@nstudio/schematics
Version: 
Cross-platform (xplat) tools for Nx workspaces.
287 lines • 13.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular-devkit/schematics");
const utils_1 = require("../utils");
const ts = require("typescript");
const test_1 = require("@schematics/angular/utility/test");
const strings_1 = require("@angular-devkit/core/src/utils/strings");
let featureName;
let projectNames;
function default_1(options) {
    if (!options.name) {
        throw new schematics_1.SchematicsException(`You did not specify the name of the feature you'd like to generate. For example: ng g feature my-feature`);
    }
    featureName = options.name.toLowerCase();
    let projects = options.projects;
    let platforms = [];
    if (options.adjustSandbox) {
        // when adjusting sandbox for the feature, turn dependent options on
        // for convenience also setup some default fallbacks to avoid requiring so many options
        // sandbox flags are meant to be quick and convenient
        options.onlyProject = true;
        options.routing = true;
        if (!projects) {
            if (!options.platforms) {
                // default to {N} sandbox 
                projects = 'nativescript-sandbox';
            }
            else {
                platforms = options.platforms.split(",");
                const projectSandboxNames = [];
                // default to project with sandbox name
                for (const p of platforms) {
                    if (utils_1.supportedSandboxPlatforms.includes(p)) {
                        projectSandboxNames.push(`${p}-sandbox`);
                    }
                    else {
                        throw new schematics_1.SchematicsException(`The --adjustSandbox flag supports the following at the moment: ${utils_1.supportedSandboxPlatforms}`);
                    }
                }
                projects = projectSandboxNames.join(',');
            }
        }
    }
    if (options.routing && !options.onlyProject) {
        throw new schematics_1.SchematicsException(`When generating a feature with the --routing option, please also specify --onlyProject. Support for shared code routing is under development and will be available in the future.`);
    }
    if (projects) {
        // building feature in shared code and in projects
        projectNames = projects.split(",");
        for (const name of projectNames) {
            const platPrefix = name.split("-")[0];
            if (utils_1.supportedPlatforms.includes(platPrefix) &&
                !platforms.includes(platPrefix)) {
                // if project name is prefixed with supported platform and not already added
                platforms.push(platPrefix);
            }
        }
    }
    else if (options.platforms) {
        // building feature in shared code only
        platforms = options.platforms.split(",");
    }
    if (platforms.length === 0) {
        let error = projects ? utils_1.platformAppPrefixError() : utils_1.generatorError("feature");
        throw new schematics_1.SchematicsException(utils_1.optionsMissingError(error));
    }
    const targetPlatforms = {};
    for (const t of platforms) {
        if (utils_1.supportedPlatforms.includes(t)) {
            targetPlatforms[t] = true;
        }
        else {
            throw new schematics_1.SchematicsException(utils_1.unsupportedPlatformError(t));
        }
    }
    const projectChains = [];
    if (options.onlyProject) {
        for (const projectName of projectNames) {
            const platPrefix = projectName.split("-")[0];
            let srcDir = platPrefix !== "nativescript" ? "src/" : "";
            // check for 2 different naming conventions on routing modules
            const routingModulePathOptions = [];
            const appDirectory = `apps/${projectName}/${srcDir}app/`;
            routingModulePathOptions.push(`${appDirectory}app.routing.ts`);
            routingModulePathOptions.push(`${appDirectory}app-routing.module.ts`);
            projectChains.push((tree, context) => {
                return addFiles(options, platPrefix, projectName)(tree, context);
            });
            if (options.routing) {
                projectChains.push((tree, context) => {
                    return adjustRouting(routingModulePathOptions, platPrefix)(tree, context);
                });
                if (options.adjustSandbox) {
                    projectChains.push((tree, context) => {
                        return adjustSandbox(platPrefix, appDirectory)(tree, context);
                    });
                }
            }
            if (!options.onlyModule) {
                projectChains.push((tree, context) => {
                    return addFiles(options, platPrefix, projectName, "_component")(tree, context);
                });
            }
        }
    }
    else {
        projectChains.push(schematics_1.noop());
    }
    return schematics_1.chain([
        utils_1.prerun(),
        // libs
        (tree, context) => options.onlyProject
            ? schematics_1.noop()(tree, context)
            : addFiles(options)(tree, context),
        // libs
        (tree, context) => options.onlyProject || !options.createBase || options.onlyModule
            ? schematics_1.noop()(tree, context)
            : addFiles(options, null, null, "_component")(tree, context),
        // update libs index
        (tree, context) => options.onlyProject
            ? schematics_1.noop()(tree, context)
            : adjustBarrelIndex("libs/features/index.ts")(tree, context),
        // web
        (tree, context) => !options.onlyProject && targetPlatforms.web
            ? addFiles(options, "web")(tree, context)
            : schematics_1.noop()(tree, context),
        // update web index
        (tree, context) => !options.onlyProject && targetPlatforms.web
            ? adjustBarrelIndex("xplat/web/features/index.ts")(tree, context)
            : schematics_1.noop()(tree, context),
        // add starting component unless onlyModule
        (tree, context) => !options.onlyProject && !options.onlyModule && targetPlatforms.web
            ? addFiles(options, "web", null, "_component")(tree, context)
            : schematics_1.noop()(tree, context),
        // nativescript
        (tree, context) => !options.onlyProject && targetPlatforms.nativescript
            ? addFiles(options, "nativescript")(tree, context)
            : schematics_1.noop()(tree, context),
        // update nativescript index
        (tree, context) => !options.onlyProject && targetPlatforms.nativescript
            ? adjustBarrelIndex("xplat/nativescript/features/index.ts")(tree, context)
            : schematics_1.noop()(tree, context),
        // add starting component unless onlyModule
        (tree, context) => !options.onlyProject &&
            !options.onlyModule &&
            targetPlatforms.nativescript
            ? addFiles(options, "nativescript", null, "_component")(tree, context)
            : schematics_1.noop()(tree, context),
        // ionic
        (tree, context) => !options.onlyProject && targetPlatforms.ionic
            ? addFiles(options, "ionic")(tree, context)
            : schematics_1.noop()(tree, context),
        // update ionic index
        (tree, context) => !options.onlyProject && targetPlatforms.ionic
            ? adjustBarrelIndex("xplat/ionic/features/index.ts")(tree, context)
            : schematics_1.noop()(tree, context),
        // add starting component unless onlyModule
        (tree, context) => !options.onlyProject && !options.onlyModule && targetPlatforms.ionic
            ? addFiles(options, "ionic", null, "_component")(tree, context)
            : schematics_1.noop()(tree, context),
        // project handling
        ...projectChains,
        options.skipFormat ? schematics_1.noop() : utils_1.formatFiles(options)
    ]);
}
exports.default = default_1;
const addFiles = (options, target = "", projectName = "", extra = "") => {
    let moveTo;
    if (target) {
        moveTo = getMoveTo(target, projectName);
    }
    else {
        target = "lib";
        moveTo = `libs/features/${featureName}`;
    }
    return schematics_1.branchAndMerge(schematics_1.mergeWith(schematics_1.apply(schematics_1.url(`./_${target}${extra}_files`), [
        schematics_1.template(getTemplateOptions(options)),
        schematics_1.move(moveTo)
    ])));
};
function adjustBarrelIndex(indexFilePath) {
    return (host) => {
        const indexSource = host.read(indexFilePath).toString("utf-8");
        const indexSourceFile = ts.createSourceFile(indexFilePath, indexSource, ts.ScriptTarget.Latest, true);
        utils_1.insert(host, indexFilePath, [
            ...utils_1.addGlobal(indexSourceFile, indexFilePath, `export * from './${featureName}';`, true)
        ]);
        return host;
    };
}
function getTemplateOptions(options) {
    const nameParts = options.name.split('-');
    let endingDashName = nameParts[0];
    if (nameParts.length > 1) {
        endingDashName = strings_1.capitalize(nameParts[nameParts.length - 1]);
    }
    return Object.assign({}, options, { name: featureName, endingDashName, npmScope: utils_1.getNpmScope(), prefix: utils_1.getPrefix(), dot: ".", utils: utils_1.stringUtils });
}
function getMoveTo(platform, projectName) {
    let moveTo = `xplat/${platform}/features/${featureName}`;
    if (projectName) {
        let srcDir = platform !== "nativescript" ? "src/" : "";
        moveTo = `apps/${projectName}/${srcDir}app/features/${featureName}`;
        // console.log('moveTo:', moveTo);
    }
    return moveTo;
}
function adjustRouting(routingModulePaths, platform) {
    return (host) => {
        let routingModulePath;
        // check which routing naming convention might be in use
        // app.routing.ts or app-routing.module.ts
        for (const modulePath of routingModulePaths) {
            if (host.exists(modulePath)) {
                routingModulePath = modulePath;
                break;
            }
        }
        // console.log('routingModulePath:',routingModulePath);
        // console.log('host.exists(routingModulePath):',host.exists(routingModulePath));
        if (routingModulePath) {
            const routingSource = host.read(routingModulePath).toString("utf-8");
            const routingSourceFile = ts.createSourceFile(routingModulePath, routingSource, ts.ScriptTarget.Latest, true);
            const changes = [];
            const loadPrefix = platform === "nativescript" ? "~" : ".";
            // add component to route config
            changes.push(...utils_1.addToCollection(routingSourceFile, routingModulePath, `{ 
              path: '${featureName}',
              loadChildren: '${loadPrefix}/features/${featureName}/${featureName}.module#${utils_1.stringUtils.classify(featureName)}Module'
          }`));
            utils_1.insert(host, routingModulePath, changes);
        }
        return host;
    };
}
function adjustSandbox(platform, appDirectory) {
    return (tree) => {
        if (utils_1.supportedSandboxPlatforms.includes(platform)) {
            const homeCmpPath = `${appDirectory}/features/home/components/home.component.html`;
            let homeTemplate = test_1.getFileContent(tree, homeCmpPath);
            switch (platform) {
                case "nativescript":
                    let buttonTag = 'Button';
                    let buttonEndIndex = homeTemplate.lastIndexOf(`</${buttonTag}>`);
                    if (buttonEndIndex === -1) {
                        // check for lowercase
                        buttonEndIndex = homeTemplate.lastIndexOf(`</${buttonTag.toLowerCase()}>`);
                        if (buttonEndIndex > -1) {
                            buttonTag = buttonTag.toLowerCase();
                        }
                    }
                    let customBtnClass = '';
                    if (buttonEndIndex === -1) {
                        // if no buttons were found this is a fresh sandbox app setup
                        // it should have a label as placeholder
                        buttonEndIndex = homeTemplate.lastIndexOf('</Label>');
                        if (buttonEndIndex === -1) {
                            buttonEndIndex = homeTemplate.lastIndexOf(`</label>`);
                        }
                    }
                    else {
                        const buttonClassStartIndex = homeTemplate.lastIndexOf('class="btn ');
                        if (buttonClassStartIndex > -1) {
                            // using custom button class
                            customBtnClass = ' ' + homeTemplate.substring(buttonClassStartIndex + 11, homeTemplate.lastIndexOf(`"></${buttonTag}>`));
                        }
                    }
                    const featureNameParts = featureName.split("-");
                    let routeName = featureName;
                    if (featureNameParts.length > 1) {
                        routeName = strings_1.capitalize(featureNameParts[featureNameParts.length - 1]);
                    }
                    homeTemplate =
                        homeTemplate.slice(0, buttonEndIndex + 9) +
                            `<${buttonTag} text="${routeName}" (tap)="goTo('/${featureName}')" class="btn${customBtnClass}"></${buttonTag}>` +
                            homeTemplate.slice(buttonEndIndex + 9);
                    break;
            }
            utils_1.createOrUpdate(tree, homeCmpPath, homeTemplate);
        }
        else {
            throw new schematics_1.SchematicsException(`The --adjustSandbox option is only supported on the following at the moment: ${utils_1.supportedSandboxPlatforms}`);
        }
        return tree;
    };
}
//# sourceMappingURL=index.js.map