@readme/cli 0.1.0 → 0.3.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/bin/git-format.js +80 -0
- package/bin/readme.js +1 -1
- package/package.json +54 -26
- package/src/bootstrap.js +9 -13
- package/src/cli.js +17 -11
- package/src/commands/components.js +35 -18
- package/src/commands/dev.js +12 -8
- package/src/commands/eyes.js +12 -8
- package/src/commands/import.js +2200 -2049
- package/src/commands/lint.js +33 -29
- package/src/commands/oas-bundle.js +6 -2
- package/src/commands/oas-sync.js +271 -161
- package/src/commands/oas-validate.js +10 -7
- package/src/commands/pretty.js +188 -165
- package/src/commands/setup.js +24 -26
- package/src/commands/versions.js +6 -2
- package/src/dev/app/[...slug]/page.js +1 -0
- package/src/dev/app/layout.js +18 -11
- package/src/dev/app/page.js +1 -0
- package/src/dev/lib/docs.js +27 -19
- package/src/dev/next.config.mjs +2 -2
- package/src/gha.js +7 -7
- package/src/prompts/index.js +16 -6
- package/src/utils/containment.js +87 -0
- package/src/utils/eyes.js +143 -51
- package/src/utils/git.js +3 -3
- package/src/utils/lint.js +39 -38
- package/src/utils/llms.js +94 -91
- package/src/utils/markdown.js +256 -0
- package/src/utils/marketplace.js +12 -5
- package/src/utils/multi-spinner.js +5 -7
- package/src/utils/promise-pool.js +7 -5
- package/src/utils/reporter.js +88 -94
- package/src/utils/setup-templates.js +12 -6
- package/src/utils/styles.js +2 -1
- package/src/utils/tamagotchi.js +257 -91
- package/src/utils/tips.js +18 -9
- package/src/utils/url-segs.js +46 -41
- package/src/validators/components.js +55 -63
- package/src/validators/content.js +16 -14
- package/src/validators/duplicates.js +6 -2
- package/src/validators/frontmatter.js +21 -29
- package/src/validators/links.js +4 -8
- package/src/validators/oas-reference.js +25 -18
- package/src/validators/oas-schema.js +2 -0
- package/src/validators/ordering.js +5 -5
- package/src/validators/recipes.js +4 -12
- package/vendor/git-format/CLAUDE.md +352 -0
- package/vendor/git-format/frontmatter.schema.json +199 -0
- package/src/commands/import-oas.test.js +0 -277
- package/src/commands/import.classify.test.js +0 -172
- package/src/commands/import.landing.test.js +0 -217
- package/src/commands/import.slug-planner.test.js +0 -86
- package/src/commands/import.staging.test.js +0 -230
- package/src/commands/import.test.js +0 -382
- package/src/utils/llms.test.js +0 -302
- package/src/utils/url-segs.test.js +0 -239
package/src/utils/eyes.js
CHANGED
|
@@ -19,7 +19,15 @@ export const palettes = {
|
|
|
19
19
|
red: { name: 'Red', body: '#EF4444', page: '#FFF5F5', pupil: '#7F1D1D', lid: '#FCA5A5' },
|
|
20
20
|
teal: { name: 'Teal', body: '#14B8A6', page: '#F0FFFE', pupil: '#134E4A', lid: '#5EEAD4' },
|
|
21
21
|
yellow: { name: 'Yellow', body: '#EAB308', page: '#FEFCE8', pupil: '#713F12', lid: '#FDE047' },
|
|
22
|
-
owl: {
|
|
22
|
+
owl: {
|
|
23
|
+
name: 'Owl',
|
|
24
|
+
body: '#8B5A2B',
|
|
25
|
+
page: '#FFF8EE',
|
|
26
|
+
pupil: '#2A1000',
|
|
27
|
+
lid: '#C4923A',
|
|
28
|
+
nose: '#FFD700',
|
|
29
|
+
hidden: true,
|
|
30
|
+
},
|
|
23
31
|
};
|
|
24
32
|
|
|
25
33
|
let currentPalette = palettes.blue;
|
|
@@ -124,7 +132,21 @@ function rebuildExpressions() {
|
|
|
124
132
|
|
|
125
133
|
export const animations = {
|
|
126
134
|
blink: {
|
|
127
|
-
frames: [
|
|
135
|
+
frames: [
|
|
136
|
+
'right',
|
|
137
|
+
'right',
|
|
138
|
+
'right',
|
|
139
|
+
'right',
|
|
140
|
+
'right',
|
|
141
|
+
'right',
|
|
142
|
+
'half-blink',
|
|
143
|
+
'squint',
|
|
144
|
+
'closed',
|
|
145
|
+
'closed',
|
|
146
|
+
'squint',
|
|
147
|
+
'half-blink',
|
|
148
|
+
'right',
|
|
149
|
+
],
|
|
128
150
|
durations: [1500, 100, 100, 100, 100, 100, 50, 50, 50, 80, 50, 50, 100],
|
|
129
151
|
},
|
|
130
152
|
|
|
@@ -134,85 +156,154 @@ export const animations = {
|
|
|
134
156
|
},
|
|
135
157
|
|
|
136
158
|
lookaround: {
|
|
137
|
-
frames: [
|
|
159
|
+
frames: [
|
|
160
|
+
'right',
|
|
161
|
+
'right',
|
|
162
|
+
'left',
|
|
163
|
+
'left',
|
|
164
|
+
'left',
|
|
165
|
+
'right',
|
|
166
|
+
'right',
|
|
167
|
+
'up-right',
|
|
168
|
+
'up-right',
|
|
169
|
+
'right',
|
|
170
|
+
'right',
|
|
171
|
+
'up-left',
|
|
172
|
+
'up-left',
|
|
173
|
+
'left',
|
|
174
|
+
'left',
|
|
175
|
+
'right',
|
|
176
|
+
],
|
|
138
177
|
durations: [600, 200, 120, 400, 200, 120, 400, 120, 400, 120, 200, 120, 400, 120, 200, 400],
|
|
139
178
|
},
|
|
140
179
|
|
|
141
180
|
'lookaround-blink': {
|
|
142
181
|
frames: [
|
|
143
|
-
'right',
|
|
144
|
-
'
|
|
145
|
-
'
|
|
146
|
-
'left',
|
|
147
|
-
'
|
|
148
|
-
'
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
182
|
+
'right',
|
|
183
|
+
'right',
|
|
184
|
+
'right',
|
|
185
|
+
'left',
|
|
186
|
+
'left',
|
|
187
|
+
'left',
|
|
188
|
+
'half-blink',
|
|
189
|
+
'squint',
|
|
190
|
+
'closed',
|
|
191
|
+
'closed',
|
|
192
|
+
'squint',
|
|
193
|
+
'half-blink',
|
|
194
|
+
'left',
|
|
195
|
+
'right',
|
|
196
|
+
'right',
|
|
197
|
+
'up-right',
|
|
198
|
+
'up-right',
|
|
199
|
+
'right',
|
|
200
|
+
'right',
|
|
201
|
+
'right',
|
|
202
|
+
'up-left',
|
|
203
|
+
'up-left',
|
|
204
|
+
'left',
|
|
205
|
+
'left',
|
|
206
|
+
'half-blink',
|
|
207
|
+
'squint',
|
|
208
|
+
'closed',
|
|
209
|
+
'closed',
|
|
210
|
+
'squint',
|
|
211
|
+
'half-blink',
|
|
212
|
+
'right',
|
|
213
|
+
'right',
|
|
152
214
|
],
|
|
153
215
|
durations: [
|
|
154
|
-
800, 200, 200,
|
|
155
|
-
|
|
156
|
-
50, 50, 50, 80, 50, 50,
|
|
157
|
-
200, 120, 400,
|
|
158
|
-
120, 500, 120,
|
|
159
|
-
200, 200,
|
|
160
|
-
120, 500, 120, 200,
|
|
161
|
-
50, 50, 50, 80, 50, 50,
|
|
162
|
-
120, 600,
|
|
216
|
+
800, 200, 200, 120, 400, 200, 50, 50, 50, 80, 50, 50, 200, 120, 400, 120, 500, 120, 200, 200, 120, 500, 120, 200,
|
|
217
|
+
50, 50, 50, 80, 50, 50, 120, 600,
|
|
163
218
|
],
|
|
164
219
|
},
|
|
165
220
|
|
|
166
221
|
all: {
|
|
167
222
|
frames: [
|
|
168
223
|
// idle, look around
|
|
169
|
-
'right',
|
|
170
|
-
'
|
|
171
|
-
'right',
|
|
224
|
+
'right',
|
|
225
|
+
'right',
|
|
226
|
+
'right',
|
|
227
|
+
'left',
|
|
228
|
+
'left',
|
|
229
|
+
'left',
|
|
230
|
+
'right',
|
|
231
|
+
'right',
|
|
172
232
|
// blink
|
|
173
|
-
'half-blink',
|
|
233
|
+
'half-blink',
|
|
234
|
+
'squint',
|
|
235
|
+
'closed',
|
|
236
|
+
'closed',
|
|
237
|
+
'squint',
|
|
238
|
+
'half-blink',
|
|
174
239
|
// look up + bounce
|
|
175
|
-
'right',
|
|
176
|
-
'
|
|
177
|
-
'
|
|
240
|
+
'right',
|
|
241
|
+
'right',
|
|
242
|
+
'up-right',
|
|
243
|
+
'up-right',
|
|
244
|
+
'right',
|
|
245
|
+
'right:up',
|
|
246
|
+
'right:up',
|
|
247
|
+
'right',
|
|
248
|
+
'right:up',
|
|
249
|
+
'right:up',
|
|
250
|
+
'right',
|
|
178
251
|
// look the other way
|
|
179
|
-
'right',
|
|
180
|
-
'
|
|
252
|
+
'right',
|
|
253
|
+
'left',
|
|
254
|
+
'left',
|
|
255
|
+
'up-left',
|
|
256
|
+
'up-left',
|
|
257
|
+
'left',
|
|
181
258
|
// blink
|
|
182
|
-
'half-blink',
|
|
259
|
+
'half-blink',
|
|
260
|
+
'squint',
|
|
261
|
+
'closed',
|
|
262
|
+
'closed',
|
|
263
|
+
'squint',
|
|
264
|
+
'half-blink',
|
|
183
265
|
// bounce
|
|
184
|
-
'left',
|
|
266
|
+
'left',
|
|
267
|
+
'left:up',
|
|
268
|
+
'left:up',
|
|
269
|
+
'left',
|
|
270
|
+
'left:up',
|
|
271
|
+
'left:up',
|
|
272
|
+
'left',
|
|
185
273
|
// settle back + bounce
|
|
186
|
-
'right',
|
|
187
|
-
'right
|
|
274
|
+
'right',
|
|
275
|
+
'right',
|
|
276
|
+
'right',
|
|
277
|
+
'right:up',
|
|
278
|
+
'right:up',
|
|
279
|
+
'right',
|
|
188
280
|
// blink
|
|
189
|
-
'half-blink',
|
|
190
|
-
'
|
|
281
|
+
'half-blink',
|
|
282
|
+
'squint',
|
|
283
|
+
'closed',
|
|
284
|
+
'closed',
|
|
285
|
+
'squint',
|
|
286
|
+
'half-blink',
|
|
287
|
+
'right',
|
|
288
|
+
'right',
|
|
191
289
|
],
|
|
192
290
|
durations: [
|
|
193
291
|
// idle, look around
|
|
194
|
-
800, 200, 200,
|
|
195
|
-
120, 400, 200,
|
|
196
|
-
120, 400,
|
|
292
|
+
800, 200, 200, 120, 400, 200, 120, 400,
|
|
197
293
|
// blink
|
|
198
294
|
50, 50, 50, 80, 50, 50,
|
|
199
295
|
// look up + bounce
|
|
200
|
-
200, 200,
|
|
201
|
-
120, 500, 120,
|
|
202
|
-
150, 150, 150, 150, 150, 200,
|
|
296
|
+
200, 200, 120, 500, 120, 150, 150, 150, 150, 150, 200,
|
|
203
297
|
// look the other way
|
|
204
|
-
300, 120, 400,
|
|
205
|
-
120, 500, 120,
|
|
298
|
+
300, 120, 400, 120, 500, 120,
|
|
206
299
|
// blink
|
|
207
300
|
50, 50, 50, 80, 50, 50,
|
|
208
301
|
// bounce
|
|
209
302
|
200, 150, 150, 150, 150, 150, 200,
|
|
210
303
|
// settle back + bounce
|
|
211
|
-
120, 200, 300,
|
|
212
|
-
150, 150, 200,
|
|
304
|
+
120, 200, 300, 150, 150, 200,
|
|
213
305
|
// blink
|
|
214
|
-
50, 50, 50, 80, 50, 50,
|
|
215
|
-
200, 800,
|
|
306
|
+
50, 50, 50, 80, 50, 50, 200, 800,
|
|
216
307
|
],
|
|
217
308
|
},
|
|
218
309
|
};
|
|
@@ -253,7 +344,7 @@ export function header(opts = {}) {
|
|
|
253
344
|
const icon = eyes(expression);
|
|
254
345
|
const gap = ' ';
|
|
255
346
|
|
|
256
|
-
const title = chalk.bold.hex(currentPalette.body)('The ReadMe CLI') + (version ?
|
|
347
|
+
const title = chalk.bold.hex(currentPalette.body)('The ReadMe CLI') + (version ? ` ${chalk.dim(`v${version}`)}` : '');
|
|
257
348
|
const bin = binName ? chalk.white(binName) : '';
|
|
258
349
|
const greetLine = greeting ? chalk.dim(greeting) : '';
|
|
259
350
|
|
|
@@ -296,7 +387,8 @@ export function animate(name, opts = {}) {
|
|
|
296
387
|
const headerLines = [];
|
|
297
388
|
if (version || bin) {
|
|
298
389
|
const gap = ' ';
|
|
299
|
-
headerLines[0] =
|
|
390
|
+
headerLines[0] =
|
|
391
|
+
gap + chalk.bold.hex(currentPalette.body)('The ReadMe CLI') + (version ? ` ${chalk.dim(`v${version}`)}` : '');
|
|
300
392
|
headerLines[1] = gap + (bin ? chalk.white(bin) : '');
|
|
301
393
|
if (subtitle) headerLines[2] = gap + subtitle;
|
|
302
394
|
}
|
|
@@ -340,7 +432,7 @@ export function animate(name, opts = {}) {
|
|
|
340
432
|
firstDraw = false;
|
|
341
433
|
|
|
342
434
|
for (const line of lines) {
|
|
343
|
-
process.stdout.write(indent + line
|
|
435
|
+
process.stdout.write(`${indent + line}\n`);
|
|
344
436
|
}
|
|
345
437
|
|
|
346
438
|
const duration = anim.durations[i % anim.durations.length];
|
package/src/utils/git.js
CHANGED
|
@@ -63,10 +63,10 @@ export function detectRemotePlatform() {
|
|
|
63
63
|
const remotes = readRemotes();
|
|
64
64
|
if (!remotes) return null;
|
|
65
65
|
for (const [key, def] of Object.entries(PLATFORMS)) {
|
|
66
|
-
if (def.remoteHosts && def.remoteHosts.some(
|
|
66
|
+
if (def.remoteHosts && def.remoteHosts.some(h => remotes.toLowerCase().includes(h))) {
|
|
67
67
|
return key;
|
|
68
68
|
}
|
|
69
|
-
if (def.remotePathHints && def.remotePathHints.some(
|
|
69
|
+
if (def.remotePathHints && def.remotePathHints.some(p => remotes.toLowerCase().includes(p))) {
|
|
70
70
|
return key;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -81,7 +81,7 @@ export function detectExistingCi(gitRoot) {
|
|
|
81
81
|
if (!gitRoot) return [];
|
|
82
82
|
const found = [];
|
|
83
83
|
for (const [key, def] of Object.entries(PLATFORMS)) {
|
|
84
|
-
const hit = def.fsMarkers.some(
|
|
84
|
+
const hit = def.fsMarkers.some(marker => fs.existsSync(path.join(gitRoot, marker)));
|
|
85
85
|
if (hit) found.push(key);
|
|
86
86
|
}
|
|
87
87
|
return found;
|
package/src/utils/lint.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
import * as
|
|
8
|
-
import * as
|
|
9
|
-
import * as
|
|
10
|
-
import * as
|
|
11
|
-
import * as
|
|
12
|
-
import * as
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import * as componentsValidator from '../validators/components.js';
|
|
5
|
+
import * as contentValidator from '../validators/content.js';
|
|
6
|
+
import * as duplicatesValidator from '../validators/duplicates.js';
|
|
7
|
+
import * as frontmatterValidator from '../validators/frontmatter.js';
|
|
8
|
+
import * as linksValidator from '../validators/links.js';
|
|
9
|
+
import * as nestingValidator from '../validators/nesting.js';
|
|
10
|
+
import * as oasReferenceValidator from '../validators/oas-reference.js';
|
|
11
|
+
import * as oasSchemaValidator from '../validators/oas-schema.js';
|
|
12
|
+
import * as orderingValidator from '../validators/ordering.js';
|
|
13
|
+
import * as recipesValidator from '../validators/recipes.js';
|
|
13
14
|
|
|
14
15
|
const TARGET_PATTERNS = [
|
|
15
16
|
{ dir: 'custom_blocks', ext: ['.mdx', '.md'] },
|
|
@@ -17,28 +18,28 @@ const TARGET_PATTERNS = [
|
|
|
17
18
|
{ dir: 'reference', ext: '.md' },
|
|
18
19
|
{ dir: 'custom_pages', ext: '.md' },
|
|
19
20
|
{ dir: 'recipes', ext: '.md' },
|
|
20
|
-
]
|
|
21
|
+
];
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Collect all target files from the repo root.
|
|
24
25
|
*/
|
|
25
26
|
export function collectFiles(gitRoot) {
|
|
26
|
-
const files = []
|
|
27
|
+
const files = [];
|
|
27
28
|
|
|
28
29
|
for (const { dir, ext } of TARGET_PATTERNS) {
|
|
29
|
-
const dirPath = path.join(gitRoot, dir)
|
|
30
|
-
if (!fs.existsSync(dirPath)) continue
|
|
30
|
+
const dirPath = path.join(gitRoot, dir);
|
|
31
|
+
if (!fs.existsSync(dirPath)) continue;
|
|
31
32
|
|
|
32
|
-
const exts = Array.isArray(ext) ? ext : [ext]
|
|
33
|
-
const entries = fs.readdirSync(dirPath, { recursive: true })
|
|
33
|
+
const exts = Array.isArray(ext) ? ext : [ext];
|
|
34
|
+
const entries = fs.readdirSync(dirPath, { recursive: true });
|
|
34
35
|
for (const entry of entries) {
|
|
35
|
-
if (exts.some(
|
|
36
|
-
files.push(path.join(dir, entry))
|
|
36
|
+
if (exts.some(e => entry.endsWith(e))) {
|
|
37
|
+
files.push(path.join(dir, entry));
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
return files.sort()
|
|
42
|
+
return files.sort();
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
// Every validator in src/validators/, imported statically (rather than
|
|
@@ -57,14 +58,14 @@ const ALL_VALIDATORS = [
|
|
|
57
58
|
oasSchemaValidator,
|
|
58
59
|
orderingValidator,
|
|
59
60
|
recipesValidator,
|
|
60
|
-
]
|
|
61
|
+
];
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
64
|
* Validators can export `validate()` for per-file checks and/or
|
|
64
65
|
* `validateAll()` for cross-file checks (like ordering).
|
|
65
66
|
*/
|
|
66
67
|
function loadValidators() {
|
|
67
|
-
return ALL_VALIDATORS.filter(
|
|
68
|
+
return ALL_VALIDATORS.filter(mod => mod.name && (mod.validate || mod.validateAll));
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
/**
|
|
@@ -73,42 +74,42 @@ function loadValidators() {
|
|
|
73
74
|
* Calls `onFile(relativePath)` before processing each file (for progress reporting).
|
|
74
75
|
*/
|
|
75
76
|
export async function runValidators(files, gitRoot, { onFile, onBeforeCrossFile, fix, nonInteractive } = {}) {
|
|
76
|
-
const validators = await loadValidators()
|
|
77
|
-
const results = []
|
|
77
|
+
const validators = await loadValidators();
|
|
78
|
+
const results = [];
|
|
78
79
|
|
|
79
80
|
// Per-file validators.
|
|
80
81
|
for (const relativePath of files) {
|
|
81
|
-
if (onFile) onFile(relativePath)
|
|
82
|
+
if (onFile) onFile(relativePath);
|
|
82
83
|
|
|
83
|
-
const filePath = path.join(gitRoot, relativePath)
|
|
84
|
-
const content = fs.readFileSync(filePath, 'utf-8')
|
|
84
|
+
const filePath = path.join(gitRoot, relativePath);
|
|
85
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
85
86
|
|
|
86
87
|
for (const validator of validators) {
|
|
87
|
-
if (!validator.validate) continue
|
|
88
|
-
const result = validator.validate({ filePath, content, relativePath, fix })
|
|
88
|
+
if (!validator.validate) continue;
|
|
89
|
+
const result = validator.validate({ filePath, content, relativePath, fix });
|
|
89
90
|
if (result) {
|
|
90
91
|
if (Array.isArray(result)) {
|
|
91
|
-
results.push(...result)
|
|
92
|
+
results.push(...result);
|
|
92
93
|
} else {
|
|
93
|
-
results.push(result)
|
|
94
|
+
results.push(result);
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
// Cross-file validators — stop the spinner first so interactive prompts work.
|
|
100
|
-
if (onBeforeCrossFile) onBeforeCrossFile()
|
|
101
|
+
if (onBeforeCrossFile) onBeforeCrossFile();
|
|
101
102
|
for (const validator of validators) {
|
|
102
|
-
if (!validator.validateAll) continue
|
|
103
|
-
const result = await validator.validateAll(files, gitRoot, { fix, nonInteractive })
|
|
103
|
+
if (!validator.validateAll) continue;
|
|
104
|
+
const result = await validator.validateAll(files, gitRoot, { fix, nonInteractive });
|
|
104
105
|
if (result) {
|
|
105
106
|
if (Array.isArray(result)) {
|
|
106
|
-
results.push(...result)
|
|
107
|
+
results.push(...result);
|
|
107
108
|
} else {
|
|
108
|
-
results.push(result)
|
|
109
|
+
results.push(result);
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
return results
|
|
114
|
+
return results;
|
|
114
115
|
}
|