indexable-array
Version:
Extended native JavaScript Array which provides indexed lookup similar to native Map.
156 lines (131 loc) • 6.45 kB
JavaScript
/* eslint-disable no-use-before-define, import/no-extraneous-dependencies, import/no-unresolved */
const os = require("os");
const { promises: fs, readFileSync } = require("fs");
const { sep, join, normalize, basename, dirname, parse } = require("path");
const childProcess = require("child_process");
const readmeasy = require("readmeasy").default;
const cwd = process.env.INIT_CWD || process.cwd();
const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), { encoding: "utf8" })); // eslint-disable-line no-use-before-define
const walk = hasDependency("typedoc") ? require("walkdir") : undefined;
const concatMd = hasDependency("typedoc") ? require("concat-md").default : undefined;
/**
* Returns entry file for TypeDoc. Uses basename of main entry in 'package.json' file and prefixes it with 'src'.
*/
function getTypeDocEntry() {
const { name } = parse(pkg.main);
return normalize(`src/${name}.ts`);
}
function hasDependency(moduleName) {
const hasNormalDependency = pkg.dependencies && pkg.dependencies[moduleName];
const hasDevDependency = pkg.devDependencies && pkg.devDependencies[moduleName];
return hasNormalDependency || hasDevDependency;
}
async function createTempDir() {
const path = await fs.mkdtemp(`${os.tmpdir()}${sep}`);
await fs.mkdir(path, { recursive: true });
return path;
}
async function spawn(cmd, args, options) {
const ps = await childProcess.spawn(cmd, args, options);
return new Promise((resolve, reject) =>
ps.on("close", (code) => (code === 0 ? resolve() : reject(new Error(`ps process exited with code ${code}`))))
);
}
// /** Gets parent module's CWD which installed this module. Otherwise returns CWD. */
// function getCwd(cwd) {
// return cwd ?? (process.env.INIT_CWD || process.cwd());
// }
/**
* Creates TypeDoc multiple or single markdown from TypeScript source files.
*
* @param out is output directory or file for generated markdown.
* @param singleFile is whether to combine all output into single markdown file.
*/
async function md({ out, singleFile }) {
// rm -rf api-docs-md && typedoc --plugin typedoc-plugin-example-tag,typedoc-plugin-markdown --excludeExternals --excludePrivate --excludeProtected --exclude 'src/bin/**/*' --theme markdown --readme none --out api-docs-md src/index.ts && find api-docs-md -name \"index.md\" -exec sh -c 'mv \"$1\" \"${1%index.md}\"index2.md' - {} \\;
// const cwd = getCwd();
const bin = join(cwd, "node_modules/.bin/typedoc");
const tmpDir = await createTempDir();
const options = [
"--plugin",
"typedoc-plugin-example-tag,typedoc-plugin-markdown",
"--excludeExternals",
"--excludePrivate",
"--excludeProtected",
"--exclude",
"'src/bin/**/*'",
"--theme",
"markdown",
"--readme",
"none",
"--out",
tmpDir,
getTypeDocEntry(),
];
if (hasDependency("vuepress")) options.unshift("--platform", "vuepress");
try {
await spawn(bin, options, { stdio: "inherit" });
// Rename all "index.md" files as "index2.md"
const createdFiles = await walk.async(tmpDir);
createdFiles.filter((file) => basename(file) === "index.md").forEach((file) => fs.rename(file, join(dirname(file), "index2.md")));
} catch (error) {
if (singleFile) await fs.rmdir(tmpDir, { recursive: true });
throw error;
}
if (singleFile) {
const apiDoc = await concatMd(tmpDir, { dirNameAsTitle: true });
fs.writeFile(out, apiDoc);
await fs.rmdir(tmpDir, { recursive: true });
} else {
await fs.rmdir(out, { recursive: true });
await fs.rename(tmpDir, out);
}
}
/**
* Creates TypeDoc HTML files from TypeScript source files.
*
* @param out is output directory for generated HTML files.
*/
async function html({ out }) {
// rm -rf api-docs-html && typedoc --plugin typedoc-plugin-example-tag --out api-docs-html src/index.ts
// const cwd = getCwd();
const bin = join(cwd, "node_modules/.bin/typedoc");
await fs.rmdir(out, { recursive: true });
await spawn(bin, ["--plugin", "typedoc-plugin-example-tag", "--out", out, getTypeDocEntry()], { stdio: "inherit" });
}
/**
* Create "README.md" from "README.njk". Also add TypeScript API docs using TypeDoc if `{% include "api.md" %}` is present in "README.njk"
*/
async function readme() {
// if grep -q '{% include \"api.md\" %}' 'README.njk'; then npm run typedoc:single-md; mkdir -p temp && mv api.md temp/; fi && readmeasy --partial-dirs temp,module-files/template-partials && rm -rf temp
// const cwd = getCwd();
const partialDirs = [join(cwd, "module-files/template-partials")];
const template = await fs.readFile(join(cwd, "README.njk"), { encoding: "utf8" });
// If remplate contains API partial or template does not exist (default template contains API partial), create API markdown.
if (template.includes('{% include "api.md" %}')) {
const tmpDir = await createTempDir();
partialDirs.push(tmpDir);
await md({ out: join(tmpDir, "api.md"), singleFile: true });
}
await readmeasy({ partialDirs, dir: cwd });
// If oclif installed execute `oclif-dev readme`;
// if (targetModule.hasAnyDependency(["@oclif/command"])) await targetModule.command("oclif-dev readme", { exitOnProcessFailure });
// intermodular.log("info", "README created: README.md");
}
async function vuepressApi() {
// npm-run-all -p typedoc:md typedoc:html && rm -rf docs/nav.02.api docs/.vuepress/public/api-site && mv api-docs-md docs/nav.02.api && mv api-docs-html docs/.vuepress/public/api-site && cp assets/typedoc/01.typedoc-iframe.md docs/nav.02.api/ && NODE_ENV=production vuepress build docs
// const cwd = getCwd();
const mdPath = join(cwd, "docs/nav.02.api");
const htmlPath = join(cwd, "docs/.vuepress/public/api-site");
const iframePath = join(cwd, "module-files/01.typedoc-iframe.md");
await Promise.all([md({ out: mdPath }), html({ out: htmlPath })]);
await fs.copyFile(iframePath, join(mdPath, basename(iframePath))); // Don't put this in `Promise.all` with `md` and `html`. It needs first directory created. Otherwise file is copied same name with directory, since there is no directory yet.
// await intermodular.targetModule.execute("vuepress", ["build", "docs"], { env: { NODE_ENV: "production" } });
// intermodular.log("info", "VuePress site updated.");
}
const commands = {
readme: () => readme(),
"vuepress-api": () => vuepressApi(),
};
const [command, ...args] = process.argv.slice(2);
commands[command](args);