@appium/docutils
Version:
Documentation generation utilities for Appium and related projects
217 lines • 8.26 kB
JavaScript
"use strict";
/**
* Functions which touch the filesystem
* @module
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readMkDocsYml = exports.findPython = exports.findMike = exports.isMkDocsInstalled = exports.readJson = exports.readPackageJson = exports.findMkDocsYml = exports.stringifyJson = exports.stringifyYaml = void 0;
exports.findInPkgDir = findInPkgDir;
exports.writeFileString = writeFileString;
exports.requirePython = requirePython;
const support_1 = require("@appium/support");
const lodash_1 = __importDefault(require("lodash"));
const node_path_1 = __importDefault(require("node:path"));
const pkg_dir_1 = __importDefault(require("pkg-dir"));
const read_pkg_1 = __importDefault(require("read-pkg"));
const yaml_1 = __importDefault(require("yaml"));
const constants_1 = require("./constants");
const error_1 = require("./error");
const logger_1 = require("./logger");
const teen_process_1 = require("teen_process");
const log = (0, logger_1.getLogger)('fs');
/**
* Finds path to closest `package.json`
*
* Caches result
*/
const findPkgDir = lodash_1.default.memoize(pkg_dir_1.default);
/**
* Stringifies a thing into a YAML
* @param value Something to yamlify
* @returns Some nice YAML 4 u
*/
exports.stringifyYaml = lodash_1.default.partialRight(yaml_1.default.stringify, { indent: 2 }, undefined);
/**
* Pretty-stringifies a JSON value
* @param value Something to stringify
* @returns JSON string
*/
exports.stringifyJson = lodash_1.default.partialRight(JSON.stringify, 2, undefined);
/**
* Reads a YAML file, parses it and caches the result
*/
const readYaml = lodash_1.default.memoize(async (filepath) => yaml_1.default.parse(await support_1.fs.readFile(filepath, 'utf8'), {
prettyErrors: false,
logLevel: 'silent',
}));
/**
* Finds a file from `cwd`. Searches up to the package root (dir containing `package.json`).
*
* @param filename Filename to look for
* @param cwd Dir it should be in
* @returns
*/
async function findInPkgDir(filename, cwd = process.cwd()) {
const pkgDir = await findPkgDir(cwd);
if (!pkgDir) {
return;
}
return node_path_1.default.join(pkgDir, filename);
}
/**
* Finds an `mkdocs.yml`, expected to be a sibling of `package.json`
*
* Caches the result.
* @param cwd - Current working directory
* @returns Path to `mkdocs.yml`
*/
exports.findMkDocsYml = lodash_1.default.memoize(lodash_1.default.partial(findInPkgDir, constants_1.NAME_MKDOCS_YML));
async function _readPkgJson(cwd, normalize) {
const pkgDir = await findPkgDir(cwd);
if (!pkgDir) {
throw new error_1.DocutilsError(`Could not find a ${constants_1.NAME_PACKAGE_JSON} near ${cwd}; please create it before using this utility`);
}
const pkgPath = node_path_1.default.join(pkgDir, constants_1.NAME_PACKAGE_JSON);
log.debug('Found `package.json` at %s', pkgPath);
if (normalize) {
const pkg = await (0, read_pkg_1.default)({ cwd: pkgDir, normalize });
return { pkg, pkgPath };
}
else {
const pkg = await (0, read_pkg_1.default)({ cwd: pkgDir });
return { pkg, pkgPath };
}
}
/**
* Given a directory to start from, reads a `package.json` file and returns its path and contents
*/
exports.readPackageJson = lodash_1.default.memoize(_readPkgJson);
/**
* Reads a JSON file and parses it
*/
exports.readJson = lodash_1.default.memoize(async (filepath) => JSON.parse(await support_1.fs.readFile(filepath, 'utf8')));
/**
* Writes contents to a file. Any JSON objects are stringified
* @param filepath - Path to file
* @param content - File contents
*/
function writeFileString(filepath, content) {
const data = lodash_1.default.isString(content) ? content : JSON.stringify(content, undefined, 2);
return support_1.fs.writeFile(filepath, data, {
encoding: 'utf8',
});
}
/**
* `which` with memoization
*/
const cachedWhich = lodash_1.default.memoize(support_1.fs.which);
/**
* Finds `python` executable
*/
const whichPython = lodash_1.default.partial(cachedWhich, constants_1.NAME_PYTHON, { nothrow: true });
/**
* Finds `python3` executable
*/
const whichPython3 = lodash_1.default.partial(cachedWhich, `${constants_1.NAME_PYTHON}3`, { nothrow: true });
/**
* Check if `mkdocs` is installed
*/
exports.isMkDocsInstalled = lodash_1.default.memoize(async () => {
// see if it's in PATH
const mkDocsPath = await cachedWhich(constants_1.NAME_MKDOCS, { nothrow: true });
if (mkDocsPath) {
return true;
}
// if it isn't, it should be invokable via `python -m`
const pythonPath = await (0, exports.findPython)();
if (!pythonPath) {
return false;
}
try {
await (0, teen_process_1.exec)(pythonPath, ['-m', constants_1.NAME_MKDOCS]);
return true;
}
catch {
return false;
}
});
/**
* `mike` cannot be invoked via `python -m`, so we need to find the script.
*/
exports.findMike = lodash_1.default.partial(async () => {
// see if it's in PATH
let mikePath = await cachedWhich(constants_1.NAME_MIKE, { nothrow: true });
if (mikePath) {
return mikePath;
}
// if it isn't, it may be in a user dir
const pythonPath = await (0, exports.findPython)();
if (!pythonPath) {
return;
}
try {
// the user dir can be found this way.
// usually it's something like ~/.local
const { stdout } = await (0, teen_process_1.exec)(pythonPath, ['-m', 'site', '--user-base']);
if (stdout) {
mikePath = node_path_1.default.join(stdout.trim(), 'bin', 'mike');
if (await support_1.fs.isExecutable(mikePath)) {
return mikePath;
}
}
}
catch { }
});
/**
* Finds the `python3` or `python` executable in the user's `PATH`.
*
* `python3` is preferred over `python`, since the latter could be Python 2.
*/
exports.findPython = lodash_1.default.memoize(async () => (await whichPython3()) ?? (await whichPython()));
/**
* Check if a path to Python exists, otherwise raise DocutilsError
*/
async function requirePython(pythonPath) {
const foundPythonPath = pythonPath ?? (await (0, exports.findPython)());
if (!foundPythonPath) {
throw new error_1.DocutilsError(constants_1.MESSAGE_PYTHON_MISSING);
}
return foundPythonPath;
}
/**
* Reads an `mkdocs.yml` file, merges inherited configs, and returns the result. The result is cached.
*
* **IMPORTANT**: The paths of `site_dir` and `docs_dir` are resolved to absolute paths, since they
* are expressed as relative paths, and each inherited config file can live in different paths.
* @param filepath Patgh to an `mkdocs.yml` file
* @returns Parsed `mkdocs.yml` file
*/
exports.readMkDocsYml = lodash_1.default.memoize(async (filepath, cwd = process.cwd()) => {
let mkDocsYml = (await readYaml(filepath));
if (mkDocsYml.site_dir) {
mkDocsYml.site_dir = node_path_1.default.resolve(cwd, node_path_1.default.dirname(filepath), mkDocsYml.site_dir);
}
if (mkDocsYml.INHERIT) {
let inheritPath = node_path_1.default.resolve(node_path_1.default.dirname(filepath), mkDocsYml.INHERIT);
while (inheritPath) {
const inheritYml = (await readYaml(inheritPath));
if (inheritYml.site_dir) {
inheritYml.site_dir = node_path_1.default.resolve(node_path_1.default.dirname(inheritPath), inheritYml.site_dir);
log.debug('Resolved site_dir to %s', inheritYml.site_dir);
}
if (inheritYml.docs_dir) {
inheritYml.docs_dir = node_path_1.default.resolve(node_path_1.default.dirname(inheritPath), inheritYml.docs_dir);
log.debug('Resolved docs_dir to %s', inheritYml.docs_dir);
}
mkDocsYml = lodash_1.default.defaultsDeep(mkDocsYml, inheritYml);
inheritPath = inheritYml.INHERIT
? node_path_1.default.resolve(node_path_1.default.dirname(inheritPath), inheritYml.INHERIT)
: undefined;
}
}
return mkDocsYml;
});
//# sourceMappingURL=fs.js.map