koguma 2.2.0 → 2.2.1
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/cli/scaffold.ts +69 -12
- package/package.json +1 -1
- package/src/admin/_bundle.ts +1 -1
package/cli/scaffold.ts
CHANGED
|
@@ -11,7 +11,11 @@ import {
|
|
|
11
11
|
import { resolve } from 'path';
|
|
12
12
|
import { ok, warn } from './log.ts';
|
|
13
13
|
import { generateKogumaToml } from './config.ts';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
findMarkdownField,
|
|
16
|
+
findMarkdownFields,
|
|
17
|
+
type ContentTypeInfo
|
|
18
|
+
} from './content.ts';
|
|
15
19
|
import matter from 'gray-matter';
|
|
16
20
|
|
|
17
21
|
// ── Template types ─────────────────────────────────────────────────
|
|
@@ -315,29 +319,50 @@ export function generateExampleFile(
|
|
|
315
319
|
ctId: string,
|
|
316
320
|
fields: Record<string, { fieldType: string }>,
|
|
317
321
|
singleton?: boolean
|
|
318
|
-
): {
|
|
322
|
+
): {
|
|
323
|
+
content: string;
|
|
324
|
+
extension: string;
|
|
325
|
+
siblingFiles?: { fieldId: string; content: string }[];
|
|
326
|
+
} {
|
|
319
327
|
const frontmatter: Record<string, unknown> = {};
|
|
320
|
-
|
|
328
|
+
const mdFields = Object.entries(fields)
|
|
329
|
+
.filter(([, meta]) => meta.fieldType === 'markdown')
|
|
330
|
+
.map(([id]) => id);
|
|
331
|
+
const primaryMdField = mdFields[0] ?? null;
|
|
332
|
+
const extraMdFields = mdFields.slice(1);
|
|
321
333
|
|
|
322
334
|
for (const [fieldId, meta] of Object.entries(fields)) {
|
|
323
335
|
if (meta.fieldType === 'markdown') {
|
|
324
|
-
|
|
325
|
-
continue; // markdown goes in body, not frontmatter
|
|
336
|
+
continue; // markdown goes in body or sibling files, not frontmatter
|
|
326
337
|
}
|
|
327
338
|
frontmatter[fieldId] = placeholderForFieldType(meta.fieldType);
|
|
328
339
|
}
|
|
329
340
|
|
|
330
|
-
|
|
341
|
+
// Build sibling example files for extra markdown fields
|
|
342
|
+
const siblingFiles: { fieldId: string; content: string }[] = [];
|
|
343
|
+
for (const fieldId of extraMdFields) {
|
|
344
|
+
siblingFiles.push({
|
|
345
|
+
fieldId,
|
|
346
|
+
content: `Write your ${fieldId} content here.`
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (primaryMdField) {
|
|
331
351
|
const fm = matter.stringify('', frontmatter).trim();
|
|
332
352
|
const bodyHint = singleton ? '' : `\nWrite your ${ctId} content here.\n`;
|
|
333
353
|
return {
|
|
334
354
|
content: `${fm}\n${bodyHint}`,
|
|
335
|
-
extension: '.md'
|
|
355
|
+
extension: '.md',
|
|
356
|
+
...(siblingFiles.length > 0 ? { siblingFiles } : {})
|
|
336
357
|
};
|
|
337
358
|
}
|
|
338
359
|
|
|
339
360
|
const fm = matter.stringify('', frontmatter).trim();
|
|
340
|
-
return {
|
|
361
|
+
return {
|
|
362
|
+
content: fm + '\n',
|
|
363
|
+
extension: '.md',
|
|
364
|
+
...(siblingFiles.length > 0 ? { siblingFiles } : {})
|
|
365
|
+
};
|
|
341
366
|
}
|
|
342
367
|
|
|
343
368
|
/**
|
|
@@ -367,7 +392,7 @@ export function scaffoldContentDirFromTemplate(
|
|
|
367
392
|
fields[fid] = { fieldType: fieldTypeFromExpression(expr) };
|
|
368
393
|
}
|
|
369
394
|
|
|
370
|
-
const { content, extension } = generateExampleFile(
|
|
395
|
+
const { content, extension, siblingFiles } = generateExampleFile(
|
|
371
396
|
ct.id,
|
|
372
397
|
fields,
|
|
373
398
|
ct.singleton
|
|
@@ -375,6 +400,14 @@ export function scaffoldContentDirFromTemplate(
|
|
|
375
400
|
const filename = `_example${extension}`;
|
|
376
401
|
writeFileSync(resolve(typeDir, filename), content);
|
|
377
402
|
ok(`Created content/${ct.id}/${filename}`);
|
|
403
|
+
|
|
404
|
+
// Write sibling example files for extra markdown fields
|
|
405
|
+
if (siblingFiles) {
|
|
406
|
+
for (const { fieldId, content: siblingContent } of siblingFiles) {
|
|
407
|
+
const siblingName = `_example.${fieldId}.md`;
|
|
408
|
+
writeFileSync(resolve(typeDir, siblingName), siblingContent + '\n');
|
|
409
|
+
}
|
|
410
|
+
}
|
|
378
411
|
} else if (!dirExisted) {
|
|
379
412
|
ok(`Created content/${ct.id}/`);
|
|
380
413
|
}
|
|
@@ -408,7 +441,7 @@ export function scaffoldContentDir(
|
|
|
408
441
|
const isEmpty = dirExisted ? readdirSync(typeDir).length === 0 : true;
|
|
409
442
|
|
|
410
443
|
if (isEmpty) {
|
|
411
|
-
const { content, extension } = generateExampleFile(
|
|
444
|
+
const { content, extension, siblingFiles } = generateExampleFile(
|
|
412
445
|
ct.id,
|
|
413
446
|
ct.fieldMeta,
|
|
414
447
|
ct.singleton
|
|
@@ -416,6 +449,14 @@ export function scaffoldContentDir(
|
|
|
416
449
|
const filename = `_example${extension}`;
|
|
417
450
|
writeFileSync(resolve(typeDir, filename), content);
|
|
418
451
|
ok(`Created content/${ct.id}/${filename}`);
|
|
452
|
+
|
|
453
|
+
// Write sibling example files for extra markdown fields
|
|
454
|
+
if (siblingFiles) {
|
|
455
|
+
for (const { fieldId, content: siblingContent } of siblingFiles) {
|
|
456
|
+
const siblingName = `_example.${fieldId}.md`;
|
|
457
|
+
writeFileSync(resolve(typeDir, siblingName), siblingContent + '\n');
|
|
458
|
+
}
|
|
459
|
+
}
|
|
419
460
|
} else if (!dirExisted) {
|
|
420
461
|
ok(`Created content/${ct.id}/`);
|
|
421
462
|
}
|
|
@@ -538,7 +579,7 @@ export function syncContentDirsWithConfig(
|
|
|
538
579
|
mkdirSync(typeDir, { recursive: true });
|
|
539
580
|
}
|
|
540
581
|
|
|
541
|
-
const { content, extension } = generateExampleFile(
|
|
582
|
+
const { content, extension, siblingFiles } = generateExampleFile(
|
|
542
583
|
ct.id,
|
|
543
584
|
ct.fieldMeta,
|
|
544
585
|
ct.singleton
|
|
@@ -551,6 +592,14 @@ export function syncContentDirsWithConfig(
|
|
|
551
592
|
if (!dryRun) {
|
|
552
593
|
writeFileSync(resolve(typeDir, filename), content);
|
|
553
594
|
ok(`Created content/${ct.id}/${filename}`);
|
|
595
|
+
|
|
596
|
+
// Write sibling example files for extra markdown fields
|
|
597
|
+
if (siblingFiles) {
|
|
598
|
+
for (const { fieldId, content: siblingContent } of siblingFiles) {
|
|
599
|
+
const siblingName = `_example.${fieldId}.md`;
|
|
600
|
+
writeFileSync(resolve(typeDir, siblingName), siblingContent + '\n');
|
|
601
|
+
}
|
|
602
|
+
}
|
|
554
603
|
}
|
|
555
604
|
continue;
|
|
556
605
|
}
|
|
@@ -559,7 +608,7 @@ export function syncContentDirsWithConfig(
|
|
|
559
608
|
|
|
560
609
|
// If dir is empty, create _example
|
|
561
610
|
if (files.length === 0) {
|
|
562
|
-
const { content, extension } = generateExampleFile(
|
|
611
|
+
const { content, extension, siblingFiles } = generateExampleFile(
|
|
563
612
|
ct.id,
|
|
564
613
|
ct.fieldMeta,
|
|
565
614
|
ct.singleton
|
|
@@ -572,6 +621,14 @@ export function syncContentDirsWithConfig(
|
|
|
572
621
|
if (!dryRun) {
|
|
573
622
|
writeFileSync(resolve(typeDir, filename), content);
|
|
574
623
|
ok(`Created content/${ct.id}/${filename}`);
|
|
624
|
+
|
|
625
|
+
// Write sibling example files for extra markdown fields
|
|
626
|
+
if (siblingFiles) {
|
|
627
|
+
for (const { fieldId, content: siblingContent } of siblingFiles) {
|
|
628
|
+
const siblingName = `_example.${fieldId}.md`;
|
|
629
|
+
writeFileSync(resolve(typeDir, siblingName), siblingContent + '\n');
|
|
630
|
+
}
|
|
631
|
+
}
|
|
575
632
|
}
|
|
576
633
|
continue;
|
|
577
634
|
}
|