ymlgen
Version:
A generator for YML/YAML files
292 lines • 12.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultIncludeFileReader = exports.isDataFile = exports.processFile = void 0;
const yamljs_1 = require("yamljs");
const path_1 = require("path");
const fs = __importStar(require("fs"));
const lodash_1 = require("lodash");
const isDataFile = (content) => {
return content.trimStart().startsWith("# ymlgen");
};
exports.isDataFile = isDataFile;
const defaultIncludeFileReader = (dataDir, name) => {
var _a;
const importFilePath = (0, path_1.resolve)(dataDir, name);
const importFileContent = fs.readFileSync(importFilePath, "utf-8");
const importExt = ((_a = (0, path_1.extname)(name)) !== null && _a !== void 0 ? _a : "").toLowerCase();
const data = importExt.endsWith(".json")
? // support JSON file
JSON.parse(importFileContent)
: // unless using yaml parser
(0, yamljs_1.parse)(importFileContent);
return data;
};
exports.defaultIncludeFileReader = defaultIncludeFileReader;
const readConfigs = (dataDir, content, configResolver, includeFileReader = defaultIncludeFileReader) => {
let defaultOutput = "";
let defaultGenerator = "";
let defaultSelect = "";
let onSuccess = "";
let onFail = "";
let onDone = "";
const importedData = [];
const generators = [];
content.replace(/# ymlgen:([^\s]+) ([^\n]+)/g, (_, name, value) => {
value = value.trim();
switch (name) {
case "merge":
if (!includeFileReader)
return "";
const data = includeFileReader(dataDir, value);
importedData.push(data);
break;
case "success":
onSuccess = value;
break;
case "fail":
onFail = value;
break;
case "done":
onDone = value;
break;
case "output":
defaultOutput = value;
break;
case "select":
defaultSelect = value;
break;
case "generator":
// custom generator
if (value.startsWith("{") && value.endsWith("}")) {
generators.push((0, yamljs_1.parse)(value));
}
else {
defaultGenerator = value;
}
break;
default:
if (!(configResolver === null || configResolver === void 0 ? void 0 : configResolver(name, value))) {
throw new Error(`Invalid config ${name}`);
}
}
return "";
});
if (defaultGenerator) {
if (!defaultOutput) {
throw new Error("No ymlgen:output config found");
}
generators.push({
name: defaultGenerator,
output: defaultOutput,
select: defaultSelect,
});
}
if (!generators.length) {
throw new Error("No ymlgen:generator config found");
}
return { generators, importedData, onSuccess, onFail, onDone };
};
const convertToString = (value) => {
return typeof value === "undefined" || value === null ? "" : String(value);
};
const selectData = (data, path) => {
if (!path) {
return data;
}
return path.split(".").reduce((prev, p) => prev === null || prev === void 0 ? void 0 : prev[p], data);
};
const processFile = ({ generatorWorkspaceDir, dataFileWorkspaceDir: _, dataFile, content, configResolver, includeFileReader, getGenerator, fileName, writeFile, }) => __awaiter(void 0, void 0, void 0, function* () {
const { generators, importedData, onDone, onFail, onSuccess } = readConfigs((0, path_1.resolve)(generatorWorkspaceDir, "data"), content, configResolver, includeFileReader);
let error;
try {
yield Promise.all(generators.map((g) => __awaiter(void 0, void 0, void 0, function* () {
const isMultipleOutput = g.output.includes("**");
const data = (0, yamljs_1.parse)(content);
if (!data) {
// invalid data
return;
}
const generator = yield getGenerator(g.name);
if (isMultipleOutput) {
const privateData = {};
const promises = Object.keys(data).map((key) => __awaiter(void 0, void 0, void 0, function* () {
const subData = data[key];
// skip private key
if (key[0] === "__") {
Object.assign(privateData, { [key]: subData });
return;
}
const selectedData = selectData(subData, g.select);
const finalData = (0, lodash_1.merge)({}, ...importedData, privateData, selectedData);
const [fileName, generatorName] = key.split(":");
const customGenerator = generatorName
? yield getGenerator(generatorName)
: generator;
const content = yield generateText(dataFile, finalData, selectedData, customGenerator);
yield writeFile(g.output.replace("**", fileName), content);
}));
yield Promise.all(promises);
return;
}
const selectedData = selectData(data, g.select);
const finalData = (0, lodash_1.merge)({}, ...importedData, selectedData);
const generatedText = yield generateText(dataFile, finalData, selectedData, generator);
yield writeFile(g.output.replace("*", fileName), generatedText);
})));
}
catch (ex) {
error = ex;
}
return { onDone, onSuccess, onFail, error };
});
exports.processFile = processFile;
const generateText = (dataFile, data, rawData, generator) => __awaiter(void 0, void 0, void 0, function* () {
const texts = [];
const options = {};
const context = createContext(dataFile, texts, data, rawData, options);
while (true) {
let result = yield generator(context);
if (typeof result !== "function")
break;
generator = result;
}
return texts.join("");
});
const $use = (data, generator) => {
return (context) => context.extends(data).write(generator);
};
const $each = (data, generator, options = {}) => {
return (context) => __awaiter(void 0, void 0, void 0, function* () {
if (!data) {
throw new Error(`$each requires object or array for rendering but got ${typeof data} `);
}
let first = true;
let alt = false;
for (const [key, value] of Object.entries(data)) {
if (first && options.start) {
yield context.extends(data, options.extra).write(options.start);
}
if (!first && options.sep) {
yield context
.extends(value, Object.assign(Object.assign({}, options.extra), { key }))
.write(options.sep);
}
if (alt && options.alt) {
yield context
.extends(value, Object.assign(Object.assign({}, options.extra), { key }))
.write(options.alt);
}
else {
yield context
.extends(value, Object.assign(Object.assign({}, options.extra), { key }))
.write(generator);
}
alt = !alt;
first = false;
}
if (first && options.end) {
yield context.extends(data, options.extra).write(options.end);
}
});
};
const createContext = (dataFile, texts, data, rawData, options, extraProps) => {
const context = Object.assign(Object.assign({ key: undefined }, extraProps), { dataFile,
texts,
data,
rawData,
options,
$each,
$use,
extra(values) {
extraProps = Object.assign({}, extraProps, values);
},
extends(newData, newExtraProps) {
return createContext(dataFile, texts, newData, rawData, options, Object.assign(Object.assign({}, extraProps), newExtraProps));
},
configure(newOptions) {
Object.assign(options, newOptions);
},
write(...args) {
if (args.length) {
return (() => __awaiter(this, void 0, void 0, function* () {
for (const arg of args) {
if (typeof arg === "function") {
yield arg(context);
}
else {
texts.push(convertToString(arg));
}
}
}))();
}
return (strings, ...values) => __awaiter(this, void 0, void 0, function* () {
const copyOfStrings = strings.slice();
const next = () => __awaiter(this, void 0, void 0, function* () {
if (!copyOfStrings.length) {
return;
}
texts.push(copyOfStrings.shift());
if (!values.length) {
return;
}
let text;
const value = values.shift();
if (typeof value === "function") {
const childContext = context.extends(data);
let f = value;
while (true) {
const result = yield f(childContext);
if (typeof result !== "function") {
text = convertToString(result);
break;
}
f = result;
}
}
else {
text = convertToString(value);
}
if (options.autoTrim === "all") {
text = text.trim();
}
texts.push(text);
yield next();
});
yield next();
});
} });
return context;
};
//# sourceMappingURL=generator.js.map