esbuild-plugin-kaitai
Version:
An esbuild plugin for importing Kaitai Struct files.
99 lines (98 loc) • 4.75 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileKaitaiCli = void 0;
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
function runCompiler(compilerPath, flags, timeout) {
return new Promise((resolve, reject) => {
(0, child_process_1.execFile)(compilerPath, flags, {
encoding: 'utf8',
timeout: timeout,
shell: false
}, (error, stdout, stderr) => {
if (error) {
reject(error);
}
else if (stderr) {
reject(new Error(stderr));
}
else {
resolve(JSON.parse(stdout));
}
});
});
}
const buildError = (text, file, detail) => ({ text, location: { file }, detail });
const buildErrorReturn = (text, file, detail) => ({ errors: [buildError(text, file, detail)] });
/**
* Compiles a ksy file with the command-line Kaitai Compiler.
* @param file The file to compile.
* @param options The compilation options.
* @returns The results of the compilation.
*/
function compileKaitaiCli(file, options) {
return __awaiter(this, void 0, void 0, function* () {
// Make a temp dir for the output
const tmpDir = yield fs_1.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'kaitai-'));
try {
// Get config options
const compilerPath = (options === null || options === void 0 ? void 0 : options.compilerPath) || process.env.KAITAI_PATH || 'kaitai-struct-compiler';
const compilerFlags = (options === null || options === void 0 ? void 0 : options.compilerFlags) || [];
const compilerTimeout = (options === null || options === void 0 ? void 0 : options.compilerTimeout) || 10000;
// Add required flags
compilerFlags.push('--ksc-json-output');
compilerFlags.push('--target', 'javascript');
compilerFlags.push('--outdir', tmpDir);
compilerFlags.push(file.path);
// Run the compiler
const result = yield runCompiler(compilerPath, compilerFlags, compilerTimeout);
// Get the result for our input file
if (result[file.path]) {
const fileResult = result[file.path];
if ('output' in fileResult) {
const jsResults = fileResult.output['javascript'];
const mainSpec = fileResult.firstSpecName;
const mainSpecResults = jsResults[mainSpec];
// Assume the first output file is the only one
const outputFileName = mainSpecResults.files[0].fileName;
// Read the file from the tmp location
const outputFilePath = path_1.default.join(tmpDir, outputFileName);
const output = yield fs_1.promises.readFile(outputFilePath, { encoding: 'utf8' });
yield fs_1.promises.writeFile('./debug.js', output);
return {
contents: output,
loader: 'js',
resolveDir: path_1.default.dirname(file.path)
};
}
else {
return {
errors: fileResult.errors.map(e => buildError(e.message, e.file, e.path))
};
}
}
else {
return buildErrorReturn('The Kaitai Compiler didn\'t return anything for this file.', file.path, result);
}
}
finally {
// Clean up the tmp folder
fs_1.promises.rm(tmpDir, { maxRetries: 4, retryDelay: 1000, recursive: true, force: true });
}
});
}
exports.compileKaitaiCli = compileKaitaiCli;