@bjmhe/automd 0.0.0
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/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +809 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-PRESENT Benjamin He <https://github.com/bjmhe>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 🤖 automd
|
|
2
|
+
|
|
3
|
+
<!-- automd:badges bundlephobia license engine provider=npmx -->
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/@bjmhe/automd)
|
|
6
|
+
[](https://npm.chart.dev/@bjmhe/automd)
|
|
7
|
+
[](https://bundlephobia.com/package/@bjmhe/automd)
|
|
8
|
+
[](https://github.com/bjmhe/automd/blob/main/LICENSE)
|
|
9
|
+
[](https://npmx.dev/api/registry/badge/engines/@bjmhe/automd)
|
|
10
|
+
|
|
11
|
+
<!-- /automd -->
|
|
12
|
+
|
|
13
|
+
Automated markdown maintainer!
|
|
14
|
+
|
|
15
|
+
📚 [documentation](https://automd.unjs.io)
|
|
16
|
+
|
|
17
|
+
<!-- automd:fetch url="gh:unjs/.github/main/snippets/readme-contrib-node-pnpm.md" -->
|
|
18
|
+
|
|
19
|
+
## Contribution
|
|
20
|
+
|
|
21
|
+
<details>
|
|
22
|
+
<summary>Local development</summary>
|
|
23
|
+
|
|
24
|
+
- Clone this repository
|
|
25
|
+
- Install the latest LTS version of [Node.js](https://nodejs.org/en/)
|
|
26
|
+
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
|
|
27
|
+
- Install dependencies using `pnpm install`
|
|
28
|
+
- Run tests using `pnpm dev` or `pnpm test`
|
|
29
|
+
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
<!-- /automd -->
|
|
33
|
+
|
|
34
|
+
## License
|
|
35
|
+
|
|
36
|
+
<!-- automd:contributors license=MIT author="pi0" -->
|
|
37
|
+
|
|
38
|
+
Published under the [MIT](https://github.com/bjmhe/automd/blob/main/LICENSE) license.
|
|
39
|
+
Made by [@pi0](https://github.com/pi0) and [community](https://github.com/bjmhe/automd/graphs/contributors) 💛
|
|
40
|
+
<br><br>
|
|
41
|
+
<a href="https://github.com/bjmhe/automd/graphs/contributors">
|
|
42
|
+
<img src="https://contrib.rocks/image?repo=bjmhe/automd" />
|
|
43
|
+
</a>
|
|
44
|
+
|
|
45
|
+
<!-- /automd -->
|
|
46
|
+
|
|
47
|
+
<!-- automd:with-automd -->
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
_🤖 auto updated with [automd](https://automd.unjs.io)_
|
|
52
|
+
|
|
53
|
+
<!-- /automd -->
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/*! Keep it simple, keep it free */
|
|
2
|
+
//#region src/_parse.d.ts
|
|
3
|
+
interface Block {
|
|
4
|
+
/**
|
|
5
|
+
* The name of the generator to use for updates.
|
|
6
|
+
*/
|
|
7
|
+
generator: string;
|
|
8
|
+
/**
|
|
9
|
+
* The arguments that are passed to the generator.
|
|
10
|
+
*/
|
|
11
|
+
rawArgs: string;
|
|
12
|
+
/**
|
|
13
|
+
* The current content of the block.
|
|
14
|
+
*/
|
|
15
|
+
contents: string;
|
|
16
|
+
/**
|
|
17
|
+
* The location of the content in the original document.
|
|
18
|
+
*/
|
|
19
|
+
loc: {
|
|
20
|
+
start: number;
|
|
21
|
+
end: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The location including the automd comments.
|
|
25
|
+
*/
|
|
26
|
+
_loc: {
|
|
27
|
+
start: number;
|
|
28
|
+
end: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/transform.d.ts
|
|
33
|
+
interface TransformResult {
|
|
34
|
+
/**
|
|
35
|
+
* Wether if the document has been modified at all.
|
|
36
|
+
*/
|
|
37
|
+
hasChanged: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Whether if there were any problems found in the document.
|
|
40
|
+
*/
|
|
41
|
+
hasIssues: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The text of the document after it was transformed.
|
|
44
|
+
*/
|
|
45
|
+
contents: string;
|
|
46
|
+
/**
|
|
47
|
+
* A list of specific parts that have been transformed in the document.
|
|
48
|
+
*/
|
|
49
|
+
updates: {
|
|
50
|
+
/**
|
|
51
|
+
* The specific part of the document that has been transformed.
|
|
52
|
+
*/
|
|
53
|
+
block: Block;
|
|
54
|
+
/**
|
|
55
|
+
* What the transform has done to this part of the document.
|
|
56
|
+
*/
|
|
57
|
+
result: GenerateResult;
|
|
58
|
+
}[];
|
|
59
|
+
/**
|
|
60
|
+
* How long the editing process took, measured in milliseconds.
|
|
61
|
+
*/
|
|
62
|
+
time: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Edits a markdown document based on certain rules and configurations.
|
|
66
|
+
*
|
|
67
|
+
* @param contents - The text of the markdown document you want to edit.
|
|
68
|
+
* @param _config - Optional. The settings that affect how the document will be edited. See {@link Config}.
|
|
69
|
+
* @param url - Optional. The URL associated with the document, if any.
|
|
70
|
+
* @returns - The result of the transformation, including any changes made and how long it took. See {@link TransformResult}.
|
|
71
|
+
*/
|
|
72
|
+
declare function transform(contents: string, _config?: Config, url?: string): Promise<TransformResult>;
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/generator.d.ts
|
|
75
|
+
interface GenerateContext {
|
|
76
|
+
args: Record<string, any>;
|
|
77
|
+
config: ResolvedConfig;
|
|
78
|
+
block: Block;
|
|
79
|
+
url?: string;
|
|
80
|
+
transform: (contents: string) => Promise<TransformResult>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The result of generating a component.
|
|
84
|
+
*/
|
|
85
|
+
interface GenerateResult {
|
|
86
|
+
/**
|
|
87
|
+
* The generated component
|
|
88
|
+
*/
|
|
89
|
+
contents: string;
|
|
90
|
+
/**
|
|
91
|
+
* A list of issues that occurred during generation.
|
|
92
|
+
*/
|
|
93
|
+
issues?: string[];
|
|
94
|
+
/**
|
|
95
|
+
* Whether to unwrap the component.
|
|
96
|
+
*/
|
|
97
|
+
unwrap?: boolean;
|
|
98
|
+
}
|
|
99
|
+
interface Generator {
|
|
100
|
+
name: string;
|
|
101
|
+
generate: (ctx: GenerateContext) => GenerateResult | Promise<GenerateResult>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
declare function defineGenerator(generator: Generator): Generator;
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/config.d.ts
|
|
109
|
+
interface Config {
|
|
110
|
+
/**
|
|
111
|
+
* The working directory
|
|
112
|
+
*
|
|
113
|
+
* @default "." (current directory)
|
|
114
|
+
*/
|
|
115
|
+
dir?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Name or path to the input file or files with glob patterns.
|
|
118
|
+
*
|
|
119
|
+
* @default "README.md"
|
|
120
|
+
*/
|
|
121
|
+
input?: string | string[];
|
|
122
|
+
/**
|
|
123
|
+
* Name or path of the output files. If not provided, the input file will be overwritten.
|
|
124
|
+
*
|
|
125
|
+
* @default input
|
|
126
|
+
*/
|
|
127
|
+
output?: string;
|
|
128
|
+
/**
|
|
129
|
+
* Ignore patterns if input is a glob pattern
|
|
130
|
+
*
|
|
131
|
+
* @default ["node_modules", "dist", "/.*"]
|
|
132
|
+
*/
|
|
133
|
+
ignore?: string[];
|
|
134
|
+
/**
|
|
135
|
+
* Watch for changes in input files and regenerate output
|
|
136
|
+
*/
|
|
137
|
+
watch?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Watch callback
|
|
140
|
+
*/
|
|
141
|
+
onWatch?: (event: {
|
|
142
|
+
results: AutomdResult[];
|
|
143
|
+
time: number;
|
|
144
|
+
}) => void;
|
|
145
|
+
/** Custom generators */
|
|
146
|
+
generators?: Record<string, Generator>;
|
|
147
|
+
}
|
|
148
|
+
declare const RESOLVED_CONFIG_SYMBOL: unique symbol;
|
|
149
|
+
type ResolvedConfig = { [P in keyof Config]-?: Config[P] } & {
|
|
150
|
+
[RESOLVED_CONFIG_SYMBOL]: true;
|
|
151
|
+
input: string[];
|
|
152
|
+
output?: string;
|
|
153
|
+
};
|
|
154
|
+
declare function resolveConfig(config?: Config | ResolvedConfig): ResolvedConfig;
|
|
155
|
+
declare function loadConfig(dir: string | undefined, overrides: Config): Promise<ResolvedConfig>;
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/automd.d.ts
|
|
158
|
+
interface AutomdResult extends TransformResult {
|
|
159
|
+
input: string;
|
|
160
|
+
output: string;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Describes what you get back from the `automd` function.
|
|
164
|
+
*/
|
|
165
|
+
interface AutomdReturn {
|
|
166
|
+
/**
|
|
167
|
+
* A list of the changes made to the file(s) by `automd`.
|
|
168
|
+
*/
|
|
169
|
+
results: AutomdResult[];
|
|
170
|
+
/**
|
|
171
|
+
* How long it took to make the changes, in milliseconds.
|
|
172
|
+
*/
|
|
173
|
+
time: number;
|
|
174
|
+
/**
|
|
175
|
+
* The resolved configuration that were used for these changes.
|
|
176
|
+
*/
|
|
177
|
+
config: ResolvedConfig;
|
|
178
|
+
/**
|
|
179
|
+
* If you started watching the file(s) for changes, this function can be called to stop watching.
|
|
180
|
+
*/
|
|
181
|
+
unwatch?: () => void | Promise<void>;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Scans a markdown file looking for special comments.
|
|
185
|
+
* These comments tell the function to add or update certain parts of the file automatically.
|
|
186
|
+
* You can change how this works by giving it different settings in the `_config` option.
|
|
187
|
+
*
|
|
188
|
+
* @param _config - The settings to use for the update process. See {@link Config}.
|
|
189
|
+
* @returns - An object containing the results of the update, including any changes made and any problems found. See {@link AutomdReturn}.
|
|
190
|
+
*
|
|
191
|
+
* @see https://automd.unjs.io/guide
|
|
192
|
+
*/
|
|
193
|
+
declare function automd(_config?: Config): Promise<AutomdReturn>;
|
|
194
|
+
//#endregion
|
|
195
|
+
export { AutomdResult, AutomdReturn, Config, GenerateContext, GenerateResult, Generator, ResolvedConfig, TransformResult, automd, defineGenerator, loadConfig, resolveConfig, transform };
|
|
196
|
+
/*! Built with love & coffee ☕ */
|
|
197
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,809 @@
|
|
|
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
|
|
806
|
+
export { automd, defineGenerator, loadConfig, resolveConfig, transform };
|
|
807
|
+
|
|
808
|
+
/*! Built with love & coffee ☕ */
|
|
809
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["resolvePath","resolvePath","resolvePath","resolvePath","_fetch","builtinGenerators","fsp"],"sources":["../src/generator.ts","../src/_utils.ts","../src/generators/jsdocs.ts","../src/generators/badges.ts","../src/generators/pm.ts","../src/generators/fetch.ts","../src/generators/jsimport.ts","../src/generators/with-automd.ts","../src/generators/file.ts","../src/generators/contributors.ts","../src/generators/dir-tree.ts","../src/generators/index.ts","../src/_parse.ts","../src/config.ts","../src/transform.ts","../src/automd.ts"],"sourcesContent":["import type { Block } from \"./_parse.ts\";\nimport type { ResolvedConfig } from \"./config.ts\";\nimport type { TransformResult } from \"./transform.ts\";\n\nexport interface GenerateContext {\n args: Record<string, any>;\n config: ResolvedConfig;\n block: Block;\n url?: string;\n transform: (contents: string) => Promise<TransformResult>;\n}\n\n/**\n * The result of generating a component.\n */\nexport interface GenerateResult {\n /**\n * The generated component\n */\n contents: string;\n\n /**\n * A list of issues that occurred during generation.\n */\n issues?: string[];\n\n /**\n * Whether to unwrap the component.\n */\n unwrap?: boolean;\n}\n\nexport interface Generator {\n name: string;\n generate: (ctx: GenerateContext) => GenerateResult | Promise<GenerateResult>;\n}\n\n/**\n * @internal\n */\nexport function defineGenerator(generator: Generator) {\n return generator;\n}\n","import type { PackageJson } from \"pkg-types\";\nimport { readPackageJSON } from \"pkg-types\";\nimport { defu } from \"defu\";\nimport { fileURLToPath } from \"mlly\";\nimport { resolve, join } from \"pathe\";\n\nexport function resolvePath(path: string, { url, dir }: { url?: string; dir: string }) {\n if (path.startsWith(\"/\")) {\n return join(dir, path);\n }\n return url ? fileURLToPath(new URL(path, url)) : resolve(dir, path);\n}\n\nexport async function getPkg(dir: string, input: Record<string, string> = {}) {\n const pkg = await readPackageJSON(dir).catch(() => undefined);\n return defu(\n {\n name: input.name,\n version: typeof input.version === \"string\" ? input.version : undefined,\n github: input.github || input.gh,\n },\n {\n name: pkg?.name,\n version: pkg?.version,\n github: _getGitRepo(pkg?.repository),\n },\n {\n name: process.env.npm_package_name,\n version: process.env.npm_package_version,\n },\n );\n}\n\nfunction _getGitRepo(repo: PackageJson[\"repository\"]) {\n const url = typeof repo === \"string\" ? repo : repo?.url;\n if (!url || typeof url !== \"string\") {\n return;\n }\n const match = /(?:https:\\/\\/github\\.com\\/|gh:|github:|)([\\w-]+)\\/([\\w-]+)/.exec(url);\n if (match && match[1] && match[2]) {\n return `${match[1]}/${match[2]}`;\n }\n}\n","import type { Schema } from \"untyped\";\nimport { titleCase } from \"scule\";\nimport { defineGenerator } from \"../generator.ts\";\nimport { resolvePath } from \"../_utils.ts\";\n\ntype RenderOptions = {\n group?: string | string[];\n defaultGroup?: string;\n};\n\nexport const jsdocs = defineGenerator({\n name: \"jsdocs\",\n async generate({ config, args, url }) {\n const { loadSchema } = await import(\"untyped/loader\");\n const fullPath = resolvePath(args.src, { url, dir: config.dir });\n\n const schema = await loadSchema(fullPath, {\n jiti: {\n // TODO: untyped should be able to reuse same jiti instance to avoid race conditions\n fsCache: false,\n moduleCache: false,\n },\n });\n\n return {\n contents: _render(schema, args as RenderOptions, Number.parseInt(args.headingLevel) || 2)\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\"),\n };\n },\n});\n\n// -- main renderer --\n\nfunction _render(schema: Schema, opts: RenderOptions, headingLevel: number) {\n const sections = Object.create(null) as Record<string, [string, string[]][]>;\n for (const [key, keySchema] of Object.entries(schema.properties || {})) {\n const section = _renderSection(key, keySchema, opts, headingLevel + 1);\n if (!section) {\n continue;\n }\n sections[section.group] = sections[section.group] || [];\n sections[section.group]!.push([section.heading, section.lines]);\n }\n\n const lines: string[] = [];\n\n const sortedGroups = Object.keys(sections).sort((a, b) => {\n if (a === \"\") {\n return 1;\n }\n if (b === \"\") {\n return -1;\n }\n return a.localeCompare(b);\n });\n for (const group of sortedGroups) {\n if (group) {\n lines.push(`\\n${\"#\".repeat(headingLevel)} ${titleCase(group)}\\n`);\n }\n const sortedSections = sections[group]!.sort((a, b) => a[0].localeCompare(b[0]));\n for (const section of sortedSections) {\n const heading = `\\n${\"#\".repeat(headingLevel + 1)} ${section[0]}\\n`;\n lines.push(heading, ...section[1]);\n }\n }\n\n return lines;\n}\n\n// --- section renderer ---\n\nfunction _renderSection(key: string, schema: Schema, opts: RenderOptions, headingLevel: number) {\n // Parse tag annotations\n const tags = _parseTags(schema.tags);\n\n // Ignore deprecated and intenral functions\n if (tags.some((t) => t.tag === \"@deprecated\" || t.tag === \"@internal\")) {\n return;\n }\n\n // Find group\n const group = tags.find((t) => t.tag === \"@group\")?.contents || opts.defaultGroup || \"\";\n\n // Filter by group if specified\n if (\n opts.group &&\n (typeof opts.group === \"string\" ? group !== opts.group : !opts.group.includes(group))\n ) {\n return;\n }\n\n let heading = `\\`${key}\\``;\n const lines: string[] = [];\n\n if (schema.type === \"function\") {\n // Function signature in heading\n heading = `\\`${_generateFunctionSig(key, schema)}\\``;\n } else if (schema.type !== \"object\") {\n // JS value\n lines.push(`- **Type**: \\`${schema.markdownType || schema.tsType || schema.type}\\``);\n if (\"default\" in schema) {\n lines.push(`- **Default**: \\`${JSON.stringify(schema.default)}\\``);\n }\n lines.push(\"\");\n }\n\n // Add body\n lines.push(..._renderBody(schema));\n\n // Render example tags\n for (const tag of tags) {\n if (tag.tag === \"@example\") {\n const codeBlock = tag.contents.startsWith(\"`\")\n ? tag.contents\n : `\\`\\`\\`ts\\n${tag.contents}\\n\\`\\`\\``;\n lines.push(\"\", \"**Example:**\", \"\", codeBlock);\n }\n }\n\n // Add object properties\n if (schema.type === \"object\") {\n lines.push(..._render(schema, opts, headingLevel));\n }\n\n return {\n heading,\n lines,\n group,\n };\n}\n\n// -- body ---\n\nfunction _renderBody(schema: Schema) {\n const lines: string[] = [];\n if (schema.title) {\n lines.push(schema.title.trim());\n }\n if (schema.title && schema.description) {\n // Insert an empty line between the title and the description to separate them.\n lines.push(\"\");\n }\n if (schema.description) {\n // Insert an empty line between each line of the description that contains a newline.\n lines.push(\n ...schema.description\n .split(\"\\n\")\n .map((line) => line.trim())\n .join(\"\\n\\n\")\n .split(\"\\n\"),\n );\n }\n\n return lines;\n}\n\n// --- tag parsing ---\n\nfunction _parseTags(lines: string[] = []) {\n const parsedTags: { tag: string; contents: string }[] = [];\n\n let tag = \"\";\n let contentLines: string[] = [];\n\n for (const line of lines.join(\"\\n\").split(\"\\n\")) {\n if (line.startsWith(\"@\")) {\n if (tag) {\n parsedTags.push({\n tag,\n contents: contentLines.join(\"\\n\"),\n });\n }\n const [_tag, ...rest] = line.split(\" \");\n tag = _tag!;\n contentLines = rest;\n } else {\n contentLines.push(line);\n }\n }\n\n if (tag) {\n parsedTags.push({ tag, contents: contentLines.join(\"\\n\") });\n }\n\n return parsedTags;\n}\n\n// --- function signature ---\n\nfunction _generateFunctionSig(name: string, meta: Schema) {\n return `${name}(${(meta.args || [])\n .map((arg) => {\n let str = arg.name;\n if (arg.optional) {\n str += \"?\";\n }\n const tsType = _simpleArgType(arg.tsType);\n if (tsType) {\n str += `: ${tsType}`;\n }\n return str;\n })\n .join(\", \")})`;\n}\n\nfunction _simpleArgType(tsType = \"\") {\n return tsType\n .split(/\\s*\\|\\s*/)\n .filter((t) => t && t !== \"object\" && t.startsWith(\"{\"))\n .map((ot) =>\n ot\n .split(/\\s*[,;]\\s*/g)\n .map((p) => p.replaceAll(/\\s*:\\s*(string|boolean|number)/g, \"\"))\n .join(\", \"),\n )\n .join(\" | \");\n}\n","import { image, link } from \"mdbox\";\nimport { defineGenerator } from \"../generator.ts\";\nimport { getPkg } from \"../_utils.ts\";\n\ntype BadgeType = keyof typeof badgeTypes;\ntype BadgeProvider = Record<BadgeType, string | false>;\n\nconst badgeTypes = {\n npmVersion: {\n name: \"npm version\",\n to: \"https://npmjs.com/package/{name}\",\n },\n npmDownloads: {\n name: \"npm downloads\",\n to: \"https://npm.chart.dev/{name}\",\n },\n bundlephobia: {\n name: \"bundle size\",\n to: \"https://bundlephobia.com/package/{name}\",\n },\n bundlejs: {\n name: \"bundle size\",\n to: \"https://bundlejs.com/?q={name}\",\n },\n packagephobia: {\n name: \"install size\",\n to: \"https://packagephobia.com/result?p={name}\",\n },\n codecov: {\n name: \"codecov\",\n to: \"https://codecov.io/gh/{github}\",\n },\n license: {\n name: \"license\",\n to: \"https://github.com/{github}/blob/{licenseBranch}/LICENSE\",\n },\n engine: {\n name: \"engine\",\n to: \"https://npmx.dev/api/registry/badge/engines/{name}\",\n }\n};\n\nconst badgeProviders: Record<string, BadgeProvider> = {\n // https://shields.io/badges/static-badge\n shields: {\n npmVersion: \"https://img.shields.io/npm/v/{name}\",\n npmDownloads: \"https://img.shields.io/npm/dm/{name}\",\n bundlephobia: \"https://img.shields.io/bundlephobia/minzip/{name}\",\n packagephobia: \"https://badgen.net/packagephobia/install/{name}\", // https://github.com/badges/shields/issues/1701\n bundlejs: \"https://img.shields.io/bundlejs/size/{name}\",\n codecov: \"https://img.shields.io/codecov/c/gh/{github}\",\n license: \"https://img.shields.io/github/license/{github}\",\n engine: false,\n },\n // https://badgen.net/help\n badgen: {\n npmVersion: \"https://flat.badgen.net/npm/v/{name}\",\n npmDownloads: \"https://flat.badgen.net/npm/dm/{name}\",\n bundlephobia: \"https://flat.badgen.net/bundlephobia/minzip/{name}\",\n bundlejs: false, // https://github.com/badgen/badgen/issues/82\n packagephobia: \"https://flat.badgen.net/packagephobia/install/{name}\",\n codecov: \"https://flat.badgen.net/codecov/c/github/{github}\",\n license: \"https://flat.badgen.net/github/license/{github}\",\n engine: false,\n },\n badgenClassic: {\n npmVersion: \"https://badgen.net/npm/v/{name}\",\n npmDownloads: \"https://badgen.net/npm/dm/{name}\",\n bundlephobia: \"https://badgen.net/bundlephobia/minzip/{name}\",\n bundlejs: false, // https://github.com/badgen/badgen/issues/82\n packagephobia: \"https://badgen.net/packagephobia/install/{name}\",\n codecov: \"https://badgen.net/codecov/c/github/{github}\",\n license: \"https://badgen.net/github/license/{github}\",\n engine: false,\n },\n npmx: {\n npmVersion: \"https://npmx.dev/api/registry/badge/version/{name}\",\n npmDownloads: \"https://npmx.dev/api/registry/badge/downloads/{name}\",\n bundlephobia: \"https://npmx.dev/api/registry/badge/size/{name}\",\n bundlejs: false,\n packagephobia: false,\n codecov: false,\n license: \"https://npmx.dev/api/registry/badge/license/{name}\",\n engine: \"https://npmx.dev/api/registry/badge/engines/{name}\",\n },\n};\n\nexport const badges = defineGenerator({\n name: \"badges\",\n async generate({ config, args }) {\n const pkg = await getPkg(config.dir, args);\n const ctx: Record<string, any> = {\n name: pkg.name,\n github: pkg.github,\n licenseBranch: \"main\",\n ...args,\n };\n\n const fillStr = (str: string) => str.replace(/{(\\w+)}/g, (_, key) => ctx[key] || \"\");\n\n const provider = badgeProviders[args.provider]! || badgeProviders.shields;\n const providerParams = Object.entries({\n color: args.color,\n labelColor: args.labelColor,\n ...args.styleParams,\n })\n .filter(([, value]) => value)\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`)\n .join(\"&\");\n\n const badges = {\n npmVersion: {\n enabled: ctx.name && args.npmVersion !== false,\n ...badgeTypes.npmVersion,\n },\n npmDownloads: {\n enabled: ctx.name && args.npmDownloads !== false,\n ...badgeTypes.npmDownloads,\n },\n bundlephobia: {\n enabled: args.bundlephobia && ctx.name,\n ...badgeTypes.bundlephobia,\n },\n bundlejs: {\n enabled: args.bundlejs && ctx.name,\n ...badgeTypes.bundlejs,\n },\n packagephobia: {\n enabled: args.packagephobia && ctx.name,\n ...badgeTypes.packagephobia,\n },\n codecov: {\n enabled: args.codecov && ctx.github,\n ...badgeTypes.codecov,\n },\n license: {\n enabled: args.license && ctx.github,\n ...badgeTypes.license,\n },\n engine: {\n enabled: args.engine && ctx.name,\n ...badgeTypes.engine,\n },\n } as const;\n\n const md: string[] = [];\n\n for (const [badgeType, badge] of Object.entries(badges)) {\n if (!badge.enabled || !provider[badgeType as BadgeType]) {\n continue;\n }\n const to = fillStr(badge.to);\n const imgURL =\n fillStr(provider[badgeType as BadgeType] as string) +\n (providerParams ? `?${providerParams}` : \"\");\n md.push(link(to, image(imgURL, badge.name)));\n }\n\n return {\n contents: md.join(\"\\n\"),\n };\n },\n});\n","import { md } from \"mdbox\";\nimport { defineGenerator } from \"../generator.ts\";\nimport { getPkg } from \"../_utils.ts\";\n\nconst INSTALL_COMMANDS = [\n [\"npm\", \"install\"],\n [\"yarn\", \"add\"],\n [\"pnpm\", \"add\"],\n [\"bun\", \"install\"],\n [\"deno\", \"install\", \" --dev\", \"npm:\"],\n] as const;\n\nconst NYPM_COMMAND = [\"npx nypm\", \"install\"] as const;\n\nconst RUN_COMMANDS = [\n [\"npm\", \"npx \"],\n [\"pnpm\", \"pnpm dlx \"],\n [\"bun\", \"bunx \"],\n [\"deno\", \"deno run -A npm:\"],\n] as const;\n\nexport const pmInstall = defineGenerator({\n name: \"pm-install\",\n async generate({ config, args }) {\n const { name, version } = await getPkg(config.dir, args);\n\n if (!name) {\n return {\n contents: \"<!-- package name is unspecified -->\",\n };\n }\n\n let versionSuffix = \"\";\n if (args.version) {\n versionSuffix = typeof args.version === \"string\" ? `@${args.version}` : `@^${version}`;\n }\n\n const commands = args.auto === false ? INSTALL_COMMANDS : [NYPM_COMMAND, ...INSTALL_COMMANDS];\n\n const contents = commands.map(\n ([cmd, install, dev = \" -D\", pkgPrefix = \"\"]) =>\n // prettier-ignore\n `# ${cmd.includes(\"nypm\") ? \"✨ Auto-detect\" : cmd}\\n${cmd} ${install}${args.dev ? dev : (args.global ? \"g\" : \"\")} ${pkgPrefix}${name}${versionSuffix}`,\n );\n\n if ((args.separate ?? false) === false) {\n return {\n contents: md.codeBlock(contents.join(\"\\n\\n\"), \"sh\"),\n };\n }\n\n return {\n contents: contents.map((cmd) => md.codeBlock(cmd, \"sh\")).join(\"\\n\\n\"),\n };\n },\n});\n\nexport const pmX = defineGenerator({\n name: \"pm-x\",\n async generate({ config, args }) {\n const { name, version } = await getPkg(config.dir, args);\n\n if (!name) {\n return {\n contents: \"<!-- package name is unspecified -->\",\n };\n }\n\n let versionSuffix = \"\";\n if (args.version) {\n versionSuffix = typeof args.version === \"string\" ? `@${args.version}` : `@${version}`;\n }\n\n const contents = RUN_COMMANDS.map(\n ([pm, cmd]) => `# ${pm}\\n${cmd}${name}${versionSuffix}${args.args ? ` ${args.args}` : \"\"}`,\n );\n\n if ((args.separate ?? false) === false) {\n return {\n contents: md.codeBlock(contents.join(\"\\n\\n\"), \"sh\"),\n };\n }\n\n return {\n contents: contents.map((cmd) => md.codeBlock(cmd, \"sh\")).join(\"\\n\\n\"),\n };\n },\n});\n","import { defineGenerator } from \"../generator.ts\";\n\nexport const fetch = defineGenerator({\n name: \"fetch\",\n async generate({ args }) {\n const { $fetch } = await import(\"ofetch\");\n\n let url = args.url;\n if (!url) {\n throw new Error(\"URL is required!\");\n }\n if (url.startsWith(\"gh:\")) {\n url = `https://raw.githubusercontent.com/${url.slice(3)}`;\n }\n\n const contents = await $fetch(url);\n\n return {\n contents,\n };\n },\n});\n","import { readFile } from \"node:fs/promises\";\nimport { md } from \"mdbox\";\nimport { findExportNames, resolvePath } from \"mlly\";\nimport { getPkg } from \"../_utils.ts\";\nimport { defineGenerator } from \"../generator.ts\";\n\nconst DEFAULT_CDN = \"https://esm.sh/\";\n\nexport const jsimport = defineGenerator({\n name: \"jsimport\",\n async generate({ config, args }) {\n const { name } = await getPkg(config.dir, args);\n\n const importPath = name + (args.path || \"\");\n\n const importNames: string[] = ([] as string[])\n .concat(args.import, args.imports) // eslint-disable-line unicorn/prefer-spread\n .filter(Boolean)\n .flatMap((i) => i.split(/\\s*,\\s*/));\n\n if (args.src) {\n const resolved = await resolvePath(args.src, { url: config.dir });\n const contents = await readFile(resolved, \"utf8\");\n const exportNames = findExportNames(contents);\n if (exportNames && exportNames.length > 0) {\n importNames.push(...exportNames);\n }\n }\n\n const lines: string[] = [];\n\n const fmtImports =\n importNames.length > 1\n ? `\\n${importNames.map((i) => \" \" + i + \",\").join(\"\\n\")}\\n`\n : (importNames[0] && ` ${importNames[0]} `) || \"\";\n\n const formatMultiLine = (str: string) => {\n return str.length > (args.printWidth || 80)\n ? str\n : str\n .replace(/\\n/g, \"\")\n .replace(/,\\s*}/, \"}\")\n .replace(/(\\w)}/, \"$1 }\")\n .replace(/\\s+/g, \" \");\n };\n\n if (args.esm !== false) {\n const code = formatMultiLine(`import {${fmtImports}} from \"${importPath}\";`);\n lines.push(\"**ESM** (Node.js, Bun, Deno)\", md.codeBlock(code, \"js\"));\n }\n\n if (args.cjs) {\n const code = formatMultiLine(`const {${fmtImports}} = require(\"${importPath}\");`);\n lines.push(\"**CommonJS** (Legacy Node.js)\", md.codeBlock(code, \"js\"));\n }\n\n if (args.cdn) {\n const cdnBase = typeof args.cdn === \"string\" ? args.cdn : DEFAULT_CDN;\n const code = formatMultiLine(`import {${fmtImports}} from \"${cdnBase}${importPath}\";`);\n lines.push(\"**CDN** (Deno and Browsers)\", md.codeBlock(code, \"js\"));\n }\n\n return {\n contents: lines.join(\"\\n\\n\"),\n };\n },\n});\n","import { defineGenerator } from \"../generator.ts\";\n\nexport const withAutomd = defineGenerator({\n name: \"with-automd\",\n generate({ args }) {\n const lastUpdate = args.lastUpdate\n ? ` (last updated: ${typeof args.lastUpdate === \"string\" ? args.lastUpdate : new Date().toDateString()})`\n : \"\";\n\n const emoji = args.emoji === false ? \"\" : \"🤖 \";\n\n const lines: string[] = [];\n\n if (args.separator !== false) {\n lines.push(\"---\", \"\");\n }\n\n lines.push(`_${emoji}auto updated with [automd](https://automd.unjs.io)${lastUpdate}_`);\n\n return {\n contents: lines.join(\"\\n\"),\n };\n },\n});\n","import { readFile } from \"node:fs/promises\";\nimport { basename, extname } from \"pathe\";\nimport { md } from \"mdbox\";\nimport { defineGenerator } from \"../generator.ts\";\nimport { resolvePath } from \"../_utils.ts\";\n\nexport const file = defineGenerator({\n name: \"file\",\n async generate({ args, config, url }) {\n const fullPath = resolvePath(args.src, { url, dir: config.dir });\n let contents = await readFile(fullPath, \"utf8\");\n if (!args.noTrim) {\n contents = contents.trim();\n }\n\n if (args.lines) {\n const groups = /^(?<startLine>\\d+)?:(?<endLine>\\d+)?$/.exec(args.lines)?.groups;\n\n if (!groups) {\n throw new Error(\"invalid lines format\");\n }\n\n const lines = contents.split(\"\\n\");\n\n const startLine = Number(groups.startLine) || 1;\n const endLine = Number(groups.endLine) || (lines.length as number);\n\n if (startLine < 1) {\n throw new Error(\"first line's index can not be smaller than 1\");\n }\n\n contents = lines.slice(startLine - 1, endLine).join(\"\\n\");\n }\n\n if (args.code) {\n contents = md.codeBlock(contents, args.lang || extname(fullPath).slice(1), {\n // prettier-ignore\n ext: args.name === false ? undefined : (typeof args.name === 'string' ? args.name : `[${basename(fullPath)}]`),\n });\n }\n\n return {\n contents,\n };\n },\n});\n","import { getPkg } from \"../_utils.ts\";\nimport { defineGenerator } from \"../generator.ts\";\n\nconst PROVIDERS = {\n CONTRIB_ROCKS: \"contrib.rocks\",\n MARKUPGO: \"markupgo\",\n};\n\nexport const contributors = defineGenerator({\n name: \"contributors\",\n async generate({ config, args }) {\n const { github } = await getPkg(config.dir, args);\n const provider = args.provider || PROVIDERS.CONTRIB_ROCKS;\n\n if (!github) {\n throw new Error(\"`github` is required!\");\n }\n\n const lines: string[] = [];\n\n // License\n if (typeof args.license === \"string\") {\n lines.push(\n `Published under the [${args.license.toUpperCase()}](https://github.com/${github}/blob/main/LICENSE) license.`,\n );\n }\n\n // Made by\n let madeBy = `[community](https://github.com/${github}/graphs/contributors) 💛`;\n if (typeof args.author === \"string\") {\n const authors = args.author\n .split(\",\")\n .map((author) => author.trim())\n .map((user) => `[@${user}](https://github.com/${user})`)\n .join(\", \");\n if (authors.length > 0) {\n madeBy = `${authors} and ${madeBy}`;\n }\n }\n lines.push(`Made by ${madeBy}`);\n\n // Contributors\n if (provider === PROVIDERS.MARKUPGO) {\n const params = [];\n\n args = {\n circleSize: \"64\",\n center: \"true\",\n ...args,\n };\n\n if (Number(args.max) >= 0) {\n params.push([\"count\", args.max]);\n }\n\n if (Number(args.width)) {\n params.push([\"width\", args.width]);\n }\n\n if (Number(args.circleSize)) {\n params.push([\"circleSize\", args.circleSize]);\n }\n\n if (Number(args.circleRadius)) {\n params.push([\"circleRadius\", args.circleRadius]);\n }\n\n if (Number(args.circleSpacing)) {\n params.push([\"circleSpacing\", args.circleSpacing]);\n }\n\n if (args.center) {\n params.push([\"center\", Boolean(args.center).toString()]);\n }\n\n if (!args.markupGoLogo) {\n params.push([\"removeLogo\", \"true\"]);\n }\n\n if (args.anon) {\n params.push([\"anon\", Boolean(args.anon).toString()]);\n }\n\n let paramsStr = params.map(([k, v]) => `${k}=${v}`).join(\"&\");\n\n paramsStr = paramsStr ? `?${paramsStr}` : \"\";\n\n lines.push(\n `<br><br>`,\n `<a href=\"https://github.com/${github}/graphs/contributors\">`,\n `<img src=\"https://markupgo.com/github/${github}/contributors${paramsStr}\" />`,\n `</a>`,\n );\n } else {\n const params = [[\"repo\", github]];\n if (args.max) {\n params.push([\"max\", args.max]);\n }\n if (args.anon) {\n params.push([\"anon\", args.anon]);\n }\n const paramsStr = params.map(([k, v]) => `${k}=${v}`).join(\"&\");\n lines.push(\n `<br><br>`,\n `<a href=\"https://github.com/${github}/graphs/contributors\">`,\n `<img src=\"https://contrib.rocks/image?${paramsStr}\" />`,\n `</a>`,\n );\n }\n\n return {\n contents: lines.join(\"\\n\"),\n };\n },\n});\n","import { readdir, stat, readFile } from \"node:fs/promises\";\nimport { join } from \"pathe\";\nimport { defineGenerator } from \"../generator.ts\";\nimport { resolvePath } from \"../_utils.ts\";\n\ninterface TreeEntry {\n name: string;\n isDirectory: boolean;\n children?: TreeEntry[];\n}\n\nconst DEFAULT_IGNORE = [\n \"node_modules\",\n \".git\",\n \".DS_Store\",\n \".nuxt\",\n \".output\",\n \".nitro\",\n \"dist\",\n \"coverage\",\n \".cache\",\n \".turbo\",\n];\n\nasync function parseGitignore(dir: string): Promise<string[]> {\n try {\n const gitignorePath = join(dir, \".gitignore\");\n const content = await readFile(gitignorePath, \"utf8\");\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"));\n } catch {\n return [];\n }\n}\n\nfunction shouldIgnore(name: string, ignorePatterns: string[], defaultIgnore: string[]): boolean {\n const allPatterns = [...defaultIgnore, ...ignorePatterns];\n for (const pattern of allPatterns) {\n const cleanPattern = pattern.replace(/^\\//, \"\").replace(/\\/$/, \"\");\n if (name === cleanPattern) {\n return true;\n }\n if (pattern.startsWith(\"*\") && name.endsWith(pattern.slice(1))) {\n return true;\n }\n if (pattern.endsWith(\"*\") && name.startsWith(pattern.slice(0, -1))) {\n return true;\n }\n }\n return false;\n}\n\nasync function buildTree(\n dir: string,\n ignorePatterns: string[],\n maxDepth: number,\n currentDepth: number = 0,\n): Promise<TreeEntry[]> {\n if (maxDepth > 0 && currentDepth >= maxDepth) {\n return [];\n }\n\n const entries = await readdir(dir);\n const result: TreeEntry[] = [];\n\n for (const entry of entries) {\n if (shouldIgnore(entry, ignorePatterns, DEFAULT_IGNORE)) {\n continue;\n }\n\n const fullPath = join(dir, entry);\n const stats = await stat(fullPath);\n const isDirectory = stats.isDirectory();\n\n const treeEntry: TreeEntry = {\n name: entry,\n isDirectory,\n };\n\n if (isDirectory) {\n treeEntry.children = await buildTree(fullPath, ignorePatterns, maxDepth, currentDepth + 1);\n }\n\n result.push(treeEntry);\n }\n\n result.sort((a, b) => {\n if (a.isDirectory !== b.isDirectory) {\n return a.isDirectory ? -1 : 1;\n }\n return a.name.localeCompare(b.name);\n });\n\n return result;\n}\n\nfunction renderTree(entries: TreeEntry[], isLast: boolean[] = []): string[] {\n const lines: string[] = [];\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i]!;\n const isLastEntry = i === entries.length - 1;\n\n let linePrefix = \"\";\n for (const element_ of isLast) {\n linePrefix += element_ ? \" \" : \"│ \";\n }\n\n const connector = isLastEntry ? \"└── \" : \"├── \";\n const suffix = entry.isDirectory ? \"/\" : \"\";\n lines.push(`${linePrefix}${connector}${entry.name}${suffix}`);\n\n if (entry.children && entry.children.length > 0) {\n const childLines = renderTree(entry.children, [...isLast, isLastEntry]);\n lines.push(...childLines);\n }\n }\n\n return lines;\n}\n\nexport const dirTree = defineGenerator({\n name: \"dir-tree\",\n async generate({ args, config, url }) {\n const srcPath = args.src || \".\";\n const fullPath = resolvePath(srcPath, { url, dir: config.dir });\n\n const stats = await stat(fullPath);\n if (!stats.isDirectory()) {\n throw new Error(`Path \"${srcPath}\" is not a directory`);\n }\n\n const userIgnore: string[] = args.ignore\n ? String(args.ignore)\n .split(\",\")\n .map((s: string) => s.trim())\n : [];\n\n const gitignorePatterns = await parseGitignore(fullPath);\n const ignorePatterns = [...gitignorePatterns, ...userIgnore];\n\n const maxDepth = args.maxDepth ? Number(args.maxDepth) : 0;\n\n const tree = await buildTree(fullPath, ignorePatterns, maxDepth);\n const treeLines = renderTree(tree);\n\n const contents = \"```\\n\" + treeLines.join(\"\\n\") + \"\\n```\";\n\n return { contents };\n },\n});\n","import type { Generator } from \"../generator.ts\";\nimport { jsdocs } from \"./jsdocs.ts\";\nimport { badges } from \"./badges.ts\";\nimport { pmX, pmInstall } from \"./pm.ts\";\nimport { fetch as _fetch } from \"./fetch.ts\";\nimport { jsimport } from \"./jsimport.ts\";\nimport { withAutomd } from \"./with-automd.ts\";\nimport { file } from \"./file.ts\";\nimport { contributors } from \"./contributors.ts\";\nimport { dirTree } from \"./dir-tree.ts\";\n\nexport default {\n jsdocs,\n badges,\n \"pm-i\": pmInstall,\n \"pm-install\": pmInstall,\n \"pm-x\": pmX,\n fetch: _fetch,\n file,\n jsimport,\n \"with-automd\": withAutomd,\n contributors,\n \"dir-tree\": dirTree,\n} as Record<string, Generator>;\n","import { destr } from \"destr\";\nimport { camelCase } from \"scule\";\n\nexport interface Block {\n /**\n * The name of the generator to use for updates.\n */\n generator: string;\n\n /**\n * The arguments that are passed to the generator.\n */\n rawArgs: string;\n\n /**\n * The current content of the block.\n */\n contents: string;\n\n /**\n * The location of the content in the original document.\n */\n loc: { start: number; end: number };\n\n /**\n * The location including the automd comments.\n */\n _loc: { start: number; end: number };\n}\n\n/**\n * Searches a markdown document for special sections that `automd` can update.\n *\n * @param md - The markdown document as a string.\n * @returns an array of blocks that can be updated automatically. {@link Block}\n */\nexport function findBlocks(md: string): Block[] {\n const blocks: Block[] = [];\n\n // Regex is stateful, so we need to reset it\n const AUTOMD_RE =\n /^(?<open><!--\\s*automd:(?<generator>.+?)\\s+(?<args>.*?)\\s*-->)(?<contents>.+?)(?<close>^<!--\\s*\\/automd\\s*-->)/gimsu;\n\n for (const match of md.matchAll(AUTOMD_RE)) {\n if (match.index === undefined || !match.groups) {\n continue;\n }\n\n const start = match.index + match.groups.open!.length || 0;\n const end = start + match.groups.contents!.length;\n\n blocks.push({\n generator: match.groups.generator!,\n rawArgs: match.groups.args!,\n contents: match.groups.contents!,\n loc: { start, end },\n _loc: { start: match.index, end: match.index + match[0].length },\n });\n }\n\n return blocks;\n}\n\n/**\n * Checks if a markdown document contains sections that can be automatically updated.\n *\n * @param md - The markdown document as a string.\n * @returns true if there are `automd` sections, false otherwise.\n */\nexport function containsAutomd(md: string) {\n return /^<!--\\s*automd:/gimsu.test(md);\n}\n\n/**\n * Converts a string of raw arguments to an object.\n * Each argument is separated by spaces. Arguments can be key-value pairs separated by '='.\n * If an argument starts with \"no-\", the key is set to false.\n * Otherwise it sets the key to true. Keys are converted to camelCase.\n * Values are processed to determine their actual type (e.g. string, boolean).\n *\n * @param {string} rawArgs - The string of arguments to parse.\n * @return {Object} - An object with keys derived from the arguments.\n * Keys are in camelCase. Values are true, false, or strings.\n */\nexport function parseRawArgs(rawArgs: string) {\n const args = Object.create(null);\n\n for (const part of rawArgs.split(/\\s+/)) {\n const [_key, value] = part.split(\"=\");\n const key = _key && camelCase(_key);\n if (key && value) {\n args[key] = destr(value);\n } else if (part.startsWith(\"no-\")) {\n args[part.slice(3)] = false;\n } else {\n args[part] = true;\n }\n }\n\n return args;\n}\n","import { resolve } from \"pathe\";\nimport type { Generator } from \"./generator.ts\";\nimport type { AutomdResult } from \"./automd.ts\";\n\nexport interface Config {\n /**\n * The working directory\n *\n * @default \".\" (current directory)\n */\n dir?: string;\n\n /**\n * Name or path to the input file or files with glob patterns.\n *\n * @default \"README.md\"\n */\n input?: string | string[];\n\n /**\n * Name or path of the output files. If not provided, the input file will be overwritten.\n *\n * @default input\n */\n output?: string;\n\n /**\n * Ignore patterns if input is a glob pattern\n *\n * @default [\"node_modules\", \"dist\", \"/.*\"]\n */\n ignore?: string[];\n\n /**\n * Watch for changes in input files and regenerate output\n */\n watch?: boolean;\n\n /**\n * Watch callback\n */\n onWatch?: (event: { results: AutomdResult[]; time: number }) => void;\n\n /** Custom generators */\n generators?: Record<string, Generator>;\n}\n\nconst RESOLVED_CONFIG_SYMBOL = Symbol(\"automdConfig\");\n\nexport type ResolvedConfig = { [P in keyof Config]-?: Config[P] } & {\n [RESOLVED_CONFIG_SYMBOL]: true;\n input: string[];\n output?: string;\n};\n\nexport function resolveConfig(config?: Config | ResolvedConfig): ResolvedConfig {\n if (config && RESOLVED_CONFIG_SYMBOL in config) {\n return config as ResolvedConfig;\n }\n\n const _config = {\n dir: \".\",\n input: \"README.md\",\n generators: {},\n [RESOLVED_CONFIG_SYMBOL]: true,\n ...(config as Partial<ResolvedConfig>),\n } as ResolvedConfig;\n\n _config.dir = resolve(_config.dir);\n\n _config.input = (Array.isArray(_config.input) ? _config.input : [_config.input]).filter(Boolean);\n\n return _config;\n}\n\nexport async function loadConfig(dir = \".\", overrides: Config): Promise<ResolvedConfig> {\n const { loadConfig } = await import(\"c12\");\n\n dir = resolve(dir);\n\n const { config } = await loadConfig<Config>({\n cwd: dir,\n name: \"automd\",\n dotenv: true,\n overrides,\n defaults: {\n ignore: [\"**/node_modules\", \"**/dist\", \"**/.*\"],\n dir,\n },\n });\n\n return resolveConfig(config as Config);\n}\n","import MagicString from \"magic-string\";\nimport builtinGenerators from \"./generators/index.ts\";\nimport type { GenerateContext, GenerateResult } from \"./generator.ts\";\nimport { type Block, containsAutomd, findBlocks, parseRawArgs } from \"./_parse.ts\";\nimport { type Config, type ResolvedConfig, resolveConfig } from \"./config.ts\";\n\nexport interface TransformResult {\n /**\n * Wether if the document has been modified at all.\n */\n hasChanged: boolean;\n\n /**\n * Whether if there were any problems found in the document.\n */\n hasIssues: boolean;\n\n /**\n * The text of the document after it was transformed.\n */\n contents: string;\n\n /**\n * A list of specific parts that have been transformed in the document.\n */\n updates: {\n /**\n * The specific part of the document that has been transformed.\n */\n block: Block;\n\n /**\n * What the transform has done to this part of the document.\n */\n result: GenerateResult;\n }[];\n\n /**\n * How long the editing process took, measured in milliseconds.\n */\n time: number;\n}\n\n/**\n * Edits a markdown document based on certain rules and configurations.\n *\n * @param contents - The text of the markdown document you want to edit.\n * @param _config - Optional. The settings that affect how the document will be edited. See {@link Config}.\n * @param url - Optional. The URL associated with the document, if any.\n * @returns - The result of the transformation, including any changes made and how long it took. See {@link TransformResult}.\n */\nexport async function transform(\n contents: string,\n _config?: Config,\n url?: string,\n): Promise<TransformResult> {\n const start = performance.now();\n const config = resolveConfig(_config);\n\n const editor = new MagicString(contents);\n\n const updates: TransformResult[\"updates\"] = [];\n\n const generators = {\n ...builtinGenerators,\n ...config.generators,\n };\n\n const blocks = findBlocks(contents);\n\n for (const block of blocks) {\n const result = await _transformBlock(block, config, generators, url);\n if (result.unwrap) {\n editor.overwrite(block._loc.start, block._loc.end, `${result.contents.trim()}`);\n } else {\n editor.overwrite(block.loc.start, block.loc.end, `\\n\\n${result.contents.trim()}\\n\\n`);\n }\n updates.push({ block, result });\n }\n\n const hasChanged = editor.hasChanged();\n const hasIssues = updates.some((u) => u.result.issues?.filter(Boolean).length);\n const time = performance.now() - start;\n\n return {\n hasChanged,\n hasIssues,\n contents: hasChanged ? editor.toString() : contents,\n updates,\n time,\n };\n}\n\nasync function _transformBlock(\n block: Block,\n config: ResolvedConfig,\n generators: Record<string, any>,\n url?: string,\n): Promise<GenerateResult> {\n const args = parseRawArgs(block.rawArgs);\n const generator = generators[block.generator];\n\n if (!generator) {\n const didYouMean = await import(\"didyoumean2\").then((r) => r.default || r);\n const suggestions = didYouMean(block.generator, Object.keys(generators));\n const error = `Unknown generator:\\`${block.generator}\\`.${suggestions ? ` Did you mean \"generator:\\`${suggestions}\\`\"?` : \"\"}`;\n return {\n contents: `<!-- ⚠️ ${error} -->`,\n issues: [error],\n };\n }\n\n const context: GenerateContext = {\n args,\n config,\n block,\n transform: (contents: string) => transform(contents, config, url),\n url,\n };\n\n try {\n const result = (await generator.generate(context)) as GenerateResult;\n\n if (!result.unwrap && containsAutomd(result.contents)) {\n result.unwrap = true;\n }\n if (result.unwrap) {\n const nestedRes = await context.transform(result.contents);\n result.contents = nestedRes.contents;\n // TODO: inherit time, issues, etc.\n if (nestedRes.hasIssues) {\n result.issues = [\n ...(result.issues || []),\n ...nestedRes.updates.flatMap((u) => u.result.issues || []),\n ].filter(Boolean);\n }\n }\n\n return result;\n } catch (error: any) {\n return {\n contents: `<!-- ⚠️ (${block.generator}) ${error.message || error} -->`,\n issues: [error],\n };\n }\n}\n","import { existsSync, promises as fsp } from \"node:fs\";\nimport { resolve, relative, dirname } from \"pathe\";\nimport type { SubscribeCallback } from \"@parcel/watcher\";\nimport { pathToFileURL } from \"mlly\";\nimport { debounce } from \"perfect-debounce\";\nimport type { Config, ResolvedConfig } from \"./config.ts\";\nimport { type TransformResult, transform } from \"./transform.ts\";\nimport { loadConfig } from \"./config.ts\";\n\nexport interface AutomdResult extends TransformResult {\n input: string;\n output: string;\n}\n\n/**\n * Describes what you get back from the `automd` function.\n */\nexport interface AutomdReturn {\n /**\n * A list of the changes made to the file(s) by `automd`.\n */\n results: AutomdResult[];\n\n /**\n * How long it took to make the changes, in milliseconds.\n */\n time: number;\n\n /**\n * The resolved configuration that were used for these changes.\n */\n config: ResolvedConfig;\n\n /**\n * If you started watching the file(s) for changes, this function can be called to stop watching.\n */\n unwatch?: () => void | Promise<void>;\n}\n\n/**\n * Scans a markdown file looking for special comments.\n * These comments tell the function to add or update certain parts of the file automatically.\n * You can change how this works by giving it different settings in the `_config` option.\n *\n * @param _config - The settings to use for the update process. See {@link Config}.\n * @returns - An object containing the results of the update, including any changes made and any problems found. See {@link AutomdReturn}.\n *\n * @see https://automd.unjs.io/guide\n */\nexport async function automd(_config: Config = {}): Promise<AutomdReturn> {\n const start = performance.now();\n const config = await loadConfig(_config.dir, _config);\n\n let inputFiles = config.input;\n if (inputFiles.some((i) => i.includes(\"*\"))) {\n const { glob } = await import(\"tinyglobby\");\n inputFiles = await glob(inputFiles, {\n cwd: config.dir,\n absolute: false,\n onlyFiles: true,\n ignore: config.ignore,\n });\n } else {\n inputFiles = inputFiles\n .map((i) => resolve(config.dir, i))\n .filter((i) => existsSync(i))\n .map((i) => relative(config.dir, i));\n }\n const multiFiles = inputFiles.length > 1;\n\n const cache: ResultCache = new Map();\n\n const results = await Promise.all(inputFiles.map((i) => _automd(i, config, multiFiles, cache)));\n\n let unwatch;\n if (config.watch) {\n unwatch = await _watch(inputFiles, config, multiFiles, cache);\n }\n\n const time = performance.now() - start;\n\n return {\n time,\n results,\n config,\n unwatch,\n };\n}\n\n// -- internal --\n\ntype ResultCache = Map<string, AutomdResult>;\n\nasync function _automd(\n relativeInput: string,\n config: ResolvedConfig,\n multiFiles: boolean,\n cache: ResultCache,\n): Promise<AutomdResult> {\n const start = performance.now();\n const input = resolve(config.dir, relativeInput);\n const contents = await fsp.readFile(input, \"utf8\");\n\n const cachedResult = await cache.get(input);\n if (cachedResult?.contents === contents) {\n cachedResult.time = performance.now() - start;\n return cachedResult;\n }\n\n const transformResult = await transform(contents, config, pathToFileURL(input));\n\n const output = multiFiles\n ? resolve(config.dir, config.output || \".\", relativeInput)\n : resolve(config.dir, config.output || relativeInput);\n\n await fsp.mkdir(dirname(output), { recursive: true });\n await fsp.writeFile(output, transformResult.contents, \"utf8\");\n\n const result: AutomdResult = {\n input,\n output,\n ...transformResult,\n };\n cache.set(input, result);\n result.time = performance.now() - start;\n return result;\n}\n\nasync function _watch(\n inputFiles: string[],\n config: ResolvedConfig,\n multiFiles: boolean,\n cache: ResultCache,\n) {\n const watcher = await import(\"@parcel/watcher\");\n\n const watchCb: SubscribeCallback = debounce(async (_err, events) => {\n const filesToUpdate = events\n .map((e) => relative(config.dir, e.path))\n .filter((p) => inputFiles.includes(p));\n const start = performance.now();\n const results = await Promise.all(\n filesToUpdate.map((f) => _automd(f, config, multiFiles, cache)),\n );\n const time = performance.now() - start;\n if (config.onWatch) {\n config.onWatch({ results, time });\n }\n });\n\n const subscription = await watcher.subscribe(config.dir, watchCb, {\n ignore: config.ignore,\n });\n\n process.on(\"SIGINT\", () => {\n subscription.unsubscribe();\n });\n\n return subscription.unsubscribe;\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bjmhe/automd",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"automdVersion": "0.4.3",
|
|
5
|
+
"description": "Your automated markdown maintainer!",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"automd",
|
|
8
|
+
"markdown",
|
|
9
|
+
"automation",
|
|
10
|
+
"documentation",
|
|
11
|
+
"generator"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/bjmhe/automd#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/bjmhe/automd/issues"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Benjamin He <hi@bjmhe.me>",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/bjmhe/automd.git"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./dist/index.js",
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"automd": "dist/cli.mjs"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"automd": "node src/cli.ts",
|
|
41
|
+
"build": "vp pack",
|
|
42
|
+
"dev": "vp pack --watch",
|
|
43
|
+
"release": "bumpp",
|
|
44
|
+
"prepublishOnly": "vp run build"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@parcel/watcher": "^2.5.6",
|
|
48
|
+
"c12": "^3.3.3",
|
|
49
|
+
"citty": "^0.2.0",
|
|
50
|
+
"consola": "^3.4.2",
|
|
51
|
+
"defu": "^6.1.4",
|
|
52
|
+
"destr": "^2.0.5",
|
|
53
|
+
"didyoumean2": "^7.0.4",
|
|
54
|
+
"magic-string": "^0.30.21",
|
|
55
|
+
"mdbox": "^0.1.1",
|
|
56
|
+
"mlly": "^1.8.0",
|
|
57
|
+
"ofetch": "^1.5.1",
|
|
58
|
+
"pathe": "^2.0.3",
|
|
59
|
+
"perfect-debounce": "^2.1.0",
|
|
60
|
+
"pkg-types": "^2.3.0",
|
|
61
|
+
"scule": "^1.3.0",
|
|
62
|
+
"tinyglobby": "^0.2.15",
|
|
63
|
+
"untyped": "^2.0.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@arethetypeswrong/core": "^0.18.3",
|
|
67
|
+
"@bjmhe/bjmhe": "^0.0.4",
|
|
68
|
+
"@bjmhe/viteplus-preset": "^2.0.1",
|
|
69
|
+
"@tsconfig/node24": "^24.0.4",
|
|
70
|
+
"@types/node": "^25.1.0",
|
|
71
|
+
"@typescript/native-preview": "7.0.0-dev.20260129.1",
|
|
72
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
73
|
+
"bumpp": "^11.1.0",
|
|
74
|
+
"prettier": "^3.8.3",
|
|
75
|
+
"publint": "^0.3.21",
|
|
76
|
+
"tsnapi": "^0.3.3",
|
|
77
|
+
"typescript": "^5.9.3",
|
|
78
|
+
"unplugin-unused": "^0.5.7",
|
|
79
|
+
"vite-plus": "^0.1.23"
|
|
80
|
+
},
|
|
81
|
+
"engines": {
|
|
82
|
+
"node": ">=24.16.0"
|
|
83
|
+
},
|
|
84
|
+
"packageManager": "pnpm@11.4.0",
|
|
85
|
+
"main": "./dist/index.js",
|
|
86
|
+
"module": "./dist/index.js"
|
|
87
|
+
}
|