@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
177 lines • 7.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
const constants_1 = require("../constants");
const LintService_1 = __importDefault(require("../services/LintService"));
class AbstractWriter {
templates;
ui;
linter;
upgradeMode;
fileDescriptions = [];
shouldConfirmBeforeWriting = true;
firstFileWriteMessage;
hasShownFirstWriteMessage = false;
settings;
isLintEnabled = true;
constructor(options) {
const { templates, term, upgradeMode, fileDescriptions, linter, settings, } = options;
this.templates = templates;
this.ui = term;
this.upgradeMode = upgradeMode;
this.fileDescriptions = fileDescriptions;
this.linter = linter;
this.settings = settings;
}
async lint(file) {
const shouldLint = !LintService_1.default.shouldIgnorePattern(file);
if (this.isLintEnabled && shouldLint) {
await this.linter?.fix(file).catch(() => { });
}
}
async writeDirectoryTemplate(options) {
const { context, destinationDir, filesToWrite, filesToSkip, shouldConfirmBeforeWriting = true, firstFileWriteMessage, } = options;
this.shouldConfirmBeforeWriting = shouldConfirmBeforeWriting;
this.firstFileWriteMessage = firstFileWriteMessage;
this.hasShownFirstWriteMessage = false;
const files = await this.templates.directoryTemplate({
kind: options.code,
context: context ?? {},
});
let results = [];
for (const generated of files) {
const shouldWrite = !filesToWrite || filesToWrite.indexOf(generated.filename) > -1;
const shouldSkip = filesToSkip && filesToSkip.indexOf(generated.filename) > -1;
if (shouldWrite && !shouldSkip) {
results = await this.writeFileIfChangedMixinResults(path_1.default.join(destinationDir, generated.relativePath), generated.contents, '', results, destinationDir);
}
}
return results;
}
async writeFileIfChangedMixinResults(destination, contents, description, results, cwd = '') {
const myResults = results ?? [];
let desc = description;
const name = path_1.default.basename(destination);
let action = 'skipped';
if (spruce_skill_utils_1.diskUtil.isDir(destination)) {
throw new Error(`Can't write to a directory ${destination}.`);
}
const fileDescription = this.getFileDescription(destination);
if (!spruce_skill_utils_1.diskUtil.doesFileExist(destination)) {
let write = true;
if (this.shouldConfirmBeforeWriting &&
fileDescription?.confirmPromptOnFirstWrite) {
this.ui.stopLoading();
write = await this.ui.confirm(fileDescription.confirmPromptOnFirstWrite);
}
if (write) {
spruce_skill_utils_1.diskUtil.writeFile(destination, contents);
action = 'generated';
}
}
else if (this.isFileDifferent(destination, contents) &&
this.shouldOverwriteIfChanged(destination)) {
const cleanedName = this.cleanFilename(destination, cwd);
const settings = { skipped: [], ...this.settings.get('writer') };
const isAlwaysSkipped = settings.skipped.indexOf(cleanedName) > -1;
let write = !isAlwaysSkipped;
if (!isAlwaysSkipped && this.shouldAskForOverwrite()) {
if (!this.hasShownFirstWriteMessage &&
this.firstFileWriteMessage) {
this.hasShownFirstWriteMessage = true;
this.ui.renderLine(this.firstFileWriteMessage);
this.ui.renderLine('');
}
const answer = await this.ui.prompt({
type: 'select',
label: `${cleanedName}`,
options: {
choices: [
{
value: constants_1.FILE_ACTION_OVERWRITE,
label: 'Overwrite',
},
{
value: constants_1.FILE_ACTION_SKIP,
label: 'Skip',
},
{
value: constants_1.FILE_ACTION_ALWAYS_SKIP,
label: 'Always skip',
},
],
},
});
if (answer === constants_1.FILE_ACTION_ALWAYS_SKIP) {
settings.skipped.push(cleanedName);
this.settings.set('writer', settings);
}
write = answer === constants_1.FILE_ACTION_OVERWRITE;
}
if (write) {
spruce_skill_utils_1.diskUtil.writeFile(destination, contents);
action = 'updated';
}
}
if (!desc) {
desc = fileDescription?.description;
}
if (!desc) {
throw new Error(`No FileDescription provided for ${destination.replace(cwd, '')}. Check your feature's fileDescriptions property.`);
}
myResults.push({ name, description: desc, path: destination, action });
await this.lint(destination);
return myResults;
}
isFileDifferent(destination, contents) {
return spruce_skill_utils_1.diskUtil.isFileDifferent(destination, contents);
}
cleanFilename(destination, cwd) {
let relativeFile = destination.replace(cwd, '');
if (relativeFile[0] === path_1.default.sep) {
relativeFile = relativeFile.substr(1);
}
return relativeFile;
}
shouldOverwriteIfChanged(destination) {
if (!this.upgradeMode) {
return true;
}
if (this.upgradeMode === 'forceEverything') {
return true;
}
let description = this.getFileDescription(destination);
return description?.shouldOverwriteWhenChanged ?? false;
}
getFileDescription(destination) {
const lower = destination.toLowerCase();
for (const d of this.fileDescriptions ?? []) {
if (lower.search(d.path.toLowerCase()) > -1) {
return d;
}
}
return undefined;
}
shouldAskForOverwrite() {
if (this.shouldConfirmBeforeWriting &&
this.upgradeMode === 'askForChanged') {
return true;
}
return false;
}
resolveFilenameWithFallback(dirOrFile, fallbackFileName) {
const isDir = spruce_skill_utils_1.diskUtil.doesDirExist(dirOrFile) &&
fs_1.default.lstatSync(dirOrFile).isDirectory() &&
path_1.default.extname(dirOrFile).length === 0;
return isDir
? spruce_skill_utils_1.diskUtil.resolvePath(dirOrFile, fallbackFileName)
: dirOrFile;
}
}
exports.default = AbstractWriter;
//# sourceMappingURL=AbstractWriter.js.map