@stephansama/auto-readme 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import { fromMarkdown } from "mdast-util-from-markdown";
2
2
  import * as cp from "node:child_process";
3
3
  import * as fsp from "node:fs/promises";
4
- import ora from "ora";
5
- import debug from "debug";
4
+ import { Spinner } from "picospinner";
5
+ import { createDebug, enable } from "obug";
6
6
  import yargs from "yargs";
7
7
  import { hideBin } from "yargs/helpers";
8
8
  import * as z from "zod";
@@ -12,12 +12,11 @@ import { cosmiconfig, getDefaultSearchPlaces } from "cosmiconfig";
12
12
  import deepmerge from "deepmerge";
13
13
  import { getPackages } from "@manypkg/get-packages";
14
14
  import * as fs from "node:fs";
15
- import * as path$1 from "node:path";
16
15
  import path from "node:path";
17
16
  import { readPackageJSON } from "pkg-types";
18
17
  import * as yaml from "yaml";
19
18
  import { zod2md } from "zod2md";
20
- import glob from "fast-glob";
19
+ import { glob } from "tinyglobby";
21
20
  import { remark } from "remark";
22
21
  import remarkCodeImport from "remark-code-import";
23
22
  import remarkCollapse from "remark-collapse";
@@ -27,7 +26,6 @@ import { VFile } from "vfile";
27
26
  import Handlebars from "handlebars";
28
27
  import { markdownTable } from "markdown-table";
29
28
  import { zone } from "mdast-zone";
30
-
31
29
  //#region src/schema.ts
