@bjmhe/automd 0.0.0 → 0.0.4

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.
package/dist/index.js CHANGED
@@ -1,809 +1,8 @@
1
1
  /*! Keep it simple, keep it free */
2
- import { existsSync, promises } from "node:fs";
3
- import { basename, dirname, extname, join, relative, resolve } from "pathe";
4
- import { fileURLToPath, findExportNames, pathToFileURL, resolvePath } from "mlly";
5
- import { debounce } from "perfect-debounce";
6
- import MagicString from "magic-string";
7
- import { camelCase, titleCase } from "scule";
8
- import { readPackageJSON } from "pkg-types";
9
- import { defu } from "defu";
10
- import { image, link, md } from "mdbox";
11
- import { readFile, readdir, stat } from "node:fs/promises";
12
- import { destr } from "destr";
13
- //#region src/generator.ts
14
- /**
15
- * @internal
16
- */
17
- function defineGenerator(generator) {
18
- return generator;
19
- }
20
- //#endregion
21
- //#region src/_utils.ts
22
- function resolvePath$1(path, { url, dir }) {
23
- if (path.startsWith("/")) return join(dir, path);
24
- return url ? fileURLToPath(new URL(path, url)) : resolve(dir, path);
25
- }
26
- async function getPkg(dir, input = {}) {
27
- const pkg = await readPackageJSON(dir).catch(() => void 0);
28
- return defu({
29
- name: input.name,
30
- version: typeof input.version === "string" ? input.version : void 0,
31
- github: input.github || input.gh
32
- }, {
33
- name: pkg?.name,
34
- version: pkg?.version,
35
- github: _getGitRepo(pkg?.repository)
36
- }, {
37
- name: process.env.npm_package_name,
38
- version: process.env.npm_package_version
39
- });
40
- }
41
- function _getGitRepo(repo) {
42
- const url = typeof repo === "string" ? repo : repo?.url;
43
- if (!url || typeof url !== "string") return;
44
- const match = /(?:https:\/\/github\.com\/|gh:|github:|)([\w-]+)\/([\w-]+)/.exec(url);
45
- if (match && match[1] && match[2]) return `${match[1]}/${match[2]}`;
46
- }
47
- //#endregion
48
- //#region src/generators/jsdocs.ts
49
- const jsdocs = defineGenerator({
50
- name: "jsdocs",
51
- async generate({ config, args, url }) {
52
- const { loadSchema } = await import("untyped/loader");
53
- return { contents: _render(await loadSchema(resolvePath$1(args.src, {
54
- url,
55
- dir: config.dir
56
- }), { jiti: {
57
- fsCache: false,
58
- moduleCache: false
59
- } }), args, Number.parseInt(args.headingLevel) || 2).join("\n").replace(/\n{3,}/g, "\n\n") };
60
- }
61
- });
62
- function _render(schema, opts, headingLevel) {
63
- const sections = Object.create(null);
64
- for (const [key, keySchema] of Object.entries(schema.properties || {})) {
65
- const section = _renderSection(key, keySchema, opts, headingLevel + 1);
66
- if (!section) continue;
67
- sections[section.group] = sections[section.group] || [];
68
- sections[section.group].push([section.heading, section.lines]);
69
- }
70
- const lines = [];
71
- const sortedGroups = Object.keys(sections).sort((a, b) => {
72
- if (a === "") return 1;
73
- if (b === "") return -1;
74
- return a.localeCompare(b);
75
- });
76
- for (const group of sortedGroups) {
77
- if (group) lines.push(`\n${"#".repeat(headingLevel)} ${titleCase(group)}\n`);
78
- const sortedSections = sections[group].sort((a, b) => a[0].localeCompare(b[0]));
79
- for (const section of sortedSections) {
80
- const heading = `\n${"#".repeat(headingLevel + 1)} ${section[0]}\n`;
81
- lines.push(heading, ...section[1]);
82
- }
83
- }
84
- return lines;
85
- }
86
- function _renderSection(key, schema, opts, headingLevel) {
87
- const tags = _parseTags(schema.tags);
88
- if (tags.some((t) => t.tag === "@deprecated" || t.tag === "@internal")) return;
89
- const group = tags.find((t) => t.tag === "@group")?.contents || opts.defaultGroup || "";
90
- if (opts.group && (typeof opts.group === "string" ? group !== opts.group : !opts.group.includes(group))) return;
91
- let heading = `\`${key}\``;
92
- const lines = [];
93
- if (schema.type === "function") heading = `\`${_generateFunctionSig(key, schema)}\``;
94
- else if (schema.type !== "object") {
95
- lines.push(`- **Type**: \`${schema.markdownType || schema.tsType || schema.type}\``);
96
- if ("default" in schema) lines.push(`- **Default**: \`${JSON.stringify(schema.default)}\``);
97
- lines.push("");
98
- }
99
- lines.push(..._renderBody(schema));
100
- for (const tag of tags) if (tag.tag === "@example") {
101
- const codeBlock = tag.contents.startsWith("`") ? tag.contents : `\`\`\`ts\n${tag.contents}\n\`\`\``;
102
- lines.push("", "**Example:**", "", codeBlock);
103
- }
104
- if (schema.type === "object") lines.push(..._render(schema, opts, headingLevel));
105
- return {
106
- heading,
107
- lines,
108
- group
109
- };
110
- }
111
- function _renderBody(schema) {
112
- const lines = [];
113
- if (schema.title) lines.push(schema.title.trim());
114
- if (schema.title && schema.description) lines.push("");
115
- if (schema.description) lines.push(...schema.description.split("\n").map((line) => line.trim()).join("\n\n").split("\n"));
116
- return lines;
117
- }
118
- function _parseTags(lines = []) {
119
- const parsedTags = [];
120
- let tag = "";
121
- let contentLines = [];
122
- for (const line of lines.join("\n").split("\n")) if (line.startsWith("@")) {
123
- if (tag) parsedTags.push({
124
- tag,
125
- contents: contentLines.join("\n")
126
- });
127
- const [_tag, ...rest] = line.split(" ");
128
- tag = _tag;
129
- contentLines = rest;
130
- } else contentLines.push(line);
131
- if (tag) parsedTags.push({
132
- tag,
133
- contents: contentLines.join("\n")
134
- });
135
- return parsedTags;
136
- }
137
- function _generateFunctionSig(name, meta) {
138
- return `${name}(${(meta.args || []).map((arg) => {
139
- let str = arg.name;
140
- if (arg.optional) str += "?";
141
- const tsType = _simpleArgType(arg.tsType);
142
- if (tsType) str += `: ${tsType}`;
143
- return str;
144
- }).join(", ")})`;
145
- }
146
- function _simpleArgType(tsType = "") {
147
- return tsType.split(/\s*\|\s*/).filter((t) => t && t !== "object" && t.startsWith("{")).map((ot) => ot.split(/\s*[,;]\s*/g).map((p) => p.replaceAll(/\s*:\s*(string|boolean|number)/g, "")).join(", ")).join(" | ");
148
- }
149
- //#endregion
150
- //#region src/generators/badges.ts
151
- const badgeTypes = {
152
- npmVersion: {
153
- name: "npm version",
154
- to: "https://npmjs.com/package/{name}"
155
- },
156
- npmDownloads: {
157
- name: "npm downloads",
158
- to: "https://npm.chart.dev/{name}"
159
- },
160
- bundlephobia: {
161
- name: "bundle size",
162
- to: "https://bundlephobia.com/package/{name}"
163
- },
164
- bundlejs: {
165
- name: "bundle size",
166
- to: "https://bundlejs.com/?q={name}"
167
- },
168
- packagephobia: {
169
- name: "install size",
170
- to: "https://packagephobia.com/result?p={name}"
171
- },
172
- codecov: {
173
- name: "codecov",
174
- to: "https://codecov.io/gh/{github}"
175
- },
176
- license: {
177
- name: "license",
178
- to: "https://github.com/{github}/blob/{licenseBranch}/LICENSE"
179
- },
180
- engine: {
181
- name: "engine",
182
- to: "https://npmx.dev/api/registry/badge/engines/{name}"
183
- }
184
- };
185
- const badgeProviders = {
186
- shields: {
187
- npmVersion: "https://img.shields.io/npm/v/{name}",
188
- npmDownloads: "https://img.shields.io/npm/dm/{name}",
189
- bundlephobia: "https://img.shields.io/bundlephobia/minzip/{name}",
190
- packagephobia: "https://badgen.net/packagephobia/install/{name}",
191
- bundlejs: "https://img.shields.io/bundlejs/size/{name}",
192
- codecov: "https://img.shields.io/codecov/c/gh/{github}",
193
- license: "https://img.shields.io/github/license/{github}",
194
- engine: false
195
- },
196
- badgen: {
197
- npmVersion: "https://flat.badgen.net/npm/v/{name}",
198
- npmDownloads: "https://flat.badgen.net/npm/dm/{name}",
199
- bundlephobia: "https://flat.badgen.net/bundlephobia/minzip/{name}",
200
- bundlejs: false,
201
- packagephobia: "https://flat.badgen.net/packagephobia/install/{name}",
202
- codecov: "https://flat.badgen.net/codecov/c/github/{github}",
203
- license: "https://flat.badgen.net/github/license/{github}",
204
- engine: false
205
- },
206
- badgenClassic: {
207
- npmVersion: "https://badgen.net/npm/v/{name}",
208
- npmDownloads: "https://badgen.net/npm/dm/{name}",
209
- bundlephobia: "https://badgen.net/bundlephobia/minzip/{name}",
210
- bundlejs: false,
211
- packagephobia: "https://badgen.net/packagephobia/install/{name}",
212
- codecov: "https://badgen.net/codecov/c/github/{github}",
213
- license: "https://badgen.net/github/license/{github}",
214
- engine: false
215
- },
216
- npmx: {
217
- npmVersion: "https://npmx.dev/api/registry/badge/version/{name}",
218
- npmDownloads: "https://npmx.dev/api/registry/badge/downloads/{name}",
219
- bundlephobia: "https://npmx.dev/api/registry/badge/size/{name}",
220
- bundlejs: false,
221
- packagephobia: false,
222
- codecov: false,
223
- license: "https://npmx.dev/api/registry/badge/license/{name}",
224
- engine: "https://npmx.dev/api/registry/badge/engines/{name}"
225
- }
226
- };
227
- const badges = defineGenerator({
228
- name: "badges",
229
- async generate({ config, args }) {
230
- const pkg = await getPkg(config.dir, args);
231
- const ctx = {
232
- name: pkg.name,
233
- github: pkg.github,
234
- licenseBranch: "main",
235
- ...args
236
- };
237
- const fillStr = (str) => str.replace(/{(\w+)}/g, (_, key) => ctx[key] || "");
238
- const provider = badgeProviders[args.provider] || badgeProviders.shields;
239
- const providerParams = Object.entries({
240
- color: args.color,
241
- labelColor: args.labelColor,
242
- ...args.styleParams
243
- }).filter(([, value]) => value).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
244
- const badges = {
245
- npmVersion: {
246
- enabled: ctx.name && args.npmVersion !== false,
247
- ...badgeTypes.npmVersion
248
- },
249
- npmDownloads: {
250
- enabled: ctx.name && args.npmDownloads !== false,
251
- ...badgeTypes.npmDownloads
252
- },
253
- bundlephobia: {
254
- enabled: args.bundlephobia && ctx.name,
255
- ...badgeTypes.bundlephobia
256
- },
257
- bundlejs: {
258
- enabled: args.bundlejs && ctx.name,
259
- ...badgeTypes.bundlejs
260
- },
261
- packagephobia: {
262
- enabled: args.packagephobia && ctx.name,
263
- ...badgeTypes.packagephobia
264
- },
265
- codecov: {
266
- enabled: args.codecov && ctx.github,
267
- ...badgeTypes.codecov
268
- },
269
- license: {
270
- enabled: args.license && ctx.github,
271
- ...badgeTypes.license
272
- },
273
- engine: {
274
- enabled: args.engine && ctx.name,
275
- ...badgeTypes.engine
276
- }
277
- };
278
- const md = [];
279
- for (const [badgeType, badge] of Object.entries(badges)) {
280
- if (!badge.enabled || !provider[badgeType]) continue;
281
- const to = fillStr(badge.to);
282
- const imgURL = fillStr(provider[badgeType]) + (providerParams ? `?${providerParams}` : "");
283
- md.push(link(to, image(imgURL, badge.name)));
284
- }
285
- return { contents: md.join("\n") };
286
- }
287
- });
288
- //#endregion
289
- //#region src/generators/pm.ts
290
- const INSTALL_COMMANDS = [
291
- ["npm", "install"],
292
- ["yarn", "add"],
293
- ["pnpm", "add"],
294
- ["bun", "install"],
295
- [
296
- "deno",
297
- "install",
298
- " --dev",
299
- "npm:"
300
- ]
301
- ];
302
- const NYPM_COMMAND = ["npx nypm", "install"];
303
- const RUN_COMMANDS = [
304
- ["npm", "npx "],
305
- ["pnpm", "pnpm dlx "],
306
- ["bun", "bunx "],
307
- ["deno", "deno run -A npm:"]
308
- ];
309
- const pmInstall = defineGenerator({
310
- name: "pm-install",
311
- async generate({ config, args }) {
312
- const { name, version } = await getPkg(config.dir, args);
313
- if (!name) return { contents: "<!-- package name is unspecified -->" };
314
- let versionSuffix = "";
315
- if (args.version) versionSuffix = typeof args.version === "string" ? `@${args.version}` : `@^${version}`;
316
- const contents = (args.auto === false ? INSTALL_COMMANDS : [NYPM_COMMAND, ...INSTALL_COMMANDS]).map(([cmd, install, dev = " -D", pkgPrefix = ""]) => `# ${cmd.includes("nypm") ? "✨ Auto-detect" : cmd}\n${cmd} ${install}${args.dev ? dev : args.global ? "g" : ""} ${pkgPrefix}${name}${versionSuffix}`);
317
- if ((args.separate ?? false) === false) return { contents: md.codeBlock(contents.join("\n\n"), "sh") };
318
- return { contents: contents.map((cmd) => md.codeBlock(cmd, "sh")).join("\n\n") };
319
- }
320
- });
321
- const pmX = defineGenerator({
322
- name: "pm-x",
323
- async generate({ config, args }) {
324
- const { name, version } = await getPkg(config.dir, args);
325
- if (!name) return { contents: "<!-- package name is unspecified -->" };
326
- let versionSuffix = "";
327
- if (args.version) versionSuffix = typeof args.version === "string" ? `@${args.version}` : `@${version}`;
328
- const contents = RUN_COMMANDS.map(([pm, cmd]) => `# ${pm}\n${cmd}${name}${versionSuffix}${args.args ? ` ${args.args}` : ""}`);
329
- if ((args.separate ?? false) === false) return { contents: md.codeBlock(contents.join("\n\n"), "sh") };
330
- return { contents: contents.map((cmd) => md.codeBlock(cmd, "sh")).join("\n\n") };
331
- }
332
- });
333
- //#endregion
334
- //#region src/generators/fetch.ts
335
- const fetch = defineGenerator({
336
- name: "fetch",
337
- async generate({ args }) {
338
- const { $fetch } = await import("ofetch");
339
- let url = args.url;
340
- if (!url) throw new Error("URL is required!");
341
- if (url.startsWith("gh:")) url = `https://raw.githubusercontent.com/${url.slice(3)}`;
342
- return { contents: await $fetch(url) };
343
- }
344
- });
345
- //#endregion
346
- //#region src/generators/jsimport.ts
347
- const DEFAULT_CDN = "https://esm.sh/";
348
- const jsimport = defineGenerator({
349
- name: "jsimport",
350
- async generate({ config, args }) {
351
- const { name } = await getPkg(config.dir, args);
352
- const importPath = name + (args.path || "");
353
- const importNames = [].concat(args.import, args.imports).filter(Boolean).flatMap((i) => i.split(/\s*,\s*/));
354
- if (args.src) {
355
- const exportNames = findExportNames(await readFile(await resolvePath(args.src, { url: config.dir }), "utf8"));
356
- if (exportNames && exportNames.length > 0) importNames.push(...exportNames);
357
- }
358
- const lines = [];
359
- const fmtImports = importNames.length > 1 ? `\n${importNames.map((i) => " " + i + ",").join("\n")}\n` : importNames[0] && ` ${importNames[0]} ` || "";
360
- const formatMultiLine = (str) => {
361
- return str.length > (args.printWidth || 80) ? str : str.replace(/\n/g, "").replace(/,\s*}/, "}").replace(/(\w)}/, "$1 }").replace(/\s+/g, " ");
362
- };
363
- if (args.esm !== false) {
364
- const code = formatMultiLine(`import {${fmtImports}} from "${importPath}";`);
365
- lines.push("**ESM** (Node.js, Bun, Deno)", md.codeBlock(code, "js"));
366
- }
367
- if (args.cjs) {
368
- const code = formatMultiLine(`const {${fmtImports}} = require("${importPath}");`);
369
- lines.push("**CommonJS** (Legacy Node.js)", md.codeBlock(code, "js"));
370
- }
371
- if (args.cdn) {
372
- const code = formatMultiLine(`import {${fmtImports}} from "${typeof args.cdn === "string" ? args.cdn : DEFAULT_CDN}${importPath}";`);
373
- lines.push("**CDN** (Deno and Browsers)", md.codeBlock(code, "js"));
374
- }
375
- return { contents: lines.join("\n\n") };
376
- }
377
- });
378
- //#endregion
379
- //#region src/generators/with-automd.ts
380
- const withAutomd = defineGenerator({
381
- name: "with-automd",
382
- generate({ args }) {
383
- const lastUpdate = args.lastUpdate ? ` (last updated: ${typeof args.lastUpdate === "string" ? args.lastUpdate : (/* @__PURE__ */ new Date()).toDateString()})` : "";
384
- const emoji = args.emoji === false ? "" : "🤖 ";
385
- const lines = [];
386
- if (args.separator !== false) lines.push("---", "");
387
- lines.push(`_${emoji}auto updated with [automd](https://automd.unjs.io)${lastUpdate}_`);
388
- return { contents: lines.join("\n") };
389
- }
390
- });
391
- //#endregion
392
- //#region src/generators/file.ts
393
- const file = defineGenerator({
394
- name: "file",
395
- async generate({ args, config, url }) {
396
- const fullPath = resolvePath$1(args.src, {
397
- url,
398
- dir: config.dir
399
- });
400
- let contents = await readFile(fullPath, "utf8");
401
- if (!args.noTrim) contents = contents.trim();
402
- if (args.lines) {
403
- const groups = /^(?<startLine>\d+)?:(?<endLine>\d+)?$/.exec(args.lines)?.groups;
404
- if (!groups) throw new Error("invalid lines format");
405
- const lines = contents.split("\n");
406
- const startLine = Number(groups.startLine) || 1;
407
- const endLine = Number(groups.endLine) || lines.length;
408
- if (startLine < 1) throw new Error("first line's index can not be smaller than 1");
409
- contents = lines.slice(startLine - 1, endLine).join("\n");
410
- }
411
- if (args.code) contents = md.codeBlock(contents, args.lang || extname(fullPath).slice(1), { ext: args.name === false ? void 0 : typeof args.name === "string" ? args.name : `[${basename(fullPath)}]` });
412
- return { contents };
413
- }
414
- });
415
- //#endregion
416
- //#region src/generators/contributors.ts
417
- const PROVIDERS = {
418
- CONTRIB_ROCKS: "contrib.rocks",
419
- MARKUPGO: "markupgo"
420
- };
421
- const contributors = defineGenerator({
422
- name: "contributors",
423
- async generate({ config, args }) {
424
- const { github } = await getPkg(config.dir, args);
425
- const provider = args.provider || PROVIDERS.CONTRIB_ROCKS;
426
- if (!github) throw new Error("`github` is required!");
427
- const lines = [];
428
- if (typeof args.license === "string") lines.push(`Published under the [${args.license.toUpperCase()}](https://github.com/${github}/blob/main/LICENSE) license.`);
429
- let madeBy = `[community](https://github.com/${github}/graphs/contributors) 💛`;
430
- if (typeof args.author === "string") {
431
- const authors = args.author.split(",").map((author) => author.trim()).map((user) => `[@${user}](https://github.com/${user})`).join(", ");
432
- if (authors.length > 0) madeBy = `${authors} and ${madeBy}`;
433
- }
434
- lines.push(`Made by ${madeBy}`);
435
- if (provider === PROVIDERS.MARKUPGO) {
436
- const params = [];
437
- args = {
438
- circleSize: "64",
439
- center: "true",
440
- ...args
441
- };
442
- if (Number(args.max) >= 0) params.push(["count", args.max]);
443
- if (Number(args.width)) params.push(["width", args.width]);
444
- if (Number(args.circleSize)) params.push(["circleSize", args.circleSize]);
445
- if (Number(args.circleRadius)) params.push(["circleRadius", args.circleRadius]);
446
- if (Number(args.circleSpacing)) params.push(["circleSpacing", args.circleSpacing]);
447
- if (args.center) params.push(["center", Boolean(args.center).toString()]);
448
- if (!args.markupGoLogo) params.push(["removeLogo", "true"]);
449
- if (args.anon) params.push(["anon", Boolean(args.anon).toString()]);
450
- let paramsStr = params.map(([k, v]) => `${k}=${v}`).join("&");
451
- paramsStr = paramsStr ? `?${paramsStr}` : "";
452
- lines.push(`<br><br>`, `<a href="https://github.com/${github}/graphs/contributors">`, `<img src="https://markupgo.com/github/${github}/contributors${paramsStr}" />`, `</a>`);
453
- } else {
454
- const params = [["repo", github]];
455
- if (args.max) params.push(["max", args.max]);
456
- if (args.anon) params.push(["anon", args.anon]);
457
- const paramsStr = params.map(([k, v]) => `${k}=${v}`).join("&");
458
- lines.push(`<br><br>`, `<a href="https://github.com/${github}/graphs/contributors">`, `<img src="https://contrib.rocks/image?${paramsStr}" />`, `</a>`);
459
- }
460
- return { contents: lines.join("\n") };
461
- }
462
- });
463
- //#endregion
464
- //#region src/generators/dir-tree.ts
465
- const DEFAULT_IGNORE = [
466
- "node_modules",
467
- ".git",
468
- ".DS_Store",
469
- ".nuxt",
470
- ".output",
471
- ".nitro",
472
- "dist",
473
- "coverage",
474
- ".cache",
475
- ".turbo"
476
- ];
477
- async function parseGitignore(dir) {
478
- try {
479
- return (await readFile(join(dir, ".gitignore"), "utf8")).split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
480
- } catch {
481
- return [];
482
- }
483
- }
484
- function shouldIgnore(name, ignorePatterns, defaultIgnore) {
485
- const allPatterns = [...defaultIgnore, ...ignorePatterns];
486
- for (const pattern of allPatterns) {
487
- if (name === pattern.replace(/^\//, "").replace(/\/$/, "")) return true;
488
- if (pattern.startsWith("*") && name.endsWith(pattern.slice(1))) return true;
489
- if (pattern.endsWith("*") && name.startsWith(pattern.slice(0, -1))) return true;
490
- }
491
- return false;
492
- }
493
- async function buildTree(dir, ignorePatterns, maxDepth, currentDepth = 0) {
494
- if (maxDepth > 0 && currentDepth >= maxDepth) return [];
495
- const entries = await readdir(dir);
496
- const result = [];
497
- for (const entry of entries) {
498
- if (shouldIgnore(entry, ignorePatterns, DEFAULT_IGNORE)) continue;
499
- const fullPath = join(dir, entry);
500
- const isDirectory = (await stat(fullPath)).isDirectory();
501
- const treeEntry = {
502
- name: entry,
503
- isDirectory
504
- };
505
- if (isDirectory) treeEntry.children = await buildTree(fullPath, ignorePatterns, maxDepth, currentDepth + 1);
506
- result.push(treeEntry);
507
- }
508
- result.sort((a, b) => {
509
- if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
510
- return a.name.localeCompare(b.name);
511
- });
512
- return result;
513
- }
514
- function renderTree(entries, isLast = []) {
515
- const lines = [];
516
- for (let i = 0; i < entries.length; i++) {
517
- const entry = entries[i];
518
- const isLastEntry = i === entries.length - 1;
519
- let linePrefix = "";
520
- for (const element_ of isLast) linePrefix += element_ ? " " : "│ ";
521
- const connector = isLastEntry ? "└── " : "├── ";
522
- const suffix = entry.isDirectory ? "/" : "";
523
- lines.push(`${linePrefix}${connector}${entry.name}${suffix}`);
524
- if (entry.children && entry.children.length > 0) {
525
- const childLines = renderTree(entry.children, [...isLast, isLastEntry]);
526
- lines.push(...childLines);
527
- }
528
- }
529
- return lines;
530
- }
531
- //#endregion
532
- //#region src/generators/index.ts
533
- var generators_default = {
534
- jsdocs,
535
- badges,
536
- "pm-i": pmInstall,
537
- "pm-install": pmInstall,
538
- "pm-x": pmX,
539
- fetch,
540
- file,
541
- jsimport,
542
- "with-automd": withAutomd,
543
- contributors,
544
- "dir-tree": defineGenerator({
545
- name: "dir-tree",
546
- async generate({ args, config, url }) {
547
- const srcPath = args.src || ".";
548
- const fullPath = resolvePath$1(srcPath, {
549
- url,
550
- dir: config.dir
551
- });
552
- if (!(await stat(fullPath)).isDirectory()) throw new Error(`Path "${srcPath}" is not a directory`);
553
- const userIgnore = args.ignore ? String(args.ignore).split(",").map((s) => s.trim()) : [];
554
- return { contents: "```\n" + renderTree(await buildTree(fullPath, [...await parseGitignore(fullPath), ...userIgnore], args.maxDepth ? Number(args.maxDepth) : 0)).join("\n") + "\n```" };
555
- }
556
- })
557
- };
558
- //#endregion
559
- //#region src/_parse.ts
560
- /**
561
- * Searches a markdown document for special sections that `automd` can update.
562
- *
563
- * @param md - The markdown document as a string.
564
- * @returns an array of blocks that can be updated automatically. {@link Block}
565
- */
566
- function findBlocks(md) {
567
- const blocks = [];
568
- for (const match of md.matchAll(/^(?<open><!--\s*automd:(?<generator>.+?)\s+(?<args>.*?)\s*-->)(?<contents>.+?)(?<close>^<!--\s*\/automd\s*-->)/gimsu)) {
569
- if (match.index === void 0 || !match.groups) continue;
570
- const start = match.index + match.groups.open.length || 0;
571
- const end = start + match.groups.contents.length;
572
- blocks.push({
573
- generator: match.groups.generator,
574
- rawArgs: match.groups.args,
575
- contents: match.groups.contents,
576
- loc: {
577
- start,
578
- end
579
- },
580
- _loc: {
581
- start: match.index,
582
- end: match.index + match[0].length
583
- }
584
- });
585
- }
586
- return blocks;
587
- }
588
- /**
589
- * Checks if a markdown document contains sections that can be automatically updated.
590
- *
591
- * @param md - The markdown document as a string.
592
- * @returns true if there are `automd` sections, false otherwise.
593
- */
594
- function containsAutomd(md) {
595
- return /^<!--\s*automd:/gimsu.test(md);
596
- }
597
- /**
598
- * Converts a string of raw arguments to an object.
599
- * Each argument is separated by spaces. Arguments can be key-value pairs separated by '='.
600
- * If an argument starts with "no-", the key is set to false.
601
- * Otherwise it sets the key to true. Keys are converted to camelCase.
602
- * Values are processed to determine their actual type (e.g. string, boolean).
603
- *
604
- * @param {string} rawArgs - The string of arguments to parse.
605
- * @return {Object} - An object with keys derived from the arguments.
606
- * Keys are in camelCase. Values are true, false, or strings.
607
- */
608
- function parseRawArgs(rawArgs) {
609
- const args = Object.create(null);
610
- for (const part of rawArgs.split(/\s+/)) {
611
- const [_key, value] = part.split("=");
612
- const key = _key && camelCase(_key);
613
- if (key && value) args[key] = destr(value);
614
- else if (part.startsWith("no-")) args[part.slice(3)] = false;
615
- else args[part] = true;
616
- }
617
- return args;
618
- }
619
- //#endregion
620
- //#region src/config.ts
621
- const RESOLVED_CONFIG_SYMBOL = Symbol("automdConfig");
622
- function resolveConfig(config) {
623
- if (config && RESOLVED_CONFIG_SYMBOL in config) return config;
624
- const _config = {
625
- dir: ".",
626
- input: "README.md",
627
- generators: {},
628
- [RESOLVED_CONFIG_SYMBOL]: true,
629
- ...config
630
- };
631
- _config.dir = resolve(_config.dir);
632
- _config.input = (Array.isArray(_config.input) ? _config.input : [_config.input]).filter(Boolean);
633
- return _config;
634
- }
635
- async function loadConfig(dir = ".", overrides) {
636
- const { loadConfig } = await import("c12");
637
- dir = resolve(dir);
638
- const { config } = await loadConfig({
639
- cwd: dir,
640
- name: "automd",
641
- dotenv: true,
642
- overrides,
643
- defaults: {
644
- ignore: [
645
- "**/node_modules",
646
- "**/dist",
647
- "**/.*"
648
- ],
649
- dir
650
- }
651
- });
652
- return resolveConfig(config);
653
- }
654
- //#endregion
655
- //#region src/transform.ts
656
- /**
657
- * Edits a markdown document based on certain rules and configurations.
658
- *
659
- * @param contents - The text of the markdown document you want to edit.
660
- * @param _config - Optional. The settings that affect how the document will be edited. See {@link Config}.
661
- * @param url - Optional. The URL associated with the document, if any.
662
- * @returns - The result of the transformation, including any changes made and how long it took. See {@link TransformResult}.
663
- */
664
- async function transform(contents, _config, url) {
665
- const start = performance.now();
666
- const config = resolveConfig(_config);
667
- const editor = new MagicString(contents);
668
- const updates = [];
669
- const generators = {
670
- ...generators_default,
671
- ...config.generators
672
- };
673
- const blocks = findBlocks(contents);
674
- for (const block of blocks) {
675
- const result = await _transformBlock(block, config, generators, url);
676
- if (result.unwrap) editor.overwrite(block._loc.start, block._loc.end, `${result.contents.trim()}`);
677
- else editor.overwrite(block.loc.start, block.loc.end, `\n\n${result.contents.trim()}\n\n`);
678
- updates.push({
679
- block,
680
- result
681
- });
682
- }
683
- const hasChanged = editor.hasChanged();
684
- const hasIssues = updates.some((u) => u.result.issues?.filter(Boolean).length);
685
- const time = performance.now() - start;
686
- return {
687
- hasChanged,
688
- hasIssues,
689
- contents: hasChanged ? editor.toString() : contents,
690
- updates,
691
- time
692
- };
693
- }
694
- async function _transformBlock(block, config, generators, url) {
695
- const args = parseRawArgs(block.rawArgs);
696
- const generator = generators[block.generator];
697
- if (!generator) {
698
- const suggestions = (await import("didyoumean2").then((r) => r.default || r))(block.generator, Object.keys(generators));
699
- const error = `Unknown generator:\`${block.generator}\`.${suggestions ? ` Did you mean "generator:\`${suggestions}\`"?` : ""}`;
700
- return {
701
- contents: `<!-- ⚠️ ${error} -->`,
702
- issues: [error]
703
- };
704
- }
705
- const context = {
706
- args,
707
- config,
708
- block,
709
- transform: (contents) => transform(contents, config, url),
710
- url
711
- };
712
- try {
713
- const result = await generator.generate(context);
714
- if (!result.unwrap && containsAutomd(result.contents)) result.unwrap = true;
715
- if (result.unwrap) {
716
- const nestedRes = await context.transform(result.contents);
717
- result.contents = nestedRes.contents;
718
- if (nestedRes.hasIssues) result.issues = [...result.issues || [], ...nestedRes.updates.flatMap((u) => u.result.issues || [])].filter(Boolean);
719
- }
720
- return result;
721
- } catch (error) {
722
- return {
723
- contents: `<!-- ⚠️ (${block.generator}) ${error.message || error} -->`,
724
- issues: [error]
725
- };
726
- }
727
- }
728
- //#endregion
729
- //#region src/automd.ts
730
- /**
731
- * Scans a markdown file looking for special comments.
732
- * These comments tell the function to add or update certain parts of the file automatically.
733
- * You can change how this works by giving it different settings in the `_config` option.
734
- *
735
- * @param _config - The settings to use for the update process. See {@link Config}.
736
- * @returns - An object containing the results of the update, including any changes made and any problems found. See {@link AutomdReturn}.
737
- *
738
- * @see https://automd.unjs.io/guide
739
- */
740
- async function automd(_config = {}) {
741
- const start = performance.now();
742
- const config = await loadConfig(_config.dir, _config);
743
- let inputFiles = config.input;
744
- if (inputFiles.some((i) => i.includes("*"))) {
745
- const { glob } = await import("tinyglobby");
746
- inputFiles = await glob(inputFiles, {
747
- cwd: config.dir,
748
- absolute: false,
749
- onlyFiles: true,
750
- ignore: config.ignore
751
- });
752
- } else inputFiles = inputFiles.map((i) => resolve(config.dir, i)).filter((i) => existsSync(i)).map((i) => relative(config.dir, i));
753
- const multiFiles = inputFiles.length > 1;
754
- const cache = /* @__PURE__ */ new Map();
755
- const results = await Promise.all(inputFiles.map((i) => _automd(i, config, multiFiles, cache)));
756
- let unwatch;
757
- if (config.watch) unwatch = await _watch(inputFiles, config, multiFiles, cache);
758
- return {
759
- time: performance.now() - start,
760
- results,
761
- config,
762
- unwatch
763
- };
764
- }
765
- async function _automd(relativeInput, config, multiFiles, cache) {
766
- const start = performance.now();
767
- const input = resolve(config.dir, relativeInput);
768
- const contents = await promises.readFile(input, "utf8");
769
- const cachedResult = await cache.get(input);
770
- if (cachedResult?.contents === contents) {
771
- cachedResult.time = performance.now() - start;
772
- return cachedResult;
773
- }
774
- const transformResult = await transform(contents, config, pathToFileURL(input));
775
- const output = multiFiles ? resolve(config.dir, config.output || ".", relativeInput) : resolve(config.dir, config.output || relativeInput);
776
- await promises.mkdir(dirname(output), { recursive: true });
777
- await promises.writeFile(output, transformResult.contents, "utf8");
778
- const result = {
779
- input,
780
- output,
781
- ...transformResult
782
- };
783
- cache.set(input, result);
784
- result.time = performance.now() - start;
785
- return result;
786
- }
787
- async function _watch(inputFiles, config, multiFiles, cache) {
788
- const watcher = await import("@parcel/watcher");
789
- const watchCb = debounce(async (_err, events) => {
790
- const filesToUpdate = events.map((e) => relative(config.dir, e.path)).filter((p) => inputFiles.includes(p));
791
- const start = performance.now();
792
- const results = await Promise.all(filesToUpdate.map((f) => _automd(f, config, multiFiles, cache)));
793
- const time = performance.now() - start;
794
- if (config.onWatch) config.onWatch({
795
- results,
796
- time
797
- });
798
- });
799
- const subscription = await watcher.subscribe(config.dir, watchCb, { ignore: config.ignore });
800
- process.on("SIGINT", () => {
801
- subscription.unsubscribe();
802
- });
803
- return subscription.unsubscribe;
804
- }
805
- //#endregion
2
+ import { loadConfig, resolveConfig } from "./config.js";
3
+ import { defineGenerator } from "./generator.js";
4
+ import { t as transform } from "./transform-BOfYBrHa.js";
5
+ import { automd } from "./automd.js";
806
6
  export { automd, defineGenerator, loadConfig, resolveConfig, transform };
807
7
 
808
- /*! Built with love & coffee ☕ */
809
- //# sourceMappingURL=index.js.map
8
+ /*! Built with love & coffee ☕ */