hygen-create
Version:
simplifies creation of hygen templates from existing projects
595 lines • 49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ts_utils_1 = require("@ronp001/ts-utils");
const templatizer_1 = require("./templatizer");
const chalk_1 = require("chalk");
const APP_VERSION = "0.2.0";
class HygenCreateError extends Error {
constructor(msg) {
super(msg);
this.msg = msg;
}
get message() { return "hygen-create - " + this.msg; }
}
exports.HygenCreateError = HygenCreateError;
(function (HygenCreateError) {
class NoSessionInProgress extends HygenCreateError {
constructor() { super("no hygen-create session definitions file found ('hygen-create start' to create one)"); }
}
HygenCreateError.NoSessionInProgress = NoSessionInProgress;
class FromNameNotDefined extends HygenCreateError {
constructor() { super("'name word' not specified (run 'hygen-create usename' to set)"); }
}
HygenCreateError.FromNameNotDefined = FromNameNotDefined;
class CantParseSessionFile extends HygenCreateError {
constructor(file) { super(`can't parse session file - ${file}`); }
}
HygenCreateError.CantParseSessionFile = CantParseSessionFile;
class SessionInProgress extends HygenCreateError {
constructor() { super("hygen-create session already in progress"); }
}
HygenCreateError.SessionInProgress = SessionInProgress;
class NothingToGenerate extends HygenCreateError {
constructor() { super("nothing to generate"); }
}
HygenCreateError.NothingToGenerate = NothingToGenerate;
class NoFilesAdded extends HygenCreateError {
constructor() { super("no files added"); }
}
HygenCreateError.NoFilesAdded = NoFilesAdded;
class TargetPathNotSet extends HygenCreateError {
constructor(reason) { super(`no target path for generator: ${reason}`); }
}
HygenCreateError.TargetPathNotSet = TargetPathNotSet;
class NoSuchPath extends HygenCreateError {
constructor(file) { super(`can't find path ${file}`); }
}
HygenCreateError.NoSuchPath = NoSuchPath;
class FileNotFound extends HygenCreateError {
constructor(file) { super(`file not found: ${file}`); }
}
HygenCreateError.FileNotFound = FileNotFound;
class InvalidSessionFile extends HygenCreateError {
constructor(file) { super(`invalid session file -- [${file}]`); }
}
HygenCreateError.InvalidSessionFile = InvalidSessionFile;
class InvalidSessionFileVersion extends HygenCreateError {
constructor(file, version) { super(`session file version too high (${version}) -- ${file}: consider upgrading hygen-create`); }
}
HygenCreateError.InvalidSessionFileVersion = InvalidSessionFileVersion;
class TryingToStartSessionWithoutPath extends HygenCreateError {
constructor() { super(`session can only be started after valid path is set`); }
}
HygenCreateError.TryingToStartSessionWithoutPath = TryingToStartSessionWithoutPath;
class AddedFileMustBeUnderBaseDir extends HygenCreateError {
constructor(file, basedir) { super(`cannot add ${file} - not under base dir (${basedir})`); }
}
HygenCreateError.AddedFileMustBeUnderBaseDir = AddedFileMustBeUnderBaseDir;
})(HygenCreateError = exports.HygenCreateError || (exports.HygenCreateError = {}));
class HygenCreateSession {
constructor() {
this.about = "This is a hygen-create definitions file. The hygen-create utility creates generators that can be executed using hygen.";
this.hygen_create_version = APP_VERSION;
this.name = "";
this.files_and_dirs = {};
this.templatize_using_name = null;
this.gen_parent_dir = false;
}
static arrayToFilesHash(arr) {
let result = {};
for (let f of arr) {
result[f] = true;
}
return result;
}
}
exports.HygenCreateSession = HygenCreateSession;
class HygenCreate {
constructor() {
this.session = null;
this.session_file_name = HygenCreate.default_session_file_name;
this.session_file_path = new ts_utils_1.AbsPath(null);
this.session_base_dir = new ts_utils_1.AbsPath(null);
this.orig_session_json = ""; // used to check if the state was changed and needs saving
this.loaded_session_version = null;
this._debug_on = false;
this.output = console.log;
this.debug = this.noOutput;
}
get targetDirWithInfo() {
let tried = [];
for (let entry of [
{ using: "HYGEN_CREATE_TMPLS", value: process.env.HYGEN_CREATE_TMPLS },
{ using: "HYGEN_TMPLS", value: process.env.HYGEN_TMPLS },
{ using: "local dir", value: './_templates' }
]) {
if (entry.value) {
let ap = new ts_utils_1.AbsPath(entry.value);
if (ap.isDir) {
let explain = tried.join(", ");
if (explain != "")
explain = "(because " + explain + ")";
return { using: `using ${entry.using} ${explain}`, path: ap };
}
else if (ap.exists) {
tried.push(`${entry.using} (${entry.value}) exists but is not a directory`);
}
else {
tried.push(`${entry.using} (${entry.value}) does not exist`);
}
}
else {
tried.push(`${entry.using} not set`);
}
}
return { using: tried.join(", "), path: new ts_utils_1.AbsPath(null) };
}
get targetDirForGenerators() {
return this.targetDirWithInfo.path;
}
get targetDirForGeneratorsReason() {
return this.targetDirWithInfo.using;
}
get targetDirForGenerator() {
if (this.session == null)
return new ts_utils_1.AbsPath(null);
if (this.session.name == "")
return new ts_utils_1.AbsPath(null);
return this.targetDirForGenerators.add(this.session.name).add('new');
}
get fileCount() {
if (this.session == null)
return 0;
let result = 0;
for (let relpath in this.session.files_and_dirs) {
if (this.session.files_and_dirs[relpath] && this.fileAbsPathFromRelPath(relpath).exists) {
result++;
}
}
return result;
}
/**
* Where to find the current session file
*
* @return AbsPath object pointing to the file. If not set, AbsPath(null).
*/
get pathToCurrentSessionFile() {
return this.session_file_path;
}
get debugOn() {
return this._debug_on;
}
activateDebug() {
this.debug = console.log;
}
noOutput(...args) { }
// private debug : (...args:any[])=>void = this.output
set outputFunc(out_func) {
this.output = out_func;
}
get outputFunc() { return this.output; }
set debugFunc(out_func) {
this.debug = out_func;
}
/**
* binds the HygenCreate instance to a specific path.
* if a session already exists for this path (i.e., a session file exists in this directory or in one
* of its ancestors) loads the session. the location of the session file marks the topmost directory
* in the interactive session.
*
* @param for_path: <directory | file>
*
* if directory: indicates where to start looking for the hygen-create session file.
* if no session file found this is where a new one should be created if necessary
*
* if file: path to a session file
*
* @returns true if existing session file loaded, false if not
* @throws error if encountered problem trying to load the file
*/
setPathAndLoadSessionIfExists(for_path) {
this.debug("HygenCreate starting:", for_path);
let p = new ts_utils_1.AbsPath(for_path);
if (p.isDir) {
let path_to_file = p.findUpwards(this.session_file_name);
if (path_to_file.isFile) {
p = path_to_file;
}
}
if (p.isFile) {
// load the session file
let sessionfile_contents = p.contentsFromJSON;
if (sessionfile_contents == null) {
throw new HygenCreateError.CantParseSessionFile(p.abspath);
}
// verify the structure
let versionstr = sessionfile_contents['hygen_create_version'];
if (!versionstr || !versionstr.split)
throw new HygenCreateError.InvalidSessionFile(p.abspath);
let version = sessionfile_contents['hygen_create_version'].split('.').map((n) => { return parseInt(n); });
if (isNaN(version[0]) || isNaN(version[1]) || isNaN(version[2])) {
if (this.debugOn) {
console.log("hygen_create_version", sessionfile_contents['hygen_create_version']);
console.log("version", version);
console.log("sessionfile contents", sessionfile_contents);
}
throw new HygenCreateError.InvalidSessionFile(p.abspath);
}
if (version[0] > 0 || version[1] > 2) {
throw new HygenCreateError.InvalidSessionFileVersion(p.abspath, version);
}
this.loaded_session_version = version;
// convert arrays to hashes if necessary
if (sessionfile_contents.files_and_dirs instanceof Array) {
sessionfile_contents.files_and_dirs = HygenCreateSession.arrayToFilesHash(sessionfile_contents.files_and_dirs);
}
// create the session object
this.session = Object.assign(new HygenCreateSession, sessionfile_contents);
if (this.session == null) {
throw new HygenCreateError.InvalidSessionFile(p.abspath);
}
this.orig_session_json = JSON.stringify(this.session);
if (version[0] == 0 && version[1] == 1 && !this.session.gen_parent_dir) { // backwards compatibility
this.session.gen_parent_dir = true;
this.output(chalk_1.default.red("Note: the session was started using hygen-create v0.1.x. Parent dir generation is turned on for compatibility.\nUse 'hygen-create setopt --no-parent-dir' to turn off"));
}
this.session_file_path = p;
this.session_base_dir = p.parent;
return true;
}
else if (p.isDir) {
this.session_base_dir = p;
this.session_file_path = this.session_base_dir.add(this.session_file_name);
return false;
}
else {
throw new HygenCreateError.NoSuchPath(p.abspath);
}
}
/**
* returns true if a session was started - either by loading one (when setPathAndLoadSessionIfExists was called)
* or via start()
*/
get isSessionActive() {
return this.session != null;
}
/**
* @returns true if there is an active session and it has been modified since loaded, or if it's new
*/
get doesSessionNeedSaving() {
this.debug("this.session", JSON.stringify(this.session));
this.debug("this.orig_session_json", this.orig_session_json);
if (!this.session)
return false;
return JSON.stringify(this.session) != this.orig_session_json;
}
/**
* @returns true if session required saving, false otherwise
*/
saveSessionIfActiveAndChanged() {
if (this.session && this.doesSessionNeedSaving) {
this.debug("saving session");
this.session.hygen_create_version = APP_VERSION;
this.session_file_path.saveStrSync(JSON.stringify(this.session, null, 2));
return true;
}
this.debug("session does not need saving");
return false;
}
/**
* start a new session
*
* throws error if another session is already in progress
*/
startSession(name) {
if (this.session != null)
throw new HygenCreateError.SessionInProgress;
if (!this.session_base_dir.isDir)
throw new HygenCreateError.TryingToStartSessionWithoutPath;
this.session = new HygenCreateSession;
this.session.name = name;
this.session.files_and_dirs[this.session_file_name] = true;
}
renameSession(name) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
this.session.name = name;
}
/**
* cancel the current session and delete the session file
*/
abort() {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
this.session = null;
if (this.session_file_path.isFile) {
this.session_file_path.rmFile();
}
}
add(files_and_dirs, recursive = false, in_subdir = false) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (this.session_base_dir == null)
throw new HygenCreateError.NoSessionInProgress;
for (let file of files_and_dirs) {
let p = ts_utils_1.AbsPath.fromStringAllowingRelative(file.toString());
if (!p.exists) {
throw new HygenCreateError.FileNotFound(p.toString());
}
let relpath = p.relativeFrom(this.session_base_dir, true);
if (relpath == null) {
throw new HygenCreateError.AddedFileMustBeUnderBaseDir(p.toString(), this.session_base_dir.toString());
}
if (p.isFile || p.isSymLink) {
if (this.session.files_and_dirs[relpath]) {
this.output("already added:", relpath);
}
else {
if (p.isBinaryFile) {
this.output(chalk_1.default.red("not adding binary file: " + relpath));
}
else {
this.output("adding: ", relpath);
this.session.files_and_dirs[relpath] = true;
this.debug("session after add", this.session);
}
}
}
else if (p.isDir) {
if (in_subdir && !recursive) {
this.debug("not recursive - ignoring subdir", relpath);
}
else {
let contents = p.dirContents;
if (contents == null || contents == []) {
this.output("not adding empty directory: ", relpath);
}
else {
this.output("adding directory: ", relpath);
this.add(contents.map(e => e.toString()), recursive, true);
}
}
}
else {
this.output("not adding", relpath, "-- illegal file type");
}
}
}
remove(files) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (this.session_base_dir == null)
throw new HygenCreateError.NoSessionInProgress;
for (let file of files) {
let p = ts_utils_1.AbsPath.fromStringAllowingRelative(file);
let relpath = p.relativeFrom(this.session_base_dir, true);
if (relpath == null) {
throw new HygenCreateError.AddedFileMustBeUnderBaseDir(p.toString(), this.session_base_dir.toString());
}
if (this.session.files_and_dirs[relpath] == true) {
this.output("removing from generator:", relpath);
delete (this.session.files_and_dirs[relpath]);
}
else {
this.output("was not previously added: ", relpath);
}
}
}
/**
* get the definition of param
*
* @param param the param to query
* @returns word that is converted into this param, or null if param is not defined
*/
getWordConversion(word) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
return this.session.templatize_using_name;
}
/**
* generate templates for all files that are included in the current session
*
* @param from_name the word to replace with <%= name %> in the included files
* @returns information about the would-be generated templates
*/
getTemplatesUsingName(from_name) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
let result = [];
for (let file in this.session.files_and_dirs) {
if (this.session.files_and_dirs[file]) {
result.push(this.getTemplate(file, from_name));
}
}
return result;
}
/**
* generate a template from a single file
*
* @param relpath relative path to the original file
* @param using_name word to use for templatization of the <%= name %> variable
*/
getTemplate(relpath, using_name) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (using_name == null) {
if (this.session.templatize_using_name == null)
throw new HygenCreateError.FromNameNotDefined;
using_name = this.session.templatize_using_name;
}
let abspath = this.fileAbsPathFromRelPath(relpath);
let tinfo = templatizer_1.Templatizer.process(relpath, abspath, using_name, this.session.gen_parent_dir);
return tinfo;
}
get templates() {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (this.session.templatize_using_name == null)
throw new HygenCreateError.FromNameNotDefined;
return this.getTemplatesUsingName(this.session.templatize_using_name);
}
setGenParentDir(value) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
this.session.gen_parent_dir = value;
}
useName(name) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (this.session.templatize_using_name == name) {
this.output(`already using '${name}' to templatize files`);
}
else {
let prev = this.session.templatize_using_name;
this.session.templatize_using_name = name;
if (prev) {
this.output(`using '${name}' as templatization word (instead of '${prev}')`);
}
else {
this.output(`using '${name}' as templatization word`);
}
}
}
paramInfo(param) {
if (param) {
return `details for ${param}`;
}
else {
return "details for all params";
}
}
fileAbsPathFromRelPath(relpath) {
return ts_utils_1.AbsPath.fromStringAllowingRelative(relpath, this.session_base_dir.toString());
}
getFileInfo(files, verbose) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (this.session_base_dir == null)
throw new HygenCreateError.NoSessionInProgress;
let result = [];
if (files instanceof Array && files.length == 0) {
let existing_files = this.session.files_and_dirs;
for (let file in existing_files) {
let abspath = this.fileAbsPathFromRelPath(file);
files.push(abspath.toString());
}
}
for (let file of files) {
let p = ts_utils_1.AbsPath.fromStringAllowingRelative(file);
let relpath_from_top = p.relativeFrom(this.session_base_dir);
let included = false;
let found = false;
let is_binary = p.isBinaryFile;
if (relpath_from_top != null) {
found = true;
included = this.session.files_and_dirs[relpath_from_top] == true;
}
let fileinfo = {
path: p,
included: included,
found: found,
is_binary: is_binary
};
result.push(fileinfo);
}
return result;
}
forEachGeneratedFile(fn) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
for (let rel_path in this.session.files_and_dirs) {
if (this.session.files_and_dirs[rel_path]) {
let src_path = this.fileAbsPathFromRelPath(rel_path);
if (src_path.isFile && !src_path.isBinaryFile) {
let target_path = this.targetDirForGenerator.add(templatizer_1.Templatizer.template_filename(rel_path));
let abort = fn(rel_path, src_path, target_path);
if (abort)
return;
}
}
}
}
isGeneratedSameAsExisting() {
let found_diff = false;
// fail if the file count is not identical
let existing_files = this.targetDirForGenerator.dirContents;
let num_existing_files = existing_files == null ? 0 : existing_files.length;
if (num_existing_files != this.fileCount)
return false;
this.forEachGeneratedFile((rel_path, src_path, target_path) => {
if (!target_path.isFile) {
found_diff = true;
return true;
}
let existing_contents = target_path.contentsBuffer.toString();
let new_contents = this.getTemplateTextFor(rel_path);
if (existing_contents != new_contents) {
found_diff = true;
return true;
}
return false;
});
return !found_diff;
}
generate(compare_to_previous = true) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (this.fileCount == 0)
throw new HygenCreateError.NothingToGenerate;
if (!this.targetDirForGenerator.isSet)
throw new HygenCreateError.TargetPathNotSet(this.targetDirForGeneratorsReason);
if (compare_to_previous && this.targetDirForGenerator.exists) {
if (!this.isGeneratedSameAsExisting()) {
let newname = this.targetDirForGenerator.renameToNextVer();
this.output(chalk_1.default.red("previous version of generator renamed to", newname));
this.generate(false);
}
else {
this.output(chalk_1.default.red("generator unchanged - not saving"));
}
return;
}
this.output("target path for new generator: ", this.targetDirForGenerators.toString());
for (let file in this.session.files_and_dirs) {
if (this.session.files_and_dirs[file]) {
this.generateTemplateForFile(file);
}
}
}
generateTemplateForFile(relpath, force = false) {
if (this.session == null)
throw new HygenCreateError.NoSessionInProgress;
if (!this.targetDirForGenerator.isSet)
throw new HygenCreateError.TargetPathNotSet(this.targetDirForGeneratorsReason);
let input_file = this.fileAbsPathFromRelPath(relpath);
if (!input_file.isFile) {
this.output(`generate ${input_file.toString()}: only regular files are currently supported`);
return;
}
// let output_file = this.targetDirForGenerator.add(relpath.replace('/','_') + ".ejs.t")
let output_file = this.targetDirForGenerator.add(templatizer_1.Templatizer.template_filename(relpath));
if (!force && output_file.exists) {
this.output("file exists (not overwriting):", output_file.abspath);
}
else {
if (force) {
this.output(chalk_1.default.red("overwriting: " + output_file.abspath));
}
else {
this.output("generating:", output_file.abspath);
}
// this.output(this.getTemplateTextFor(relpath, input_file))
output_file.saveStrSync(this.getTemplateTextFor(relpath));
}
}
getTemplateTextFor(relpath) {
let tinfo = this.getTemplate(relpath, null);
if (tinfo.is_binary) {
return "<binary file>";
}
return tinfo.header + tinfo.contentsAfterReplacements;
}
}
HygenCreate.default_session_file_name = "hygen-create.json";
exports.HygenCreate = HygenCreate;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHlnZW4tY3JlYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2h5Z2VuLWNyZWF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGdEQUEyQztBQUMzQywrQ0FBeUQ7QUFDekQsaUNBQXlCO0FBSXpCLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQTtBQUUzQixNQUFhLGdCQUFpQixTQUFRLEtBQUs7SUFDdkMsWUFBbUIsR0FBVztRQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUF6QixRQUFHLEdBQUgsR0FBRyxDQUFRO0lBQWUsQ0FBQztJQUM5QyxJQUFXLE9BQU8sS0FBSyxPQUFPLGlCQUFpQixHQUFHLElBQUksQ0FBQyxHQUFHLENBQUEsQ0FBQyxDQUFDO0NBQy9EO0FBSEQsNENBR0M7QUFFRCxXQUFpQixnQkFBZ0I7SUFDN0IsTUFBYSxtQkFBb0IsU0FBUSxnQkFBZ0I7UUFBRyxnQkFBZ0IsS0FBSyxDQUFDLHFGQUFxRixDQUFDLENBQUEsQ0FBQyxDQUFDO0tBQUU7SUFBL0osb0NBQW1CLHNCQUE0SSxDQUFBO0lBQzVLLE1BQWEsa0JBQW1CLFNBQVEsZ0JBQWdCO1FBQUcsZ0JBQWdCLEtBQUssQ0FBQywrREFBK0QsQ0FBQyxDQUFBLENBQUMsQ0FBQztLQUFFO0lBQXhJLG1DQUFrQixxQkFBc0gsQ0FBQTtJQUNySixNQUFhLG9CQUFxQixTQUFRLGdCQUFnQjtRQUFHLFlBQVksSUFBbUIsSUFBSSxLQUFLLENBQUMsOEJBQThCLElBQUksRUFBRSxDQUFDLENBQUEsQ0FBQyxDQUFDO0tBQUU7SUFBbEkscUNBQW9CLHVCQUE4RyxDQUFBO0lBQy9JLE1BQWEsaUJBQWtCLFNBQVEsZ0JBQWdCO1FBQUcsZ0JBQWdCLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFBLENBQUMsQ0FBQztLQUFFO0lBQWxILGtDQUFpQixvQkFBaUcsQ0FBQTtJQUMvSCxNQUFhLGlCQUFrQixTQUFRLGdCQUFnQjtRQUFHLGdCQUFnQixLQUFL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