32
30
  const actionsSchema = z.enum([
33
31
  "ACTION",
@@ -70,8 +68,8 @@ const tableHeadingsSchema = z.record(actionsSchema, headingsSchema.array().optio
70
68
  ZOD: []
71
69
  }).meta({ description: "Table heading action configuration" });
72
70
  const templatesSchema = z.object({
73
- downloadImage: z.string().default("https://img.shields.io/npm/dw/{{name}}?labelColor=211F1F"),
74
- emojis: z.record(headingsSchema, z.string()).default({
71
+ downloadImage: z.string().trim().default("https://img.shields.io/npm/dw/{{name}}?labelColor=211F1F"),
72
+ emojis: z.record(headingsSchema, z.string().trim()).default({
75
73
  default: "⚙️",
76
74
  description: "📝",
77
75
  devDependency: "💻",
@@ -81,14 +79,14 @@ const templatesSchema = z.object({
81
79
  required: "",
82
80
  version: ""
83
81
  }).meta({ description: "Table heading emojis used when enabled" }),
84
- registryUrl: z.string().default("https://www.npmjs.com/package/{{name}}"),
85
- versionImage: z.string().default("https://img.shields.io/npm/v/{{uri_name}}?logo=npm&logoColor=red&color=211F1F&labelColor=211F1F")
82
+ registryUrl: z.string().trim().default("https://www.npmjs.com/package/{{name}}"),
83
+ versionImage: z.string().trim().default("https://img.shields.io/npm/v/{{uri_name}}?logo=npm&logoColor=red&color=211F1F&labelColor=211F1F")
86
84
  });
87
85
  const defaultTemplates = templatesSchema.parse({});
88
- const defaultTableHeadings = tableHeadingsSchema.parse(void 0);
89
- const _configSchema = z.object({
90
- affectedRegexes: z.array(z.string()),
91
- collapseHeadings: z.array(z.string()),
86
+ const defaultTableHeadings = tableHeadingsSchema.parse({});
87
+ const configSchema = z.object({
88
+ affectedRegexes: z.array(z.string().trim()),
89
+ collapseHeadings: z.array(z.string().trim()),
92
90
  defaultLanguage: languageSchema.meta({
93
91
  alias: "l",
94
92
  description: "Default language to infer projects from"
@@ -113,27 +111,25 @@ const _configSchema = z.object({
113
111
  alias: "p",
114
112
  description: "Only show public packages in workspaces"
115
113
  }),
116
- removeScope: z.string().default("").meta({ description: "Remove common workspace scope" }),
114
+ removeScope: z.string().trim().default("").meta({ description: "Remove common workspace scope" }),
117
115
  templates: templatesSchema.optional().default(defaultTemplates).describe("Handlebars templates used to fuel list and table generation"),
118
- tocHeading: z.string().default("Table of contents").meta({ description: "Markdown heading used to generate table of contents" }),
119
- usageFile: z.string().default("").meta({ description: "Workspace level usage file" }),
120
- usageHeading: z.string().default("Usage").meta({ description: "Markdown heading used to generate usage example" }),
116
+ tocHeading: z.string().trim().default("Table of contents").meta({ description: "Markdown heading used to generate table of contents" }),
117
+ usageFile: z.string().trim().default("").meta({ description: "Workspace level usage file" }),
118
+ usageHeading: z.string().trim().default("Usage").meta({ description: "Markdown heading used to generate usage example" }),
121
119
  verbose: z.boolean().default(false).meta({
122
120
  alias: "v",
123
121
  description: "whether or not to display verbose logging"
124
122
  })
125
- });
126
- const configSchema = _configSchema.optional();
127
-
123
+ }).optional();
128
124
  //#endregion
129
- //#region src/args.ts
125
+ //#region src/arguments.ts
130
126
  const complexOptions = [
131
127
  "affectedRegexes",
132
128
  "collapseHeadings",
133
129
  "headings",
134
130
  "templates"
135
131
  ];
136
- const args = {
132
+ const arguments_ = {
137
133
  ...zodToYargs(),
138
134
  changes: {
139
135
  alias: "g",
@@ -153,10 +149,10 @@ const args = {
153
149
  type: "string"
154
150
  }
155
151
  };
156
- async function parseArgs() {
157
- const yargsInstance = yargs(hideBin(process.argv)).options(args).help("h").alias("h", "help").epilogue(`--> @stephansama open-source ${(/* @__PURE__ */ new Date()).getFullYear()}`);
152
+ async function parseArguments() {
153
+ const yargsInstance = yargs(hideBin(process.argv)).options(arguments_).help("h").alias("h", "help").epilogue(`--> @stephansama open-source ${(/* @__PURE__ */ new Date()).getFullYear()}`);
158
154
  const parsed = await yargsInstance.wrap(yargsInstance.terminalWidth()).parse();
159
- if (parsed.verbose) debug.enable("autoreadme*");
155
+ if (parsed.verbose) enable("autoreadme*");
160
156
  return parsed;
161
157
  }
162
158
  function zodToYargs() {
@@ -179,25 +175,12 @@ function zodToYargs() {
179
175
  });
180
176
  return Object.fromEntries(entries);
181
177
  }
182
-
183
178
  //#endregion
184
179
  //#region src/log.ts
185
- const error = debug("autoreadme:error");
186
- const info = debug("autoreadme:info");
187
- const warn = debug("autoreadme:warn");
188
- function ERROR(...rest) {
189
- const [first, ...remaining] = rest;
190
- error(`${first} %O`, ...remaining);
191
- }
192
- function INFO(...rest) {
193
- const [first, ...remaining] = rest;
194
- info(`${first} %O`, ...remaining);
195
- }
196
- function WARN(...rest) {
197
- const [first, ...remaining] = rest;
198
- warn(`${first} %O`, ...remaining);
199
- }
200
-
180
+ const debug = createDebug("autoreadme", { useColors: true });
181
+ const ERROR = debug.extend("error");
182
+ const INFO = debug.extend("info");
183
+ const WARN = debug.extend("warn");
201
184
  //#endregion
202
185
  //#region src/comment.ts
203
186
  const SEPARATOR = "-";
@@ -214,7 +197,7 @@ function parseComment(comment) {
214
197
  });
215
198
  const languageInput = third ? first : void 0;
216
199
  const actionInput = third ? second : first;
217
- const formatInput = third ? third : second;
200
+ const formatInput = third || second;
218
201
  const language = languageSchema.parse(languageInput);
219
202
  const parsed = {
220
203
  action: actionsSchema.parse(actionInput),
@@ -228,8 +211,9 @@ function parseComment(comment) {
228
211
  }
229
212
  const startComment = "<!--";
230
213
  const endComment = "-->";
214
+ const commentRegex = /start|end/;
231
215
  function trimComment(comment) {
232
- return comment.replace(startComment, "").replace(/start|end/, "").replace(endComment, "").trim();
216
+ return comment.replace(startComment, "").replace(commentRegex, "").replace(endComment, "").trim();
233
217
  }
234
218
  function getComment(comment) {
235
219
  if (!isComment(comment.value)) return false;
@@ -239,29 +223,28 @@ function getComment(comment) {
239
223
  function isComment(comment) {
240
224
  return comment.startsWith(startComment) && comment.endsWith(endComment);
241
225
  }
242
-
243
226
  //#endregion
244
227
  //#region src/config.ts
245
228
  const moduleName = "autoreadme";
246
229
  const searchPlaces = getSearchPlaces();
247
230
  const loaders = { [".toml"]: loadToml };
248
- async function loadConfig(args$1) {
249
- const opts$1 = {
231
+ async function loadConfig(arguments_) {
232
+ const options = {
250
233
  loaders,
251
234
  searchPlaces
252
235
  };
253
- if (args$1.config) opts$1.searchPlaces = [args$1.config];
254
- const search = await cosmiconfig(moduleName, opts$1).search();
255
- if (!search) {
256
- WARN(`no config file found`, args$1.config ? " at location: " + args$1.config : "");
257
- INFO("using default configuration");
258
- } else {
236
+ if (arguments_.config) options.searchPlaces = [arguments_.config];
237
+ const search = await cosmiconfig(moduleName, options).search();
238
+ if (search) {
259
239
  INFO("found configuration file at: ", search.filepath);
260
240
  INFO("loaded cosmiconfig", search.config);
241
+ } else {
242
+ WARN(`no config file found`, arguments_.config ? " at location: " + arguments_.config : "");
243
+ INFO("using default configuration");
261
244
  }
262
- args$1 = removeFalsy(args$1);
263
- INFO("merging config with args", args$1);
264
- return configSchema.parse(deepmerge(search?.config || {}, args$1, { arrayMerge: (_, sourceArray) => sourceArray }));
245
+ arguments_ = removeFalsy(arguments_);
246
+ INFO("merging config with args", arguments_);
247
+ return configSchema.parse(deepmerge(search?.config || {}, arguments_, { arrayMerge: (_, sourceArray) => sourceArray }));
265
248
  }
266
249
  function loadToml(_filepath, content) {
267
250
  return toml.parse(content);
@@ -278,14 +261,13 @@ function getSearchPlaces() {
278
261
  `.config/.${moduleName}rc.yml`
279
262
  ];
280
263
  }
281
- function removeFalsy(obj) {
282
- return Object.fromEntries(Object.entries(obj).map(([k, v]) => !v ? false : [k, v]).filter((e) => Boolean(e)));
264
+ function removeFalsy(object) {
265
+ return Object.fromEntries(Object.entries(object).map(([k, v]) => v ? [k, v] : false).filter(Boolean));
283
266
  }
284
-
285
267
  //#endregion
286
- //#region src/utils.ts
268
+ //#region src/utilities.ts
287
269
  const sh = String.raw;
288
- const opts = { encoding: "utf8" };
270
+ const options = { encoding: "utf8" };
289
271
  const ignore = ["**/node_modules/**"];
290
272
  const matches = [
291
273
  /.*README\.md$/gi,
@@ -298,21 +280,23 @@ async function fileExists(file) {
298
280
  return await fsp.access(file).then(() => true).catch(() => false);
299
281
  }
300
282
  function findAffectedMarkdowns(root, config) {
301
- const affected = cp.execSync(sh`git diff --cached --name-only --diff-filter=MACT`, opts).trim().split("\n").filter(Boolean);
302
- if (!affected.length) ERROR("no staged files found");
283
+ const affected = cp.execSync(sh`git diff --cached --name-only --diff-filter=MACT`, options).trim().split("\n").filter((item) => !!item);
284
+ if (affected.length === 0) ERROR("no staged files found");
303
285
  if (config.affectedRegexes?.length) INFO("adding the following expressions: ", config.affectedRegexes);
304
286
  const allMatches = [...matches, ...config.affectedRegexes?.map((r) => new RegExp(r)) || []];
305
287
  INFO("Checking affected files against regexes", affected, allMatches);
306
288
  const eligible = affected.filter((a) => allMatches.some((m) => a.match(m)));
307
289
  INFO("Found the following eligible affected files", eligible);
308
- const md = eligible.map((e) => findNearestReadme(root, path$1.resolve(e)));
309
- const rootMd = path$1.join(root, "README.md");
310
- const dedupe = [...new Set(md), rootMd].filter((s) => Boolean(s));
290
+ const md = eligible.map((current) => {
291
+ return findNearestReadme(root, path.resolve(current));
292
+ });
293
+ const rootMd = path.join(root, "README.md");
294
+ const dedupe = [...new Set(md), rootMd].filter((item) => !!item);
311
295
  INFO("Found the following readmes", dedupe);
312
296
  return dedupe;
313
297
  }
314
298
  function getGitRoot() {
315
- const root = cp.execSync(sh`git rev-parse --show-toplevel`, opts).trim();
299
+ const root = cp.execSync(sh`git rev-parse --show-toplevel`, options).trim();
316
300
  if (!root) throw new Error("must be ran within a git directory.");
317
301
  INFO("found git root at location: ", root);
318
302
  return root;
@@ -321,33 +305,31 @@ async function getMarkdownPaths(cwd, config) {
321
305
  return (await glob(`**/${config?.onlyReadmes ? "README" : "*"}.md`, {
322
306
  cwd,
323
307
  ignore
324
- })).map((readme) => path$1.resolve(cwd, readme));
308
+ })).map((readme) => path.resolve(cwd, readme));
325
309
  }
326
310
  async function getPrettierPaths(paths) {
327
311
  return await Promise.all(paths.map(async (file) => {
328
312
  if (!(await fsp.lstat(file)).isSymbolicLink()) return file;
329
313
  const symlink = await fsp.readlink(file);
330
- return path$1.join(path$1.dirname(file), symlink);
314
+ return path.join(path.dirname(file), symlink);
331
315
  }));
332
316
  }
333
317
  function findNearestReadme(gitRoot, inputFile, maxRotations = 15) {
334
- let dir = path$1.dirname(inputFile);
318
+ let dirname = path.dirname(inputFile);
335
319
  let rotations = 0;
336
320
  while (true) {
337
- const option = path$1.join(dir, "README.md");
321
+ const option = path.join(dirname, "README.md");
338
322
  if (fs.existsSync(option)) return option;
339
- const parent = path$1.dirname(dir);
340
- if (parent === dir || dir === gitRoot || ++rotations > maxRotations) break;
341
- dir = parent;
323
+ const parent = path.dirname(dirname);
324
+ if (parent === dirname || dirname === gitRoot || ++rotations > maxRotations) break;
325
+ dirname = parent;
342
326
  }
343
- return null;
344
327
  }
345
-
346
328
  //#endregion
347
329
  //#region src/data.ts
348
330
  function createFindParameter(parameterList) {
349
331
  return function(parameterName) {
350
- return parameterList?.find((p) => p.startsWith(parameterName))?.replace(parameterName + "=", "")?.replace(/"/gi, "")?.replace(/_/gi, " ");
332
+ return parameterList?.find((p) => p.startsWith(parameterName))?.replace(parameterName + "=", "")?.replaceAll("\"", "")?.replaceAll("_", " ");
351
333
  };
352
334
  }
353
335
  async function loadActionData(actions, file, root) {
@@ -356,7 +338,7 @@ async function loadActionData(actions, file, root) {
356
338
  const find = createFindParameter(action.parameters);
357
339
  switch (action.action) {
358
340
  case "ACTION": {
359
- const actionYaml = await loadActionYaml(path$1.dirname(file));
341
+ const actionYaml = await loadActionYaml(path.dirname(file));
360
342
  return {
361
343
  action: action.action,
362
344
  actionYaml,
@@ -365,7 +347,7 @@ async function loadActionData(actions, file, root) {
365
347
  }
366
348
  case "PKG": {
367
349
  const inputPath = find("path");
368
- const pkgJson = await readPackageJSON(inputPath ? path$1.resolve(path$1.dirname(file), inputPath) : path$1.dirname(file));
350
+ const pkgJson = await readPackageJSON(inputPath ? path.resolve(path.dirname(file), inputPath) : path.dirname(file));
369
351
  return {
370
352
  action: action.action,
371
353
  parameters: action.parameters,
@@ -378,7 +360,7 @@ async function loadActionData(actions, file, root) {
378
360
  };
379
361
  case "WORKSPACE": {
380
362
  const workspaces = await getPackages(process.cwd());
381
- const pnpmPath = path$1.resolve(root, "pnpm-workspace.yaml");
363
+ const pnpmPath = path.resolve(root, "pnpm-workspace.yaml");
382
364
  const isPnpm = fs.existsSync(pnpmPath);
383
365
  return {
384
366
  action: action.action,
@@ -392,11 +374,11 @@ async function loadActionData(actions, file, root) {
392
374
  if (action.format === "LIST") throw new Error("cannot display zod in list format");
393
375
  const inputPath = find("path");
394
376
  if (!inputPath) {
395
- const error$1 = `no path found for zod table at markdown file ${file}`;
396
- throw new Error(error$1);
377
+ const error = `no path found for zod table at markdown file ${file}`;
378
+ throw new Error(error);
397
379
  }
398
380
  const body = await zod2md({
399
- entry: path$1.resolve(path$1.dirname(file), inputPath),
381
+ entry: path.resolve(path.dirname(file), inputPath),
400
382
  title: find("title") || "Zod Schema"
401
383
  });
402
384
  return {
@@ -409,18 +391,17 @@ async function loadActionData(actions, file, root) {
409
391
  }
410
392
  }));
411
393
  }
412
- async function loadActionYaml(baseDir) {
413
- const actionYmlPath = path$1.resolve(baseDir, "action.yml");
414
- const actionYamlPath = path$1.resolve(baseDir, "action.yaml");
394
+ async function loadActionYaml(baseDirectory) {
395
+ const actionYmlPath = path.resolve(baseDirectory, "action.yml");
396
+ const actionYamlPath = path.resolve(baseDirectory, "action.yaml");
415
397
  const actualPath = await fileExists(actionYamlPath) && actionYamlPath || await fileExists(actionYmlPath) && actionYmlPath;
416
398
  if (!actualPath) {
417
- const error$1 = `no yaml file found at locations: ${[actionYmlPath, actionYamlPath]}`;
418
- throw new Error(error$1);
399
+ const error = `no yaml file found at locations: ${[actionYmlPath, actionYamlPath].join(",")}`;
400
+ throw new Error(error);
419
401
  }
420
402
  const actionFile = await fsp.readFile(actualPath, { encoding: "utf8" });
421
403
  return yaml.parse(actionFile);
422
404
  }
423
-
424
405
  //#endregion
425
406
  //#region src/plugin.ts
426
407
  function createHeading(headings, disableEmojis = false, emojis = defaultTemplates.emojis) {
@@ -448,8 +429,8 @@ const autoReadmeRemarkPlugin = (config, data) => (tree) => {
448
429
  const heading = `### ${config.disableEmojis ? "" : "🧰"} actions`;
449
430
  if (options.format === "LIST") return [
450
431
  start,
451
- fromMarkdown(`${heading}\n` + Object.entries(inputs).sort((a) => a[1].required ? -1 : 1).map(([key, value$1]) => {
452
- return `- ${wrapRequired(value$1.required, key)}: (default: ${value$1.default})\n\n${value$1.description}`;
432
+ fromMarkdown(`${heading}\n` + Object.entries(inputs).toSorted((a) => a[1].required ? -1 : 1).map(([key, value]) => {
433
+ return `- ${wrapRequired(value.required, key)}: (default: ${value.default})\n\n${value.description}`;
453
434
  }).join("\n")),
454
435
  end
455
436
  ];
@@ -459,7 +440,7 @@ const autoReadmeRemarkPlugin = (config, data) => (tree) => {
459
440
  fromMarkdown([
460
441
  heading,
461
442
  "",
462
- markdownTable([createHeading(headings, config.disableEmojis, config.templates?.emojis), ...Object.entries(inputs).map(([k, v]) => headings.map((heading$1) => v[heading$1] || k).map(String))])
443
+ markdownTable([createHeading(headings, config.disableEmojis, config.templates?.emojis), ...Object.entries(inputs).map(([k, v]) => headings.map((heading) => v[heading] || k).map(String))])
463
444
  ].join("\n")),
464
445
  end
465
446
  ];
@@ -470,11 +451,11 @@ const autoReadmeRemarkPlugin = (config, data) => (tree) => {
470
451
  const workspace = data.find((d) => d?.action === "WORKSPACE");
471
452
  const templates = loadTemplates(config.templates);
472
453
  const packages = workspace?.workspaces?.packages || [];
473
- const headings = config.headings?.WORKSPACE?.length && config.headings?.WORKSPACE || defaultTableHeadings.WORKSPACE;
454
+ const headings = config.headings?.WORKSPACE?.length && config.headings?.WORKSPACE || defaultTableHeadings.WORKSPACE || [];
474
455
  if (comment && comment.format === "LIST") {}
475
- const table = markdownTable([createHeading(headings, config.disableEmojis, config.templates?.emojis), ...packages.filter((pkg) => config.onlyShowPublicPackages ? !pkg.packageJson.private : true).map((pkg) => {
456
+ const table = markdownTable([createHeading(headings, config.disableEmojis, config.templates?.emojis) || [], ...packages.filter((pkg) => config.onlyShowPublicPackages ? !pkg.packageJson.private : true).map((pkg) => {
476
457
  const { name } = pkg.packageJson;
477
- return headings.map((heading) => {
458
+ return headings?.map((heading) => {
478
459
  if (heading === "name") return `[${config.removeScope ? name.replace(config.removeScope, "") : name}](${path.relative(process.cwd(), path.resolve(pkg.dir, "README.md"))})`;
479
460
  if (heading === "version") return `![npm version image](${templates.versionImage({ uri_name: encodeURIComponent(name) })})`;
480
461
  if (heading === "downloads") return `![npm downloads](${templates.downloadImage({ name })})`;
@@ -503,13 +484,13 @@ const autoReadmeRemarkPlugin = (config, data) => (tree) => {
503
484
  fromMarkdown(""),
504
485
  end
505
486
  ];
506
- function mapDependencies(isDev) {
487
+ function mapDependencies(isDevelopment) {
507
488
  return function([name, version]) {
508
489
  const url = templates.registryUrl({ name });
509
490
  return headings.map((key) => {
510
491
  if (key === "devDependency") {
511
- if (config.disableEmojis) return `\`${isDev}\``;
512
- return `${isDev ? "⌨️" : "👥"}`;
492
+ if (config.disableEmojis) return `\`${isDevelopment}\``;
493
+ return `${isDevelopment ? "⌨️" : "👥"}`;
513
494
  }
514
495
  if (key === "name") return `[${name}](${url})`;
515
496
  if (key === "version") {
@@ -547,7 +528,6 @@ function loadTemplates(templates) {
547
528
  return [key, Handlebars.compile(value)];
548
529
  }));
549
530
  }
550
-
551
531
  //#endregion
552
532
  //#region src/pipeline.ts
553
533
  async function parse(file, filepath, root, config, data) {
@@ -555,10 +535,10 @@ async function parse(file, filepath, root, config, data) {
555
535
  const usage = data.find((d) => d.action === "USAGE");
556
536
  if (usage?.action === "USAGE" || config.enableUsage) {
557
537
  const examplePath = createFindParameter(usage?.parameters || [])("path");
558
- const dirname = path$1.dirname(filepath);
559
- const resolvePath = examplePath && path$1.resolve(dirname, examplePath);
560
- const relativeProjectPath = config.usageFile && path$1.relative(root, path$1.resolve(dirname, config.usageFile));
561
- const example = examplePath && resolvePath && path$1.relative(root, resolvePath) || relativeProjectPath || void 0;
538
+ const dirname = path.dirname(filepath);
539
+ const resolvePath = examplePath && path.resolve(dirname, examplePath);
540
+ const relativeProjectPath = config.usageFile && path.relative(root, path.resolve(dirname, config.usageFile));
541
+ const example = examplePath && resolvePath && path.relative(root, resolvePath) || relativeProjectPath || void 0;
562
542
  if (example && await fileExists(example)) {
563
543
  INFO("generating usage section");
564
544
  pipeline.use(remarkUsage, {
@@ -576,58 +556,57 @@ async function parse(file, filepath, root, config, data) {
576
556
  pipeline.use(remarkCollapse, { test: {
577
557
  ignoreFinalDefinitions: true,
578
558
  test: (value, _) => {
579
- return headings.some((i) => value.trim() === i?.trim());
559
+ return headings.some((item) => value.trim() === item?.trim());
580
560
  }
581
561
  } });
582
562
  }
583
563
  const vfile = new VFile({
584
- path: path$1.resolve(filepath),
564
+ path: path.resolve(filepath),
585
565
  value: file
586
566
  });
587
567
  return (await pipeline.process(vfile)).toString();
588
568
  }
589
-
590
569
  //#endregion
591
570
  //#region src/index.ts
592
571
  async function run() {
593
- const args$1 = await parseArgs();
594
- const config = await loadConfig(args$1) || {};
572
+ const arguments_ = await parseArguments();
573
+ const config = await loadConfig(arguments_) || {};
595
574
  INFO("Loaded the following configuration:", config);
596
575
  const root = getGitRoot();
597
- const isAffected = args$1.changes && "affected";
598
- INFO(`Loading ${!isAffected ? "all " : "affected "}files`);
576
+ const isAffected = arguments_.changes && "affected";
577
+ INFO(`Loading ${isAffected ? "affected " : "all "}files`);
599
578
  const paths = isAffected ? findAffectedMarkdowns(root, config) : await getMarkdownPaths(root, config);
600
579
  INFO("Loaded the following files:", paths.join("\n"));
601
- const type = args$1.onlyReadmes ? "readmes" : "all markdown files";
602
- if (!paths.length) return ERROR(`no ${isAffected} readmes found to update`);
603
- const spinner = !args$1.verbose && ora(`Updating ${type}`).start();
604
- await Promise.all(paths.map(async (path$2) => {
605
- const file = await fsp.readFile(path$2, { encoding: "utf8" });
606
- const actions = (() => {
607
- return loadAstComments(fromMarkdown(file));
608
- })();
609
- if (!actions.length) {
610
- WARN(`no action comments found in`, path$2);
580
+ if (paths.length === 0) return ERROR(`no ${isAffected} readmes found to update`);
581
+ const spinner = !arguments_.verbose && makeSpinner();
582
+ if (spinner) spinner.start();
583
+ await Promise.all(paths.filter((path) => !!path).map(async (path) => {
584
+ const file = await fsp.readFile(path, { encoding: "utf8" });
585
+ const actions = loadAstComments(fromMarkdown(file));
586
+ if (actions.length === 0) {
587
+ WARN(`no action comments found in`, path);
611
588
  if (!config.enableUsage || !config.enableToc) return ERROR("no action or plugins found");
612
- else INFO("plugins enabled. continuing parsing", path$2);
589
+ else INFO("plugins enabled. continuing parsing", path);
613
590
  }
614
- const data = await loadActionData(actions, path$2, root);
591
+ const data = await loadActionData(actions, path, root);
615
592
  INFO("Loaded comment action data", data);
616
- const content = await parse(file, path$2, root, config, data);
617
- await fsp.writeFile(path$2, content);
593
+ const content = await parse(file, path, root, config, data);
594
+ await fsp.writeFile(path, content);
618
595
  }));
619
- const opts$1 = { stdio: "inherit" };
596
+ const options = { stdio: "inherit" };
620
597
  if (config.enablePrettier) {
621
598
  INFO("formatting with prettier");
622
599
  const prettierPaths = await getPrettierPaths(paths);
623
- cp.execFileSync("prettier", ["--write", ...prettierPaths], opts$1);
600
+ cp.execFileSync("prettier", ["--write", ...prettierPaths], options);
624
601
  }
625
602
  if (isAffected) {
626
603
  INFO("adding affected files to git stage");
627
- cp.execFileSync("git", ["add", ...paths], opts$1);
604
+ cp.execFileSync("git", ["add", ...paths], options);
628
605
  }
629
606
  if (spinner) spinner.stop();
630
607
  }
631
-
608
+ function makeSpinner() {
609
+ return new Spinner("Updating readme...", { colors: { spinner: "red" } });
610
+ }
632
611
  //#endregion
633
- export { run };
612
+ export { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stephansama/auto-readme",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Generate lists and tables for your README automagically based on your repository and comments",
5
5
  "keywords": [
6
6
  "auto",
@@ -24,48 +24,41 @@
24
24
  "email": "stephanrandle.dev@gmail.com",
25
25
  "url": "https://stephansama.info"
26
26
  },
27
+ "sideEffects": false,
27
28
  "type": "module",
28
29
  "exports": {
29
30
  ".": {
30
- "import": {
31
- "types": "./config/schema.d.ts",
32
- "default": "./config/schema.js"
33
- },
34
- "require": {
35
- "types": "./config/schema.d.cts",
36
- "default": "./config/schema.cjs"
37
- }
31
+ "import": "./config/schema.mjs",
32
+ "require": "./config/schema.cjs"
38
33
  },
39
- "./schema.json": "./config/schema.json",
40
34
  "./package.json": "./package.json"
41
35
  },
42
- "main": "./config/schema.js",
43
- "types": "./config/schema.d.ts",
36
+ "main": "./config/schema.cjs",
37
+ "types": "./config/schema.d.cts",
44
38
  "bin": "./cli.mjs",
45
39
  "files": [
46
40
  "./dist",
47
- "./config",
48
- "./cli.mjs"
41
+ "./config"
49
42
  ],
50
43
  "dependencies": {
51
- "@iarna/toml": "^2.2.5",
52
- "@manypkg/get-packages": "^3.1.0",
44
+ "@iarna/toml": "2.2.5",
45
+ "@manypkg/get-packages": "3.1.0",
53
46
  "cosmiconfig": "9.0.0",
54
- "debug": "^4.4.3",
55
- "deepmerge": "^4.3.1",
56
- "fast-glob": "^3.3.3",
57
- "handlebars": "4.7.8",
47
+ "deepmerge": "4.3.1",
48
+ "handlebars": "4.7.9",
58
49
  "markdown-table": "^3.0.4",
50
+ "mdast": "3.0.0",
59
51
  "mdast-comment-marker": "^3.0.0",
60
52
  "mdast-util-from-markdown": "^2.0.2",
61
53
  "mdast-zone": "github:stephansama/mdast-zone#1c5b08cd97240debeed4c9c6afad49df5877a132",
62
- "ora": "^8.2.0",
54
+ "obug": "2.1.1",
63
55
  "pkg-types": "^2.3.0",
64
56
  "remark": "15.0.1",
65
57
  "remark-code-import": "^1.2.0",
66
58
  "remark-collapse": "^0.1.2",
67
59
  "remark-toc": "^9.0.0",
68
60
  "remark-usage": "^11.0.1",
61
+ "tinyglobby": "0.2.16",
69
62
  "vfile": "^6.0.3",
70
63
  "yaml": "^2.8.2",
71
64
  "yargs": "18.0.0",
@@ -73,22 +66,26 @@
73
66
  "zod2md": "^0.2.5"
74
67
  },
75
68
  "devDependencies": {
76
- "@types/debug": "^4.1.12",
77
- "@types/mdast": "^4.0.4",
78
- "@types/vfile": "^4.0.0",
79
- "@types/yargs": "^17.0.35",
80
- "mdast": "^3.0.0",
81
- "tsdown": "0.15.12",
82
- "unified": "^11.0.5"
69
+ "@types/mdast": "4.0.4",
70
+ "@types/vfile": "4.0.0",
71
+ "@types/yargs": "17.0.35",
72
+ "picospinner": "3.0.0",
73
+ "tsdown": "0.21.10",
74
+ "unified": "11.0.5"
75
+ },
76
+ "engines": {
77
+ "node": ">=24"
83
78
  },
84
79
  "publishConfig": {
85
80
  "access": "public",
86
81
  "provenance": true
87
82
  },
83
+ "module": "./config/schema.mjs",
88
84
  "scripts": {
89
85
  "build": "node build.mjs",
90
86
  "postbuild": "publint",
91
87
  "dev": "node --watch-path=./src build.mjs",
92
- "lint": "eslint ./src/ --pass-on-no-patterns --no-error-on-unmatched-pattern"
88
+ "lint": "eslint ./src/ --pass-on-no-patterns --no-error-on-unmatched-pattern",
89
+ "lint:fix": "eslint ./src/ --pass-on-no-patterns --no-error-on-unmatched-pattern --fix"
93
90
  }
94
91
  }
File without changes
File without changes