All files / src cli-module.ts

0% Statements 0/41
0% Branches 0/19
0% Functions 0/11
0% Lines 0/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140                                                                                                                                                                                                                                                                                       
import { Command } from 'commander';
import { runCommand } from '@decaf-ts/utils';
import { Logging } from '@decaf-ts/logging';
 
 
enum Projects {
  FOR_ANGULAR = "for-angular",
  FOR_ANGULAR_APP = "for-angular-app",
  LIB = "lib",
  APP = "app"
};
 
enum Types {
  PAGE = "page",
  SERVICE = "service",
  COMPONENT = "component",
  DIRECTIVE = "directive",
  SCHEMATICS = "schematics"
};
 
const logger = Logging.for("for-angular-cli");
 
/**
 * Creates and returns a Command object for the Angular CLI module in decaf-ts.
 * This function sets up a 'generate' command that can create various Angular artifacts.
 *
 * @returns {Command} A Command object configured with the 'generate' subcommand and its action.
 *
 * The command syntax is: generate <type> <name> [project]
 * @param {Types} type - The type of artifact to generate (e.g., service, component, directive, page).
 * @param {string} name - The name of the artifact to be generated.
 * @param {Projects} [project=Projects.FOR_ANGULAR] - The project for which to generate the artifact.
 *                   Defaults to the main Angular project if not specified.
 *
 * @throws {Error} If an invalid type is provided.
 *
 * @example
 * // Usage in CLI
 * // decaf-ts generate service my-service
 * // decaf-ts generate component my-component for-angular-app
 */
export default function angular() {
  return new Command()
    .name('decaf generate')
    .command('generate <type> <name> [project]')
    .description(`decaf-ts Angular CLI module`)
    .action(async(type: Types, name: string, project: Projects = Projects.FOR_ANGULAR) => {
      Iif(!validateType(type))
        return logger.error(`${type} is not valid. Use service, component or directive.`)
 
      Iif(type === Types.SCHEMATICS)
        return await generateSchematics();
 
      Iif(type === Types.PAGE) {
        logger.info(`Pages can be only generate for app. Forcing project to: ${Projects.FOR_ANGULAR_APP}`);
        project = Projects.FOR_ANGULAR_APP;
      }
 
      (project as string) = parseProjectName(project);
 
      Iif(!validateProject(project))
        project = Projects.FOR_ANGULAR;
      const command = project === Projects.FOR_ANGULAR_APP ?
        'ionic generate' : `ng generate --project=${Projects.FOR_ANGULAR} --path=src/lib/${type}s`;
 
      try {
        const result = await execute(`${command} ${type} ${name}`);
        logger.info(result as string);
      } catch(error: any) {
        logger.error(error?.message || error);
      }
    });
}
 
 
async function generateSchematics() {
  return Promise.all([
    execute(`npm link schematics`),
    execute(`cd schematics`),
    execute(`npm install`),
    execute(`npm run build`),
    execute(`npx schematics .:schematics --name=decaf`)
  ])
  .then(res => res)
  .catch(error => error)
}
 
 
/**
 * Executes a shell command asynchronously.
 *
 * @param command - The shell command to execute.
 * @returns A Promise that resolves with the command's stdout output as a string if successful,
 *          or rejects with an error message if the command fails or produces stderr output.
 */
async function execute(command: string): Promise<string|void> {
  try {
    return await runCommand(command).promise;
  } catch (error: any) {
    logger.error(error?.message || error);
  }
}
 
/**
 * Parses and normalizes the project name input.
 *
 * @param value - The input project name to be parsed.
 *                Can be 'app', 'lib', or any other string value.
 * @returns A normalized string representation of the project name.
 *          Returns 'for-angular-app' if input is 'app',
 *          'for-angular' if input is 'lib',
 *          or the lowercase version of the input for any other value.
 */
function parseProjectName(value: string): string {
  return (value === Projects.APP ?
    Projects.FOR_ANGULAR_APP : value === Projects.LIB ?
      Projects.FOR_ANGULAR : value).toLowerCase();
}
 
/**
 * Validates if the given type value is a valid enum member of Types.
 *
 * @param value - The type value to validate.
 * @returns A boolean indicating whether the value is a valid Types enum member.
 */
function validateType(value: Types): boolean {
  return Object.values(Types).includes(value);
}
 
 
/**
 * Validates if the given project value is a valid enum member of Projects.
 *
 * @param value - The project value to validate.
 * @returns A boolean indicating whether the value is a valid Projects enum member.
 */
function validateProject(value: string): boolean {
  return Object.values(Projects).includes(value as Projects);
}