UNPKG

@harboor/core

Version:
255 lines (246 loc) 9 kB
'use strict'; var path = require('node:path'); var promises = require('node:fs/promises'); var clientSecretsManager = require('@aws-sdk/client-secrets-manager'); var os = require('node:os'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path); var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os); async function fileFinder(possibleFileNames, possiblePaths) { const possibleAbsPaths = possiblePaths.map(_p => _p.startsWith("/") ? _p : path.resolve(process.cwd(), _p)); const possibleFiles = createLoadingOrder(possibleFileNames, possibleAbsPaths); return findFile(possibleFiles); } function createLoadingOrder(filenames, possibleAbsPaths) { return possibleAbsPaths.reduce((memo, _path) => { memo = memo.concat(filenames.map(_name => path.resolve(_path, _name))); return memo; }, []); } async function findFile(possibleFiles) { for await (const file of possibleFiles) { if (await verifyFile(file)) { return file; } } return null; } async function verifyFile(_filepath) { try { await promises.access(_filepath, promises.constants.R_OK); return true; } catch (e) { return false; } } async function readTsConfig(possiblePaths, possibleFileNames = ["tsconfig.json"]) { const location = await fileFinder(possibleFileNames, possiblePaths); if (!location) return null; return JSON.parse(await promises.readFile(location, "utf-8")); } function isAliasPath(filepath, tsconfig) { const aliases = findAliases(tsconfig); return Object.keys(aliases).some(pattern => filepath.startsWith(pattern.replace("*", ""))); } function resolveAlias(alias, tsconfig, projectPath) { const _searchPath = projectPath ?? process.cwd(); const aliases = findAliases(tsconfig); const pattern = Object.keys(aliases).find(_pattern => alias.startsWith(_pattern.replace("*", ""))); if (!pattern.includes("*")) { return aliases[pattern].map(p => path.resolve(_searchPath, p)); } const _input = alias.replace(pattern.replace("*", ""), ""); return aliases[pattern].map(p => path.resolve(_searchPath, p.replace("*", _input))); } function findAliases(tsconfig) { return tsconfig ? tsconfig?.compilerOptions?.paths ?? {} : {}; } function pathv(relativePath) { return relativePath; } const rePathvCalls = `(pathv\\(('|")(.*)('|"))\\)`; const rePathvCallsGM = new RegExp(rePathvCalls, "gm"); const rePathvCallsNoFlag = new RegExp(rePathvCalls, ""); function hasPathvCalls(content) { return rePathvCallsGM.test(content); } function findProjectPath(sourceRelativePath) { const _src = path.normalize(sourceRelativePath); const cwd = process.cwd(); return cwd.endsWith(_src) ? path.resolve(cwd, _src.split("/").map(() => "..").join("/")) : cwd; } async function processPathvCalls(content, fileAbsPath, sourceRelativePath, distRelativePath) { const projectPath = findProjectPath(sourceRelativePath); const tsconfig = await readTsConfig([path.resolve(projectPath, sourceRelativePath), projectPath]); const analysis = analysePaths(content, fileAbsPath, projectPath, tsconfig, sourceRelativePath, distRelativePath); await distAnalysedFiles(analysis, projectPath); return formatSourceContent(content, analysis); } function formatSourceContent(content, analysis) { return Object.keys(analysis).reduce((memo, token) => memo.replace(token, analysis[token].pathvExp), `import * as path from 'node:path';` + content); } async function distAnalysedFiles(analysis, projectPath) { for await (const { realRelPath, relDistPath } of Object.values(analysis)) { const fileDistDir = path.resolve(projectPath, path.dirname(relDistPath)); await promises.mkdir(fileDistDir, { recursive: true }); await promises.copyFile(path.resolve(projectPath, realRelPath), path.resolve(projectPath, relDistPath)); } } function analysePaths(content, fileAbsPath, projectPath, tsconfig, sourceRelativePath, distRelativePath) { const matches = content.match(rePathvCallsGM); if (!matches) { return {}; } const matchesFormatted = matches.map(text => text.match(rePathvCallsNoFlag)); const result = {}; for (const _matches of matchesFormatted) { if (!_matches) continue; const input = _matches[3]; const inputType = findInputType(input); const realRelPath = findRealRelativePath(input, inputType); const relDistPath = findCorrespondingDistPath(realRelPath, inputType); result[_matches[0]] = { realRelPath, relDistPath, pathvExp: `path.resolve(import.meta.dirname, '${"./" + path.relative(distRelativePath, relDistPath)}')` }; } return result; function findRealRelativePath(input, inputType) { switch (inputType) { case "PROJECT_RELATIVE_OUTSIDE_SOURCE": return input; case "PROJECT_RELATIVE_IN_SOURCE": return input; case "ALIAS": const resolved = resolveAlias(input, tsconfig, projectPath)[0]; return "./" + path.relative(projectPath, resolved); case "ABSOLUTE": return input.includes(projectPath) ? path.relative(path.resolve(projectPath, sourceRelativePath), input) : input; } } function findCorrespondingDistPath(projectRelativeFilePath, inputType) { if (projectRelativeFilePath.startsWith("/")) { return path.join(projectPath, distRelativePath, projectRelativeFilePath); } if (inputType === "PROJECT_RELATIVE_OUTSIDE_SOURCE") { return "./" + path.join(distRelativePath, projectRelativeFilePath); } return "./" + path.join(distRelativePath, path.relative(sourceRelativePath, projectRelativeFilePath)); } function findInputType(input) { if (input.startsWith("/")) { return "ABSOLUTE"; } else if (tsconfig && isAliasPath(input, tsconfig)) { return "ALIAS"; } else if (path.normalize(input).includes(path.normalize(sourceRelativePath))) { return "PROJECT_RELATIVE_IN_SOURCE"; } else { return "PROJECT_RELATIVE_OUTSIDE_SOURCE"; } } } async function fetchSecretsAws({ aws, dest }) { const { credentials, secretName } = aws; const { region, accessKey, accessKeySecret } = credentials; const client = new clientSecretsManager.SecretsManagerClient({ region, credentials: { accessKeyId: accessKey, secretAccessKey: accessKeySecret } }); let response; try { response = await client.send(new clientSecretsManager.GetSecretValueCommand({ SecretId: secretName })); } catch (e) { return e; } if (!response.SecretString) { return new Error("No text found in the response."); } const secrets = JSON.parse(response.SecretString); const resolved = resolveReferencesRecursive(secrets); if (dest) { await save(dest, secrets); } return resolved; } function resolveReferencesRecursive(secrets, hadAtLeastOneReference = true) { if (!hadAtLeastOneReference) { return secrets; } const re = /\${([^}]*)}/g; const keys = Object.keys(secrets); const resolved = {}; let references = 0; for (const key of keys) { const v = secrets[key]; const matches = [...v.matchAll(re)]; if (matches.length > 0) references += matches.filter(m => m[1] in secrets).length; const resolvedValue = matches.reduce((memo, m) => m[1] in secrets ? memo.replace(m[0], secrets[m[1]]) : memo, v); resolved[key] = resolvedValue; } return resolveReferencesRecursive(resolved, references > 0); } async function save(dest, secrets) { const _dest = path__namespace.isAbsolute(dest) ? dest : path__namespace.resolve(process.cwd(), dest); const dir = path__namespace.dirname(_dest); await promises.mkdir(dir, { recursive: true }); const ext = path__namespace.extname(_dest); const format = ext === ".env" ? "dotenv" : ext === ".sh" ? "shell" : "dotenv"; const data = Object.keys(secrets).reduce((memo, name) => memo + processPair(format, name, secrets[name]), ""); await promises.writeFile(_dest, data, { mode: process.env.VITEST ? 0o777 : 0o455 }); return true; function processPair(format, name, value) { switch (format) { case "dotenv": return name + '="' + value + '"' + os__namespace.EOL; case "shell": return "export " + name + '="' + value + '"' + os__namespace.EOL; default: return name + '="' + value + '"' + os__namespace.EOL; } } } exports.fetchSecretsAws = fetchSecretsAws; exports.hasPathvCalls = hasPathvCalls; exports.pathv = pathv; exports.processPathvCalls = processPathvCalls; //# sourceMappingURL=index.cjs.map