smart-column-indenter
Version:
A smart source code indenter that indent the code into columns
70 lines • 3.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const assert = require("assert");
const LanguageFactory_1 = require("./languages/LanguageFactory");
const multiple_lcs_1 = require("multiple-lcs");
const Columnizer_1 = require("./Columnizer");
const intersection = require("lodash.intersection");
class Indenter {
constructor(code, extension, config) {
this.code = code;
this.extension = extension;
this.config = this.overrideDefaultConfig(config);
}
overrideDefaultConfig(newConfig) {
const jsonDefaultConfig = fs.readFileSync(`${__dirname}/config.json`, { encoding: "utf-8" });
const defaultConfig = JSON.parse(jsonDefaultConfig);
return Object.assign({}, defaultConfig, newConfig);
}
indent(type) {
const language = LanguageFactory_1.default.getLanguage(this.config, this.extension);
const linesOfCode = this.code.split(/\r\n|\r|\n/).map(l => l.trim()).filter(l => l !== "");
assert.ok(linesOfCode.length >= 2, "The code to indent must have at least 2 lines of code.");
const linesOfTokens = language.tokenize(linesOfCode);
const inputTokens = language.preProcessInput(linesOfTokens);
const commonTokens = this.commonTokens(language, inputTokens, type);
const outputTokens = language.preProcessOutput(linesOfTokens);
const columnizedTokens = new Columnizer_1.default(language, commonTokens, outputTokens).columnize();
const indentedCode = this.stringify(language, columnizedTokens);
this.ensureSameCode(this.code, indentedCode);
return indentedCode;
}
commonTokens(language, linesOfTokens, type) {
const sequencesOfStrings = linesOfTokens.map(line => line.map(token => language.token2string(token)));
if (type === "N") {
return new multiple_lcs_1.default().execute(sequencesOfStrings);
}
else if (type === "2") {
let firstCommonToken;
let i = 0;
do {
firstCommonToken = intersection(...sequencesOfStrings.map(line => line.slice(0, ++i)));
} while (!firstCommonToken.length);
return [firstCommonToken[0]];
}
else {
throw new Error("Unknown indentation type.");
}
}
stringify(language, columnizedTokens) {
const spacesBefore = this.code.replace(/\S[\s\S]*/, "");
const spacesAfter = this.code.replace(/[\s\S]*\S/, "");
const lineBreak = (this.code.match(/\r\n|\r|\n/) || ["\n"])[0];
const indentation = this.code.trim().split(/\r\n|\r|\n/g)[1].replace(/^(\s*).*/, "$1");
const indentedCode = language
.stringify(columnizedTokens)
.map(line => line.replace(/\s+$/, ""))
.join(lineBreak + indentation);
return spacesBefore + indentedCode + spacesAfter;
}
ensureSameCode(code, indentedCode) {
const codeWithoutIndentation = code.replace(/[ \t]/g, "").replace(/\r\n|\r|\n/g, "\n").trim();
const indentedCodeWithoutIndentation = indentedCode.replace(/[ \t]/g, "").replace(/\r\n|\r|\n/g, "\n").trim();
if (codeWithoutIndentation !== indentedCodeWithoutIndentation) {
throw new Error("The indentation process are trying to change the code. It is a bug, please, open an issue: https://github.com/lmcarreiro/smart-column-indenter");
}
}
}
exports.default = Indenter;
//# sourceMappingURL=Indenter.js.map