mscgenjs/mscgenjs-cli

View on GitHub
src/cli/validations.ts

Summary

Maintainability
A
3 hrs
Test Coverage
A
100%
"use strict";
import Ajv from "ajv";
import * as fs from "fs";
import * as mscgenjs from "mscgenjs";
import {
  INormalizedOptions,
  IPuppeteerOptions,
  NamedStyleType,
  OutputType,
} from "../types";
/* tslint:disable-next-line */
const puppeteerOptionsSchema = require("./puppeteer-options.schema.json");

const VALID_GRAPHICS_TYPES = Object.freeze(["svg", "png", "jpeg"]);
const VALID_OUTPUT_TYPES = VALID_GRAPHICS_TYPES.concat(
  mscgenjs.getAllowedValues().outputType.map((pValue) => pValue.name)
);
const ajv = new Ajv();

function isStdout(pFilename: string): boolean {
  return "-" === pFilename;
}

function fileExists(pFilename: string): boolean {
  try {
    if (!isStdout(pFilename)) {
      fs.accessSync(pFilename, fs.constants.R_OK);
    }
    return true;
  } catch (e: any) {
    return false;
  }
}

function getValidValues(pAttribute: string): string {
  return (mscgenjs.getAllowedValues() as any)[pAttribute]
    .filter((pValue: mscgenjs.IValueDetails) => pValue.experimental === false)
    .map((pValue: mscgenjs.IValueDetails) => pValue.name)
    .join(", ");
}

function isValidValue(pAttribute: string, pCandidateValue: string): boolean {
  return (mscgenjs.getAllowedValues() as any)[pAttribute].some(
    (pValue: mscgenjs.IValueDetails) => pValue.name === pCandidateValue
  );
}

export function validOutputType(pType: OutputType): OutputType {
  if (VALID_OUTPUT_TYPES.some((pName) => pName === pType)) {
    return pType;
  }

  throw Error(
    `\n  error: '${pType}' is not a valid output type. mscgen_js can emit:` +
      `\n          - the grapics formats svg, jpeg and png` +
      `\n          - the text formats dot, doxygen, mscgen, msgenny, xu and json.\n\n`
  );
}

export function validInputType(pType: string): string {
  if (isValidValue("inputType", pType)) {
    return pType as mscgenjs.InputType;
  }

  throw Error(
    `\n  error: '${pType}' is not a valid input type.` +
      `\n         mscgen_js can read ${getValidValues("inputType")}\n\n`
  );
}

export function validNamedStyle(pStyle: NamedStyleType): NamedStyleType {
  if (isValidValue("namedStyle", pStyle)) {
    return pStyle as NamedStyleType;
  }

  throw Error(
    `\n  error: '${pStyle}' is not a recognized named style.` +
      `\n         You can use one of these: ${getValidValues("namedStyle")}\n\n`
  );
}

export function validVerticalAlignment(
  pAlignment: string
): mscgenjs.RegularArcTextVerticalAlignmentType {
  if (isValidValue("regularArcTextVerticalAlignment", pAlignment)) {
    return pAlignment as mscgenjs.RegularArcTextVerticalAlignmentType;
  }

  throw Error(
    `\n  error: '${pAlignment}' is not a recognized vertical alignment.` +
      `\n         You can use one of these: ${getValidValues(
        "regularArcTextVerticalAlignment"
      )}\n\n`
  );
}

export function validateArguments(
  pOptions: INormalizedOptions
): Promise<INormalizedOptions> {
  return new Promise((pResolve, pReject) => {
    if (!pOptions.inputFrom) {
      pReject(Error(`\n  error: Please specify an input file.\n\n`));
    }

    if (!pOptions.outputTo) {
      pReject(Error(`\n  error: Please specify an output file.\n\n`));
    }

    if (!fileExists(pOptions.inputFrom)) {
      pReject(
        Error(
          `\n  error: Failed to open input file '${pOptions.inputFrom}'\n\n`
        )
      );
    }

    pResolve(pOptions);
  });
}

export function validPuppeteerOptions(
  pPuppeteerConfigFileName: string
): IPuppeteerOptions {
  let lPuppeteerConfigFileContents = "";
  let lPuppeteerConfigObject = {};

  try {
    lPuppeteerConfigFileContents = fs.readFileSync(
      pPuppeteerConfigFileName,
      "utf8"
    );
  } catch (pException) {
    throw Error(
      `\n  error: Failed to open puppeteer options configuration file '${pPuppeteerConfigFileName}'\n\n`
    );
  }

  try {
    lPuppeteerConfigObject = JSON.parse(lPuppeteerConfigFileContents);
  } catch (pException) {
    throw Error(
      `\n  error: '${pPuppeteerConfigFileName}' does not contain valid JSON\n\n`
    );
  }

  if (!ajv.validate(puppeteerOptionsSchema, lPuppeteerConfigObject)) {
    throw Error(`\n  error: '${pPuppeteerConfigFileName}' does not contain
         puppeteer options that are valid for use in mscgenjs-cli.

         These options you can use:
         - args (an array of options)
         - devtools (boolean)
         - executablePath (path to an executable)
         - headless (boolean)
         - slowMo (delay in ms)
         - timeout (in ms)\n\n`);
  }

  return lPuppeteerConfigObject as IPuppeteerOptions;
}

export const validOutputTypeRE = VALID_OUTPUT_TYPES.join("|");

export const validInputTypeRE = mscgenjs
  .getAllowedValues()
  .inputType.map((pValue) => pValue.name)
  .join("|");

export const validNamedStyleRE = mscgenjs
  .getAllowedValues()
  .namedStyle.filter(
    (pValue) => pValue.experimental === false && pValue.deprecated === false
  )
  .map((pValue) => pValue.name)
  .join("|");

export const validVerticalAlignmentRE = mscgenjs
  .getAllowedValues()
  .regularArcTextVerticalAlignment.map((pValue) => pValue.name)
  .join("|");

/*
    This file is part of mscgenjs-cli.
    mscgenjs-cli is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    mscgen_js is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with mscgenjs-cli.  If not, see <http://www.gnu.org/licenses/>.
*/