piral-cli
Version:
The standard CLI for creating and building a Piral instance or a Pilet.
481 lines • 18.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDestination = getDestination;
exports.removeAny = removeAny;
exports.removeDirectory = removeDirectory;
exports.createDirectory = createDirectory;
exports.getEntryFiles = getEntryFiles;
exports.makeTempDir = makeTempDir;
exports.checkExists = checkExists;
exports.checkExistingDirectory = checkExistingDirectory;
exports.checkIsDirectory = checkIsDirectory;
exports.getFileNames = getFileNames;
exports.findFile = findFile;
exports.matchAnyPilet = matchAnyPilet;
exports.matchFiles = matchFiles;
exports.createFileIfNotExists = createFileIfNotExists;
exports.updateExistingFile = updateExistingFile;
exports.getHash = getHash;
exports.mergeWithJson = mergeWithJson;
exports.readJson = readJson;
exports.readBinary = readBinary;
exports.readText = readText;
exports.writeJson = writeJson;
exports.writeText = writeText;
exports.writeBinary = writeBinary;
exports.updateExistingJson = updateExistingJson;
exports.copy = copy;
exports.remove = remove;
exports.removeFile = removeFile;
exports.move = move;
exports.getSourceFiles = getSourceFiles;
const typescript_1 = require("typescript");
const path_1 = require("path");
const fs_1 = require("fs");
const fs_2 = require("fs");
const fs_3 = require("fs");
const constants_1 = require("./constants");
const log_1 = require("./log");
const merge_1 = require("./merge");
const hash_1 = require("./hash");
const enums_1 = require("./enums");
const interactive_1 = require("./interactive");
const external_1 = require("../external");
function promptOverwrite(file) {
const message = `The file ${file} exists already. Do you want to overwrite it?`;
return (0, interactive_1.promptConfirm)(message, false);
}
function isFile(file) {
return (0, fs_1.statSync)(file).isFile();
}
function getDestination(entryFiles, target) {
const isdir = (0, path_1.extname)(target) !== '.html';
if (isdir) {
return {
outDir: target,
outFile: (0, path_1.basename)(entryFiles),
};
}
else {
return {
outDir: (0, path_1.dirname)(target),
outFile: (0, path_1.basename)(target),
};
}
}
async function removeAny(target) {
const isDir = await checkIsDirectory(target);
if (isDir) {
await removeDirectory(target);
}
else {
await removeFile(target);
}
}
function removeDirectory(targetDir) {
(0, log_1.log)('generalDebug_0003', `Removing the directory "${targetDir}" ...`);
return (0, external_1.rimraf)(targetDir);
}
async function createDirectory(targetDir) {
try {
(0, log_1.log)('generalDebug_0003', `Trying to create "${targetDir}" ...`);
await new Promise((resolve, reject) => {
(0, fs_2.mkdir)(targetDir, { recursive: true }, (err) => (err ? reject(err) : resolve()));
});
return true;
}
catch (e) {
(0, log_1.log)('cannotCreateDirectory_0044');
(0, log_1.log)('generalDebug_0003', `Error while creating ${targetDir}: ${e}`);
return false;
}
}
async function getEntryFiles(content, basePath) {
(0, log_1.log)('generalDebug_0003', `Extract entry files from "${basePath}".`);
const matcher = /<script\s.*?src=(?:"(.*?)"|'(.*?)'|([^\s>]*)).*?>/gi;
const results = [];
let result = undefined;
while ((result = matcher.exec(content))) {
const src = result[1] || result[2] || result[3];
(0, log_1.log)('generalDebug_0003', `Found potential entry file "${src}".`);
const filePath = (0, path_1.resolve)(basePath, src);
const exists = await checkExists(filePath);
if (exists) {
results.push(filePath);
}
}
return results;
}
function makeTempDir(prefix) {
return new Promise((resolve, reject) => (0, fs_2.mkdtemp)(prefix, (err, folder) => {
if (err) {
reject(err);
}
else {
resolve(folder);
}
}));
}
function checkExists(target) {
return new Promise((resolve) => {
if (target !== undefined) {
(0, fs_1.exists)(target, resolve);
}
else {
resolve(false);
}
});
}
async function checkExistingDirectory(target) {
(0, log_1.log)('generalDebug_0003', `Checking directory "${target}" ...`);
if (await checkExists(target)) {
(0, log_1.log)('generalDebug_0003', `Target exists, but not yet clear if directory.`);
return await checkIsDirectory(target);
}
return false;
}
function checkIsDirectory(target) {
return new Promise((resolve) => {
(0, fs_1.lstat)(target, (err, stats) => {
if (err) {
resolve((0, path_1.extname)(target) === '');
}
else {
resolve(stats.isDirectory());
}
});
});
}
function getFileNames(target) {
return new Promise((resolve, reject) => {
(0, fs_3.readdir)(target, (err, files) => (err ? reject(err) : resolve(files)));
});
}
async function findFile(topDir, fileName, stopDir = (0, path_1.resolve)(topDir, '/')) {
const fileNames = Array.isArray(fileName) ? fileName : [fileName];
for (const fn of fileNames) {
const path = (0, path_1.join)(topDir, fn);
const exists = await checkExists(path);
if (exists) {
return path;
}
}
if (topDir !== stopDir) {
const parentDir = (0, path_1.resolve)(topDir, '..');
return await findFile(parentDir, fileNames, stopDir);
}
return undefined;
}
function matchPattern(baseDir, pattern) {
return new Promise((resolve, reject) => {
(0, external_1.glob)(pattern, {
cwd: baseDir,
nodir: true,
absolute: true,
}, (err, files) => {
if (err) {
reject(err);
}
else {
resolve(files);
}
});
});
}
async function matchAnyPattern(baseDir, pattern) {
const matches = await Promise.all(pattern.patterns.map((pattern) => matchPattern(baseDir, pattern)));
return {
pattern: pattern.original,
results: matches.reduce((agg, curr) => [...agg, ...curr], []),
};
}
const preferences = ['.tsx', '.ts', '.jsx', '.js', '.mjs', '.cjs', '.esm', '.es', '.es6', '.html'];
async function matchAnyPilet(baseDir, patterns) {
const matches = [];
const pilets = [];
const matched = (name, path) => {
pilets.push(name);
matches.push(path);
};
const exts = preferences.map((s) => s.substring(1)).join(',');
const allPatterns = patterns.reduce((agg, curr) => {
const patterns = [];
if (/[a-zA-Z0-9\-\*]$/.test(curr) && !preferences.find((ext) => curr.endsWith(ext))) {
patterns.push(curr, `${curr}.{${exts}}`, `${curr}/${constants_1.packageJson}`, `${curr}/${constants_1.piletJson}`);
}
else if (curr.endsWith('/')) {
patterns.push(`${curr}index.{${exts}}`, `${curr}${constants_1.packageJson}`, `${curr}${constants_1.piletJson}`);
}
else if (curr === '.' || curr === '..') {
patterns.push(`${curr}/index.{${exts}}`, `${curr}/${constants_1.packageJson}`, `${curr}/${constants_1.piletJson}`);
}
else {
patterns.push(curr);
}
agg.push({ original: curr, patterns });
return agg;
}, []);
await Promise.all(allPatterns.map((patterns) => matchAnyPattern(baseDir, patterns).then(async ({ results, pattern }) => {
if (!results.length) {
(0, log_1.log)('generalDebug_0003', `Found no potential entry points using "${pattern}".`);
}
else {
//TODO -> shouldn't take the first one,
// should be the first one, yes, but, PER pilet
// so that multiple pilets can be considered, too
(0, log_1.log)('generalDebug_0003', `Found ${results.length} potential entry points in "${pattern}".`);
for (const result of results) {
const fileName = (0, path_1.basename)(result);
if (fileName === constants_1.packageJson) {
(0, log_1.log)('generalDebug_0003', `Entry point is a "${constants_1.packageJson}" and needs further inspection.`);
const targetDir = (0, path_1.dirname)(result);
const { source, name } = await readJson(targetDir, fileName);
if (!pilets.includes(name)) {
if (typeof source === 'string') {
(0, log_1.log)('generalDebug_0003', `Found a "source" field with value "${source}".`);
const target = (0, path_1.resolve)(targetDir, source);
const exists = await checkExists(target);
if (exists) {
(0, log_1.log)('generalDebug_0003', `Taking existing target as "${target}".`);
matched(name, target);
}
else {
(0, log_1.log)('generalDebug_0003', `Source target "${target}" does not exist. Skipped.`);
}
}
else {
(0, log_1.log)('generalDebug_0003', `No "source" field found. Trying combinations in "src".`);
const files = await matchPattern(targetDir, `src/index.{${exts}}`);
if (files.length > 0) {
(0, log_1.log)('generalDebug_0003', `Found a result; taking "${files[0]}".`);
matched(name, files[0]);
}
else {
(0, log_1.log)('generalDebug_0003', `Found no results in "src". Skipped.`);
}
}
}
}
else {
const packageJsonPath = await findFile(result, constants_1.packageJson);
if (packageJsonPath) {
const targetDir = (0, path_1.dirname)(packageJsonPath);
const { name } = await readJson(targetDir, constants_1.packageJson);
if (!pilets.includes(name)) {
(0, log_1.log)('generalDebug_0003', `Entry point result is "${result}".`);
matched(name, result);
}
}
else {
(0, log_1.log)('generalDebug_0003', `Could not find "${constants_1.packageJson}" for entry "${result}". Skipping.`);
}
}
}
}
})));
return matches;
}
function matchFiles(baseDir, pattern) {
return new Promise((resolve, reject) => {
(0, external_1.glob)(pattern, {
cwd: baseDir,
absolute: true,
dot: true,
}, (err, files) => {
if (err) {
reject(err);
}
else {
resolve(files.filter(isFile));
}
});
});
}
async function createFileIfNotExists(targetDir, fileName, content, forceOverwrite = enums_1.ForceOverwrite.no) {
const targetFile = (0, path_1.join)(targetDir, fileName);
(0, log_1.log)('generalDebug_0003', `Checking if file "${targetFile}" exists ...`);
const exists = await checkExists(targetFile);
if (!exists ||
forceOverwrite === enums_1.ForceOverwrite.yes ||
(forceOverwrite === enums_1.ForceOverwrite.prompt && (await promptOverwrite(targetFile)))) {
await createDirectory((0, path_1.dirname)(targetFile));
(0, log_1.log)('generalDebug_0003', `Creating file "${targetFile}" ...`);
if (typeof content === 'string') {
await writeText(targetDir, fileName, content);
}
else {
await writeBinary(targetDir, fileName, content);
}
}
}
async function updateExistingFile(targetDir, fileName, content) {
const targetFile = (0, path_1.join)(targetDir, fileName);
(0, log_1.log)('generalDebug_0003', `Checking if file "${targetFile}" exists ...`);
const exists = await checkExists(targetFile);
if (exists) {
(0, log_1.log)('generalDebug_0003', `Updating file "${targetFile}" ...`);
await new Promise((resolve, reject) => {
(0, fs_3.writeFile)(targetFile, content, 'utf8', (err) => (err ? reject(err) : resolve()));
});
}
}
async function getHash(targetFile) {
return new Promise((resolve) => {
(0, fs_3.readFile)(targetFile, (err, c) => (err ? resolve(undefined) : resolve((0, hash_1.computeHash)(c))));
});
}
async function mergeWithJson(targetDir, fileName, newContent) {
const targetFile = (0, path_1.join)(targetDir, fileName);
const content = await new Promise((resolve) => {
(0, fs_3.readFile)(targetFile, 'utf8', (err, c) => (err ? resolve('{}') : resolve(c)));
});
const originalContent = JSON.parse(content);
return (0, merge_1.deepMerge)(originalContent, newContent);
}
async function readJson(targetDir, fileName, defaultValue = {}) {
const targetFile = (0, path_1.join)(targetDir, fileName);
const content = await new Promise((resolve) => {
(0, fs_3.readFile)(targetFile, 'utf8', (err, c) => (err ? resolve('') : resolve(c)));
});
if (content) {
try {
return JSON.parse(content);
}
catch (ex) {
(0, log_1.log)('generalError_0002', `Invalid JSON found in file "${fileName}" at "${targetDir}".`);
}
}
return defaultValue;
}
function readBinary(targetDir, fileName) {
const targetFile = (0, path_1.join)(targetDir, fileName);
return new Promise((resolve) => {
(0, fs_3.readFile)(targetFile, (err, c) => (err ? resolve(undefined) : resolve(c)));
});
}
function readText(targetDir, fileName) {
const targetFile = (0, path_1.join)(targetDir, fileName);
return new Promise((resolve) => {
(0, fs_3.readFile)(targetFile, 'utf8', (err, c) => (err ? resolve(undefined) : resolve(c)));
});
}
function writeJson(targetDir, fileName, data, beautify = false) {
const text = beautify ? JSON.stringify(data, undefined, 2) : JSON.stringify(data);
return writeText(targetDir, fileName, text + '\n');
}
function writeText(targetDir, fileName, content) {
const data = Buffer.from(content, 'utf8');
return writeBinary(targetDir, fileName, data);
}
function writeBinary(targetDir, fileName, data) {
const targetFile = (0, path_1.join)(targetDir, fileName);
return new Promise((resolve, reject) => {
(0, fs_3.writeFile)(targetFile, data, (err) => (err ? reject(err) : resolve()));
});
}
async function updateExistingJson(targetDir, fileName, newContent) {
const content = await mergeWithJson(targetDir, fileName, newContent);
const text = JSON.stringify(content, undefined, 2);
await updateExistingFile(targetDir, fileName, text + '\n');
}
async function copy(source, target, forceOverwrite = enums_1.ForceOverwrite.no) {
await createDirectory((0, path_1.dirname)(target));
try {
const flag = forceOverwrite === enums_1.ForceOverwrite.yes ? 0 : fs_2.constants.COPYFILE_EXCL;
const isDir = await checkIsDirectory(source);
if (isDir) {
const files = await getFileNames(source);
const results = await Promise.all(files.map((file) => copy((0, path_1.resolve)(source, file), (0, path_1.resolve)(target, file), forceOverwrite)));
return results.every(Boolean);
}
else {
await new Promise((resolve, reject) => {
(0, fs_3.copyFile)(source, target, flag, (err) => (err ? reject(err) : resolve()));
});
return true;
}
}
catch (e) {
if (forceOverwrite === enums_1.ForceOverwrite.prompt) {
const shouldOverwrite = await promptOverwrite(target);
if (shouldOverwrite) {
return await copy(source, target, enums_1.ForceOverwrite.yes);
}
}
else {
(0, log_1.log)('didNotOverWriteFile_0045', target);
}
}
return false;
}
/**
* @deprecated Will be removed with v1. Please use "removeFile".
*/
function remove(target) {
return removeFile(target);
}
function removeFile(target) {
return new Promise((resolve, reject) => {
(0, fs_1.unlink)(target, (err) => {
if (err) {
reject(err);
}
else {
resolve();
}
});
});
}
async function move(source, target, forceOverwrite = enums_1.ForceOverwrite.no) {
const dir = await checkIsDirectory(target);
if (dir) {
const file = (0, path_1.basename)(source);
target = (0, path_1.resolve)(target, file);
}
const success = await copy(source, target, forceOverwrite);
if (success) {
await removeFile(source);
return target;
}
return source;
}
function isVersion5OrHigher() {
const currentMajor = parseInt(typescript_1.version.split('.').shift());
return currentMajor >= 5;
}
async function getSourceFiles(entry) {
const dir = (0, path_1.dirname)(entry);
(0, log_1.log)('generalDebug_0003', `Trying to get source files from "${dir}" ...`);
const files = await matchFiles(dir, '**/*.?(jsx|tsx|js|ts)');
return files.map((path) => {
const directory = (0, path_1.dirname)(path);
const name = (0, path_1.basename)(path);
return {
path,
directory,
name,
async read() {
const content = await readText(directory, name);
if (name.endsWith('.ts') || name.endsWith('.tsx')) {
return (0, typescript_1.transpileModule)(content, {
fileName: path,
moduleName: name,
compilerOptions: {
allowJs: true,
skipLibCheck: true,
declaration: false,
sourceMap: false,
checkJs: false,
jsx: typescript_1.JsxEmit.React,
module: typescript_1.ModuleKind.ESNext,
moduleResolution: isVersion5OrHigher() ? typescript_1.ModuleResolutionKind.Bundler : typescript_1.ModuleResolutionKind.Node10,
target: typescript_1.ScriptTarget.ESNext,
},
}).outputText;
}
return content;
},
};
});
}
//# sourceMappingURL=io.js.map