@stephansama/auto-readme
Version:
Generate lists and tables for your README automagically based on your repository and comments
726 lines (710 loc) • 28.3 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
run: () => run
});
module.exports = __toCommonJS(index_exports);
var import_mdast_util_from_markdown2 = require("mdast-util-from-markdown");
var cp2 = __toESM(require("child_process"), 1);
var fsp3 = __toESM(require("fs/promises"), 1);
var import_ora = __toESM(require("ora"), 1);
// src/args.ts
var import_debug = __toESM(require("debug"), 1);
var import_yargs = __toESM(require("yargs"), 1);
var import_helpers = require("yargs/helpers");
var import_zod2 = __toESM(require("zod"), 1);
// src/schema.js
var import_zod = require("zod");
var actionsSchema = import_zod.z.enum(["ACTION", "PKG", "USAGE", "WORKSPACE", "ZOD"]).describe("Comment action options");
var formatsSchema = import_zod.z.enum(["LIST", "TABLE"]).default("TABLE").optional();
var languageSchema = import_zod.z.enum(["JS", "RS"]).optional().default("JS");
var headingsSchema = import_zod.z.enum([
"default",
"description",
"devDependency",
"downloads",
"name",
"private",
"required",
"version"
]).describe("Table heading options");
var tableHeadingsSchema = import_zod.z.record(actionsSchema, headingsSchema.array().optional()).optional().describe("Table heading action configuration").default({
ACTION: ["name", "required", "default", "description"],
PKG: ["name", "version", "devDependency"],
WORKSPACE: ["name", "version", "downloads", "description"],
ZOD: []
});
var templatesSchema = import_zod.z.object({
downloadImage: import_zod.z.string().optional().default("https://img.shields.io/npm/dw/{{name}}?labelColor=211F1F"),
emojis: import_zod.z.record(headingsSchema, import_zod.z.string()).optional().describe("Table heading emojis used when enabled").default({
default: "\u2699\uFE0F",
description: "\u{1F4DD}",
devDependency: "\u{1F4BB}",
downloads: "\u{1F4E5}",
name: "\u{1F3F7}\uFE0F",
private: "\u{1F512}",
required: "",
version: ""
}),
registryUrl: import_zod.z.string().optional().default("https://www.npmjs.com/package/{{name}}"),
versionImage: import_zod.z.string().optional().default(
"https://img.shields.io/npm/v/{{uri_name}}?logo=npm&logoColor=red&color=211F1F&labelColor=211F1F"
)
});
var defaultTemplates = templatesSchema.parse({});
var defaultTableHeadings = tableHeadingsSchema.parse(void 0);
var _configSchema = import_zod.z.object({
affectedRegexes: import_zod.z.string().array().optional().default([]),
collapseHeadings: import_zod.z.string().array().optional().default([]),
defaultLanguage: languageSchema.meta({
alias: "l",
description: "Default language to infer projects from"
}),
disableEmojis: import_zod.z.boolean().default(false).meta({
alias: "e",
description: "Whether or not to use emojis in markdown table headings"
}),
disableMarkdownHeadings: import_zod.z.boolean().default(false).meta({
description: "Whether or not to display markdown headings"
}),
enableToc: import_zod.z.boolean().default(false).meta({
alias: "t",
description: "generate table of contents for readmes"
}),
enableUsage: import_zod.z.boolean().optional().default(false).meta({
description: "Whether or not to enable usage plugin"
}),
headings: tableHeadingsSchema.optional().default(defaultTableHeadings).describe("List of headings for different table outputs"),
onlyReadmes: import_zod.z.boolean().default(true).meta({
alias: "r",
description: "Whether or not to only traverse readmes"
}),
onlyShowPublicPackages: import_zod.z.boolean().default(false).meta({
alias: "p",
description: "Only show public packages in workspaces"
}),
removeScope: import_zod.z.string().optional().default("").meta({
description: "Remove common workspace scope"
}),
templates: templatesSchema.optional().default(defaultTemplates).describe(
"Handlebars templates used to fuel list and table generation"
),
tocHeading: import_zod.z.string().optional().default("Table of contents").meta({
description: "Markdown heading used to generate table of contents"
}),
usageFile: import_zod.z.string().optional().default("").meta({
description: "Workspace level usage file"
}),
usageHeading: import_zod.z.string().optional().default("Usage").meta({
description: "Markdown heading used to generate usage example"
}),
verbose: import_zod.z.boolean().default(false).meta({
alias: "v",
description: "whether or not to display verbose logging"
})
});
var configSchema = _configSchema.optional();
// src/args.ts
var complexOptions = [
"affectedRegexes",
"collapseHeadings",
"headings",
"templates"
];
var args = {
...zodToYargs(),
changes: {
alias: "g",
default: false,
description: "Check only changed git files",
type: "boolean"
},
check: {
alias: "k",
default: false,
description: "Do not write to files. Only check for changes",
type: "boolean"
},
config: { alias: "c", description: "Path to config file", type: "string" }
};
async function parseArgs() {
const yargsInstance = (0, import_yargs.default)((0, import_helpers.hideBin)(process.argv)).options(args).help("h").alias("h", "help").epilogue(`--> @stephansama open-source ${(/* @__PURE__ */ new Date()).getFullYear()}`);
const parsed = await yargsInstance.wrap(yargsInstance.terminalWidth()).parse();
if (parsed.verbose) import_debug.default.enable("autoreadme*");
return parsed;
}
function zodToYargs() {
const { shape } = configSchema.unwrap();
const entries = Object.entries(shape).map(([key, value]) => {
if (complexOptions.includes(key)) return [];
if (value.def.innerType instanceof import_zod2.default.ZodObject) return [];
const meta = value.meta();
const { innerType } = value.def;
const isBoolean = innerType instanceof import_zod2.default.ZodBoolean;
const isNumber = innerType instanceof import_zod2.default.ZodNumber;
const isArray = innerType instanceof import_zod2.default.ZodArray;
const yargType = isArray && "array" || isNumber && "number" || isBoolean && "boolean" || "string";
const options = {
default: value.def.defaultValue,
type: yargType
};
if (meta?.alias) options.alias = meta.alias;
if (meta?.description) options.description = meta.description;
return [key, options];
});
return Object.fromEntries(entries);
}
// src/comment.ts
var import_mdast_comment_marker = require("mdast-comment-marker");
// src/log.ts
var import_debug2 = __toESM(require("debug"), 1);
var error = (0, import_debug2.default)("autoreadme:error");
var info = (0, import_debug2.default)("autoreadme:info");
var warn = (0, import_debug2.default)("autoreadme:warn");
function ERROR(...rest) {
const [first, ...remaining] = rest;
error(`${first} %O`, ...remaining);
}
function INFO(...rest) {
const [first, ...remaining] = rest;
info(`${first} %O`, ...remaining);
}
function WARN(...rest) {
const [first, ...remaining] = rest;
warn(`${first} %O`, ...remaining);
}
// src/comment.ts
var SEPARATOR = "-";
function loadAstComments(root) {
return root.children.map((child) => child.type === "html" && getComment(child)).filter((f) => f !== false);
}
function parseComment(comment) {
const input = trimComment(comment);
const [type, ...parameters] = input.split(" ");
const [first, second, third] = type.split(SEPARATOR);
INFO("parsing inputs", { first, second, third });
const languageInput = third ? first : void 0;
const actionInput = third ? second : first;
const formatInput = third ? third : second;
const language = languageSchema.parse(languageInput);
const action = actionsSchema.parse(actionInput);
const format = formatsSchema.parse(formatInput);
const isStart = comment.includes("start");
const parsed = { action, format, isStart, language, parameters };
INFO(`Parsed comment ${comment}`, parsed);
return parsed;
}
var startComment = "<!--";
var endComment = "-->";
function trimComment(comment) {
return comment.replace(startComment, "").replace(/start|end/, "").replace(endComment, "").trim();
}
function getComment(comment) {
if (!isComment(comment.value)) return false;
const marker = (0, import_mdast_comment_marker.commentMarker)(comment);
if (!marker) return false;
return parseComment(comment.value);
}
function isComment(comment) {
return comment.startsWith(startComment) && comment.endsWith(endComment);
}
// src/config.ts
var import_toml = __toESM(require("@iarna/toml"), 1);
var import_cosmiconfig = require("cosmiconfig");
var import_deepmerge = __toESM(require("deepmerge"), 1);
var moduleName = "autoreadme";
var searchPlaces = getSearchPlaces();
var loaders = { [".toml"]: loadToml };
async function loadConfig(args2) {
const opts2 = { loaders, searchPlaces };
if (args2.config) opts2.searchPlaces = [args2.config];
const explorer = (0, import_cosmiconfig.cosmiconfig)(moduleName, opts2);
const search = await explorer.search();
if (!search) {
const location = args2.config ? " at location: " + args2.config : "";
WARN(`no config file found`, location);
INFO("using default configuration");
} else {
INFO("found configuration file at: ", search.filepath);
INFO("loaded cosmiconfig", search.config);
}
args2 = removeFalsy(args2);
INFO("merging config with args", args2);
return configSchema.parse(
(0, import_deepmerge.default)(search?.config || {}, args2, {
arrayMerge: (_, sourceArray) => sourceArray
})
);
}
function loadToml(_filepath, content) {
return import_toml.default.parse(content);
}
function getSearchPlaces() {
return [
...(0, import_cosmiconfig.getDefaultSearchPlaces)(moduleName),
`.${moduleName}rc.toml`,
`.config/.${moduleName}rc`,
`.config/${moduleName}rc.toml`,
`.config/.${moduleName}rc.toml`,
`.config/.${moduleName}rc.json`,
`.config/.${moduleName}rc.yaml`,
`.config/.${moduleName}rc.yml`
];
}
function removeFalsy(obj) {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => !v ? false : [k, v]).filter((e) => Boolean(e))
);
}
// src/data.ts
var import_get_packages = require("@manypkg/get-packages");
var fs2 = __toESM(require("fs"), 1);
var fsp2 = __toESM(require("fs/promises"), 1);
var path2 = __toESM(require("path"), 1);
var import_pkg_types = require("pkg-types");
var yaml = __toESM(require("yaml"), 1);
var import_zod2md = require("zod2md");
// src/utils.ts
var import_fast_glob = __toESM(require("fast-glob"), 1);
var cp = __toESM(require("child_process"), 1);
var fs = __toESM(require("fs"), 1);
var fsp = __toESM(require("fs/promises"), 1);
var path = __toESM(require("path"), 1);
var sh = String.raw;
var opts = { encoding: "utf8" };
var ignore = ["**/node_modules/**"];
var matches = [
/.*README\.md$/gi,
/.*Cargo\.toml$/gi,
/.*action\.ya?ml$/gi,
/.*package\.json$/gi,
/.*pnpm-workspace\.yaml$/gi
];
async function fileExists(file) {
return await fsp.access(file).then(() => true).catch(() => false);
}
function findAffectedMarkdowns(root, config) {
const affected = cp.execSync(sh`git diff --cached --name-only --diff-filter=MACT`, opts).trim().split("\n").filter(Boolean);
if (!affected.length) ERROR("no staged files found");
if (config.affectedRegexes?.length) {
INFO("adding the following expressions: ", config.affectedRegexes);
}
const allMatches = [
...matches,
...config.affectedRegexes?.map((r) => new RegExp(r)) || []
];
INFO("Checking affected files against regexes", affected, allMatches);
const eligible = affected.filter((a) => allMatches.some((m) => a.match(m)));
INFO("Found the following eligible affected files", eligible);
const md = eligible.map((e) => findNearestReadme(root, path.resolve(e)));
const rootMd = path.join(root, "README.md");
const dedupe = [...new Set(md), rootMd].filter(
(s) => Boolean(s)
);
INFO("Found the following readmes", dedupe);
return dedupe;
}
function findNearestReadme(gitRoot, inputFile, maxRotations = 15) {
let dir = path.dirname(inputFile);
let rotations = 0;
while (true) {
const option = path.join(dir, "README.md");
if (fs.existsSync(option)) return option;
const parent = path.dirname(dir);
if (parent === dir || dir === gitRoot || ++rotations > maxRotations) {
break;
}
dir = parent;
}
return null;
}
function getGitRoot() {
const root = cp.execSync(sh`git rev-parse --show-toplevel`, opts).trim();
if (!root) {
throw new Error("must be ran within a git directory.");
}
INFO("found git root at location: ", root);
return root;
}
async function getMarkdownPaths(cwd, config) {
const pattern = `**/${config?.onlyReadmes ? "README" : "*"}.md`;
const readmes = await (0, import_fast_glob.default)(pattern, { cwd, ignore });
return readmes.map((readme) => path.resolve(cwd, readme));
}
// src/data.ts
function createFindParameter(parameterList) {
return function(parameterName) {
return parameterList?.find((p) => p.startsWith(parameterName))?.replace(parameterName + "=", "")?.replace(/"/gi, "")?.replace(/_/gi, " ");
};
}
async function loadActionData(actions, file, root) {
const startActions = actions.filter((action) => action.isStart);
return await Promise.all(
startActions.map(async (action) => {
const find = createFindParameter(action.parameters);
switch (action.action) {
case "ACTION": {
const baseDir = path2.dirname(file);
const actionYaml = await loadActionYaml(baseDir);
return {
action: action.action,
actionYaml,
parameters: action.parameters
};
}
case "PKG": {
const inputPath = find("path");
const filename = inputPath ? path2.resolve(path2.dirname(file), inputPath) : path2.dirname(file);
const pkgJson = await (0, import_pkg_types.readPackageJSON)(filename);
return {
action: action.action,
parameters: action.parameters,
pkgJson
};
}
case "USAGE": {
return {
action: action.action,
parameters: action.parameters
};
}
case "WORKSPACE": {
const workspaces = await (0, import_get_packages.getPackages)(process.cwd());
const pnpmPath = path2.resolve(root, "pnpm-workspace.yaml");
const isPnpm = fs2.existsSync(pnpmPath);
return {
action: action.action,
isPnpm,
parameters: action.parameters,
root,
workspaces
};
}
case "ZOD": {
if (action.format === "LIST") {
throw new Error("cannot display zod in list format");
}
const inputPath = find("path");
if (!inputPath) {
const error2 = `no path found for zod table at markdown file ${file}`;
throw new Error(error2);
}
const body = await (0, import_zod2md.zod2md)({
entry: path2.resolve(path2.dirname(file), inputPath),
title: find("title") || "Zod Schema"
});
return {
action: action.action,
body,
parameters: action.parameters
};
}
default:
throw new Error("feature not yet implemented");
}
})
);
}
async function loadActionYaml(baseDir) {
const actionYmlPath = path2.resolve(baseDir, "action.yml");
const actionYamlPath = path2.resolve(baseDir, "action.yaml");
const actualPath = await fileExists(actionYamlPath) && actionYamlPath || await fileExists(actionYmlPath) && actionYmlPath;
if (!actualPath) {
const locations = [actionYmlPath, actionYamlPath];
const error2 = `no yaml file found at locations: ${locations}`;
throw new Error(error2);
}
const actionFile = await fsp2.readFile(actualPath, { encoding: "utf8" });
return yaml.parse(actionFile);
}
// src/pipeline.ts
var path4 = __toESM(require("path"), 1);
var import_remark = require("remark");
var import_remark_code_import = __toESM(require("remark-code-import"), 1);
var import_remark_collapse = __toESM(require("remark-collapse"), 1);
var import_remark_toc = __toESM(require("remark-toc"), 1);
var import_remark_usage = __toESM(require("remark-usage"), 1);
var import_vfile = require("vfile");
// src/plugin.ts
var import_handlebars = __toESM(require("handlebars"), 1);
var import_markdown_table = require("markdown-table");
var import_mdast_util_from_markdown = require("mdast-util-from-markdown");
var import_mdast_zone = require("mdast-zone");
var import_node_path = __toESM(require("path"), 1);
function createHeading(headings, disableEmojis = false, emojis = defaultTemplates.emojis) {
return headings.map(
(h) => `${disableEmojis ? "" : emojis[h] + " "}${h?.at(0)?.toUpperCase() + h?.slice(1)}`
);
}
function wrapRequired(required, input) {
if (!required) return input;
return `<b>*${input}</b>`;
}
var autoReadmeRemarkPlugin = (config, data) => (tree) => {
(0, import_mdast_zone.zone)(tree, /.*ZOD.*/gi, function(start, _, end) {
const zod = data.find((d) => d?.action === "ZOD");
if (!zod?.body) {
throw new Error("unable to load zod body");
}
const ast = (0, import_mdast_util_from_markdown.fromMarkdown)(zod.body);
return [start, ast, end];
});
(0, import_mdast_zone.zone)(tree, /.*ACTION.*/gi, function(start, _, end) {
const value = start.type === "html" && start.value;
const options = value && parseComment(value);
if (!options) throw new Error("not able to parse comment");
const first = data.find((d) => d?.action === "ACTION");
const inputs = first?.actionYaml?.inputs || {};
const heading = `### ${config.disableEmojis ? "" : "\u{1F9F0}"} actions`;
if (options.format === "LIST") {
const body2 = `${heading}
` + Object.entries(inputs).sort((a) => a[1].required ? -1 : 1).map(([key, value2]) => {
return `- ${wrapRequired(value2.required, key)}: (default: ${value2.default})
${value2.description}`;
}).join("\n");
const ast2 = (0, import_mdast_util_from_markdown.fromMarkdown)(body2);
return [start, ast2, end];
}
const headings = config.headings?.ACTION?.length && config.headings.ACTION || defaultTableHeadings.ACTION;
const table = (0, import_markdown_table.markdownTable)([
createHeading(
headings,
config.disableEmojis,
config.templates?.emojis
),
...Object.entries(inputs).map(
([k, v]) => headings.map((heading2) => v[heading2] || k).map(String)
)
]);
const body = [heading, "", table].join("\n");
const ast = (0, import_mdast_util_from_markdown.fromMarkdown)(body);
return [start, ast, end];
});
(0, import_mdast_zone.zone)(tree, /.*WORKSPACE.*/gi, function(start, _, end) {
const value = start.type === "html" && start.value;
const comment = value && parseComment(value);
const workspace = data.find((d) => d?.action === "WORKSPACE");
const templates = loadTemplates(config.templates);
const packages = workspace?.workspaces?.packages || [];
const headings = config.headings?.WORKSPACE?.length && config.headings?.WORKSPACE || defaultTableHeadings.WORKSPACE;
if (comment && comment.format === "LIST") {
}
const tableHeadings = createHeading(
headings,
config.disableEmojis,
config.templates?.emojis
);
const table = (0, import_markdown_table.markdownTable)([
tableHeadings,
...packages.filter(
(pkg) => config.onlyShowPublicPackages ? !pkg.packageJson.private : true
).map((pkg) => {
const { name } = pkg.packageJson;
return headings.map((heading2) => {
if (heading2 === "name") {
const scoped = config.removeScope ? name.replace(config.removeScope, "") : name;
return `[${scoped}](${import_node_path.default.relative(
process.cwd(),
import_node_path.default.resolve(pkg.dir, "README.md")
)})`;
}
if (heading2 === "version") {
return ` }
)})`;
}
if (heading2 === "downloads") {
return `})`;
}
if (heading2 === "description") {
return pkg.packageJson?.description;
}
return ``;
});
})
]);
const heading = `### ${config.disableEmojis ? "" : "\u{1F3ED}"} workspace`;
const body = [heading, "", table].join("\n");
const ast = (0, import_mdast_util_from_markdown.fromMarkdown)(body);
return [start, ast, end];
});
(0, import_mdast_zone.zone)(tree, /.*PKG.*/gi, function(start, _, end) {
const value = start.type === "html" && start.value;
const comment = value && parseComment(value);
const first = data.find((d) => d?.action === "PKG");
const templates = loadTemplates(config.templates);
const headings = config.headings?.PKG?.length && config.headings?.PKG || defaultTableHeadings.PKG;
if (comment && comment.format === "LIST") {
const ast = (0, import_mdast_util_from_markdown.fromMarkdown)("");
return [start, ast, end];
}
function mapDependencies(isDev) {
return function([name, version]) {
const url = templates.registryUrl({ name });
return headings.map((key) => {
if (key === "devDependency") {
if (config.disableEmojis) {
return `\`${isDev}\``;
}
return `${isDev ? "\u2328\uFE0F" : "\u{1F465}"}`;
}
if (key === "name") {
return `[${name}](${url})`;
}
if (key === "version") {
if (["workspace", "catalog", "*"].some(
(type) => version.includes(type)
)) {
return `\`${version}\``;
}
return ` })})`;
}
});
};
}
const { dependencies = {}, devDependencies = {} } = first?.pkgJson || {};
const table = (0, import_markdown_table.markdownTable)([
createHeading(
headings,
config.disableEmojis,
config.templates?.emojis
),
...Object.entries(devDependencies).map(mapDependencies(true)),
...Object.entries(dependencies).map(mapDependencies(false))
]);
const heading = `### ${config.disableEmojis ? "" : "\u{1F4E6}"} packages`;
const body = [heading, "", table].join("\n");
const tableAst = (0, import_mdast_util_from_markdown.fromMarkdown)(body);
return [start, tableAst, end];
});
};
function loadTemplates(templates) {
if (!templates) throw new Error("failed to load templates");
return Object.fromEntries(
Object.entries(templates).map(([key, value]) => {
if (typeof value !== "string") return [];
return [key, import_handlebars.default.compile(value)];
})
);
}
// src/pipeline.ts
async function parse2(file, filepath, root, config, data) {
const pipeline = (0, import_remark.remark)().use(autoReadmeRemarkPlugin, config, data).use(import_remark_code_import.default, {});
const usage = data.find((d) => d.action === "USAGE");
if (usage?.action === "USAGE" || config.enableUsage) {
const find = createFindParameter(usage?.parameters || []);
const examplePath = find("path");
const dirname4 = path4.dirname(filepath);
const resolvePath = examplePath && path4.resolve(dirname4, examplePath);
const relativeProjectPath = config.usageFile && path4.relative(root, path4.resolve(dirname4, config.usageFile));
const example = examplePath && resolvePath && path4.relative(root, resolvePath) || relativeProjectPath || void 0;
if (example && await fileExists(example)) {
INFO("generating usage section");
pipeline.use(import_remark_usage.default, {
example,
heading: config.usageHeading
});
} else {
WARN("not able to find example file for readme", filepath, example);
}
}
if (config.enableToc) {
INFO("generating table of contents section");
pipeline.use(import_remark_toc.default, { heading: config.tocHeading });
}
if (config.enableToc || config.collapseHeadings?.length) {
const additional = config.collapseHeadings?.length ? config.collapseHeadings : [];
const headings = [...additional, config.tocHeading];
pipeline.use(import_remark_collapse.default, {
test: {
ignoreFinalDefinitions: true,
test: (value, _) => {
return headings.some((i) => value.trim() === i?.trim());
}
}
});
}
const vfile = new import_vfile.VFile({ path: path4.resolve(filepath), value: file });
const markdown = await pipeline.process(vfile);
return markdown.toString();
}
// src/index.ts
async function run() {
const args2 = await parseArgs();
const config = await loadConfig(args2) || {};
INFO("Loaded the following configuration:", config);
const root = getGitRoot();
const isAffected = args2.changes ? "affected" : "";
INFO(`Loading ${!isAffected ? "all " : "affected "}files`);
const paths = isAffected ? findAffectedMarkdowns(root, config) : await getMarkdownPaths(root, config);
INFO("Loaded the following files:", paths.join("\n"));
const type = args2.onlyReadmes ? "readmes" : "all markdown files";
if (!paths.length) {
return ERROR(`no ${isAffected} readmes found to update`);
}
const spinner = !args2.verbose && (0, import_ora.default)(`Updating ${type}`).start();
await Promise.all(
paths.map(async (path5) => {
const file = await fsp3.readFile(path5, { encoding: "utf8" });
const actions = (() => {
const ast = (0, import_mdast_util_from_markdown2.fromMarkdown)(file);
return loadAstComments(ast);
})();
if (!actions.length) {
WARN(`no action comments found in`, path5);
if (!config.enableUsage || !config.enableToc) {
return ERROR("no action or plugins found");
} else {
INFO("plugins enabled. continuing parsing", path5);
}
}
const data = await loadActionData(actions, path5, root);
INFO("Loaded comment action data", data);
const content = await parse2(file, path5, root, config, data);
await fsp3.writeFile(path5, content);
})
);
const opts2 = { stdio: "inherit" };
INFO("formatting with prettier");
cp2.execFileSync("prettier", ["--write", ...paths], opts2);
if (isAffected) {
INFO("adding affected files to git stage");
cp2.execFileSync("git", ["add", ...paths], opts2);
}
if (spinner) spinner.stop();
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
run
});
//# sourceMappingURL=index.cjs.map