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
JavaScript
;
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);
}