pegjs-require-import
Version:
PEG.js Require Extension
95 lines (81 loc) • 2.98 kB
JavaScript
const peg = require('pegjs');
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
class PegImportHelper {
constructor(loaderContext = {}) {
this.loaderContext = loaderContext;
this.pegContentParser = this.getPegContentParser();
this.fileContentObj = {};
this.graphState = {};
}
addLoaderDependency(filePath) {
if (typeof this.loaderContext.addDependency === 'function') {
this.loaderContext.addDependency(filePath);
}
}
getPegContentParser() {
const filePath = path.resolve(__dirname, './parser-pegjs.pegjs');
const pegGrammar = fs.readFileSync(filePath, 'utf-8');
this.addLoaderDependency(filePath);
const pegContentParser = peg.generate(pegGrammar, {
format: 'commonjs',
dependencies: {
_: 'lodash'
}
});
return pegContentParser;
}
loadDependencies(normalizeFilePath) {
this.graphState[normalizeFilePath] = 'EXPLORED';
const dependencies = [];
const fileContent = fs.readFileSync(normalizeFilePath, 'utf-8');
this.addLoaderDependency(normalizeFilePath);
const { initializer, content, dependencies: rawDependencies } = this.pegContentParser.parse(fileContent);
this.fileContentObj[normalizeFilePath] = {
initializer,
content
};
rawDependencies.forEach((rawDependency) => {
const nextNormalizeFilePath = path.resolve(path.dirname(normalizeFilePath), rawDependency);
if (!this.graphState[nextNormalizeFilePath]) {
this.loadDependencies(nextNormalizeFilePath).forEach((val) => {
dependencies.push(val);
});
} else if (this.graphState[nextNormalizeFilePath] === 'EXPLORED') {
throw Error(`Circular dependencies detected at ${nextNormalizeFilePath}`);
}
});
this.graphState[normalizeFilePath] = 'VISITED';
dependencies.push(normalizeFilePath);
return dependencies;
}
generateAllFileContent(rootPath) {
const normalizeRootPath = path.normalize(rootPath);
const dependencies = this.loadDependencies(normalizeRootPath);
let { initializer, content } = this.fileContentObj[normalizeRootPath];
if (!initializer) {
initializer = '';
}
_.pull(dependencies, normalizeRootPath);
dependencies.forEach((filePath) => {
const fileInitializer = this.fileContentObj[filePath].initializer;
const fileContent = this.fileContentObj[filePath].content;
if (fileInitializer) {
initializer += `\n${fileInitializer}`;
}
content += `\n${fileContent}`;
});
const finalResult = `{\n${initializer}\n}\n${content}`;
return finalResult;
}
generateParser(rootPath, options) {
const data = this.generateAllFileContent(rootPath);
let parser = peg.generate(data, options);
if (!options.output || options.output === 'parser') {
parser = Object.assign(parser, { sourceCode: data });
}
return parser;
}
}
module.exports = PegImportHelper;