UNPKG

tyson

Version:

A tool that generates a TypeScript file from your Jison grammar's semantic actions so the TypeScript compiler will check those semantic actions for errors.

323 lines (322 loc) 13.7 kB
#! /usr/bin/env node "use strict"; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var rusty_ts_1 = require("rusty-ts"); var _1 = require("."); var fs_1 = __importDefault(require("fs")); var path_1 = __importDefault(require("path")); var packageVersion_generated_1 = __importDefault(require("./packageVersion.generated")); var CommandType; (function (CommandType) { CommandType[CommandType["Invalid"] = 0] = "Invalid"; CommandType[CommandType["Help"] = 1] = "Help"; CommandType[CommandType["Version"] = 2] = "Version"; CommandType[CommandType["GenerateTypescriptFile"] = 3] = "GenerateTypescriptFile"; })(CommandType || (CommandType = {})); var InvalidTysonConfigErrorType; (function (InvalidTysonConfigErrorType) { InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["InvalidFile"] = 0] = "InvalidFile"; InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["WrongTypeOfFile"] = 1] = "WrongTypeOfFile"; InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["DuplicateGrammarFileDefs"] = 2] = "DuplicateGrammarFileDefs"; InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["DuplicateTypeDictFileDefs"] = 3] = "DuplicateTypeDictFileDefs"; InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["DuplicateOutputFileDefs"] = 4] = "DuplicateOutputFileDefs"; InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["DuplicateTypeDictInterfaceDefs"] = 5] = "DuplicateTypeDictInterfaceDefs"; InvalidTysonConfigErrorType[InvalidTysonConfigErrorType["MissingRequiredArgs"] = 6] = "MissingRequiredArgs"; })(InvalidTysonConfigErrorType || (InvalidTysonConfigErrorType = {})); var HELP_TEXT = "A tool that generates a TypeScript file from your Jison grammar's semantic actions so you can typecheck those semantic actions.\n\nUSAGE:\n tyson <grammar-file> <type-dict-file> --out <output-file> [--type-dict-interface <type-dict-interface>]\n\nOPTIONS:\n -h, --help Prints the help info\n -v, --version Prints the version info and exits\n \nARGUMENTS:\n <grammar-file> A Jison file\n <type-dict-file> A TypeScript file that exports a `TysonTypeDictionary` interface\n <output-file> The file to the generated code should be written to\n <type-dict-interface> (optional) The name of the type dictionary interface. Defaults to \"TysonTypeDictionary\"\n"; if (require.main === module) { main(process.argv); } function main(argv) { var args = argv.slice(2); var command = getCommand(args); handleCommand(command); } exports.main = main; function getCommand(args) { if (args.length === 0) { return { commandType: CommandType.Help }; } if (args[0] === "-h" || args[0] === "--help") { return { commandType: CommandType.Help }; } if (args[0] === "-v" || args[0] === "--version") { return { commandType: CommandType.Version }; } var config = getConfig(args); return config.match({ err: function (error) { return { commandType: CommandType.Invalid, error: error }; }, ok: function (config) { return { commandType: CommandType.GenerateTypescriptFile, config: config }; }, }); } function getConfig(args) { var e_1, _a; var AcceptMode; (function (AcceptMode) { AcceptMode[AcceptMode["JisonAndTypeDict"] = 0] = "JisonAndTypeDict"; AcceptMode[AcceptMode["OutputFile"] = 1] = "OutputFile"; AcceptMode[AcceptMode["TypeDictInterfaceName"] = 2] = "TypeDictInterfaceName"; })(AcceptMode || (AcceptMode = {})); var mode = AcceptMode.JisonAndTypeDict; var pathToBnfGrammarFile = undefined; var pathToTypeDictFile = undefined; var pathToOutputFile = undefined; var typeDictInterfaceName = undefined; var emitUnusedLocations = undefined; var emitUnusedSemanticValueParams = undefined; try { for (var args_1 = __values(args), args_1_1 = args_1.next(); !args_1_1.done; args_1_1 = args_1.next()) { var arg = args_1_1.value; if (arg === "--in") { mode = AcceptMode.JisonAndTypeDict; continue; } if (arg === "--out" || arg === "-o") { mode = AcceptMode.OutputFile; continue; } if (arg === "--type-dict-interface" || arg === "-t") { mode = AcceptMode.TypeDictInterfaceName; continue; } if (arg === "--emit-unused-locations") { emitUnusedLocations = true; continue; } if (arg === "--emit-unused-semantic-value-params") { emitUnusedSemanticValueParams = true; continue; } if (mode === AcceptMode.JisonAndTypeDict) { if (/\.jison$/.test(arg)) { if (!isValidFile(arg)) { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.InvalidFile, path: arg, }); } if (pathToBnfGrammarFile !== undefined) { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.DuplicateGrammarFileDefs, paths: [pathToBnfGrammarFile, arg], }); } pathToBnfGrammarFile = arg; continue; } if (/\.ts$/.test(arg)) { if (!isValidFile(arg)) { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.InvalidFile, path: arg, }); } if (pathToTypeDictFile !== undefined) { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.DuplicateTypeDictFileDefs, paths: [pathToTypeDictFile, arg], }); } pathToTypeDictFile = arg; continue; } return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.WrongTypeOfFile, expectedExtensions: [".jison", ".ts"], actualPath: arg, }); } if (mode === AcceptMode.OutputFile) { if (/\.ts$/.test(arg)) { if (pathToOutputFile !== undefined) { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.DuplicateOutputFileDefs, paths: [pathToOutputFile, arg], }); } pathToOutputFile = arg; continue; } return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.WrongTypeOfFile, expectedExtensions: [".ts"], actualPath: arg, }); } if (mode === AcceptMode.TypeDictInterfaceName) { if (typeDictInterfaceName !== undefined) { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.DuplicateTypeDictInterfaceDefs, interfaceNames: [typeDictInterfaceName, arg], }); } typeDictInterfaceName = arg; continue; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (args_1_1 && !args_1_1.done && (_a = args_1.return)) _a.call(args_1); } finally { if (e_1) throw e_1.error; } } if (pathToBnfGrammarFile !== undefined && pathToTypeDictFile !== undefined && pathToOutputFile !== undefined) { return rusty_ts_1.result.ok({ pathToBnfGrammarFile: pathToBnfGrammarFile, pathToTypeDictFile: pathToTypeDictFile, pathToOutputFile: pathToOutputFile, typeDictInterfaceName: typeDictInterfaceName, emitUnusedLocations: emitUnusedLocations, emitUnusedSemanticValueParams: emitUnusedSemanticValueParams, }); } else { return rusty_ts_1.result.err({ errorType: InvalidTysonConfigErrorType.MissingRequiredArgs, missingArgs: __spread((pathToBnfGrammarFile === undefined ? ["grammar-file"] : []), (pathToTypeDictFile === undefined ? ["type-dict-file"] : []), (pathToOutputFile === undefined ? ["output-file"] : [])), }); } } function isValidFile(p) { var absolutePath = path_1.default.isAbsolute(p) ? p : path_1.default.join(process.cwd(), p); return fs_1.default.existsSync(absolutePath) && fs_1.default.lstatSync(absolutePath).isFile(); } function handleCommand(command) { switch (command.commandType) { case CommandType.Invalid: handleInvalidCommand(command); break; case CommandType.Help: handleHelpCommand(); break; case CommandType.Version: handleVersionCommand(); break; case CommandType.GenerateTypescriptFile: handleGenerateCommand(command); break; } } function handleInvalidCommand(command) { var error = command.error; switch (error.errorType) { case InvalidTysonConfigErrorType.InvalidFile: handleInvalidFileError(error); break; case InvalidTysonConfigErrorType.WrongTypeOfFile: handleWrongTypeOfFileError(error); break; case InvalidTysonConfigErrorType.DuplicateGrammarFileDefs: handleDuplicateGrammarFileDefsError(error); break; case InvalidTysonConfigErrorType.DuplicateTypeDictFileDefs: handleDuplicateTypeDictFileDefsError(error); break; case InvalidTysonConfigErrorType.DuplicateOutputFileDefs: handleDuplicateOutputFileDefsError(error); break; case InvalidTysonConfigErrorType.DuplicateTypeDictInterfaceDefs: handleDuplicateTypeDictInterfaceDefsError(error); break; case InvalidTysonConfigErrorType.MissingRequiredArgs: handleMissingRequiredArgsError(error); break; } } function handleInvalidFileError(error) { console.log('No file named "' + error.path + '" exists.'); process.exit(1); } function handleWrongTypeOfFileError(error) { console.log("Expecting a file with one of the following extensions: [" + error.expectedExtensions.map(function (ext) { return '"' + ext + '"'; }).join(", ") + '], but received "' + error.actualPath + '".'); process.exit(1); } function handleDuplicateGrammarFileDefsError(error) { console.log('Duplicate grammar file definitions:\n First: "' + error.paths[0] + '"\n Second: "' + error.paths[1] + '"'); } function handleDuplicateTypeDictFileDefsError(error) { console.log('Duplicate type dictionary file definitions:\n First: "' + error.paths[0] + '"\n Second: "' + error.paths[1] + '"'); } function handleDuplicateOutputFileDefsError(error) { console.log('Duplicate output file definitions:\n First: "' + error.paths[0] + '"\n Second: "' + error.paths[1] + '"'); } function handleDuplicateTypeDictInterfaceDefsError(error) { console.log('Duplicate type dictionary interface definitions:\n First: "' + error.interfaceNames[0] + '"\n Second: "' + error.interfaceNames[1] + '"'); } function handleMissingRequiredArgsError(error) { console.log("Missing the following required arguments: [" + error.missingArgs.join(", ") + "]."); process.exit(1); } function handleHelpCommand() { console.log(HELP_TEXT); } function handleVersionCommand() { console.log("tyson " + packageVersion_generated_1.default); } function handleGenerateCommand(command) { _1.generateTypeScriptFile(command.config); }