mdat 3.0.0 → 3.1.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 CHANGED
@@ -29,7 +29,7 @@ import { confirm, group, intro, note, outro, select } from "@clack/prompts";
29
29
 
30
30
  //#region package.json
31
31
  var name = "mdat";
32
- var version = "3.0.0";
32
+ var version = "3.1.0";
33
33
 
34
34
  //#endregion
35
35
  //#region src/lib/deep-merge-defined.ts
@@ -41,7 +41,8 @@ function stripUndefinedDeep(object) {
41
41
  }, {});
42
42
  }
43
43
  function deepMergeDefined(...objects) {
44
- return deepmerge(...objects.map((v, i) => i === 0 ? v : stripUndefinedDeep(v)));
44
+ const stripped = objects.map((v, i) => i === 0 ? v : stripUndefinedDeep(v));
45
+ return deepmerge(...stripped);
45
46
  }
46
47
 
47
48
  //#endregion
@@ -111,6 +112,7 @@ async function getContextMetadata() {
111
112
  "codemetaJson",
112
113
  "gitConfig",
113
114
  "githubActions",
115
+ "gitStats",
114
116
  "goGoMod",
115
117
  "goGoreleaserYaml",
116
118
  "javaPomXml",
@@ -140,8 +142,9 @@ async function getContextMetadata() {
140
142
  const GIT_PREFIX_REGEX = /^git\+/v;
141
143
  const GIT_SUFFIX_REGEX = /\.git$/v;
142
144
  const TRAILING_SLASH_REGEX = /\/$/v;
145
+ const PACKAGE_MANAGER_REGEX = /^(?<name>[^@]+)@(?<version>[^+]+)/v;
143
146
  const readmeMetadataTemplate = defineTemplate((context) => {
144
- const { githubActions, licenseFile, metascope, nodePackageJson } = context;
147
+ const { githubActions, gitStats, licenseFile, metascope, nodePackageJson } = context;
145
148
  const codemeta = templates.codemetaJson(context, {});
146
149
  const nodePackage = helpers.firstOf(nodePackageJson)?.data;
147
150
  const licenseFileData = helpers.firstOf(licenseFile);
@@ -174,6 +177,27 @@ const readmeMetadataTemplate = defineTemplate((context) => {
174
177
  version
175
178
  }));
176
179
  })();
180
+ const developmentDependencies = (() => {
181
+ if (nodePackage === void 0) return;
182
+ const runtimes = helpers.ensureArray(nodePackage.devEngines?.runtime).map(({ name, version }) => ({
183
+ name,
184
+ version
185
+ }));
186
+ const packageManagers = helpers.ensureArray(nodePackage.devEngines?.packageManager).map(({ name, version }) => ({
187
+ name,
188
+ version
189
+ }));
190
+ const pinnedPackageManager = nodePackage.packageManager === void 0 ? void 0 : PACKAGE_MANAGER_REGEX.exec(nodePackage.packageManager)?.groups;
191
+ if (pinnedPackageManager?.name !== void 0 && pinnedPackageManager.version !== void 0 && packageManagers.every((entry) => entry.name !== pinnedPackageManager.name)) packageManagers.push({
192
+ name: pinnedPackageManager.name,
193
+ version: pinnedPackageManager.version
194
+ });
195
+ if (runtimes.length === 0 && packageManagers.length === 0) return;
196
+ return {
197
+ packageManagers: packageManagers.length > 0 ? packageManagers : void 0,
198
+ runtimes: runtimes.length > 0 ? runtimes : void 0
199
+ };
200
+ })();
177
201
  const firstAuthor = helpers.firstOf(helpers.ensureArray(codemeta.author));
178
202
  return {
179
203
  author: helpers.firstOf(helpers.mixedStringsToArray(helpers.toBasicNames(codemeta.author))),
@@ -181,6 +205,7 @@ const readmeMetadataTemplate = defineTemplate((context) => {
181
205
  bin,
182
206
  ciActionFileName: ciActionFilePath === void 0 ? void 0 : path.basename(ciActionFilePath),
183
207
  description: codemeta.description,
208
+ developmentDependencies,
184
209
  engines,
185
210
  isPublicNpmPackage: nodePackage?.private !== true && (nodePackage?.name.startsWith("@") && nodePackage.publishConfig?.access === "public" || true),
186
211
  issuesUrl: codemeta.issueTracker,
@@ -193,6 +218,7 @@ const readmeMetadataTemplate = defineTemplate((context) => {
193
218
  projectDirectory: metascope?.data.options.path === void 0 ? void 0 : `file://${metascope.data.options.path}`,
194
219
  repositoryUrl: repoUrl,
195
220
  runtimePlatform: codemeta.runtimePlatform,
221
+ usesGitLfs: helpers.firstOf(gitStats)?.data.hasLfs === true,
196
222
  usesPnpm: helpers.usesPnpm(nodePackageJson)
197
223
  };
198
224
  });
@@ -220,13 +246,14 @@ var badges_default = { badges: { async content(options) {
220
246
  npm: z.array(z.string()).optional()
221
247
  }).optional().parse(options);
222
248
  const metadata = await getReadmeMetadata();
223
- const { ciActionFileName, license, licenseUrl, name, repositoryUrl } = metadata;
249
+ const { ciActionFileName, license, licenseUrl, name, repositoryUrl, usesGitLfs } = metadata;
224
250
  const badges = [];
225
251
  if (validOptions?.npm === void 0) {
226
252
  if (metadata.isPublicNpmPackage) badges.push(`[![NPM Package ${name}](https://img.shields.io/npm/v/${name}.svg)](https://www.npmjs.com/package/${name})`);
227
253
  } else for (const packageName of validOptions.npm) badges.push(`[![NPM Package ${packageName}](https://img.shields.io/npm/v/${packageName}.svg)](https://www.npmjs.com/package/${packageName})`);
228
254
  if (license !== void 0 && licenseUrl !== void 0) badges.push(`[![License: ${license}](https://img.shields.io/badge/License-${license.replaceAll("-", "--")}-yellow.svg)](${licenseUrl})`);
229
255
  if (ciActionFileName !== void 0 && repositoryUrl !== void 0) badges.push(`[![CI](${repositoryUrl}/actions/workflows/${ciActionFileName}/badge.svg)](${repositoryUrl}/actions/workflows/${ciActionFileName})`);
256
+ if (usesGitLfs) badges.push("![Git LFS](https://img.shields.io/badge/Git%20LFS-enabled-F64935?logo=gitlfs&logoColor=white)");
230
257
  if (validOptions?.custom !== void 0) for (const [badgeName, { image, link }] of Object.entries(validOptions.custom)) badges.push(`[![${badgeName}](${image})](${link})`);
231
258
  return badges.join("\n");
232
259
  } } };
@@ -349,7 +376,7 @@ const PLATFORM_INFO = {
349
376
  },
350
377
  node: {
351
378
  display: "Node.js",
352
- url: "https://nodejs.org/"
379
+ url: "https://nodejs.org/en"
353
380
  },
354
381
  python: {
355
382
  display: "Python",
@@ -409,6 +436,58 @@ var description_default = { description: { async content() {
409
436
  return `**${description}**`;
410
437
  } } };
411
438
 
439
+ //#endregion
440
+ //#region src/lib/readme/rules/development-dependencies.ts
441
+ const TOOL_INFO = {
442
+ bun: {
443
+ display: "Bun",
444
+ url: "https://bun.sh/"
445
+ },
446
+ deno: {
447
+ display: "Deno",
448
+ url: "https://deno.land/"
449
+ },
450
+ node: {
451
+ display: "Node.js",
452
+ url: "https://nodejs.org/en"
453
+ },
454
+ npm: {
455
+ display: "npm",
456
+ url: "https://www.npmjs.com/"
457
+ },
458
+ pnpm: {
459
+ display: "pnpm",
460
+ url: "https://pnpm.io/"
461
+ },
462
+ yarn: {
463
+ display: "Yarn",
464
+ url: "https://yarnpkg.com/"
465
+ }
466
+ };
467
+ var development_dependencies_default = { "development-dependencies": { async content() {
468
+ const { developmentDependencies } = await getReadmeMetadata();
469
+ if (developmentDependencies === void 0) return "";
470
+ const { packageManagers, runtimes } = developmentDependencies;
471
+ const items = [];
472
+ for (const { name, version } of [...runtimes ?? [], ...packageManagers ?? []]) {
473
+ const info = TOOL_INFO[name.toLowerCase()];
474
+ const display = info ? `[${info.display}](${info.url})` : name;
475
+ items.push(version === void 0 || version === "" ? `- ${display}` : `- ${display} ${version}`);
476
+ }
477
+ return [
478
+ "## Development Dependencies",
479
+ "",
480
+ ...items
481
+ ].join("\n");
482
+ } } };
483
+
484
+ //#endregion
485
+ //#region src/lib/readme/rules/dev-dependencies.ts
486
+ /**
487
+ * Simple alias for `development-dependencies`
488
+ */
489
+ var dev_dependencies_default = { "dev-dependencies": getSoleRule(development_dependencies_default) };
490
+
412
491
  //#endregion
413
492
  //#region src/lib/readme/rules/license.ts
414
493
  var license_default = { license: { async content() {
@@ -543,7 +622,8 @@ function getSizeForCompression(report, compression) {
543
622
  }
544
623
  var size_default = { size: { async content(options) {
545
624
  const validOptions = optionsSchema$1.parse(options);
546
- return getSizeForCompression(await createSizeReport(path.join(process.cwd(), validOptions.file)), validOptions.compression);
625
+ const fullPath = path.join(process.cwd(), validOptions.file);
626
+ return getSizeForCompression(await createSizeReport(fullPath), validOptions.compression);
547
627
  } } };
548
628
 
549
629
  //#endregion
@@ -593,7 +673,8 @@ function formatMarkdownTable(reports, options) {
593
673
  var size_table_default = { "size-table": { async content(options) {
594
674
  const validOptions = optionsSchema.parse(options);
595
675
  return formatMarkdownTable(await Promise.all(validOptions.files.map(async (file) => {
596
- return [file, await createSizeReport(path.join(process.cwd(), file))];
676
+ const fullPath = path.join(process.cwd(), file);
677
+ return [file, await createSizeReport(fullPath)];
597
678
  })), {
598
679
  brotli: validOptions.brotli,
599
680
  gzip: validOptions.gzip,
@@ -606,16 +687,17 @@ var size_table_default = { "size-table": { async content(options) {
606
687
  //#region src/lib/readme/rules/table-of-contents.ts
607
688
  var table_of_contents_default = { "table-of-contents": {
608
689
  async content(options, { tree }) {
690
+ const validOptions = z.object({ depth: z.union([
691
+ z.literal(1),
692
+ z.literal(2),
693
+ z.literal(3),
694
+ z.literal(4),
695
+ z.literal(5),
696
+ z.literal(6)
697
+ ]).optional() }).optional().parse(options);
609
698
  const result = toc(tree, {
610
699
  heading: null,
611
- maxDepth: z.object({ depth: z.union([
612
- z.literal(1),
613
- z.literal(2),
614
- z.literal(3),
615
- z.literal(4),
616
- z.literal(5),
617
- z.literal(6)
618
- ]).optional() }).optional().parse(options)?.depth ?? 3,
700
+ maxDepth: validOptions?.depth ?? 3,
619
701
  tight: true
620
702
  });
621
703
  if (result.map === void 0) throw new Error("Could not generate table of contents");
@@ -645,6 +727,8 @@ var rules_default = {
645
727
  ...contributing_default,
646
728
  ...dependencies_default,
647
729
  ...description_default,
730
+ ...dev_dependencies_default,
731
+ ...development_dependencies_default,
648
732
  ...footer_default,
649
733
  ...header_default,
650
734
  ...install_default,
@@ -700,11 +784,13 @@ async function loadConfig(options) {
700
784
  let loaded;
701
785
  if (typeof configOrPath === "string") {
702
786
  let loadResults;
703
- if (path.basename(configOrPath).endsWith("package.json")) loadResults = {
704
- config: mdatJsonLoader(configOrPath, await fs.readFile(configOrPath, "utf8")),
705
- filepath: configOrPath
706
- };
707
- else loadResults = await getAdditionalConfigExplorer().load(configOrPath);
787
+ if (path.basename(configOrPath).endsWith("package.json")) {
788
+ const packageJson = await fs.readFile(configOrPath, "utf8");
789
+ loadResults = {
790
+ config: mdatJsonLoader(configOrPath, packageJson),
791
+ filepath: configOrPath
792
+ };
793
+ } else loadResults = await getAdditionalConfigExplorer().load(configOrPath);
708
794
  if (loadResults === null || loadResults === void 0) continue;
709
795
  const { config: loadedConfig, filepath } = loadResults;
710
796
  log.debug(`Loaded additional config from "${filepath}"`);
@@ -867,7 +953,8 @@ function stripLintPlugins(config) {
867
953
  //#region src/lib/processors.ts
868
954
  async function processFiles(files, loader, processorGetter, name, output, config) {
869
955
  const [resolvedConfig, localRemarkConfig] = await Promise.all([loader({ additionalConfig: config }), loadAmbientRemarkConfig()]);
870
- const inputOutputPaths = await getInputOutputPaths(ensureArray(files), output, name, "md");
956
+ const resolvedFiles = ensureArray(files);
957
+ const inputOutputPaths = await getInputOutputPaths(resolvedFiles, output, name, "md");
871
958
  const resolvedProcessor = processorGetter(resolvedConfig, localRemarkConfig);
872
959
  return await Promise.all(inputOutputPaths.map(async ({ input, name: outputName, output: outputDirectory }) => {
873
960
  const inputFile = await read(input);
@@ -1222,7 +1309,8 @@ try {
1222
1309
  output,
1223
1310
  print
1224
1311
  });
1225
- const results = await expand(files, fileName, output, collectConfig(config), { format });
1312
+ const mergedConfig = collectConfig(config);
1313
+ const results = await expand(files, fileName, output, mergedConfig, { format });
1226
1314
  for (const file of results) if (print) process.stdout.write(file.toString());
1227
1315
  else await write(file);
1228
1316
  reporterMdat(results);
@@ -1253,7 +1341,8 @@ try {
1253
1341
  log.debug(`Stripped comments in ${prettyMilliseconds(performance.now() - startTime)}.`);
1254
1342
  process.exitCode = getExitCode(results);
1255
1343
  }).command("check [files..] [options]", "Check if MDAT placeholder comments are up to date. Exits with code 1 if any files have stale or unexpanded content.", (commandYargs) => commandYargs.positional(...filesPositional).option(configOption).option(formatOption), async ({ config, files, format }) => {
1256
- const results = await check(files, collectConfig(config), { format });
1344
+ const mergedConfig = collectConfig(config);
1345
+ const results = await check(files, mergedConfig, { format });
1257
1346
  let allInSync = true;
1258
1347
  for (const { inSync, result } of results) {
1259
1348
  const filePath = result.path === "" ? "unknown" : result.path;
@@ -156,6 +156,16 @@ declare const readmeMetadataTemplate: import("metascope").Template<{
156
156
  bin: string[] | undefined;
157
157
  ciActionFileName: string | undefined;
158
158
  description: string | undefined;
159
+ developmentDependencies: {
160
+ packageManagers: {
161
+ name: string;
162
+ version: string | undefined;
163
+ }[] | undefined;
164
+ runtimes: {
165
+ name: string;
166
+ version: string | undefined;
167
+ }[] | undefined;
168
+ } | undefined;
159
169
  engines: {
160
170
  [k: string]: string;
161
171
  } | undefined;
@@ -174,6 +184,7 @@ declare const readmeMetadataTemplate: import("metascope").Template<{
174
184
  projectDirectory: string | undefined;
175
185
  repositoryUrl: string | undefined;
176
186
  runtimePlatform: string[] | undefined;
187
+ usesGitLfs: boolean;
177
188
  usesPnpm: boolean;
178
189
  }>;
179
190
  type ReadmeMetadata = ReturnType<typeof readmeMetadataTemplate>;
@@ -188,6 +199,16 @@ declare function getReadmeMetadata(): Promise<{
188
199
  bin: string[] | undefined;
189
200
  ciActionFileName: string | undefined;
190
201
  description: string | undefined;
202
+ developmentDependencies: {
203
+ packageManagers: {
204
+ name: string;
205
+ version: string | undefined;
206
+ }[] | undefined;
207
+ runtimes: {
208
+ name: string;
209
+ version: string | undefined;
210
+ }[] | undefined;
211
+ } | undefined;
191
212
  engines: {
192
213
  [k: string]: string;
193
214
  } | undefined;
@@ -206,6 +227,7 @@ declare function getReadmeMetadata(): Promise<{
206
227
  projectDirectory: string | undefined;
207
228
  repositoryUrl: string | undefined;
208
229
  runtimePlatform: string[] | undefined;
230
+ usesGitLfs: boolean;
209
231
  usesPnpm: boolean;
210
232
  }>;
211
233
  /**
package/dist/lib/index.js CHANGED
@@ -31,7 +31,8 @@ function stripUndefinedDeep(object) {
31
31
  }, {});
32
32
  }
33
33
  function deepMergeDefined(...objects) {
34
- return deepmerge(...objects.map((v, i) => i === 0 ? v : stripUndefinedDeep(v)));
34
+ const stripped = objects.map((v, i) => i === 0 ? v : stripUndefinedDeep(v));
35
+ return deepmerge(...stripped);
35
36
  }
36
37
  //#endregion
37
38
  //#region src/lib/log.ts
@@ -98,6 +99,7 @@ async function getContextMetadata() {
98
99
  "codemetaJson",
99
100
  "gitConfig",
100
101
  "githubActions",
102
+ "gitStats",
101
103
  "goGoMod",
102
104
  "goGoreleaserYaml",
103
105
  "javaPomXml",
@@ -127,6 +129,7 @@ async function getContextMetadata() {
127
129
  const GIT_PREFIX_REGEX = /^git\+/v;
128
130
  const GIT_SUFFIX_REGEX = /\.git$/v;
129
131
  const TRAILING_SLASH_REGEX = /\/$/v;
132
+ const PACKAGE_MANAGER_REGEX = /^(?<name>[^@]+)@(?<version>[^+]+)/v;
130
133
  /**
131
134
  * Reset cached context metadata. Call between tests or when the underlying
132
135
  * project files may have changed on disk.
@@ -137,7 +140,7 @@ function resetContextMetadata() {
137
140
  metascopeMetadata = void 0;
138
141
  }
139
142
  const readmeMetadataTemplate = defineTemplate((context) => {
140
- const { githubActions, licenseFile, metascope, nodePackageJson } = context;
143
+ const { githubActions, gitStats, licenseFile, metascope, nodePackageJson } = context;
141
144
  const codemeta = templates.codemetaJson(context, {});
142
145
  const nodePackage = helpers.firstOf(nodePackageJson)?.data;
143
146
  const licenseFileData = helpers.firstOf(licenseFile);
@@ -170,6 +173,27 @@ const readmeMetadataTemplate = defineTemplate((context) => {
170
173
  version
171
174
  }));
172
175
  })();
176
+ const developmentDependencies = (() => {
177
+ if (nodePackage === void 0) return;
178
+ const runtimes = helpers.ensureArray(nodePackage.devEngines?.runtime).map(({ name, version }) => ({
179
+ name,
180
+ version
181
+ }));
182
+ const packageManagers = helpers.ensureArray(nodePackage.devEngines?.packageManager).map(({ name, version }) => ({
183
+ name,
184
+ version
185
+ }));
186
+ const pinnedPackageManager = nodePackage.packageManager === void 0 ? void 0 : PACKAGE_MANAGER_REGEX.exec(nodePackage.packageManager)?.groups;
187
+ if (pinnedPackageManager?.name !== void 0 && pinnedPackageManager.version !== void 0 && packageManagers.every((entry) => entry.name !== pinnedPackageManager.name)) packageManagers.push({
188
+ name: pinnedPackageManager.name,
189
+ version: pinnedPackageManager.version
190
+ });
191
+ if (runtimes.length === 0 && packageManagers.length === 0) return;
192
+ return {
193
+ packageManagers: packageManagers.length > 0 ? packageManagers : void 0,
194
+ runtimes: runtimes.length > 0 ? runtimes : void 0
195
+ };
196
+ })();
173
197
  const firstAuthor = helpers.firstOf(helpers.ensureArray(codemeta.author));
174
198
  return {
175
199
  author: helpers.firstOf(helpers.mixedStringsToArray(helpers.toBasicNames(codemeta.author))),
@@ -177,6 +201,7 @@ const readmeMetadataTemplate = defineTemplate((context) => {
177
201
  bin,
178
202
  ciActionFileName: ciActionFilePath === void 0 ? void 0 : path.basename(ciActionFilePath),
179
203
  description: codemeta.description,
204
+ developmentDependencies,
180
205
  engines,
181
206
  isPublicNpmPackage: nodePackage?.private !== true && (nodePackage?.name.startsWith("@") && nodePackage.publishConfig?.access === "public" || true),
182
207
  issuesUrl: codemeta.issueTracker,
@@ -189,6 +214,7 @@ const readmeMetadataTemplate = defineTemplate((context) => {
189
214
  projectDirectory: metascope?.data.options.path === void 0 ? void 0 : `file://${metascope.data.options.path}`,
190
215
  repositoryUrl: repoUrl,
191
216
  runtimePlatform: codemeta.runtimePlatform,
217
+ usesGitLfs: helpers.firstOf(gitStats)?.data.hasLfs === true,
192
218
  usesPnpm: helpers.usesPnpm(nodePackageJson)
193
219
  };
194
220
  });
@@ -232,13 +258,14 @@ var badges_default = { badges: { async content(options) {
232
258
  npm: z.array(z.string()).optional()
233
259
  }).optional().parse(options);
234
260
  const metadata = await getReadmeMetadata();
235
- const { ciActionFileName, license, licenseUrl, name, repositoryUrl } = metadata;
261
+ const { ciActionFileName, license, licenseUrl, name, repositoryUrl, usesGitLfs } = metadata;
236
262
  const badges = [];
237
263
  if (validOptions?.npm === void 0) {
238
264
  if (metadata.isPublicNpmPackage) badges.push(`[![NPM Package ${name}](https://img.shields.io/npm/v/${name}.svg)](https://www.npmjs.com/package/${name})`);
239
265
  } else for (const packageName of validOptions.npm) badges.push(`[![NPM Package ${packageName}](https://img.shields.io/npm/v/${packageName}.svg)](https://www.npmjs.com/package/${packageName})`);
240
266
  if (license !== void 0 && licenseUrl !== void 0) badges.push(`[![License: ${license}](https://img.shields.io/badge/License-${license.replaceAll("-", "--")}-yellow.svg)](${licenseUrl})`);
241
267
  if (ciActionFileName !== void 0 && repositoryUrl !== void 0) badges.push(`[![CI](${repositoryUrl}/actions/workflows/${ciActionFileName}/badge.svg)](${repositoryUrl}/actions/workflows/${ciActionFileName})`);
268
+ if (usesGitLfs) badges.push("![Git LFS](https://img.shields.io/badge/Git%20LFS-enabled-F64935?logo=gitlfs&logoColor=white)");
242
269
  if (validOptions?.custom !== void 0) for (const [badgeName, { image, link }] of Object.entries(validOptions.custom)) badges.push(`[![${badgeName}](${image})](${link})`);
243
270
  return badges.join("\n");
244
271
  } } };
@@ -357,7 +384,7 @@ const PLATFORM_INFO = {
357
384
  },
358
385
  node: {
359
386
  display: "Node.js",
360
- url: "https://nodejs.org/"
387
+ url: "https://nodejs.org/en"
361
388
  },
362
389
  python: {
363
390
  display: "Python",
@@ -416,6 +443,56 @@ var description_default = { description: { async content() {
416
443
  return `**${description}**`;
417
444
  } } };
418
445
  //#endregion
446
+ //#region src/lib/readme/rules/development-dependencies.ts
447
+ const TOOL_INFO = {
448
+ bun: {
449
+ display: "Bun",
450
+ url: "https://bun.sh/"
451
+ },
452
+ deno: {
453
+ display: "Deno",
454
+ url: "https://deno.land/"
455
+ },
456
+ node: {
457
+ display: "Node.js",
458
+ url: "https://nodejs.org/en"
459
+ },
460
+ npm: {
461
+ display: "npm",
462
+ url: "https://www.npmjs.com/"
463
+ },
464
+ pnpm: {
465
+ display: "pnpm",
466
+ url: "https://pnpm.io/"
467
+ },
468
+ yarn: {
469
+ display: "Yarn",
470
+ url: "https://yarnpkg.com/"
471
+ }
472
+ };
473
+ var development_dependencies_default = { "development-dependencies": { async content() {
474
+ const { developmentDependencies } = await getReadmeMetadata();
475
+ if (developmentDependencies === void 0) return "";
476
+ const { packageManagers, runtimes } = developmentDependencies;
477
+ const items = [];
478
+ for (const { name, version } of [...runtimes ?? [], ...packageManagers ?? []]) {
479
+ const info = TOOL_INFO[name.toLowerCase()];
480
+ const display = info ? `[${info.display}](${info.url})` : name;
481
+ items.push(version === void 0 || version === "" ? `- ${display}` : `- ${display} ${version}`);
482
+ }
483
+ return [
484
+ "## Development Dependencies",
485
+ "",
486
+ ...items
487
+ ].join("\n");
488
+ } } };
489
+ //#endregion
490
+ //#region src/lib/readme/rules/dev-dependencies.ts
491
+ /**
492
+ * Simple alias for `development-dependencies`
493
+ */
494
+ var dev_dependencies_default = { "dev-dependencies": getSoleRule(development_dependencies_default) };
495
+ //#endregion
419
496
  //#region src/lib/readme/rules/license.ts
420
497
  var license_default = { license: { async content() {
421
498
  const { author, authorUrl, license, licenseFilePath } = await getReadmeMetadata();
@@ -603,16 +680,17 @@ var size_table_default = { "size-table": { async content(options) {
603
680
  //#region src/lib/readme/rules/table-of-contents.ts
604
681
  var table_of_contents_default = { "table-of-contents": {
605
682
  async content(options, { tree }) {
683
+ const validOptions = z.object({ depth: z.union([
684
+ z.literal(1),
685
+ z.literal(2),
686
+ z.literal(3),
687
+ z.literal(4),
688
+ z.literal(5),
689
+ z.literal(6)
690
+ ]).optional() }).optional().parse(options);
606
691
  const result = toc(tree, {
607
692
  heading: null,
608
- maxDepth: z.object({ depth: z.union([
609
- z.literal(1),
610
- z.literal(2),
611
- z.literal(3),
612
- z.literal(4),
613
- z.literal(5),
614
- z.literal(6)
615
- ]).optional() }).optional().parse(options)?.depth ?? 3,
693
+ maxDepth: validOptions?.depth ?? 3,
616
694
  tight: true
617
695
  });
618
696
  if (result.map === void 0) throw new Error("Could not generate table of contents");
@@ -640,6 +718,8 @@ var rules_default = {
640
718
  ...contributing_default,
641
719
  ...dependencies_default,
642
720
  ...description_default,
721
+ ...dev_dependencies_default,
722
+ ...development_dependencies_default,
643
723
  ...footer_default,
644
724
  ...header_default,
645
725
  ...install_default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdat",
3
- "version": "3.0.0",
3
+ "version": "3.1.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",
@@ -44,13 +44,13 @@
44
44
  ],
45
45
  "dependencies": {
46
46
  "@clack/prompts": "^1.7.0",
47
- "cosmiconfig": "^9.0.2",
47
+ "cosmiconfig": "^10.0.0",
48
48
  "cosmiconfig-typescript-loader": "^6.3.0",
49
49
  "deepmerge-ts": "^7.1.5",
50
50
  "globby": "^16.2.2",
51
- "lognow": "^0.7.1",
51
+ "lognow": "^0.8.0",
52
52
  "mdast-util-toc": "^7.1.0",
53
- "metascope": "^0.9.0",
53
+ "metascope": "^0.10.0",
54
54
  "path-type": "^6.0.0",
55
55
  "picocolors": "^1.1.1",
56
56
  "plur": "^6.0.0",
@@ -58,29 +58,29 @@
58
58
  "pretty-ms": "^9.3.0",
59
59
  "remark": "^15.0.1",
60
60
  "remark-gfm": "^4.0.1",
61
- "remark-mdat": "^3.0.0",
61
+ "remark-mdat": "^3.0.1",
62
62
  "to-vfile": "^8.0.0",
63
63
  "type-fest": "^5.8.0",
64
64
  "unified-engine": "^11.2.2",
65
65
  "untildify": "^6.0.0",
66
66
  "vfile": "^6.0.3",
67
- "yargs": "^18.0.0",
67
+ "yargs": "^18.1.0",
68
68
  "zod": "^4.4.3"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@arethetypeswrong/core": "^0.18.5",
72
- "@kitschpatrol/shared-config": "^8.4.0",
72
+ "@kitschpatrol/shared-config": "^8.6.0",
73
73
  "@types/mdast": "^4.0.4",
74
74
  "@types/node": "~24.13.3",
75
75
  "@types/unist": "^3.0.3",
76
76
  "@types/yargs": "^17.0.35",
77
77
  "@vitest/coverage-v8": "^4.1.10",
78
- "bumpp": "^12.0.0",
79
- "execa": "^10.0.0",
80
- "mdat-plugin-cli-help": "^3.0.2",
81
- "mdat-plugin-example": "^2.0.1",
82
- "mdat-plugin-tldraw": "^2.0.3",
83
- "nanoid": "^6.0.0",
78
+ "bumpp": "^12.1.1",
79
+ "execa": "^10.0.1",
80
+ "mdat-plugin-cli-help": "^3.1.0",
81
+ "mdat-plugin-example": "^3.0.0",
82
+ "mdat-plugin-tldraw": "^3.0.0",
83
+ "nanoid": "^6.0.1",
84
84
  "prettier": "^3.9.6",
85
85
  "publint": "^0.3.22",
86
86
  "shx": "^0.4.0",
package/readme.md CHANGED
@@ -6,8 +6,8 @@
6
6
 
7
7
  <!-- badges -->
8
8
 
9
- [![NPM Package mdat](https://img.shields.io/npm/v/mdat.svg)](https://npmjs.com/package/mdat)
10
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/mit/)
9
+ [![NPM Package mdat](https://img.shields.io/npm/v/mdat.svg)](https://www.npmjs.com/package/mdat)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/mit)
11
11
  [![CI](https://github.com/kitschpatrol/mdat/actions/workflows/ci.yml/badge.svg)](https://github.com/kitschpatrol/mdat/actions/workflows/ci.yml)
12
12
 
13
13
  <!-- /badges -->
@@ -176,7 +176,7 @@ pnpm install --global mdat
176
176
  }
177
177
  ```
178
178
 
179
- See the [bundled rules](src/lib/readme/rules) for more complex examples.
179
+ See the [bundled rules](./src/lib/readme/rules) for more complex examples.
180
180
 
181
181
  JSON files can also be used as rule sets. MDAT flattens them so any dot-notated key path becomes a comment keyword.
182
182
 
@@ -192,7 +192,7 @@ pnpm install --global mdat
192
192
 
193
193
  Compound rules combine several individual rules into a single comment keyword.
194
194
 
195
- See [`<!-- header -->`](src/lib/readme/rules/header.ts) for an example.
195
+ See [`<!-- header -->`](./src/lib/readme/rules/header.ts) for an example.
196
196
 
197
197
  8. **Polyglot metadata**
198
198
 
@@ -548,7 +548,7 @@ When multiple config files are loaded, they are merged. CLI `--config` takes pre
548
548
 
549
549
  ### Creating custom rules
550
550
 
551
- See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples) of the `remark-mdat` readme, or look at the [bundled rules](src/lib/readme/rules) for complex examples.
551
+ See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples) of the `remark-mdat` readme, or look at the [bundled rules](./src/lib/readme/rules) for complex examples.
552
552
 
553
553
  ### Bundled rules
554
554
 
@@ -564,7 +564,7 @@ See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples)
564
564
 
565
565
  - ##### `<!-- badges -->`
566
566
 
567
- Generates badges based on project metadata. Supports NPM version, license, and CI status badges.
567
+ Generates badges based on project metadata. Supports NPM version, license, CI status, and Git LFS badges.
568
568
 
569
569
  - ##### `<!-- description -->`
570
570
 
@@ -578,6 +578,10 @@ See the [Examples section](https://github.com/kitschpatrol/remark-mdat#examples)
578
578
 
579
579
  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.
580
580
 
581
+ - ##### `<!-- development-dependencies -->`
582
+
583
+ 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 -->`.
584
+
581
585
  - ##### `<!-- table-of-contents -->`
582
586
 
583
587
  Auto-generated via [mdast-util-toc](https://github.com/syntax-tree/mdast-util-toc). Also aliased as `<!-- toc -->`.