UNPKG

piral-cli

Version:

The standard CLI for creating and building a Piral instance or a Pilet.

481 lines • 18.9 kB
"use strict"; 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