mdat 3.2.2 → 3.4.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/dist/bin/cli.js +1 -1
- package/dist/lib/index.d.ts +8 -2
- package/dist/lib/index.js +1 -1
- package/dist/{lib-BEZJR3k_.js → lib-D8QaJZ-l.js} +262 -66
- package/package.json +4 -4
- package/readme.md +49 -20
package/dist/bin/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { S as version, a as expand, b as setLogger$1, d as templates_default, f as ensureArray, l as createReadme, r as collapse, s as strip, t as check, u as createReadmeInteractive, x as name, y as log } from "../lib-
|
|
2
|
+
import { S as version, a as expand, b as setLogger$1, d as templates_default, f as ensureArray, l as createReadme, r as collapse, s as strip, t as check, u as createReadmeInteractive, x as name, y as log } from "../lib-D8QaJZ-l.js";
|
|
3
3
|
import { createLogger } from "lognow";
|
|
4
4
|
import picocolors from "picocolors";
|
|
5
5
|
import prettyMilliseconds from "pretty-ms";
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -169,6 +169,10 @@ declare const readmeMetadataTemplate: import("metascope").Template<{
|
|
|
169
169
|
engines: {
|
|
170
170
|
[k: string]: string;
|
|
171
171
|
} | undefined;
|
|
172
|
+
hasTypes: boolean;
|
|
173
|
+
homebrewFormula: string | undefined;
|
|
174
|
+
isLibrary: boolean;
|
|
175
|
+
isNodePackage: boolean;
|
|
172
176
|
isPublicNpmPackage: boolean;
|
|
173
177
|
issuesUrl: string | undefined;
|
|
174
178
|
license: string | undefined;
|
|
@@ -185,7 +189,6 @@ declare const readmeMetadataTemplate: import("metascope").Template<{
|
|
|
185
189
|
repositoryUrl: string | undefined;
|
|
186
190
|
runtimePlatform: string[] | undefined;
|
|
187
191
|
usesGitLfs: boolean;
|
|
188
|
-
usesPnpm: boolean;
|
|
189
192
|
}>;
|
|
190
193
|
type ReadmeMetadata = ReturnType<typeof readmeMetadataTemplate>;
|
|
191
194
|
/**
|
|
@@ -212,6 +215,10 @@ export declare function getReadmeMetadata(): Promise<{
|
|
|
212
215
|
engines: {
|
|
213
216
|
[k: string]: string;
|
|
214
217
|
} | undefined;
|
|
218
|
+
hasTypes: boolean;
|
|
219
|
+
homebrewFormula: string | undefined;
|
|
220
|
+
isLibrary: boolean;
|
|
221
|
+
isNodePackage: boolean;
|
|
215
222
|
isPublicNpmPackage: boolean;
|
|
216
223
|
issuesUrl: string | undefined;
|
|
217
224
|
license: string | undefined;
|
|
@@ -228,7 +235,6 @@ export declare function getReadmeMetadata(): Promise<{
|
|
|
228
235
|
repositoryUrl: string | undefined;
|
|
229
236
|
runtimePlatform: string[] | undefined;
|
|
230
237
|
usesGitLfs: boolean;
|
|
231
|
-
usesPnpm: boolean;
|
|
232
238
|
}>;
|
|
233
239
|
/**
|
|
234
240
|
* Reset all cached metadata. Call between tests or when the underlying project
|
package/dist/lib/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as getReadmeMetadata, a as expand, b as setLogger, c as stripString, g as getContextMetadata, h as mergeConfig, i as collapseString, l as createReadme, m as loadConfig, n as checkString, o as expandString, p as defineConfig, r as collapse, s as strip, t as check, u as createReadmeInteractive, v as resetMetadataCaches } from "../lib-
|
|
1
|
+
import { _ as getReadmeMetadata, a as expand, b as setLogger, c as stripString, g as getContextMetadata, h as mergeConfig, i as collapseString, l as createReadme, m as loadConfig, n as checkString, o as expandString, p as defineConfig, r as collapse, s as strip, t as check, u as createReadmeInteractive, v as resetMetadataCaches } from "../lib-D8QaJZ-l.js";
|
|
2
2
|
|
|
3
3
|
export { check, checkString, collapse, collapseString, createReadme as create, createReadmeInteractive as createInteractive, defineConfig, expand, expandString, getContextMetadata, getReadmeMetadata, loadConfig, mergeConfig, resetMetadataCaches, setLogger, strip, stripString };
|
|
@@ -9,7 +9,7 @@ import { TypeScriptLoader } from "cosmiconfig-typescript-loader";
|
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import plur from "plur";
|
|
12
|
-
import {
|
|
12
|
+
import { deepmergeCustom } from "deepmerge-ts";
|
|
13
13
|
import { defineTemplate, getMetadata, helpers, setLogger as setLogger$1, templates } from "metascope";
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
import { globby } from "globby";
|
|
@@ -25,10 +25,11 @@ import { confirm, group, intro, note, outro, select } from "@clack/prompts";
|
|
|
25
25
|
|
|
26
26
|
//#region package.json
|
|
27
27
|
var name = "mdat";
|
|
28
|
-
var version = "3.
|
|
28
|
+
var version = "3.4.0";
|
|
29
29
|
|
|
30
30
|
//#endregion
|
|
31
31
|
//#region src/lib/deep-merge-defined.ts
|
|
32
|
+
const deepmerge = deepmergeCustom({ mergeArrays: false });
|
|
32
33
|
function stripUndefinedDeep(object) {
|
|
33
34
|
if (Array.isArray(object)) return object.map((v) => v !== null && typeof v === "object" ? stripUndefinedDeep(v) : v).filter((v) => v !== void 0);
|
|
34
35
|
return Object.entries(object).map(([k, v]) => [k, v !== null && typeof v === "object" ? stripUndefinedDeep(v) : v]).reduce((acc, [k, v]) => v === void 0 ? acc : {
|
|
@@ -139,6 +140,57 @@ const GIT_PREFIX_REGEX = /^git\+/v;
|
|
|
139
140
|
const GIT_SUFFIX_REGEX = /\.git$/v;
|
|
140
141
|
const TRAILING_SLASH_REGEX = /\/$/v;
|
|
141
142
|
const PACKAGE_MANAGER_REGEX = /^(?<name>[^@]+)@(?<version>[^+]+)/v;
|
|
143
|
+
const BREWPUB_TAP_REGEX = /\bbrewpub\b[^&;]*?--tap[ =](?<tap>[\w.\-\/]+)/v;
|
|
144
|
+
const BREWPUB_NAME_REGEX = /\bbrewpub\b[^&;]*?--name[ =](?<name>[\w.\-\/@+]+)/v;
|
|
145
|
+
const HOMEBREW_TAP_PREFIX_REGEX = /^homebrew-/v;
|
|
146
|
+
/**
|
|
147
|
+
* True if the package.json `exports` field declares a `types` condition
|
|
148
|
+
* anywhere in its (possibly nested) structure.
|
|
149
|
+
*/
|
|
150
|
+
function containsTypesKey(exports) {
|
|
151
|
+
return typeof exports === "object" && exports !== null && Object.entries(exports).some(([key, value]) => key === "types" || containsTypesKey(value));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* True if the package is importable as a library, as opposed to a CLI-only
|
|
155
|
+
* package that only exposes a `bin`.
|
|
156
|
+
*/
|
|
157
|
+
function isLibraryPackage(nodePackage) {
|
|
158
|
+
return nodePackage !== void 0 && [
|
|
159
|
+
nodePackage.exports,
|
|
160
|
+
nodePackage.main,
|
|
161
|
+
nodePackage.module,
|
|
162
|
+
nodePackage.types
|
|
163
|
+
].some((entry) => entry !== void 0);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Supported operating systems from the package.json `os` field, which codemeta
|
|
167
|
+
* doesn't carry. Exclusions like `!win32` are ignored since they don't name a
|
|
168
|
+
* supported platform.
|
|
169
|
+
*/
|
|
170
|
+
function getSupportedOperatingSystems(os) {
|
|
171
|
+
const supported = helpers.ensureArray(os).filter((entry) => !entry.startsWith("!"));
|
|
172
|
+
return supported.length > 0 ? supported : void 0;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Derive the `brew install` path for a package published to a Homebrew tap with
|
|
176
|
+
* [brewpub](https://github.com/kitschpatrol/brewpub), by finding the `brewpub
|
|
177
|
+
* --tap <owner>/<tap>` invocation in the package.json scripts. Mirrors
|
|
178
|
+
* brewpub's formula naming: the `--name` option if passed, otherwise the
|
|
179
|
+
* package name without its scope.
|
|
180
|
+
*
|
|
181
|
+
* @returns E.g. `kitschpatrol/tap/mdat`, or undefined if brewpub isn't used
|
|
182
|
+
*/
|
|
183
|
+
function getHomebrewFormula(packageName, scripts) {
|
|
184
|
+
if (packageName === void 0 || scripts === void 0) return;
|
|
185
|
+
for (const script of Object.values(scripts)) {
|
|
186
|
+
const tap = BREWPUB_TAP_REGEX.exec(script ?? "")?.groups?.tap;
|
|
187
|
+
if (tap === void 0) continue;
|
|
188
|
+
const [owner, tapName] = tap.split("/", 2);
|
|
189
|
+
if (owner === void 0 || tapName === void 0) continue;
|
|
190
|
+
const formula = BREWPUB_NAME_REGEX.exec(script ?? "")?.groups?.name ?? packageName.slice(packageName.indexOf("/") + 1).toLowerCase();
|
|
191
|
+
return `${owner}/${tapName.replace(HOMEBREW_TAP_PREFIX_REGEX, "")}/${formula}`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
142
194
|
/**
|
|
143
195
|
* Reset cached context metadata. Call between tests or when the underlying
|
|
144
196
|
* project files may have changed on disk.
|
|
@@ -203,6 +255,7 @@ const readmeMetadataTemplate = defineTemplate((context) => {
|
|
|
203
255
|
runtimes: runtimes.length > 0 ? runtimes : void 0
|
|
204
256
|
};
|
|
205
257
|
})();
|
|
258
|
+
const homebrewFormula = getHomebrewFormula(nodePackage?.name, nodePackage?.scripts);
|
|
206
259
|
const firstAuthor = helpers.firstOf(helpers.ensureArray(codemeta.author));
|
|
207
260
|
return {
|
|
208
261
|
author: helpers.firstOf(helpers.mixedStringsToArray(helpers.toBasicNames(codemeta.author))),
|
|
@@ -212,19 +265,22 @@ const readmeMetadataTemplate = defineTemplate((context) => {
|
|
|
212
265
|
description: codemeta.description,
|
|
213
266
|
developmentDependencies,
|
|
214
267
|
engines,
|
|
215
|
-
|
|
268
|
+
hasTypes: nodePackage?.types !== void 0 || containsTypesKey(nodePackage?.exports),
|
|
269
|
+
homebrewFormula,
|
|
270
|
+
isLibrary: isLibraryPackage(nodePackage),
|
|
271
|
+
isNodePackage: nodePackage !== void 0,
|
|
272
|
+
isPublicNpmPackage: nodePackage !== void 0 && nodePackage.private !== true,
|
|
216
273
|
issuesUrl: codemeta.issueTracker,
|
|
217
274
|
license: helpers.toBasicLicense(helpers.firstOf(helpers.ensureArray(codemeta.license))),
|
|
218
275
|
licenseFilePath: licenseFileData?.source,
|
|
219
276
|
licenseUrl: licenseFileData?.data.match?.spdxUrl,
|
|
220
277
|
name: codemeta.name,
|
|
221
|
-
operatingSystem: codemeta.operatingSystem,
|
|
278
|
+
operatingSystem: codemeta.operatingSystem ?? getSupportedOperatingSystems(nodePackage?.os),
|
|
222
279
|
peerDependencies,
|
|
223
280
|
projectDirectory: metascope?.data.options.path === void 0 ? void 0 : `file://${metascope.data.options.path}`,
|
|
224
281
|
repositoryUrl: repoUrl,
|
|
225
282
|
runtimePlatform: codemeta.runtimePlatform,
|
|
226
|
-
usesGitLfs: helpers.firstOf(gitStats)?.data.hasLfs === true
|
|
227
|
-
usesPnpm: helpers.usesPnpm(nodePackageJson)
|
|
283
|
+
usesGitLfs: helpers.firstOf(gitStats)?.data.hasLfs === true
|
|
228
284
|
};
|
|
229
285
|
});
|
|
230
286
|
let readmeMetadata;
|
|
@@ -359,13 +415,30 @@ var code_default = { code: { async content(options) {
|
|
|
359
415
|
return `\`\`\`${lang}\n${validOptions.trim ? exampleCode.trim() : exampleCode}\n\`\`\``;
|
|
360
416
|
} } };
|
|
361
417
|
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region src/lib/readme/rules/utilities/heading.ts
|
|
420
|
+
/**
|
|
421
|
+
* Option schema for the Markdown heading level (1-6) at which a rule emits its
|
|
422
|
+
* section heading. Sub-headings, if any, are nested one level deeper. Rules
|
|
423
|
+
* default to level 3, matching their placement under a level 2 section like
|
|
424
|
+
* "Getting started" in the house readme template.
|
|
425
|
+
*/
|
|
426
|
+
const headingLevelSchema = z.number().int().min(1).max(6).optional();
|
|
427
|
+
/**
|
|
428
|
+
* The `#` prefix for a Markdown heading, clamped to the maximum level of 6.
|
|
429
|
+
*/
|
|
430
|
+
function getHeadingPrefix(level) {
|
|
431
|
+
return "#".repeat(Math.min(level, 6));
|
|
432
|
+
}
|
|
433
|
+
|
|
362
434
|
//#endregion
|
|
363
435
|
//#region src/lib/readme/rules/contributing.ts
|
|
364
|
-
var contributing_default = { contributing: { async content() {
|
|
436
|
+
var contributing_default = { contributing: { async content(options) {
|
|
437
|
+
const validOptions = z.object({ headingLevel: headingLevelSchema }).optional().parse(options);
|
|
365
438
|
const { issuesUrl } = await getReadmeMetadata();
|
|
366
439
|
if (issuesUrl === void 0) throw new Error("Could not find \"bugs.url\" entry in package.json");
|
|
367
440
|
return [
|
|
368
|
-
|
|
441
|
+
`${getHeadingPrefix(validOptions?.headingLevel ?? 2)} Contributing`,
|
|
369
442
|
"",
|
|
370
443
|
`[Issues](${issuesUrl}) are welcome and appreciated.`,
|
|
371
444
|
"",
|
|
@@ -375,6 +448,37 @@ var contributing_default = { contributing: { async content() {
|
|
|
375
448
|
].join("\n");
|
|
376
449
|
} } };
|
|
377
450
|
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region src/lib/readme/rules/utilities/version-range.ts
|
|
453
|
+
const BARE_VERSION_REGEX = /^v?\d+(?:\.\d+){0,2}$/v;
|
|
454
|
+
const MINIMUM_ONLY_REGEX = /^>=\s*v?(?<version>\d+(?:\.\d+){0,2})$/v;
|
|
455
|
+
const LOWER_BOUND_REGEX = /(?:^|[\s\|\(^~]|>=)\s*v?(?<version>\d+(?:\.\d+){0,2})/gv;
|
|
456
|
+
function compareVersions(a, b) {
|
|
457
|
+
const partsA = a.split(".").map(Number);
|
|
458
|
+
const partsB = b.split(".").map(Number);
|
|
459
|
+
for (let index = 0; index < Math.max(partsA.length, partsB.length); index++) {
|
|
460
|
+
const difference = (partsA[index] ?? 0) - (partsB[index] ?? 0);
|
|
461
|
+
if (difference !== 0) return difference;
|
|
462
|
+
}
|
|
463
|
+
return 0;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Describe a semver range in plain language for readme prose.
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* `>=24.16.0` → `24.16.0 or newer`
|
|
470
|
+
* `^24.16.0 || >=26.3.0` → `24.16.0 or newer (specifically \`^24.16.0 || >=26.3.0\`)`
|
|
471
|
+
* `3.13` → `3.13`
|
|
472
|
+
*/
|
|
473
|
+
function describeVersionRange(range) {
|
|
474
|
+
const trimmed = range.trim();
|
|
475
|
+
if (BARE_VERSION_REGEX.test(trimmed)) return trimmed;
|
|
476
|
+
const minimumOnly = MINIMUM_ONLY_REGEX.exec(trimmed)?.groups?.version;
|
|
477
|
+
if (minimumOnly !== void 0) return `${minimumOnly} or newer`;
|
|
478
|
+
const floor = trimmed.matchAll(LOWER_BOUND_REGEX).map((match) => match.groups?.version).filter((version) => version !== void 0).toArray().toSorted(compareVersions)[0];
|
|
479
|
+
return floor === void 0 ? `\`${trimmed}\`` : `${floor} or newer (specifically \`${trimmed}\`)`;
|
|
480
|
+
}
|
|
481
|
+
|
|
378
482
|
//#endregion
|
|
379
483
|
//#region src/lib/readme/rules/dependencies.ts
|
|
380
484
|
const PLATFORM_INFO = {
|
|
@@ -396,7 +500,7 @@ const PLATFORM_INFO = {
|
|
|
396
500
|
},
|
|
397
501
|
node: {
|
|
398
502
|
display: "Node.js",
|
|
399
|
-
url: "https://nodejs.org/
|
|
503
|
+
url: "https://nodejs.org/"
|
|
400
504
|
},
|
|
401
505
|
python: {
|
|
402
506
|
display: "Python",
|
|
@@ -411,38 +515,46 @@ const PLATFORM_INFO = {
|
|
|
411
515
|
url: "https://www.rust-lang.org/"
|
|
412
516
|
}
|
|
413
517
|
};
|
|
414
|
-
|
|
518
|
+
const OPERATING_SYSTEM_NAMES = {
|
|
519
|
+
darwin: "macOS",
|
|
520
|
+
linux: "Linux",
|
|
521
|
+
win32: "Windows"
|
|
522
|
+
};
|
|
523
|
+
function getPlatformDisplay(key) {
|
|
524
|
+
const info = PLATFORM_INFO[key.toLowerCase()];
|
|
525
|
+
return info ? `[${info.display}](${info.url})` : key;
|
|
526
|
+
}
|
|
527
|
+
function getPlatformItem(key, version) {
|
|
528
|
+
const display = getPlatformDisplay(key);
|
|
529
|
+
return version === void 0 || version.trim() === "" ? `- ${display}` : `- ${display} ${describeVersionRange(version)}`;
|
|
530
|
+
}
|
|
531
|
+
var dependencies_default = { dependencies: { async content(options) {
|
|
532
|
+
const validOptions = z.object({ headingLevel: headingLevelSchema }).optional().parse(options);
|
|
415
533
|
const { engines, operatingSystem, peerDependencies, runtimePlatform } = await getReadmeMetadata();
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const spaceIndex = entry.indexOf(" ");
|
|
424
|
-
const platformKey = spaceIndex > 0 ? entry.slice(0, spaceIndex) : entry;
|
|
425
|
-
const version = spaceIndex > 0 ? entry.slice(spaceIndex + 1) : void 0;
|
|
534
|
+
const items = [];
|
|
535
|
+
const engineEntries = Object.entries(engines ?? {});
|
|
536
|
+
const runtimePlatformEntries = runtimePlatform ?? [];
|
|
537
|
+
const peerDependencyEntries = (peerDependencies ?? []).filter(({ optional }) => !optional);
|
|
538
|
+
for (const [name, version] of engineEntries) items.push(getPlatformItem(name, version));
|
|
539
|
+
for (const entry of runtimePlatformEntries) {
|
|
540
|
+
const [platformKey = entry, ...versionParts] = entry.split(" ");
|
|
426
541
|
if (engines?.[platformKey] !== void 0) continue;
|
|
427
|
-
|
|
428
|
-
const display = info ? `[${info.display}](${info.url})` : platformKey;
|
|
429
|
-
platformItems.push(version === void 0 || version === "" ? `- ${display}` : `- ${display} ${version}`);
|
|
542
|
+
items.push(getPlatformItem(platformKey, versionParts.join(" ")));
|
|
430
543
|
}
|
|
431
|
-
if (operatingSystem !== void 0 && operatingSystem.length > 0)
|
|
432
|
-
|
|
433
|
-
|
|
544
|
+
if (operatingSystem !== void 0 && operatingSystem.length > 0) {
|
|
545
|
+
const names = operatingSystem.map((os) => OPERATING_SYSTEM_NAMES[os] ?? os);
|
|
546
|
+
items.push(`- Supported operating systems: ${names.join(", ")}`);
|
|
547
|
+
}
|
|
548
|
+
for (const { name, version } of peerDependencyEntries) {
|
|
434
549
|
const npmUrl = `https://www.npmjs.com/package/${name}`;
|
|
435
|
-
|
|
436
|
-
peerItems.push(`- [${name}](${npmUrl}) ${version}${optionalSuffix}`);
|
|
550
|
+
items.push(`- [${name}](${npmUrl}) \`${version}\` _(peer dependency)_`);
|
|
437
551
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
else sections.push("", ...peerItems);
|
|
445
|
-
return sections.join("\n");
|
|
552
|
+
if (items.length === 0) return "";
|
|
553
|
+
return [
|
|
554
|
+
`${getHeadingPrefix(validOptions?.headingLevel ?? 3)} Dependencies`,
|
|
555
|
+
"",
|
|
556
|
+
...items
|
|
557
|
+
].join("\n");
|
|
446
558
|
} } };
|
|
447
559
|
|
|
448
560
|
//#endregion
|
|
@@ -469,7 +581,7 @@ const TOOL_INFO = {
|
|
|
469
581
|
},
|
|
470
582
|
node: {
|
|
471
583
|
display: "Node.js",
|
|
472
|
-
url: "https://nodejs.org/
|
|
584
|
+
url: "https://nodejs.org/"
|
|
473
585
|
},
|
|
474
586
|
npm: {
|
|
475
587
|
display: "npm",
|
|
@@ -484,7 +596,8 @@ const TOOL_INFO = {
|
|
|
484
596
|
url: "https://yarnpkg.com/"
|
|
485
597
|
}
|
|
486
598
|
};
|
|
487
|
-
var development_dependencies_default = { "development-dependencies": { async content() {
|
|
599
|
+
var development_dependencies_default = { "development-dependencies": { async content(options) {
|
|
600
|
+
const validOptions = z.object({ headingLevel: headingLevelSchema }).optional().parse(options);
|
|
488
601
|
const { developmentDependencies } = await getReadmeMetadata();
|
|
489
602
|
if (developmentDependencies === void 0) return "";
|
|
490
603
|
const { packageManagers, runtimes } = developmentDependencies;
|
|
@@ -495,7 +608,7 @@ var development_dependencies_default = { "development-dependencies": { async con
|
|
|
495
608
|
items.push(version === void 0 || version === "" ? `- ${display}` : `- ${display} ${version}`);
|
|
496
609
|
}
|
|
497
610
|
return [
|
|
498
|
-
|
|
611
|
+
`${getHeadingPrefix(validOptions?.headingLevel ?? 3)} Development dependencies`,
|
|
499
612
|
"",
|
|
500
613
|
...items
|
|
501
614
|
].join("\n");
|
|
@@ -510,11 +623,13 @@ var dev_dependencies_default = { "dev-dependencies": getSoleRule(development_dep
|
|
|
510
623
|
|
|
511
624
|
//#endregion
|
|
512
625
|
//#region src/lib/readme/rules/license.ts
|
|
513
|
-
var license_default = { license: { async content() {
|
|
626
|
+
var license_default = { license: { async content(options) {
|
|
627
|
+
const validOptions = z.object({ headingLevel: headingLevelSchema }).optional().parse(options);
|
|
514
628
|
const { author, authorUrl, license, licenseFilePath } = await getReadmeMetadata();
|
|
515
629
|
if (author === void 0) throw new Error("Could not find author name in project");
|
|
516
630
|
if (license === void 0 || licenseFilePath === void 0) throw new Error("Could not find license for project");
|
|
517
|
-
|
|
631
|
+
const authorDisplay = authorUrl === void 0 ? author : `[${author}](${authorUrl})`;
|
|
632
|
+
return `${`${getHeadingPrefix(validOptions?.headingLevel ?? 2)} License`}\n[${license}](${licenseFilePath}) © ${authorDisplay}`;
|
|
518
633
|
} } };
|
|
519
634
|
|
|
520
635
|
//#endregion
|
|
@@ -564,21 +679,99 @@ var header_default = { header: {
|
|
|
564
679
|
|
|
565
680
|
//#endregion
|
|
566
681
|
//#region src/lib/readme/rules/install.ts
|
|
567
|
-
|
|
568
|
-
|
|
682
|
+
const listFormatter = new Intl.ListFormat("en", {
|
|
683
|
+
style: "long",
|
|
684
|
+
type: "conjunction"
|
|
685
|
+
});
|
|
686
|
+
function codeBlock(command) {
|
|
687
|
+
return [
|
|
688
|
+
"```sh",
|
|
689
|
+
command,
|
|
690
|
+
"```"
|
|
691
|
+
];
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Install instructions for command-line use: run once with `npx`, or install
|
|
695
|
+
* globally with Homebrew (if published to a tap) or npm.
|
|
696
|
+
*/
|
|
697
|
+
function getCliLines(name, homebrewFormula) {
|
|
698
|
+
return [
|
|
699
|
+
"Run it once without installing:",
|
|
700
|
+
"",
|
|
701
|
+
...codeBlock(`npx ${name}`),
|
|
702
|
+
...homebrewFormula === void 0 ? [] : [
|
|
703
|
+
"",
|
|
704
|
+
"Or install it globally with Homebrew:",
|
|
705
|
+
"",
|
|
706
|
+
...codeBlock(`brew install ${homebrewFormula}`)
|
|
707
|
+
],
|
|
708
|
+
"",
|
|
709
|
+
"Or install it globally with npm:",
|
|
710
|
+
"",
|
|
711
|
+
...codeBlock(`npm install --global ${name}`)
|
|
712
|
+
];
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Install instructions for use as a project dependency.
|
|
716
|
+
*/
|
|
717
|
+
function getLibraryLines(name, bin, hasTypes, dev) {
|
|
718
|
+
const lead = dev ? "Add it to your project as a development dependency" : "Add it to your project";
|
|
719
|
+
const command = `npm install ${dev ? "--save-dev " : ""}${name}`;
|
|
720
|
+
if (bin === void 0 || bin.length === 0) return [
|
|
721
|
+
`${lead}:`,
|
|
722
|
+
"",
|
|
723
|
+
...codeBlock(command)
|
|
724
|
+
];
|
|
725
|
+
return [
|
|
726
|
+
`${lead} to import the ${hasTypes ? "TypeScript API" : "API"}. This also puts the ${listFormatter.format(bin.map((binName) => `\`${binName}\``))} ${bin.length === 1 ? "CLI" : "CLIs"} on your project's path:`,
|
|
727
|
+
"",
|
|
728
|
+
...codeBlock(command)
|
|
729
|
+
];
|
|
730
|
+
}
|
|
731
|
+
var install_default = { install: { async content(options) {
|
|
732
|
+
const validOptions = z.object({
|
|
733
|
+
dev: z.boolean().optional(),
|
|
734
|
+
headingLevel: headingLevelSchema,
|
|
735
|
+
homebrew: z.union([z.string(), z.literal(false)]).optional()
|
|
736
|
+
}).optional().parse(options);
|
|
737
|
+
const { bin, hasTypes, homebrewFormula, isLibrary, isNodePackage, isPublicNpmPackage, name, runtimePlatform } = await getReadmeMetadata();
|
|
569
738
|
if (name === void 0) throw new Error("Could not find project name");
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
739
|
+
const headingLevel = validOptions?.headingLevel ?? 3;
|
|
740
|
+
const heading = `${getHeadingPrefix(headingLevel)} Installation`;
|
|
741
|
+
const subheading = getHeadingPrefix(headingLevel + 1);
|
|
742
|
+
if (isNodePackage) {
|
|
743
|
+
if (!isPublicNpmPackage) throw new Error("Install instructions require a publishable package, but package.json sets \"private\": true");
|
|
744
|
+
const homebrew = validOptions?.homebrew === void 0 ? homebrewFormula : validOptions.homebrew === false ? void 0 : validOptions.homebrew;
|
|
745
|
+
const hasCli = bin !== void 0 && bin.length > 0;
|
|
746
|
+
const cliLines = getCliLines(name, homebrew);
|
|
747
|
+
const libraryLines = getLibraryLines(name, bin, hasTypes, validOptions?.dev ?? false);
|
|
748
|
+
if (hasCli && isLibrary) return [
|
|
749
|
+
heading,
|
|
750
|
+
"",
|
|
751
|
+
"Pick the option that matches how you plan to use it.",
|
|
752
|
+
"",
|
|
753
|
+
`${subheading} CLI`,
|
|
754
|
+
"",
|
|
755
|
+
...cliLines,
|
|
756
|
+
"",
|
|
757
|
+
`${subheading} Library`,
|
|
758
|
+
"",
|
|
759
|
+
...libraryLines
|
|
760
|
+
].join("\n");
|
|
761
|
+
return [
|
|
762
|
+
heading,
|
|
763
|
+
"",
|
|
764
|
+
...hasCli ? cliLines : libraryLines
|
|
765
|
+
].join("\n");
|
|
766
|
+
}
|
|
767
|
+
const platform = (prefix) => runtimePlatform?.some((p) => p.startsWith(prefix));
|
|
768
|
+
const command = platform("python") ? `pip install ${name}` : platform("rust") ? `cargo install ${name}` : platform("go") ? `go install ${name}@latest` : platform("ruby") ? `gem install ${name}` : void 0;
|
|
769
|
+
if (command === void 0) throw new Error("Could not determine project ecosystem for install instructions");
|
|
770
|
+
return [
|
|
771
|
+
heading,
|
|
772
|
+
"",
|
|
773
|
+
...codeBlock(command)
|
|
774
|
+
].join("\n");
|
|
582
775
|
} } };
|
|
583
776
|
|
|
584
777
|
//#endregion
|
|
@@ -710,21 +903,24 @@ var size_table_default = { "size-table": { async content(options) {
|
|
|
710
903
|
//#region src/lib/readme/rules/table-of-contents.ts
|
|
711
904
|
var table_of_contents_default = { "table-of-contents": {
|
|
712
905
|
async content(options, { tree }) {
|
|
713
|
-
const validOptions = z.object({
|
|
714
|
-
z.
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
906
|
+
const validOptions = z.object({
|
|
907
|
+
depth: z.union([
|
|
908
|
+
z.literal(1),
|
|
909
|
+
z.literal(2),
|
|
910
|
+
z.literal(3),
|
|
911
|
+
z.literal(4),
|
|
912
|
+
z.literal(5),
|
|
913
|
+
z.literal(6)
|
|
914
|
+
]).optional(),
|
|
915
|
+
headingLevel: headingLevelSchema
|
|
916
|
+
}).optional().parse(options);
|
|
721
917
|
const result = toc(tree, {
|
|
722
918
|
heading: null,
|
|
723
919
|
maxDepth: validOptions?.depth ?? 3,
|
|
724
920
|
tight: true
|
|
725
921
|
});
|
|
726
922
|
if (result.map === void 0) throw new Error("Could not generate table of contents");
|
|
727
|
-
const heading =
|
|
923
|
+
const heading = `${getHeadingPrefix(validOptions?.headingLevel ?? 2)} Table of contents`;
|
|
728
924
|
const rootWrapper = {
|
|
729
925
|
children: result.map.children,
|
|
730
926
|
type: "root"
|
|
@@ -1034,11 +1230,11 @@ function getStripProcessor(_config, ambientRemarkConfig) {
|
|
|
1034
1230
|
|
|
1035
1231
|
//#endregion
|
|
1036
1232
|
//#region src/lib/readme/templates/mdat-readme-compound.md?raw
|
|
1037
|
-
var mdat_readme_compound_default = "<!-- header -->\n\n<!-- table-of-contents -->\n\n## Overview\n\n## Getting started\n\n
|
|
1233
|
+
var mdat_readme_compound_default = "<!-- header -->\n\n<!-- table-of-contents -->\n\n## Overview\n\n## Getting started\n\n<!-- dependencies -->\n\n<!-- install -->\n\n## Usage\n\n### Library\n\n#### API\n\n#### Examples\n\n### CLI\n\n#### Commands\n\n#### Examples\n\n## Background\n\n### Motivation\n\n### Implementation notes\n\n### Similar projects\n\n## The future\n\n## Maintainers\n\n_List maintainer(s) for a repository, along with one way of contacting them (e.g. GitHub link or email)._\n\n## Acknowledgments\n\n_State anyone or anything that significantly helped with the development of your project. State public contact hyper-links if applicable._\n\n<!-- footer -->\n";
|
|
1038
1234
|
|
|
1039
1235
|
//#endregion
|
|
1040
1236
|
//#region src/lib/readme/templates/mdat-readme.md?raw
|
|
1041
|
-
var mdat_readme_default = "<!-- title -->\n\n<!-- banner -->\n\n<!-- badges -->\n\n<!-- short-description -->\n\n<!-- table-of-contents -->\n\n## Overview\n\n## Getting started\n\n
|
|
1237
|
+
var mdat_readme_default = "<!-- title -->\n\n<!-- banner -->\n\n<!-- badges -->\n\n<!-- short-description -->\n\n<!-- table-of-contents -->\n\n## Overview\n\n## Getting started\n\n<!-- dependencies -->\n\n<!-- install -->\n\n## Usage\n\n### Library\n\n#### API\n\n#### Examples\n\n### CLI\n\n#### Commands\n\n#### Examples\n\n## Background\n\n### Motivation\n\n### Implementation notes\n\n### Similar projects\n\n## The future\n\n## Maintainers\n\n_List maintainer(s) for a repository, along with one way of contacting them (e.g. GitHub link or email)._\n\n## Acknowledgments\n\n_State anyone or anything that significantly helped with the development of your project. State public contact hyper-links if applicable._\n\n<!-- contributing -->\n\n<!-- license -->\n";
|
|
1042
1238
|
|
|
1043
1239
|
//#endregion
|
|
1044
1240
|
//#region src/lib/readme/templates/standard-readme-basic-compound.md?raw
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdat",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "CLI tool and TypeScript library implementing the Markdown Autophagic Template (MDAT) system. MDAT lets you use comments as dynamic content templates in Markdown files, making it easy to generate and update readme boilerplate.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mdat",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"pretty-ms": "^9.3.1",
|
|
59
59
|
"remark": "^15.0.1",
|
|
60
60
|
"remark-gfm": "^4.0.1",
|
|
61
|
-
"remark-mdat": "^3.0
|
|
61
|
+
"remark-mdat": "^3.1.0",
|
|
62
62
|
"to-vfile": "^8.0.0",
|
|
63
63
|
"type-fest": "^5.10.0",
|
|
64
64
|
"unified-engine": "^11.2.2",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@arethetypeswrong/core": "^0.18.5",
|
|
72
72
|
"@kitschpatrol/shared-config": "^8.10.0",
|
|
73
73
|
"@types/mdast": "^4.0.4",
|
|
74
|
-
"@types/node": "~24.13.
|
|
74
|
+
"@types/node": "~24.13.6",
|
|
75
75
|
"@types/unist": "^3.0.3",
|
|
76
76
|
"@types/yargs": "^17.0.35",
|
|
77
77
|
"@vitest/coverage-v8": "^5.0.1",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
}
|
|
100
100
|
},
|
|
101
101
|
"engines": {
|
|
102
|
-
"node": "
|
|
102
|
+
"node": "^24.16.0 || >=26.3.0"
|
|
103
103
|
},
|
|
104
104
|
"scripts": {
|
|
105
105
|
"bench": "vitest bench --run --reporter=default",
|
package/readme.md
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
<!-- badges({
|
|
8
8
|
custom: {
|
|
9
|
-
"
|
|
10
|
-
image:
|
|
11
|
-
|
|
9
|
+
"Homebrew": {
|
|
10
|
+
image:
|
|
11
|
+
"https://img.shields.io/badge/Homebrew-kitschpatrol%2Ftap%2Fmdat-FBB040?logo=homebrew&logoColor=white",
|
|
12
|
+
link: "https://github.com/kitschpatrol/homebrew-tap/blob/main/Formula/mdat.rb",
|
|
12
13
|
},
|
|
13
14
|
}
|
|
14
15
|
}) -->
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
[](https://www.npmjs.com/package/mdat)
|
|
17
18
|
[](https://opensource.org/license/mit)
|
|
18
19
|
[](https://github.com/kitschpatrol/mdat/actions/workflows/ci.yml)
|
|
19
|
-
[](https://github.com/kitschpatrol/homebrew-tap/blob/main/Formula/mdat.rb)
|
|
20
21
|
|
|
21
22
|
<!-- /badges -->
|
|
22
23
|
|
|
@@ -36,8 +37,8 @@
|
|
|
36
37
|
- [Installation](#installation)
|
|
37
38
|
- [Features](#features)
|
|
38
39
|
- [Usage](#usage)
|
|
39
|
-
- [CLI](#cli)
|
|
40
|
-
- [
|
|
40
|
+
- [CLI](#cli-1)
|
|
41
|
+
- [Library](#library-1)
|
|
41
42
|
- [Configuration](#configuration)
|
|
42
43
|
- [Creating custom rules](#creating-custom-rules)
|
|
43
44
|
- [Bundled rules](#bundled-rules)
|
|
@@ -109,30 +110,52 @@ The `<!-- title -->` comment was expanded with content derived from your project
|
|
|
109
110
|
|
|
110
111
|
## Getting started
|
|
111
112
|
|
|
113
|
+
<!-- dependencies -->
|
|
114
|
+
|
|
112
115
|
### Dependencies
|
|
113
116
|
|
|
114
|
-
Node 24
|
|
117
|
+
- [Node.js](https://nodejs.org/) 24.16.0 or newer (specifically `^24.16.0 || >=26.3.0`)
|
|
118
|
+
|
|
119
|
+
<!-- /dependencies -->
|
|
120
|
+
|
|
121
|
+
Written in TypeScript with bundled type definitions.
|
|
122
|
+
|
|
123
|
+
<!-- install -->
|
|
115
124
|
|
|
116
125
|
### Installation
|
|
117
126
|
|
|
118
|
-
|
|
127
|
+
Pick the option that matches how you plan to use it.
|
|
128
|
+
|
|
129
|
+
#### CLI
|
|
130
|
+
|
|
131
|
+
Run it once without installing:
|
|
119
132
|
|
|
120
133
|
```sh
|
|
121
|
-
|
|
134
|
+
npx mdat
|
|
122
135
|
```
|
|
123
136
|
|
|
124
|
-
Or install globally:
|
|
137
|
+
Or install it globally with Homebrew:
|
|
125
138
|
|
|
126
139
|
```sh
|
|
127
|
-
|
|
140
|
+
brew install kitschpatrol/tap/mdat
|
|
128
141
|
```
|
|
129
142
|
|
|
130
|
-
|
|
143
|
+
Or install it globally with npm:
|
|
131
144
|
|
|
132
145
|
```sh
|
|
133
|
-
|
|
146
|
+
npm install --global mdat
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Library
|
|
150
|
+
|
|
151
|
+
Add it to your project to import the TypeScript API. This also puts the `mdat` CLI on your project's path:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
npm install mdat
|
|
134
155
|
```
|
|
135
156
|
|
|
157
|
+
<!-- /install -->
|
|
158
|
+
|
|
136
159
|
## Features
|
|
137
160
|
|
|
138
161
|
1. **Minimalist syntax**
|
|
@@ -423,7 +446,7 @@ mdat --format
|
|
|
423
446
|
mdat create
|
|
424
447
|
```
|
|
425
448
|
|
|
426
|
-
###
|
|
449
|
+
### Library
|
|
427
450
|
|
|
428
451
|
`mdat` exports functions for expanding, collapsing, checking, and creating Markdown files programmatically.
|
|
429
452
|
|
|
@@ -566,6 +589,8 @@ See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples)
|
|
|
566
589
|
|
|
567
590
|
### Bundled rules
|
|
568
591
|
|
|
592
|
+
Every rule that emits a section heading accepts a `headingLevel` option (`1`-`6`) to control the heading's Markdown level, with any sub-headings nested one level deeper. The defaults match each rule's placement in the bundled MDAT Readme template: `2` for top-level sections (`table-of-contents`, `contributing`, and `license`), and `3` for the rules that sit under "Getting started" (`dependencies`, `install`, and `development-dependencies`).
|
|
593
|
+
|
|
569
594
|
#### Stand-alone
|
|
570
595
|
|
|
571
596
|
- ##### `<!-- title -->`
|
|
@@ -586,19 +611,23 @@ See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples)
|
|
|
586
611
|
|
|
587
612
|
- ##### `<!-- install -->`
|
|
588
613
|
|
|
589
|
-
|
|
614
|
+
Install instructions derived from `package.json`, written for people consuming the package rather than developing it, so they always use `npm`. Packages with a `bin` get CLI instructions (`npx`, Homebrew, and `npm install --global`), packages with an entry point (`exports`, `main`, `module`, or `types`) get library instructions (`npm install`), and packages with both get a section for each. The Homebrew option appears automatically when a `brewpub --tap` invocation is found in the package scripts, and can be set explicitly with `homebrew: "owner/tap/formula"` or suppressed with `homebrew: false`. Pass `dev: true` to recommend `npm install --save-dev` for tooling packages. Private packages are rejected. Falls back to `pip`, `cargo`, `gem`, or `go install` for Python, Rust, Ruby, and Go projects. The optional `headingLevel` sets the Markdown heading level and defaults to `3`, matching the template's placement under a "Getting started" section:
|
|
615
|
+
|
|
616
|
+
```md
|
|
617
|
+
<!-- install({ headingLevel: 2, dev: true, homebrew: false }) -->
|
|
618
|
+
```
|
|
590
619
|
|
|
591
620
|
- ##### `<!-- dependencies -->`
|
|
592
621
|
|
|
593
|
-
Documents platform requirements and peer dependencies. Lists runtime platforms (Node, Python, Rust, Go, Ruby, etc.) with version constraints from `engines` or equivalent metadata, supported operating systems, and peer dependencies with links to npm.
|
|
622
|
+
Documents platform requirements and peer dependencies. Lists runtime platforms (Node, Python, Rust, Go, Ruby, etc.) with version constraints from `engines` or equivalent metadata, supported operating systems, and required peer dependencies with links to npm. Optional peer dependencies are left out. Version ranges are described in plain language (`>=24.16.0` becomes "24.16.0 or newer"), with the exact range included when it can't be summarized that simply. The optional `headingLevel` sets the Markdown heading level and defaults to `3`.
|
|
594
623
|
|
|
595
624
|
- ##### `<!-- development-dependencies -->`
|
|
596
625
|
|
|
597
|
-
Documents the tools needed to work on the project itself, derived from the `devEngines` and `packageManager` fields in `package.json`. Lists required runtimes and package managers with links and version constraints. Also aliased as `<!-- dev-dependencies -->`.
|
|
626
|
+
Documents the tools needed to work on the project itself, derived from the `devEngines` and `packageManager` fields in `package.json`. Lists required runtimes and package managers with links and version constraints. The optional `headingLevel` sets the Markdown heading level and defaults to `3`. Also aliased as `<!-- dev-dependencies -->`.
|
|
598
627
|
|
|
599
628
|
- ##### `<!-- table-of-contents -->`
|
|
600
629
|
|
|
601
|
-
Auto-generated via [mdast-util-toc](https://github.com/syntax-tree/mdast-util-toc). Also aliased as `<!-- toc -->`.
|
|
630
|
+
Auto-generated via [mdast-util-toc](https://github.com/syntax-tree/mdast-util-toc). The optional `depth` limits how deeply nested headings are listed and defaults to `3`. Also aliased as `<!-- toc -->`.
|
|
602
631
|
|
|
603
632
|
- ##### `<!-- contributing -->`
|
|
604
633
|
|
|
@@ -631,7 +660,7 @@ See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples)
|
|
|
631
660
|
|
|
632
661
|
#### Compound
|
|
633
662
|
|
|
634
|
-
Compound rules combine several stand-alone rules under a single keyword.
|
|
663
|
+
Compound rules combine several stand-alone rules under a single keyword. Options are passed as an array with one entry per stand-alone rule, in order, e.g. `<!-- footer([{ headingLevel: 3 }, { headingLevel: 3 }]) -->`.
|
|
635
664
|
|
|
636
665
|
- ##### `<!-- header -->`
|
|
637
666
|
|
|
@@ -668,7 +697,7 @@ Rule plugins are packages for sharing mdat expansion rules across projects.
|
|
|
668
697
|
### Installing a rule plugin
|
|
669
698
|
|
|
670
699
|
```sh
|
|
671
|
-
|
|
700
|
+
npm install mdat-plugin-example
|
|
672
701
|
```
|
|
673
702
|
|
|
674
703
|
Spread the plugin into your configuration:
|