mdat 2.3.6 → 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 +205 -103
- package/dist/lib/index.d.ts +22 -1
- package/dist/lib/index.js +159 -66
- package/package.json +26 -32
- package/readme.md +12 -10
package/dist/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { Rule, Rule as Rule$1 } from "remark-mdat";
|
|
|
2
2
|
import { ILogBasic, ILogLayer } from "lognow";
|
|
3
3
|
import { MetadataContext } from "metascope";
|
|
4
4
|
import { VFile } from "vfile";
|
|
5
|
-
|
|
6
5
|
//#region src/lib/config.d.ts
|
|
7
6
|
/**
|
|
8
7
|
* An mdat configuration is a record of expansion rules. Keys become comment
|
|
@@ -157,6 +156,16 @@ declare const readmeMetadataTemplate: import("metascope").Template<{
|
|
|
157
156
|
bin: string[] | undefined;
|
|
158
157
|
ciActionFileName: string | undefined;
|
|
159
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;
|
|
160
169
|
engines: {
|
|
161
170
|
[k: string]: string;
|
|
162
171
|
} | undefined;
|
|
@@ -175,6 +184,7 @@ declare const readmeMetadataTemplate: import("metascope").Template<{
|
|
|
175
184
|
projectDirectory: string | undefined;
|
|
176
185
|
repositoryUrl: string | undefined;
|
|
177
186
|
runtimePlatform: string[] | undefined;
|
|
187
|
+
usesGitLfs: boolean;
|
|
178
188
|
usesPnpm: boolean;
|
|
179
189
|
}>;
|
|
180
190
|
type ReadmeMetadata = ReturnType<typeof readmeMetadataTemplate>;
|
|
@@ -189,6 +199,16 @@ declare function getReadmeMetadata(): Promise<{
|
|
|
189
199
|
bin: string[] | undefined;
|
|
190
200
|
ciActionFileName: string | undefined;
|
|
191
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;
|
|
192
212
|
engines: {
|
|
193
213
|
[k: string]: string;
|
|
194
214
|
} | undefined;
|
|
@@ -207,6 +227,7 @@ declare function getReadmeMetadata(): Promise<{
|
|
|
207
227
|
projectDirectory: string | undefined;
|
|
208
228
|
repositoryUrl: string | undefined;
|
|
209
229
|
runtimePlatform: string[] | undefined;
|
|
230
|
+
usesGitLfs: boolean;
|
|
210
231
|
usesPnpm: boolean;
|
|
211
232
|
}>;
|
|
212
233
|
/**
|
package/dist/lib/index.js
CHANGED
|
@@ -24,14 +24,15 @@ import untildify from "untildify";
|
|
|
24
24
|
import { confirm, group, intro, note, outro, select } from "@clack/prompts";
|
|
25
25
|
//#region src/lib/deep-merge-defined.ts
|
|
26
26
|
function stripUndefinedDeep(object) {
|
|
27
|
-
if (Array.isArray(object)) return object.map((v) => v && typeof v === "object" ? stripUndefinedDeep(v) : v).filter((v) => v !== void 0);
|
|
28
|
-
return Object.entries(object).map(([k, v]) => [k, v && typeof v === "object" ? stripUndefinedDeep(v) : v]).reduce((acc, [k, v]) => v === void 0 ? acc : {
|
|
27
|
+
if (Array.isArray(object)) return object.map((v) => v !== null && typeof v === "object" ? stripUndefinedDeep(v) : v).filter((v) => v !== void 0);
|
|
28
|
+
return Object.entries(object).map(([k, v]) => [k, v !== null && typeof v === "object" ? stripUndefinedDeep(v) : v]).reduce((acc, [k, v]) => v === void 0 ? acc : {
|
|
29
29
|
...acc,
|
|
30
30
|
[k]: v
|
|
31
31
|
}, {});
|
|
32
32
|
}
|
|
33
33
|
function deepMergeDefined(...objects) {
|
|
34
|
-
|
|
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
|
|
@@ -70,7 +71,7 @@ function mdatJsonLoader(filePath, content) {
|
|
|
70
71
|
}
|
|
71
72
|
function flattenJson(jsonObject, parentKey = "", result = {}) {
|
|
72
73
|
for (const [key, value] of Object.entries(jsonObject)) {
|
|
73
|
-
const fullPath = parentKey ? `${parentKey}.${key}
|
|
74
|
+
const fullPath = parentKey === "" ? key : `${parentKey}.${key}`;
|
|
74
75
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) flattenJson(value, fullPath, result);
|
|
75
76
|
else if (value === null) result[fullPath] = "null";
|
|
76
77
|
else result[fullPath] = value.toString();
|
|
@@ -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",
|
|
@@ -124,9 +126,10 @@ async function getContextMetadata() {
|
|
|
124
126
|
});
|
|
125
127
|
return metascopeMetadata;
|
|
126
128
|
}
|
|
127
|
-
const GIT_PREFIX_REGEX = /^git
|
|
128
|
-
const GIT_SUFFIX_REGEX = /\.git
|
|
129
|
-
const TRAILING_SLASH_REGEX =
|
|
129
|
+
const GIT_PREFIX_REGEX = /^git\+/v;
|
|
130
|
+
const GIT_SUFFIX_REGEX = /\.git$/v;
|
|
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,12 +140,12 @@ 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);
|
|
144
147
|
const ciActionFilePath = helpers.ensureArray(githubActions).find((entry) => entry.data.name.toLowerCase() === "ci")?.source;
|
|
145
|
-
const
|
|
148
|
+
const repoUrl = codemeta.codeRepository?.replace(GIT_PREFIX_REGEX, "").replace(GIT_SUFFIX_REGEX, "").replace(TRAILING_SLASH_REGEX, "");
|
|
146
149
|
const bin = (() => {
|
|
147
150
|
if (nodePackage === void 0) return;
|
|
148
151
|
const binField = nodePackage.bin;
|
|
@@ -170,13 +173,35 @@ 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))),
|
|
176
200
|
authorUrl: firstAuthor?.url,
|
|
177
201
|
bin,
|
|
178
|
-
ciActionFileName: ciActionFilePath ? path.basename(ciActionFilePath)
|
|
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,
|
|
@@ -187,8 +212,9 @@ const readmeMetadataTemplate = defineTemplate((context) => {
|
|
|
187
212
|
operatingSystem: codemeta.operatingSystem,
|
|
188
213
|
peerDependencies,
|
|
189
214
|
projectDirectory: metascope?.data.options.path === void 0 ? void 0 : `file://${metascope.data.options.path}`,
|
|
190
|
-
repositoryUrl,
|
|
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
|
});
|
|
@@ -200,7 +226,8 @@ let readmeMetadata;
|
|
|
200
226
|
*/
|
|
201
227
|
async function getReadmeMetadata() {
|
|
202
228
|
if (readmeMetadata !== void 0) return readmeMetadata;
|
|
203
|
-
|
|
229
|
+
const contextMetadata = await getContextMetadata();
|
|
230
|
+
readmeMetadata = readmeMetadataTemplate(contextMetadata, {});
|
|
204
231
|
return readmeMetadata;
|
|
205
232
|
}
|
|
206
233
|
/**
|
|
@@ -231,14 +258,15 @@ var badges_default = { badges: { async content(options) {
|
|
|
231
258
|
npm: z.array(z.string()).optional()
|
|
232
259
|
}).optional().parse(options);
|
|
233
260
|
const metadata = await getReadmeMetadata();
|
|
234
|
-
const { ciActionFileName, license, licenseUrl, name, repositoryUrl } = metadata;
|
|
261
|
+
const { ciActionFileName, license, licenseUrl, name, repositoryUrl, usesGitLfs } = metadata;
|
|
235
262
|
const badges = [];
|
|
236
263
|
if (validOptions?.npm === void 0) {
|
|
237
|
-
if (metadata.isPublicNpmPackage) badges.push(`[](https://npmjs.com/package/${name})`);
|
|
238
|
-
} else for (const
|
|
264
|
+
if (metadata.isPublicNpmPackage) badges.push(`[](https://www.npmjs.com/package/${name})`);
|
|
265
|
+
} else for (const packageName of validOptions.npm) badges.push(`[](https://www.npmjs.com/package/${packageName})`);
|
|
239
266
|
if (license !== void 0 && licenseUrl !== void 0) badges.push(`[}-yellow.svg)](${licenseUrl})`);
|
|
240
267
|
if (ciActionFileName !== void 0 && repositoryUrl !== void 0) badges.push(`[](${repositoryUrl}/actions/workflows/${ciActionFileName})`);
|
|
241
|
-
if (
|
|
268
|
+
if (usesGitLfs) badges.push("");
|
|
269
|
+
if (validOptions?.custom !== void 0) for (const [badgeName, { image, link }] of Object.entries(validOptions.custom)) badges.push(`[](${link})`);
|
|
242
270
|
return badges.join("\n");
|
|
243
271
|
} } };
|
|
244
272
|
//#endregion
|
|
@@ -250,7 +278,7 @@ var banner_default = { banner: { async content(options) {
|
|
|
250
278
|
}).optional().parse(options);
|
|
251
279
|
const src = validOptions?.src ?? await getBannerSrc();
|
|
252
280
|
if (src === void 0) throw new Error("Banner image not found at any typical location, consider adding something at ./assets/banner.webp");
|
|
253
|
-
|
|
281
|
+
if (!isUrl(src) && !await isFile(src)) throw new Error(`Banner image not found at "${src}"`);
|
|
254
282
|
let alt = validOptions?.alt;
|
|
255
283
|
if (alt === void 0) {
|
|
256
284
|
const { name: packageName } = await getReadmeMetadata();
|
|
@@ -262,7 +290,7 @@ var banner_default = { banner: { async content(options) {
|
|
|
262
290
|
async function getBannerSrc() {
|
|
263
291
|
const { projectDirectory } = await getReadmeMetadata();
|
|
264
292
|
if (projectDirectory === void 0) throw new Error("No project directory found");
|
|
265
|
-
const
|
|
293
|
+
const [firstPath] = await globby([
|
|
266
294
|
".",
|
|
267
295
|
"assets",
|
|
268
296
|
"media",
|
|
@@ -298,19 +326,18 @@ async function getBannerSrc() {
|
|
|
298
326
|
]
|
|
299
327
|
}
|
|
300
328
|
});
|
|
301
|
-
|
|
329
|
+
return firstPath === void 0 ? void 0 : path.relative(process.cwd(), firstPath);
|
|
302
330
|
}
|
|
303
331
|
function isUrl(text, lenient = true) {
|
|
304
332
|
if (typeof text !== "string") throw new TypeError("Expected a string");
|
|
305
333
|
text = text.trim();
|
|
306
334
|
if (text.includes(" ")) return false;
|
|
307
335
|
if (URL.canParse(text)) return true;
|
|
308
|
-
|
|
309
|
-
return false;
|
|
336
|
+
return lenient && URL.canParse(`https://${text}`);
|
|
310
337
|
}
|
|
311
338
|
//#endregion
|
|
312
339
|
//#region src/lib/readme/rules/code.ts
|
|
313
|
-
const LEADING_DOT_REGEX =
|
|
340
|
+
const LEADING_DOT_REGEX = /^\./v;
|
|
314
341
|
var code_default = { code: { async content(options) {
|
|
315
342
|
const validOptions = z.object({
|
|
316
343
|
file: z.string(),
|
|
@@ -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",
|
|
@@ -387,7 +414,7 @@ var dependencies_default = { dependencies: { async content() {
|
|
|
387
414
|
if (engines?.[platformKey] !== void 0) continue;
|
|
388
415
|
const info = PLATFORM_INFO[platformKey.toLowerCase()];
|
|
389
416
|
const display = info ? `[${info.display}](${info.url})` : platformKey;
|
|
390
|
-
platformItems.push(version ? `- ${display}
|
|
417
|
+
platformItems.push(version === void 0 || version === "" ? `- ${display}` : `- ${display} ${version}`);
|
|
391
418
|
}
|
|
392
419
|
if (operatingSystem !== void 0 && operatingSystem.length > 0) platformItems.push(`- Supported platforms: ${operatingSystem.join(", ")}`);
|
|
393
420
|
const peerItems = [];
|
|
@@ -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();
|
|
@@ -449,7 +526,7 @@ var title_default = { title: {
|
|
|
449
526
|
},
|
|
450
527
|
order: 2
|
|
451
528
|
} };
|
|
452
|
-
const SPLIT_FOR_TITLE_CASE_REGEX = /[ _
|
|
529
|
+
const SPLIT_FOR_TITLE_CASE_REGEX = /[ _\-]+/v;
|
|
453
530
|
function makeTitleCase(text) {
|
|
454
531
|
return text.split(SPLIT_FOR_TITLE_CASE_REGEX).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
455
532
|
}
|
|
@@ -520,7 +597,7 @@ async function createSizeReport(filePath) {
|
|
|
520
597
|
original: createSizeInfo(originalSize, originalSize)
|
|
521
598
|
};
|
|
522
599
|
} catch (error) {
|
|
523
|
-
throw new Error(`Failed to analyze file: ${error instanceof Error ? error.message : "Unknown error"}
|
|
600
|
+
throw new Error(`Failed to analyze file: ${error instanceof Error ? error.message : "Unknown error"}`, { cause: error });
|
|
524
601
|
}
|
|
525
602
|
}
|
|
526
603
|
//#endregion
|
|
@@ -603,20 +680,21 @@ 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:
|
|
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
|
-
const heading = `## Table of contents`;
|
|
619
696
|
if (result.map === void 0) throw new Error("Could not generate table of contents");
|
|
697
|
+
const heading = `## Table of contents`;
|
|
620
698
|
const rootWrapper = {
|
|
621
699
|
children: result.map.children,
|
|
622
700
|
type: "root"
|
|
@@ -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,
|
|
@@ -674,13 +754,13 @@ function getAdditionalConfigExplorer() {
|
|
|
674
754
|
async function loadConfig(options) {
|
|
675
755
|
const { additionalConfig, defaults = rules_default, searchFrom } = options ?? {};
|
|
676
756
|
let finalConfig = { mdat: `Powered by the Markdown Autophagic Template system: [mdat](https://github.com/kitschpatrol/mdat).` };
|
|
677
|
-
|
|
757
|
+
finalConfig = deepMergeDefined(finalConfig, defaults);
|
|
678
758
|
const results = await getConfigExplorer().search(searchFrom);
|
|
679
759
|
if (results) {
|
|
680
760
|
const { config, filepath } = results;
|
|
681
761
|
let possibleRules = config;
|
|
682
762
|
log.debug(`Using config from "${filepath}"`);
|
|
683
|
-
if (filepath.endsWith("package.json")
|
|
763
|
+
if (typeof config === "string" && filepath.endsWith("package.json")) {
|
|
684
764
|
log.debug(`Detected shared config string: "${config}"`);
|
|
685
765
|
const { default: sharedConfig } = await import(config);
|
|
686
766
|
possibleRules = sharedConfig;
|
|
@@ -693,14 +773,14 @@ async function loadConfig(options) {
|
|
|
693
773
|
for (const configOrPath of additionalConfigArray) {
|
|
694
774
|
let loaded;
|
|
695
775
|
if (typeof configOrPath === "string") {
|
|
696
|
-
let
|
|
697
|
-
if (path.basename(configOrPath).endsWith("package.json"))
|
|
776
|
+
let loadResults;
|
|
777
|
+
if (path.basename(configOrPath).endsWith("package.json")) loadResults = {
|
|
698
778
|
config: mdatJsonLoader(configOrPath, await fs.readFile(configOrPath, "utf8")),
|
|
699
779
|
filepath: configOrPath
|
|
700
780
|
};
|
|
701
|
-
else
|
|
702
|
-
if (
|
|
703
|
-
const { config: loadedConfig, filepath } =
|
|
781
|
+
else loadResults = await getAdditionalConfigExplorer().load(configOrPath);
|
|
782
|
+
if (loadResults === null || loadResults === void 0) continue;
|
|
783
|
+
const { config: loadedConfig, filepath } = loadResults;
|
|
704
784
|
log.debug(`Loaded additional config from "${filepath}"`);
|
|
705
785
|
loaded = loadedConfig;
|
|
706
786
|
} else loaded = configOrPath;
|
|
@@ -745,7 +825,7 @@ async function formatWithPrettier(content, filePath) {
|
|
|
745
825
|
} catch {
|
|
746
826
|
throw new Error("The --format flag requires `prettier` to be installed. Run: pnpm add -D prettier");
|
|
747
827
|
}
|
|
748
|
-
const configKey = filePath ?
|
|
828
|
+
const configKey = filePath === void 0 || filePath === "" ? process.cwd() : path.dirname(filePath);
|
|
749
829
|
let config = configCache.get(configKey);
|
|
750
830
|
if (config === void 0 && !configCache.has(configKey)) {
|
|
751
831
|
config = await cachedPrettier.resolveConfig(filePath ?? process.cwd());
|
|
@@ -767,22 +847,22 @@ function zeroPad(n, nMax) {
|
|
|
767
847
|
async function getInputOutputPaths(inputs, output, name, extension) {
|
|
768
848
|
const paths = [];
|
|
769
849
|
for (const [index, file] of inputs.entries()) {
|
|
770
|
-
const inputOutputPath = await getInputOutputPath(file, output, name, extension, name && inputs.length > 1 ? `-${zeroPad(index + 1, inputs.length)}` : "");
|
|
850
|
+
const inputOutputPath = await getInputOutputPath(file, output, name, extension, name !== void 0 && name !== "" && inputs.length > 1 ? `-${zeroPad(index + 1, inputs.length)}` : "");
|
|
771
851
|
paths.push(inputOutputPath);
|
|
772
852
|
}
|
|
773
853
|
return paths;
|
|
774
854
|
}
|
|
775
855
|
async function getInputOutputPath(input, output, name, extension, nameSuffix = "") {
|
|
776
856
|
const resolvedInput = expandPath(input);
|
|
777
|
-
const resolvedOutput = output ? expandPath(output) : void 0;
|
|
778
857
|
if (!isFileSync(resolvedInput)) throw new Error(`Input file not found: "${resolvedInput}"`);
|
|
779
|
-
|
|
858
|
+
const resolvedOutput = output === void 0 || output === "" ? void 0 : expandPath(output);
|
|
859
|
+
if (resolvedOutput !== void 0) {
|
|
780
860
|
if (isFileSync(resolvedOutput)) throw new Error(`Output path must be a directory, received a file path: "${resolvedOutput}"`);
|
|
781
861
|
await fs.mkdir(resolvedOutput, { recursive: true });
|
|
782
862
|
}
|
|
783
863
|
return {
|
|
784
864
|
input: resolvedInput,
|
|
785
|
-
name: `${name ? path.basename(
|
|
865
|
+
name: `${name === void 0 || name === "" ? path.basename(resolvedInput, path.extname(resolvedInput)) : path.basename(name, path.extname(name))}${nameSuffix}${extension === void 0 ? name !== void 0 && path.extname(name) !== "" ? path.extname(name) : path.extname(input) : `.${extension}`}`,
|
|
786
866
|
output: resolvedOutput ?? path.dirname(resolvedInput)
|
|
787
867
|
};
|
|
788
868
|
}
|
|
@@ -793,7 +873,7 @@ function ensureArray(value) {
|
|
|
793
873
|
if (value === void 0 || value === null) return [];
|
|
794
874
|
return Array.isArray(value) ? value : [value];
|
|
795
875
|
}
|
|
796
|
-
const README_SEARCH_REGEX = /^readme(?:\.\w+)?$/
|
|
876
|
+
const README_SEARCH_REGEX = /^readme(?:\.\w+)?$/iv;
|
|
797
877
|
/**
|
|
798
878
|
* Finds a readme file in the current working directory (case-insensitive).
|
|
799
879
|
*/
|
|
@@ -869,20 +949,20 @@ function stripLintPlugins(config) {
|
|
|
869
949
|
//#endregion
|
|
870
950
|
//#region src/lib/processors.ts
|
|
871
951
|
async function processFiles(files, loader, processorGetter, name, output, config) {
|
|
872
|
-
const [resolvedConfig,
|
|
952
|
+
const [resolvedConfig, localRemarkConfig] = await Promise.all([loader({ additionalConfig: config }), loadAmbientRemarkConfig()]);
|
|
873
953
|
const inputOutputPaths = await getInputOutputPaths(ensureArray(files), output, name, "md");
|
|
874
|
-
const resolvedProcessor = processorGetter(resolvedConfig,
|
|
875
|
-
return await Promise.all(inputOutputPaths.map(async ({ input, name, output }) => {
|
|
954
|
+
const resolvedProcessor = processorGetter(resolvedConfig, localRemarkConfig);
|
|
955
|
+
return await Promise.all(inputOutputPaths.map(async ({ input, name: outputName, output: outputDirectory }) => {
|
|
876
956
|
const inputFile = await read(input);
|
|
877
957
|
const result = await resolvedProcessor.process(inputFile);
|
|
878
|
-
result.dirname =
|
|
879
|
-
result.basename =
|
|
958
|
+
result.dirname = outputDirectory;
|
|
959
|
+
result.basename = outputName;
|
|
880
960
|
return result;
|
|
881
961
|
}));
|
|
882
962
|
}
|
|
883
963
|
async function processString(markdown, loader, processorGetter, config) {
|
|
884
|
-
const [resolvedConfig,
|
|
885
|
-
return processorGetter(resolvedConfig,
|
|
964
|
+
const [resolvedConfig, localRemarkConfig] = await Promise.all([loader({ additionalConfig: config }), loadAmbientRemarkConfig()]);
|
|
965
|
+
return processorGetter(resolvedConfig, localRemarkConfig).process(new VFile(markdown));
|
|
886
966
|
}
|
|
887
967
|
function getExpandProcessor(config, ambientRemarkConfig) {
|
|
888
968
|
return remark().use({ settings: {
|
|
@@ -951,13 +1031,15 @@ async function createReadmeInteractive() {
|
|
|
951
1031
|
const readmePath = await findReadme();
|
|
952
1032
|
intro(`Running ${picocolors.bold("mdat create")} interactively`);
|
|
953
1033
|
const newReadmePath = await createReadme(await group({
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1034
|
+
async overwrite() {
|
|
1035
|
+
if (readmePath === void 0) return true;
|
|
1036
|
+
if (await confirm({
|
|
1037
|
+
message: `Found an existing readme at "${picocolors.blue(readmePath)}". Do you want to overwrite it?`,
|
|
1038
|
+
active: "Overwrite",
|
|
1039
|
+
inactive: "Exit"
|
|
1040
|
+
}) === false) throw new Error("`mdat create` was cancelled to avoid an overwrite - no changes were made");
|
|
1041
|
+
return true;
|
|
1042
|
+
},
|
|
961
1043
|
template: async () => select({
|
|
962
1044
|
message: "Which template would you like to use?",
|
|
963
1045
|
options: getTemplateOptions()
|
|
@@ -999,17 +1081,24 @@ async function createReadme(options) {
|
|
|
999
1081
|
const templateString = getTemplateForConfig(resolvedOptions.template, resolvedOptions.compound);
|
|
1000
1082
|
const readmePath = path.join(resolvedOptions.output, "readme.md");
|
|
1001
1083
|
if (!resolvedOptions.overwrite) {
|
|
1002
|
-
|
|
1084
|
+
let exists = true;
|
|
1085
|
+
try {
|
|
1086
|
+
await fs.access(readmePath);
|
|
1087
|
+
} catch {
|
|
1088
|
+
exists = false;
|
|
1089
|
+
}
|
|
1090
|
+
if (exists) throw new Error(`Readme already exists at "${readmePath}". Use the overwrite option to replace it.`);
|
|
1003
1091
|
}
|
|
1004
1092
|
await fs.writeFile(readmePath, templateString, "utf8");
|
|
1005
1093
|
if (resolvedOptions.expand) {
|
|
1006
1094
|
const [result] = await expand(readmePath);
|
|
1095
|
+
if (result === void 0) throw new Error(`Failed to expand readme at "${readmePath}"`);
|
|
1007
1096
|
await write(result);
|
|
1008
1097
|
}
|
|
1009
1098
|
return readmePath;
|
|
1010
1099
|
}
|
|
1011
1100
|
function getTemplateForConfig(templateKey, compound) {
|
|
1012
|
-
if (!(templateKey
|
|
1101
|
+
if (!Object.hasOwn(templates_default, templateKey)) throw new Error(`Unknown template "${templateKey}". Available templates: ${Object.keys(templates_default).join(", ")}`);
|
|
1013
1102
|
return templates_default[templateKey].content[compound ? "compound" : "explicit"];
|
|
1014
1103
|
}
|
|
1015
1104
|
function getTemplateOptions() {
|
|
@@ -1097,7 +1186,11 @@ async function check(files, config, options) {
|
|
|
1097
1186
|
const resolvedFiles = Array.isArray(files) ? files : [files];
|
|
1098
1187
|
const [originals, results] = await Promise.all([Promise.all(resolvedFiles.map(async (f) => read(f))), processFiles(files, loadConfig, getExpandProcessor, void 0, void 0, config)]);
|
|
1099
1188
|
if (options?.format) await formatResults(results);
|
|
1100
|
-
return results.map((result, i) =>
|
|
1189
|
+
return results.map((result, i) => {
|
|
1190
|
+
const original = originals[i];
|
|
1191
|
+
if (original === void 0) throw new Error(`Missing original file for comparison at index ${i}`);
|
|
1192
|
+
return compareWithDiff(original, result, options);
|
|
1193
|
+
});
|
|
1101
1194
|
}
|
|
1102
1195
|
/**
|
|
1103
1196
|
* Check if MDAT comments in a Markdown string are up to date by expanding and
|
|
@@ -1130,7 +1223,7 @@ function compareWithDiff(original, result, options) {
|
|
|
1130
1223
|
};
|
|
1131
1224
|
}
|
|
1132
1225
|
async function formatResults(results) {
|
|
1133
|
-
for (const file of results) file.value = await formatWithPrettier(file.toString(), file.path
|
|
1226
|
+
for (const file of results) file.value = await formatWithPrettier(file.toString(), file.path === "" ? void 0 : file.path);
|
|
1134
1227
|
}
|
|
1135
1228
|
//#endregion
|
|
1136
1229
|
export { check, checkString, collapse, collapseString, createReadme as create, createReadmeInteractive as createInteractive, defineConfig, expand, expandString, getContextMetadata, getReadmeMetadata, loadConfig, mergeConfig, resetMetadataCaches, setLogger, strip, stripString };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdat",
|
|
3
|
-
"version": "
|
|
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",
|
|
@@ -43,51 +43,51 @@
|
|
|
43
43
|
"dist/*"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@clack/prompts": "^1.
|
|
47
|
-
"cosmiconfig": "^
|
|
46
|
+
"@clack/prompts": "^1.7.0",
|
|
47
|
+
"cosmiconfig": "^10.0.0",
|
|
48
48
|
"cosmiconfig-typescript-loader": "^6.3.0",
|
|
49
49
|
"deepmerge-ts": "^7.1.5",
|
|
50
|
-
"globby": "^16.2.
|
|
51
|
-
"lognow": "^0.
|
|
50
|
+
"globby": "^16.2.2",
|
|
51
|
+
"lognow": "^0.8.0",
|
|
52
52
|
"mdast-util-toc": "^7.1.0",
|
|
53
|
-
"metascope": "^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",
|
|
57
|
-
"pretty-bytes": "^7.1.
|
|
57
|
+
"pretty-bytes": "^7.1.1",
|
|
58
58
|
"pretty-ms": "^9.3.0",
|
|
59
59
|
"remark": "^15.0.1",
|
|
60
60
|
"remark-gfm": "^4.0.1",
|
|
61
|
-
"remark-mdat": "^
|
|
61
|
+
"remark-mdat": "^3.0.1",
|
|
62
62
|
"to-vfile": "^8.0.0",
|
|
63
|
-
"type-fest": "^5.
|
|
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.
|
|
67
|
+
"yargs": "^18.1.0",
|
|
68
68
|
"zod": "^4.4.3"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@arethetypeswrong/core": "^0.18.
|
|
72
|
-
"@kitschpatrol/shared-config": "^
|
|
71
|
+
"@arethetypeswrong/core": "^0.18.5",
|
|
72
|
+
"@kitschpatrol/shared-config": "^8.6.0",
|
|
73
73
|
"@types/mdast": "^4.0.4",
|
|
74
|
-
"@types/node": "~
|
|
74
|
+
"@types/node": "~24.13.3",
|
|
75
75
|
"@types/unist": "^3.0.3",
|
|
76
76
|
"@types/yargs": "^17.0.35",
|
|
77
|
-
"@vitest/coverage-v8": "^4.1.
|
|
78
|
-
"bumpp": "^
|
|
79
|
-
"execa": "^
|
|
80
|
-
"mdat-plugin-cli-help": "^3.0
|
|
81
|
-
"mdat-plugin-example": "^
|
|
82
|
-
"mdat-plugin-tldraw": "^
|
|
83
|
-
"nanoid": "^
|
|
84
|
-
"prettier": "^3.
|
|
85
|
-
"publint": "^0.3.
|
|
77
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
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
|
+
"prettier": "^3.9.6",
|
|
85
|
+
"publint": "^0.3.22",
|
|
86
86
|
"shx": "^0.4.0",
|
|
87
|
-
"tsdown": "^0.22.
|
|
88
|
-
"typescript": "~
|
|
87
|
+
"tsdown": "^0.22.14",
|
|
88
|
+
"typescript": "~6.0.3",
|
|
89
89
|
"unplugin-raw": "^0.7.0",
|
|
90
|
-
"vitest": "^4.1.
|
|
90
|
+
"vitest": "^4.1.10"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
93
93
|
"prettier": "^3.0.0"
|
|
@@ -98,13 +98,7 @@
|
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"engines": {
|
|
101
|
-
"node": ">=
|
|
102
|
-
},
|
|
103
|
-
"devEngines": {
|
|
104
|
-
"runtime": {
|
|
105
|
-
"name": "node",
|
|
106
|
-
"version": ">=22.22.2"
|
|
107
|
-
}
|
|
101
|
+
"node": ">=24.16.0"
|
|
108
102
|
},
|
|
109
103
|
"scripts": {
|
|
110
104
|
"bench": "vitest bench --run --compare test/benchmarks/baseline.json",
|