@imjp/writenex-astro 1.3.6 → 1.5.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/chunk-E4PQLKAH.js +282 -0
- package/dist/chunk-E4PQLKAH.js.map +1 -0
- package/dist/{chunk-NSW7AIVF.js → chunk-EEUN46Q2.js} +3 -3
- package/dist/{chunk-YBCPOLMY.js → chunk-P5KMSHFP.js} +2 -1
- package/dist/{chunk-YBCPOLMY.js.map → chunk-P5KMSHFP.js.map} +1 -1
- package/dist/{chunk-JMNCPNQX.js → chunk-XVQNYPOI.js} +65 -3
- package/dist/chunk-XVQNYPOI.js.map +1 -0
- package/dist/chunk-YRSIZLHE.js +1 -0
- package/dist/{chunk-N37EPLKG.js → chunk-ZWUGHWHD.js} +79 -10
- package/dist/chunk-ZWUGHWHD.js.map +1 -0
- package/dist/client/index.css +1 -1
- package/dist/client/index.css.map +1 -1
- package/dist/client/index.js +114 -114
- package/dist/client/index.js.map +1 -1
- package/dist/config/index.d.ts +3 -2
- package/dist/config/index.js +11 -3
- package/dist/{config-CliL0CoN.d.ts → config-B7t8CjL1.d.ts} +38 -60
- package/dist/{content-TuL3GT66.d.ts → content-CwcgR8P6.d.ts} +1 -1
- package/dist/discovery/index.d.ts +2 -2
- package/dist/discovery/index.js +2 -2
- package/dist/fields/index.d.ts +16 -0
- package/dist/fields/index.js +13 -0
- package/dist/fields-DUSm13nm.d.ts +223 -0
- package/dist/filesystem/index.d.ts +2 -2
- package/dist/filesystem/index.js +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/{loader-53VVP2IN.js → loader-B5WZCVBC.js} +3 -3
- package/dist/loader-B5WZCVBC.js.map +1 -0
- package/dist/{schema-DDJyoVkj.d.ts → schema-nLMfZ9-o.d.ts} +79 -53
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +3 -3
- package/package.json +5 -1
- package/src/client/components/FrontmatterForm/FrontmatterForm.css +104 -0
- package/src/client/components/FrontmatterForm/FrontmatterForm.tsx +452 -26
- package/src/config/defaults.ts +1 -0
- package/src/config/index.ts +3 -0
- package/src/config/schema.ts +114 -73
- package/src/discovery/schema.ts +120 -1
- package/src/fields/collection.ts +67 -0
- package/src/fields/fields.ts +150 -0
- package/src/fields/index.ts +42 -0
- package/src/fields/resolve.ts +203 -0
- package/src/fields/types.ts +179 -0
- package/src/index.ts +3 -0
- package/src/types/config.ts +87 -63
- package/src/types/index.ts +3 -0
- package/dist/chunk-JMNCPNQX.js.map +0 -1
- package/dist/chunk-KIKIPIFA.js +0 -1
- package/dist/chunk-N37EPLKG.js.map +0 -1
- /package/dist/{chunk-NSW7AIVF.js.map → chunk-EEUN46Q2.js.map} +0 -0
- /package/dist/{chunk-KIKIPIFA.js.map → chunk-YRSIZLHE.js.map} +0 -0
- /package/dist/{loader-53VVP2IN.js.map → fields/index.js.map} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// src/fields/resolve.ts
|
|
2
|
+
var FIELD_KIND_TO_TYPE = {
|
|
3
|
+
text: "string",
|
|
4
|
+
slug: "string",
|
|
5
|
+
url: "string",
|
|
6
|
+
number: "number",
|
|
7
|
+
integer: "number",
|
|
8
|
+
select: "string",
|
|
9
|
+
multiselect: "array",
|
|
10
|
+
checkbox: "boolean",
|
|
11
|
+
date: "date",
|
|
12
|
+
datetime: "date",
|
|
13
|
+
image: "image",
|
|
14
|
+
file: "file",
|
|
15
|
+
object: "object",
|
|
16
|
+
array: "array",
|
|
17
|
+
blocks: "blocks",
|
|
18
|
+
relationship: "relationship",
|
|
19
|
+
"path-reference": "string",
|
|
20
|
+
markdoc: "markdoc",
|
|
21
|
+
mdx: "mdx",
|
|
22
|
+
conditional: "object",
|
|
23
|
+
child: "child",
|
|
24
|
+
"cloud-image": "image",
|
|
25
|
+
empty: "empty",
|
|
26
|
+
"empty-content": "empty-content",
|
|
27
|
+
"empty-document": "empty-document",
|
|
28
|
+
ignored: "ignored"
|
|
29
|
+
};
|
|
30
|
+
function resolveObjectFields(fields2) {
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const [key, value] of Object.entries(fields2)) {
|
|
33
|
+
result[key] = resolveFieldDefinition(value);
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function resolveBlockTypes(blockTypes) {
|
|
38
|
+
const result = {};
|
|
39
|
+
for (const [key, value] of Object.entries(blockTypes)) {
|
|
40
|
+
result[key] = resolveFieldDefinition(value);
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function resolveFieldDefinition(field) {
|
|
45
|
+
const type = FIELD_KIND_TO_TYPE[field.fieldKind] ?? "string";
|
|
46
|
+
const base = {
|
|
47
|
+
type,
|
|
48
|
+
required: field.validation?.isRequired ?? false,
|
|
49
|
+
label: field.label,
|
|
50
|
+
description: field.description,
|
|
51
|
+
default: field.defaultValue
|
|
52
|
+
};
|
|
53
|
+
switch (field.fieldKind) {
|
|
54
|
+
case "text":
|
|
55
|
+
return {
|
|
56
|
+
...base,
|
|
57
|
+
multiline: field.multiline
|
|
58
|
+
};
|
|
59
|
+
case "slug":
|
|
60
|
+
case "url":
|
|
61
|
+
return base;
|
|
62
|
+
case "number":
|
|
63
|
+
return {
|
|
64
|
+
...base,
|
|
65
|
+
default: field.defaultValue ?? field.placeholder
|
|
66
|
+
};
|
|
67
|
+
case "integer":
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
default: field.defaultValue ?? field.placeholder
|
|
71
|
+
};
|
|
72
|
+
case "select":
|
|
73
|
+
return {
|
|
74
|
+
...base,
|
|
75
|
+
options: field.options,
|
|
76
|
+
default: field.defaultValue
|
|
77
|
+
};
|
|
78
|
+
case "multiselect":
|
|
79
|
+
return {
|
|
80
|
+
...base,
|
|
81
|
+
items: "string",
|
|
82
|
+
default: field.defaultValue
|
|
83
|
+
};
|
|
84
|
+
case "checkbox":
|
|
85
|
+
return {
|
|
86
|
+
...base,
|
|
87
|
+
default: field.defaultValue
|
|
88
|
+
};
|
|
89
|
+
case "date":
|
|
90
|
+
return {
|
|
91
|
+
...base,
|
|
92
|
+
format: "date",
|
|
93
|
+
default: field.defaultValue
|
|
94
|
+
};
|
|
95
|
+
case "datetime":
|
|
96
|
+
return {
|
|
97
|
+
...base,
|
|
98
|
+
format: "datetime-local",
|
|
99
|
+
default: field.defaultValue
|
|
100
|
+
};
|
|
101
|
+
case "image":
|
|
102
|
+
return {
|
|
103
|
+
...base,
|
|
104
|
+
directory: field.directory,
|
|
105
|
+
publicPath: field.publicPath
|
|
106
|
+
};
|
|
107
|
+
case "file":
|
|
108
|
+
return {
|
|
109
|
+
...base,
|
|
110
|
+
directory: field.directory,
|
|
111
|
+
publicPath: field.publicPath
|
|
112
|
+
};
|
|
113
|
+
case "object":
|
|
114
|
+
return {
|
|
115
|
+
...base,
|
|
116
|
+
fields: resolveObjectFields(field.fields)
|
|
117
|
+
};
|
|
118
|
+
case "array":
|
|
119
|
+
return {
|
|
120
|
+
...base,
|
|
121
|
+
itemField: resolveFieldDefinition(field.itemField),
|
|
122
|
+
itemLabel: field.itemLabel
|
|
123
|
+
};
|
|
124
|
+
case "blocks":
|
|
125
|
+
return {
|
|
126
|
+
...base,
|
|
127
|
+
blockTypes: resolveBlockTypes(field.blockTypes),
|
|
128
|
+
itemLabel: field.itemLabel
|
|
129
|
+
};
|
|
130
|
+
case "relationship":
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
collection: field.collection
|
|
134
|
+
};
|
|
135
|
+
case "path-reference":
|
|
136
|
+
return {
|
|
137
|
+
...base,
|
|
138
|
+
allowExternal: field.contentTypes?.includes("url")
|
|
139
|
+
};
|
|
140
|
+
case "markdoc":
|
|
141
|
+
case "mdx":
|
|
142
|
+
return base;
|
|
143
|
+
case "conditional":
|
|
144
|
+
return {
|
|
145
|
+
...base,
|
|
146
|
+
matchField: field.matchField,
|
|
147
|
+
matchValue: field.matchValue,
|
|
148
|
+
showField: resolveFieldDefinition(field.showField)
|
|
149
|
+
};
|
|
150
|
+
case "child":
|
|
151
|
+
case "cloud-image":
|
|
152
|
+
return base;
|
|
153
|
+
case "empty":
|
|
154
|
+
case "empty-content":
|
|
155
|
+
case "empty-document":
|
|
156
|
+
case "ignored":
|
|
157
|
+
default:
|
|
158
|
+
return base;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/fields/collection.ts
|
|
163
|
+
function collection(config) {
|
|
164
|
+
const schema = {};
|
|
165
|
+
for (const [key, fieldDef] of Object.entries(config.schema)) {
|
|
166
|
+
schema[key] = resolveFieldDefinition(fieldDef);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
name: config.name,
|
|
170
|
+
path: config.path,
|
|
171
|
+
filePattern: config.filePattern,
|
|
172
|
+
previewUrl: config.previewUrl,
|
|
173
|
+
schema,
|
|
174
|
+
images: config.images
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function singleton(config) {
|
|
178
|
+
const schema = {};
|
|
179
|
+
for (const [key, fieldDef] of Object.entries(config.schema)) {
|
|
180
|
+
schema[key] = resolveFieldDefinition(fieldDef);
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
name: config.name,
|
|
184
|
+
path: config.path,
|
|
185
|
+
previewUrl: config.previewUrl,
|
|
186
|
+
schema,
|
|
187
|
+
images: config.images
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/fields/fields.ts
|
|
192
|
+
function createField(fieldKind, config) {
|
|
193
|
+
return { fieldKind, ...config };
|
|
194
|
+
}
|
|
195
|
+
var fields = {
|
|
196
|
+
text(config = {}) {
|
|
197
|
+
return createField("text", config);
|
|
198
|
+
},
|
|
199
|
+
slug(config = {}) {
|
|
200
|
+
return createField("slug", config);
|
|
201
|
+
},
|
|
202
|
+
url(config = {}) {
|
|
203
|
+
return createField("url", config);
|
|
204
|
+
},
|
|
205
|
+
number(config = {}) {
|
|
206
|
+
return createField("number", config);
|
|
207
|
+
},
|
|
208
|
+
integer(config = {}) {
|
|
209
|
+
return createField("integer", config);
|
|
210
|
+
},
|
|
211
|
+
select(config) {
|
|
212
|
+
return createField("select", config);
|
|
213
|
+
},
|
|
214
|
+
multiselect(config) {
|
|
215
|
+
return createField("multiselect", config);
|
|
216
|
+
},
|
|
217
|
+
checkbox(config = {}) {
|
|
218
|
+
return createField("checkbox", config);
|
|
219
|
+
},
|
|
220
|
+
date(config = {}) {
|
|
221
|
+
return createField("date", config);
|
|
222
|
+
},
|
|
223
|
+
datetime(config = {}) {
|
|
224
|
+
return createField("datetime", config);
|
|
225
|
+
},
|
|
226
|
+
image(config = {}) {
|
|
227
|
+
return createField("image", config);
|
|
228
|
+
},
|
|
229
|
+
file(config = {}) {
|
|
230
|
+
return createField("file", config);
|
|
231
|
+
},
|
|
232
|
+
object(config) {
|
|
233
|
+
return createField("object", config);
|
|
234
|
+
},
|
|
235
|
+
array(config) {
|
|
236
|
+
return createField("array", config);
|
|
237
|
+
},
|
|
238
|
+
blocks(config) {
|
|
239
|
+
return createField("blocks", config);
|
|
240
|
+
},
|
|
241
|
+
relationship(config) {
|
|
242
|
+
return createField("relationship", config);
|
|
243
|
+
},
|
|
244
|
+
pathReference(config = {}) {
|
|
245
|
+
return createField("path-reference", config);
|
|
246
|
+
},
|
|
247
|
+
markdoc(config = {}) {
|
|
248
|
+
return createField("markdoc", config);
|
|
249
|
+
},
|
|
250
|
+
mdx(config = {}) {
|
|
251
|
+
return createField("mdx", config);
|
|
252
|
+
},
|
|
253
|
+
conditional(config) {
|
|
254
|
+
return createField("conditional", config);
|
|
255
|
+
},
|
|
256
|
+
child(config = {}) {
|
|
257
|
+
return createField("child", config);
|
|
258
|
+
},
|
|
259
|
+
cloudImage(config = {}) {
|
|
260
|
+
return createField("cloud-image", config);
|
|
261
|
+
},
|
|
262
|
+
empty(config = {}) {
|
|
263
|
+
return createField("empty", config);
|
|
264
|
+
},
|
|
265
|
+
emptyContent(config = {}) {
|
|
266
|
+
return createField("empty-content", config);
|
|
267
|
+
},
|
|
268
|
+
emptyDocument(config = {}) {
|
|
269
|
+
return createField("empty-document", config);
|
|
270
|
+
},
|
|
271
|
+
ignored(config = {}) {
|
|
272
|
+
return createField("ignored", config);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
export {
|
|
277
|
+
resolveFieldDefinition,
|
|
278
|
+
collection,
|
|
279
|
+
singleton,
|
|
280
|
+
fields
|
|
281
|
+
};
|
|
282
|
+
//# sourceMappingURL=chunk-E4PQLKAH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fields/resolve.ts","../src/fields/collection.ts","../src/fields/fields.ts"],"sourcesContent":["/**\n * @fileoverview FieldDefinition to SchemaField conversion\n *\n * This module converts FieldDefinition objects (from the builder API)\n * to the internal SchemaField format used by the form system.\n *\n * @module @writenex/astro/fields/resolve\n */\n\nimport type { SchemaField } from \"@/types\";\nimport type { FieldDefinition } from \"./types\";\n\nconst FIELD_KIND_TO_TYPE: Record<string, string> = {\n text: \"string\",\n slug: \"string\",\n url: \"string\",\n number: \"number\",\n integer: \"number\",\n select: \"string\",\n multiselect: \"array\",\n checkbox: \"boolean\",\n date: \"date\",\n datetime: \"date\",\n image: \"image\",\n file: \"file\",\n object: \"object\",\n array: \"array\",\n blocks: \"blocks\",\n relationship: \"relationship\",\n \"path-reference\": \"string\",\n markdoc: \"markdoc\",\n mdx: \"mdx\",\n conditional: \"object\",\n child: \"child\",\n \"cloud-image\": \"image\",\n empty: \"empty\",\n \"empty-content\": \"empty-content\",\n \"empty-document\": \"empty-document\",\n ignored: \"ignored\",\n};\n\nfunction resolveObjectFields(\n fields: Record<string, FieldDefinition>\n): Record<string, SchemaField> {\n const result: Record<string, SchemaField> = {};\n for (const [key, value] of Object.entries(fields)) {\n result[key] = resolveFieldDefinition(value);\n }\n return result;\n}\n\nfunction resolveBlockTypes(\n blockTypes: Record<string, FieldDefinition>\n): Record<string, SchemaField> {\n const result: Record<string, SchemaField> = {};\n for (const [key, value] of Object.entries(blockTypes)) {\n result[key] = resolveFieldDefinition(value);\n }\n return result;\n}\n\nexport function resolveFieldDefinition(field: FieldDefinition): SchemaField {\n const type = FIELD_KIND_TO_TYPE[field.fieldKind] ?? \"string\";\n\n const base: SchemaField = {\n type: type as SchemaField[\"type\"],\n required: field.validation?.isRequired ?? false,\n label: field.label,\n description: field.description,\n default: field.defaultValue,\n };\n\n switch (field.fieldKind) {\n case \"text\":\n return {\n ...base,\n multiline: field.multiline,\n };\n\n case \"slug\":\n case \"url\":\n return base;\n\n case \"number\":\n return {\n ...base,\n default:\n field.defaultValue ?? (field as { placeholder?: number }).placeholder,\n };\n\n case \"integer\":\n return {\n ...base,\n default:\n field.defaultValue ?? (field as { placeholder?: number }).placeholder,\n };\n\n case \"select\":\n return {\n ...base,\n options: field.options,\n default: field.defaultValue,\n };\n\n case \"multiselect\":\n return {\n ...base,\n items: \"string\",\n default: field.defaultValue,\n };\n\n case \"checkbox\":\n return {\n ...base,\n default: field.defaultValue,\n };\n\n case \"date\":\n return {\n ...base,\n format: \"date\",\n default: field.defaultValue,\n };\n\n case \"datetime\":\n return {\n ...base,\n format: \"datetime-local\",\n default: field.defaultValue,\n };\n\n case \"image\":\n return {\n ...base,\n directory: field.directory,\n publicPath: field.publicPath,\n };\n\n case \"file\":\n return {\n ...base,\n directory: field.directory,\n publicPath: field.publicPath,\n };\n\n case \"object\":\n return {\n ...base,\n fields: resolveObjectFields(field.fields),\n };\n\n case \"array\":\n return {\n ...base,\n itemField: resolveFieldDefinition(field.itemField),\n itemLabel: field.itemLabel,\n };\n\n case \"blocks\":\n return {\n ...base,\n blockTypes: resolveBlockTypes(field.blockTypes),\n itemLabel: field.itemLabel,\n };\n\n case \"relationship\":\n return {\n ...base,\n collection: field.collection,\n };\n\n case \"path-reference\":\n return {\n ...base,\n allowExternal: (\n field as { contentTypes?: string[] }\n ).contentTypes?.includes(\"url\"),\n };\n\n case \"markdoc\":\n case \"mdx\":\n return base;\n\n case \"conditional\":\n return {\n ...base,\n matchField: field.matchField,\n matchValue: field.matchValue,\n showField: resolveFieldDefinition(field.showField),\n };\n\n case \"child\":\n case \"cloud-image\":\n return base;\n\n case \"empty\":\n case \"empty-content\":\n case \"empty-document\":\n case \"ignored\":\n default:\n return base;\n }\n}\n","/**\n * @fileoverview Collection and Singleton schema helpers\n *\n * These helpers provide a typed way to define collection and singleton\n * schemas using the fields builder API. They convert FieldDefinition\n * objects to internal SchemaField format.\n *\n * @module @writenex/astro/fields/collection\n */\n\nimport type { CollectionConfig, ImageConfig } from \"@/types\";\nimport { resolveFieldDefinition } from \"./resolve\";\nimport type { FieldDefinition } from \"./types\";\n\nexport interface CollectionSchemaConfig {\n name: string;\n path: string;\n filePattern?: string;\n previewUrl?: string;\n schema: Record<string, FieldDefinition>;\n images?: ImageConfig;\n}\n\nexport interface SingletonSchemaConfig {\n name: string;\n path: string;\n previewUrl?: string;\n schema: Record<string, FieldDefinition>;\n images?: ImageConfig;\n}\n\nexport function collection(config: CollectionSchemaConfig): CollectionConfig {\n const schema: Record<string, import(\"@/types\").SchemaField> = {};\n for (const [key, fieldDef] of Object.entries(config.schema)) {\n schema[key] = resolveFieldDefinition(fieldDef);\n }\n\n return {\n name: config.name,\n path: config.path,\n filePattern: config.filePattern,\n previewUrl: config.previewUrl,\n schema,\n images: config.images,\n };\n}\n\nexport function singleton(config: SingletonSchemaConfig): {\n name: string;\n path: string;\n previewUrl?: string;\n schema: Record<string, import(\"@/types\").SchemaField>;\n images?: ImageConfig;\n} {\n const schema: Record<string, import(\"@/types\").SchemaField> = {};\n for (const [key, fieldDef] of Object.entries(config.schema)) {\n schema[key] = resolveFieldDefinition(fieldDef);\n }\n\n return {\n name: config.name,\n path: config.path,\n previewUrl: config.previewUrl,\n schema,\n images: config.images,\n };\n}\n","/**\n * @fileoverview Fields builder API for @writenex/astro\n *\n * This module provides a TypeScript-first builder pattern for defining\n * content schema fields. Each field type is a method on the `fields` object.\n *\n * @module @writenex/astro/fields/fields\n */\n\nimport type {\n ArrayFieldConfig,\n BaseFieldConfig,\n BlocksFieldConfig,\n CheckboxFieldConfig,\n ChildFieldConfig,\n CloudImageFieldConfig,\n ConditionalFieldConfig,\n DateFieldConfig,\n DatetimeFieldConfig,\n FieldDefinition,\n FileFieldConfig,\n ImageFieldConfig,\n IntegerFieldConfig,\n MarkdocFieldConfig,\n MdxFieldConfig,\n MultiselectFieldConfig,\n NumberFieldConfig,\n ObjectFieldConfig,\n PathReferenceFieldConfig,\n RelationshipFieldConfig,\n SelectFieldConfig,\n SlugFieldConfig,\n TextFieldConfig,\n UrlFieldConfig,\n} from \"./types\";\n\nfunction createField<K extends FieldDefinition[\"fieldKind\"]>(\n fieldKind: K,\n config: Omit<Extract<FieldDefinition, { fieldKind: K }>, \"fieldKind\">\n): Extract<FieldDefinition, { fieldKind: K }> {\n return { fieldKind, ...config } as Extract<FieldDefinition, { fieldKind: K }>;\n}\n\nexport const fields = {\n text(config: TextFieldConfig = {}): FieldDefinition {\n return createField(\"text\", config);\n },\n\n slug(config: SlugFieldConfig = {}): FieldDefinition {\n return createField(\"slug\", config);\n },\n\n url(config: UrlFieldConfig = {}): FieldDefinition {\n return createField(\"url\", config);\n },\n\n number(config: NumberFieldConfig = {}): FieldDefinition {\n return createField(\"number\", config);\n },\n\n integer(config: IntegerFieldConfig = {}): FieldDefinition {\n return createField(\"integer\", config);\n },\n\n select(config: SelectFieldConfig): FieldDefinition {\n return createField(\"select\", config);\n },\n\n multiselect(config: MultiselectFieldConfig): FieldDefinition {\n return createField(\"multiselect\", config);\n },\n\n checkbox(config: CheckboxFieldConfig = {}): FieldDefinition {\n return createField(\"checkbox\", config);\n },\n\n date(config: DateFieldConfig = {}): FieldDefinition {\n return createField(\"date\", config);\n },\n\n datetime(config: DatetimeFieldConfig = {}): FieldDefinition {\n return createField(\"datetime\", config);\n },\n\n image(config: ImageFieldConfig = {}): FieldDefinition {\n return createField(\"image\", config);\n },\n\n file(config: FileFieldConfig = {}): FieldDefinition {\n return createField(\"file\", config);\n },\n\n object(config: ObjectFieldConfig): FieldDefinition {\n return createField(\"object\", config);\n },\n\n array(config: ArrayFieldConfig): FieldDefinition {\n return createField(\"array\", config);\n },\n\n blocks(config: BlocksFieldConfig): FieldDefinition {\n return createField(\"blocks\", config);\n },\n\n relationship(config: RelationshipFieldConfig): FieldDefinition {\n return createField(\"relationship\", config);\n },\n\n pathReference(config: PathReferenceFieldConfig = {}): FieldDefinition {\n return createField(\"path-reference\", config);\n },\n\n markdoc(config: MarkdocFieldConfig = {}): FieldDefinition {\n return createField(\"markdoc\", config);\n },\n\n mdx(config: MdxFieldConfig = {}): FieldDefinition {\n return createField(\"mdx\", config);\n },\n\n conditional(config: ConditionalFieldConfig): FieldDefinition {\n return createField(\"conditional\", config);\n },\n\n child(config: ChildFieldConfig = {}): FieldDefinition {\n return createField(\"child\", config);\n },\n\n cloudImage(config: CloudImageFieldConfig = {}): FieldDefinition {\n return createField(\"cloud-image\", config);\n },\n\n empty(config: BaseFieldConfig = {}): FieldDefinition {\n return createField(\"empty\", config);\n },\n\n emptyContent(config: BaseFieldConfig = {}): FieldDefinition {\n return createField(\"empty-content\", config);\n },\n\n emptyDocument(config: BaseFieldConfig = {}): FieldDefinition {\n return createField(\"empty-document\", config);\n },\n\n ignored(config: BaseFieldConfig = {}): FieldDefinition {\n return createField(\"ignored\", config);\n },\n};\n\nexport type Fields = typeof fields;\n"],"mappings":";AAYA,IAAM,qBAA6C;AAAA,EACjD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,SAAS;AAAA,EACT,KAAK;AAAA,EACL,aAAa;AAAA,EACb,OAAO;AAAA,EACP,eAAe;AAAA,EACf,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,SAAS;AACX;AAEA,SAAS,oBACPA,SAC6B;AAC7B,QAAM,SAAsC,CAAC;AAC7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQA,OAAM,GAAG;AACjD,WAAO,GAAG,IAAI,uBAAuB,KAAK;AAAA,EAC5C;AACA,SAAO;AACT;AAEA,SAAS,kBACP,YAC6B;AAC7B,QAAM,SAAsC,CAAC;AAC7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,WAAO,GAAG,IAAI,uBAAuB,KAAK;AAAA,EAC5C;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,OAAqC;AAC1E,QAAM,OAAO,mBAAmB,MAAM,SAAS,KAAK;AAEpD,QAAM,OAAoB;AAAA,IACxB;AAAA,IACA,UAAU,MAAM,YAAY,cAAc;AAAA,IAC1C,OAAO,MAAM;AAAA,IACb,aAAa,MAAM;AAAA,IACnB,SAAS,MAAM;AAAA,EACjB;AAEA,UAAQ,MAAM,WAAW;AAAA,IACvB,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,MAAM;AAAA,MACnB;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SACE,MAAM,gBAAiB,MAAmC;AAAA,MAC9D;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SACE,MAAM,gBAAiB,MAAmC;AAAA,MAC9D;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,MAAM;AAAA,QACf,SAAS,MAAM;AAAA,MACjB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,OAAO;AAAA,QACP,SAAS,MAAM;AAAA,MACjB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,MAAM;AAAA,MACjB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,SAAS,MAAM;AAAA,MACjB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,SAAS,MAAM;AAAA,MACjB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,MACpB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,MACpB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ,oBAAoB,MAAM,MAAM;AAAA,MAC1C;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,uBAAuB,MAAM,SAAS;AAAA,QACjD,WAAW,MAAM;AAAA,MACnB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,YAAY,kBAAkB,MAAM,UAAU;AAAA,QAC9C,WAAW,MAAM;AAAA,MACnB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,YAAY,MAAM;AAAA,MACpB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eACE,MACA,cAAc,SAAS,KAAK;AAAA,MAChC;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,YAAY,MAAM;AAAA,QAClB,YAAY,MAAM;AAAA,QAClB,WAAW,uBAAuB,MAAM,SAAS;AAAA,MACnD;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;;;AC3KO,SAAS,WAAW,QAAkD;AAC3E,QAAM,SAAwD,CAAC;AAC/D,aAAW,CAAC,KAAK,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC3D,WAAO,GAAG,IAAI,uBAAuB,QAAQ;AAAA,EAC/C;AAEA,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,aAAa,OAAO;AAAA,IACpB,YAAY,OAAO;AAAA,IACnB;AAAA,IACA,QAAQ,OAAO;AAAA,EACjB;AACF;AAEO,SAAS,UAAU,QAMxB;AACA,QAAM,SAAwD,CAAC;AAC/D,aAAW,CAAC,KAAK,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC3D,WAAO,GAAG,IAAI,uBAAuB,QAAQ;AAAA,EAC/C;AAEA,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,YAAY,OAAO;AAAA,IACnB;AAAA,IACA,QAAQ,OAAO;AAAA,EACjB;AACF;;;AC9BA,SAAS,YACP,WACA,QAC4C;AAC5C,SAAO,EAAE,WAAW,GAAG,OAAO;AAChC;AAEO,IAAM,SAAS;AAAA,EACpB,KAAK,SAA0B,CAAC,GAAoB;AAClD,WAAO,YAAY,QAAQ,MAAM;AAAA,EACnC;AAAA,EAEA,KAAK,SAA0B,CAAC,GAAoB;AAClD,WAAO,YAAY,QAAQ,MAAM;AAAA,EACnC;AAAA,EAEA,IAAI,SAAyB,CAAC,GAAoB;AAChD,WAAO,YAAY,OAAO,MAAM;AAAA,EAClC;AAAA,EAEA,OAAO,SAA4B,CAAC,GAAoB;AACtD,WAAO,YAAY,UAAU,MAAM;AAAA,EACrC;AAAA,EAEA,QAAQ,SAA6B,CAAC,GAAoB;AACxD,WAAO,YAAY,WAAW,MAAM;AAAA,EACtC;AAAA,EAEA,OAAO,QAA4C;AACjD,WAAO,YAAY,UAAU,MAAM;AAAA,EACrC;AAAA,EAEA,YAAY,QAAiD;AAC3D,WAAO,YAAY,eAAe,MAAM;AAAA,EAC1C;AAAA,EAEA,SAAS,SAA8B,CAAC,GAAoB;AAC1D,WAAO,YAAY,YAAY,MAAM;AAAA,EACvC;AAAA,EAEA,KAAK,SAA0B,CAAC,GAAoB;AAClD,WAAO,YAAY,QAAQ,MAAM;AAAA,EACnC;AAAA,EAEA,SAAS,SAA8B,CAAC,GAAoB;AAC1D,WAAO,YAAY,YAAY,MAAM;AAAA,EACvC;AAAA,EAEA,MAAM,SAA2B,CAAC,GAAoB;AACpD,WAAO,YAAY,SAAS,MAAM;AAAA,EACpC;AAAA,EAEA,KAAK,SAA0B,CAAC,GAAoB;AAClD,WAAO,YAAY,QAAQ,MAAM;AAAA,EACnC;AAAA,EAEA,OAAO,QAA4C;AACjD,WAAO,YAAY,UAAU,MAAM;AAAA,EACrC;AAAA,EAEA,MAAM,QAA2C;AAC/C,WAAO,YAAY,SAAS,MAAM;AAAA,EACpC;AAAA,EAEA,OAAO,QAA4C;AACjD,WAAO,YAAY,UAAU,MAAM;AAAA,EACrC;AAAA,EAEA,aAAa,QAAkD;AAC7D,WAAO,YAAY,gBAAgB,MAAM;AAAA,EAC3C;AAAA,EAEA,cAAc,SAAmC,CAAC,GAAoB;AACpE,WAAO,YAAY,kBAAkB,MAAM;AAAA,EAC7C;AAAA,EAEA,QAAQ,SAA6B,CAAC,GAAoB;AACxD,WAAO,YAAY,WAAW,MAAM;AAAA,EACtC;AAAA,EAEA,IAAI,SAAyB,CAAC,GAAoB;AAChD,WAAO,YAAY,OAAO,MAAM;AAAA,EAClC;AAAA,EAEA,YAAY,QAAiD;AAC3D,WAAO,YAAY,eAAe,MAAM;AAAA,EAC1C;AAAA,EAEA,MAAM,SAA2B,CAAC,GAAoB;AACpD,WAAO,YAAY,SAAS,MAAM;AAAA,EACpC;AAAA,EAEA,WAAW,SAAgC,CAAC,GAAoB;AAC9D,WAAO,YAAY,eAAe,MAAM;AAAA,EAC1C;AAAA,EAEA,MAAM,SAA0B,CAAC,GAAoB;AACnD,WAAO,YAAY,SAAS,MAAM;AAAA,EACpC;AAAA,EAEA,aAAa,SAA0B,CAAC,GAAoB;AAC1D,WAAO,YAAY,iBAAiB,MAAM;AAAA,EAC5C;AAAA,EAEA,cAAc,SAA0B,CAAC,GAAoB;AAC3D,WAAO,YAAY,kBAAkB,MAAM;AAAA,EAC7C;AAAA,EAEA,QAAQ,SAA0B,CAAC,GAAoB;AACrD,WAAO,YAAY,WAAW,MAAM;AAAA,EACtC;AACF;","names":["fields"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
discoverCollections,
|
|
3
3
|
mergeCollections
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XVQNYPOI.js";
|
|
5
5
|
import {
|
|
6
6
|
ApiBadRequestError,
|
|
7
7
|
ApiMethodNotAllowedError,
|
|
@@ -634,7 +634,7 @@ var handleGetConfig = async (_req, res, _params, context) => {
|
|
|
634
634
|
};
|
|
635
635
|
var handleGetConfigPath = async (_req, res, _params, context) => {
|
|
636
636
|
const { projectRoot } = context;
|
|
637
|
-
const { findConfigFile } = await import("./loader-
|
|
637
|
+
const { findConfigFile } = await import("./loader-B5WZCVBC.js");
|
|
638
638
|
const configPath = findConfigFile(projectRoot);
|
|
639
639
|
sendJson(res, {
|
|
640
640
|
configPath,
|
|
@@ -1328,4 +1328,4 @@ export {
|
|
|
1328
1328
|
sendError,
|
|
1329
1329
|
sendWritenexError
|
|
1330
1330
|
};
|
|
1331
|
-
//# sourceMappingURL=chunk-
|
|
1331
|
+
//# sourceMappingURL=chunk-EEUN46Q2.js.map
|
|
@@ -32,6 +32,7 @@ function applyCollectionDefaults(collection) {
|
|
|
32
32
|
function applyConfigDefaults(config = {}) {
|
|
33
33
|
return {
|
|
34
34
|
collections: (config.collections ?? []).map(applyCollectionDefaults),
|
|
35
|
+
singletons: (config.singletons ?? []).map(applyCollectionDefaults),
|
|
35
36
|
images: config.images ? { ...DEFAULT_IMAGE_CONFIG, ...config.images } : DEFAULT_IMAGE_CONFIG,
|
|
36
37
|
editor: config.editor ? { ...DEFAULT_EDITOR_CONFIG, ...config.editor } : DEFAULT_EDITOR_CONFIG,
|
|
37
38
|
discovery: config.discovery ? { ...DEFAULT_DISCOVERY_CONFIG, ...config.discovery } : DEFAULT_DISCOVERY_CONFIG,
|
|
@@ -49,4 +50,4 @@ export {
|
|
|
49
50
|
applyCollectionDefaults,
|
|
50
51
|
applyConfigDefaults
|
|
51
52
|
};
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-P5KMSHFP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/defaults.ts"],"sourcesContent":["/**\n * @fileoverview Default configuration values for @writenex/astro\n *\n * This module provides default values for all configuration options.\n * These defaults are applied when loading configuration to ensure\n * all required values are present.\n *\n * @module @writenex/astro/config/defaults\n */\n\nimport type {\n CollectionConfig,\n DiscoveryConfig,\n EditorConfig,\n ImageConfig,\n VersionHistoryConfig,\n WritenexConfig,\n} from \"@/types\";\n\n/**\n * Default image configuration\n */\nexport const DEFAULT_IMAGE_CONFIG: Required<ImageConfig> = {\n strategy: \"colocated\",\n publicPath: \"/images\",\n storagePath: \"public/images\",\n};\n\n/**\n * Default editor configuration\n */\nexport const DEFAULT_EDITOR_CONFIG: Required<EditorConfig> = {\n autosave: true,\n autosaveInterval: 3000,\n};\n\n/**\n * Default discovery configuration\n */\nexport const DEFAULT_DISCOVERY_CONFIG: Required<DiscoveryConfig> = {\n enabled: true,\n ignore: [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\"],\n};\n\n/**\n * Default version history configuration\n */\nexport const DEFAULT_VERSION_HISTORY_CONFIG: Required<VersionHistoryConfig> = {\n enabled: true,\n maxVersions: 20,\n storagePath: \".writenex/versions\",\n};\n\n/**\n * Default file pattern for content files\n */\nexport const DEFAULT_FILE_PATTERN = \"{slug}.md\";\n\n/**\n * Default content directory path\n */\nexport const DEFAULT_CONTENT_PATH = \"src/content\";\n\n/**\n * Apply defaults to a collection configuration\n *\n * @param collection - Partial collection configuration\n * @returns Collection configuration with defaults applied\n */\nexport function applyCollectionDefaults(\n collection: CollectionConfig\n): Required<CollectionConfig> {\n return {\n name: collection.name,\n path: collection.path,\n filePattern: collection.filePattern ?? DEFAULT_FILE_PATTERN,\n previewUrl: collection.previewUrl ?? `/${collection.name}/{slug}`,\n schema: collection.schema ?? {},\n images: collection.images\n ? { ...DEFAULT_IMAGE_CONFIG, ...collection.images }\n : DEFAULT_IMAGE_CONFIG,\n };\n}\n\n/**\n * Apply defaults to the main Writenex configuration\n *\n * @param config - Partial Writenex configuration\n * @returns Configuration with all defaults applied\n */\nexport function applyConfigDefaults(\n config: WritenexConfig = {}\n): Required<WritenexConfig> {\n return {\n collections: (config.collections ?? []).map(applyCollectionDefaults),\n images: config.images\n ? { ...DEFAULT_IMAGE_CONFIG, ...config.images }\n : DEFAULT_IMAGE_CONFIG,\n editor: config.editor\n ? { ...DEFAULT_EDITOR_CONFIG, ...config.editor }\n : DEFAULT_EDITOR_CONFIG,\n discovery: config.discovery\n ? { ...DEFAULT_DISCOVERY_CONFIG, ...config.discovery }\n : DEFAULT_DISCOVERY_CONFIG,\n versionHistory: config.versionHistory\n ? { ...DEFAULT_VERSION_HISTORY_CONFIG, ...config.versionHistory }\n : DEFAULT_VERSION_HISTORY_CONFIG,\n };\n}\n"],"mappings":";AAsBO,IAAM,uBAA8C;AAAA,EACzD,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,aAAa;AACf;AAKO,IAAM,wBAAgD;AAAA,EAC3D,UAAU;AAAA,EACV,kBAAkB;AACpB;AAKO,IAAM,2BAAsD;AAAA,EACjE,SAAS;AAAA,EACT,QAAQ,CAAC,sBAAsB,cAAc,YAAY;AAC3D;AAKO,IAAM,iCAAiE;AAAA,EAC5E,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AACf;AAKO,IAAM,uBAAuB;AAK7B,IAAM,uBAAuB;AAQ7B,SAAS,wBACd,YAC4B;AAC5B,SAAO;AAAA,IACL,MAAM,WAAW;AAAA,IACjB,MAAM,WAAW;AAAA,IACjB,aAAa,WAAW,eAAe;AAAA,IACvC,YAAY,WAAW,cAAc,IAAI,WAAW,IAAI;AAAA,IACxD,QAAQ,WAAW,UAAU,CAAC;AAAA,IAC9B,QAAQ,WAAW,SACf,EAAE,GAAG,sBAAsB,GAAG,WAAW,OAAO,IAChD;AAAA,EACN;AACF;AAQO,SAAS,oBACd,SAAyB,CAAC,GACA;AAC1B,SAAO;AAAA,IACL,cAAc,OAAO,eAAe,CAAC,GAAG,IAAI,uBAAuB;AAAA,IACnE,QAAQ,OAAO,SACX,EAAE,GAAG,sBAAsB,GAAG,OAAO,OAAO,IAC5C;AAAA,IACJ,QAAQ,OAAO,SACX,EAAE,GAAG,uBAAuB,GAAG,OAAO,OAAO,IAC7C;AAAA,IACJ,WAAW,OAAO,YACd,EAAE,GAAG,0BAA0B,GAAG,OAAO,UAAU,IACnD;AAAA,IACJ,gBAAgB,OAAO,iBACnB,EAAE,GAAG,gCAAgC,GAAG,OAAO,eAAe,IAC9D;AAAA,EACN;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config/defaults.ts"],"sourcesContent":["/**\n * @fileoverview Default configuration values for @writenex/astro\n *\n * This module provides default values for all configuration options.\n * These defaults are applied when loading configuration to ensure\n * all required values are present.\n *\n * @module @writenex/astro/config/defaults\n */\n\nimport type {\n CollectionConfig,\n DiscoveryConfig,\n EditorConfig,\n ImageConfig,\n VersionHistoryConfig,\n WritenexConfig,\n} from \"@/types\";\n\n/**\n * Default image configuration\n */\nexport const DEFAULT_IMAGE_CONFIG: Required<ImageConfig> = {\n strategy: \"colocated\",\n publicPath: \"/images\",\n storagePath: \"public/images\",\n};\n\n/**\n * Default editor configuration\n */\nexport const DEFAULT_EDITOR_CONFIG: Required<EditorConfig> = {\n autosave: true,\n autosaveInterval: 3000,\n};\n\n/**\n * Default discovery configuration\n */\nexport const DEFAULT_DISCOVERY_CONFIG: Required<DiscoveryConfig> = {\n enabled: true,\n ignore: [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\"],\n};\n\n/**\n * Default version history configuration\n */\nexport const DEFAULT_VERSION_HISTORY_CONFIG: Required<VersionHistoryConfig> = {\n enabled: true,\n maxVersions: 20,\n storagePath: \".writenex/versions\",\n};\n\n/**\n * Default file pattern for content files\n */\nexport const DEFAULT_FILE_PATTERN = \"{slug}.md\";\n\n/**\n * Default content directory path\n */\nexport const DEFAULT_CONTENT_PATH = \"src/content\";\n\n/**\n * Apply defaults to a collection configuration\n *\n * @param collection - Partial collection configuration\n * @returns Collection configuration with defaults applied\n */\nexport function applyCollectionDefaults(\n collection: CollectionConfig\n): Required<CollectionConfig> {\n return {\n name: collection.name,\n path: collection.path,\n filePattern: collection.filePattern ?? DEFAULT_FILE_PATTERN,\n previewUrl: collection.previewUrl ?? `/${collection.name}/{slug}`,\n schema: collection.schema ?? {},\n images: collection.images\n ? { ...DEFAULT_IMAGE_CONFIG, ...collection.images }\n : DEFAULT_IMAGE_CONFIG,\n };\n}\n\n/**\n * Apply defaults to the main Writenex configuration\n *\n * @param config - Partial Writenex configuration\n * @returns Configuration with all defaults applied\n */\nexport function applyConfigDefaults(\n config: WritenexConfig = {}\n): Required<WritenexConfig> {\n return {\n collections: (config.collections ?? []).map(applyCollectionDefaults),\n singletons: (config.singletons ?? []).map(applyCollectionDefaults),\n images: config.images\n ? { ...DEFAULT_IMAGE_CONFIG, ...config.images }\n : DEFAULT_IMAGE_CONFIG,\n editor: config.editor\n ? { ...DEFAULT_EDITOR_CONFIG, ...config.editor }\n : DEFAULT_EDITOR_CONFIG,\n discovery: config.discovery\n ? { ...DEFAULT_DISCOVERY_CONFIG, ...config.discovery }\n : DEFAULT_DISCOVERY_CONFIG,\n versionHistory: config.versionHistory\n ? { ...DEFAULT_VERSION_HISTORY_CONFIG, ...config.versionHistory }\n : DEFAULT_VERSION_HISTORY_CONFIG,\n };\n}\n"],"mappings":";AAsBO,IAAM,uBAA8C;AAAA,EACzD,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,aAAa;AACf;AAKO,IAAM,wBAAgD;AAAA,EAC3D,UAAU;AAAA,EACV,kBAAkB;AACpB;AAKO,IAAM,2BAAsD;AAAA,EACjE,SAAS;AAAA,EACT,QAAQ,CAAC,sBAAsB,cAAc,YAAY;AAC3D;AAKO,IAAM,iCAAiE;AAAA,EAC5E,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AACf;AAKO,IAAM,uBAAuB;AAK7B,IAAM,uBAAuB;AAQ7B,SAAS,wBACd,YAC4B;AAC5B,SAAO;AAAA,IACL,MAAM,WAAW;AAAA,IACjB,MAAM,WAAW;AAAA,IACjB,aAAa,WAAW,eAAe;AAAA,IACvC,YAAY,WAAW,cAAc,IAAI,WAAW,IAAI;AAAA,IACxD,QAAQ,WAAW,UAAU,CAAC;AAAA,IAC9B,QAAQ,WAAW,SACf,EAAE,GAAG,sBAAsB,GAAG,WAAW,OAAO,IAChD;AAAA,EACN;AACF;AAQO,SAAS,oBACd,SAAyB,CAAC,GACA;AAC1B,SAAO;AAAA,IACL,cAAc,OAAO,eAAe,CAAC,GAAG,IAAI,uBAAuB;AAAA,IACnE,aAAa,OAAO,cAAc,CAAC,GAAG,IAAI,uBAAuB;AAAA,IACjE,QAAQ,OAAO,SACX,EAAE,GAAG,sBAAsB,GAAG,OAAO,OAAO,IAC5C;AAAA,IACJ,QAAQ,OAAO,SACX,EAAE,GAAG,uBAAuB,GAAG,OAAO,OAAO,IAC7C;AAAA,IACJ,WAAW,OAAO,YACd,EAAE,GAAG,0BAA0B,GAAG,OAAO,UAAU,IACnD;AAAA,IACJ,gBAAgB,OAAO,iBACnB,EAAE,GAAG,gCAAgC,GAAG,OAAO,eAAe,IAC9D;AAAA,EACN;AACF;","names":[]}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-GYAFIVVI.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_FILE_PATTERN
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-P5KMSHFP.js";
|
|
9
9
|
|
|
10
10
|
// src/discovery/schema.ts
|
|
11
11
|
var MAX_SAMPLE_FILES = 20;
|
|
@@ -21,6 +21,34 @@ var IMAGE_EXTENSIONS = [
|
|
|
21
21
|
".avif",
|
|
22
22
|
".svg"
|
|
23
23
|
];
|
|
24
|
+
var URL_PATTERN = /^https?:\/\//;
|
|
25
|
+
var SLUG_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
26
|
+
var DATETIME_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
|
|
27
|
+
function isUrlValue(value) {
|
|
28
|
+
if (typeof value !== "string") return false;
|
|
29
|
+
return URL_PATTERN.test(value);
|
|
30
|
+
}
|
|
31
|
+
function isSlugValue(value) {
|
|
32
|
+
if (typeof value !== "string") return false;
|
|
33
|
+
if (value.length < 2 || value.length > 100) return false;
|
|
34
|
+
return SLUG_PATTERN.test(value);
|
|
35
|
+
}
|
|
36
|
+
function isDatetimeValue(value) {
|
|
37
|
+
if (typeof value !== "string") return false;
|
|
38
|
+
return DATETIME_PATTERN.test(value);
|
|
39
|
+
}
|
|
40
|
+
function isFilePath(value) {
|
|
41
|
+
if (typeof value !== "string") return false;
|
|
42
|
+
if (isImagePath(value)) return false;
|
|
43
|
+
return /\.\w{2,5}$/.test(value);
|
|
44
|
+
}
|
|
45
|
+
function isMultiselectArray(values) {
|
|
46
|
+
if (values.length === 0) return false;
|
|
47
|
+
const allStrings = values.every((v) => typeof v === "string" && v.length > 0);
|
|
48
|
+
if (!allStrings) return false;
|
|
49
|
+
const uniqueValues = [...new Set(values)];
|
|
50
|
+
return uniqueValues.length <= ENUM_MAX_VALUES && values.length > uniqueValues.length;
|
|
51
|
+
}
|
|
24
52
|
function isImagePath(value) {
|
|
25
53
|
if (typeof value !== "string") return false;
|
|
26
54
|
const lowered = value.toLowerCase();
|
|
@@ -46,7 +74,17 @@ function detectValueType(value) {
|
|
|
46
74
|
}
|
|
47
75
|
function inferFieldType(analysis) {
|
|
48
76
|
if (analysis.hasImagePaths) return "image";
|
|
77
|
+
if (analysis.hasDatetimeValues) return "datetime";
|
|
49
78
|
if (analysis.hasDateValues) return "date";
|
|
79
|
+
if (analysis.hasFilePaths) return "file";
|
|
80
|
+
if (analysis.hasUrlValues) return "url";
|
|
81
|
+
if (analysis.hasSlugValues && analysis.types.size === 1) {
|
|
82
|
+
const typesArr = [...analysis.types];
|
|
83
|
+
if (typesArr.length === 1 && typesArr[0] === "string") {
|
|
84
|
+
return "slug";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (analysis.isMultiselect) return "multiselect";
|
|
50
88
|
const nonNullTypes = new Set([...analysis.types].filter((t) => t !== "null"));
|
|
51
89
|
if (nonNullTypes.size === 1) {
|
|
52
90
|
const type = [...nonNullTypes][0];
|
|
@@ -54,7 +92,7 @@ function inferFieldType(analysis) {
|
|
|
54
92
|
case "boolean":
|
|
55
93
|
return "boolean";
|
|
56
94
|
case "number":
|
|
57
|
-
return "number";
|
|
95
|
+
return analysis.allIntegers ? "integer" : "number";
|
|
58
96
|
case "array":
|
|
59
97
|
return "array";
|
|
60
98
|
case "object":
|
|
@@ -112,6 +150,12 @@ async function detectSchema(collectionPath) {
|
|
|
112
150
|
values: [],
|
|
113
151
|
hasImagePaths: false,
|
|
114
152
|
hasDateValues: false,
|
|
153
|
+
hasUrlValues: false,
|
|
154
|
+
hasSlugValues: false,
|
|
155
|
+
hasDatetimeValues: false,
|
|
156
|
+
hasFilePaths: false,
|
|
157
|
+
allIntegers: true,
|
|
158
|
+
isMultiselect: false,
|
|
115
159
|
arrayItemTypes: /* @__PURE__ */ new Set()
|
|
116
160
|
};
|
|
117
161
|
fieldAnalyses.set(fieldName, analysis);
|
|
@@ -125,10 +169,28 @@ async function detectSchema(collectionPath) {
|
|
|
125
169
|
if (isDateValue(value)) {
|
|
126
170
|
analysis.hasDateValues = true;
|
|
127
171
|
}
|
|
172
|
+
if (isUrlValue(value)) {
|
|
173
|
+
analysis.hasUrlValues = true;
|
|
174
|
+
}
|
|
175
|
+
if (isSlugValue(value)) {
|
|
176
|
+
analysis.hasSlugValues = true;
|
|
177
|
+
}
|
|
178
|
+
if (isDatetimeValue(value)) {
|
|
179
|
+
analysis.hasDatetimeValues = true;
|
|
180
|
+
}
|
|
181
|
+
if (isFilePath(value)) {
|
|
182
|
+
analysis.hasFilePaths = true;
|
|
183
|
+
}
|
|
184
|
+
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
185
|
+
analysis.allIntegers = false;
|
|
186
|
+
}
|
|
128
187
|
if (Array.isArray(value)) {
|
|
129
188
|
for (const item2 of value) {
|
|
130
189
|
analysis.arrayItemTypes.add(detectValueType(item2));
|
|
131
190
|
}
|
|
191
|
+
if (isMultiselectArray(value)) {
|
|
192
|
+
analysis.isMultiselect = true;
|
|
193
|
+
}
|
|
132
194
|
}
|
|
133
195
|
}
|
|
134
196
|
}
|
|
@@ -307,4 +369,4 @@ export {
|
|
|
307
369
|
getCollection,
|
|
308
370
|
collectionExists
|
|
309
371
|
};
|
|
310
|
-
//# sourceMappingURL=chunk-
|
|
372
|
+
//# sourceMappingURL=chunk-XVQNYPOI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/discovery/schema.ts","../src/discovery/collections.ts"],"sourcesContent":["/**\n * @fileoverview Schema auto-detection for content collections\n *\n * This module analyzes frontmatter from sample content files to automatically\n * infer the schema (field types, required status, enums, etc.).\n *\n * ## Detection Process:\n * 1. Read sample files from the collection (up to 20)\n * 2. Parse frontmatter from each file\n * 3. Analyze field patterns across all samples\n * 4. Infer field types and constraints\n * 5. Generate schema definition\n *\n * ## Detected Types:\n * - string: Plain text values\n * - number: Numeric values\n * - boolean: True/false values\n * - date: ISO date strings or Date objects\n * - array: Arrays (with item type detection)\n * - image: Paths ending with image extensions\n *\n * @module @writenex/astro/discovery/schema\n */\n\nimport { readCollection } from \"@/filesystem/reader\";\nimport type { CollectionSchema, FieldType, SchemaField } from \"@/types\";\n\n/**\n * Maximum number of files to sample for schema detection\n */\nconst MAX_SAMPLE_FILES = 20;\n\n/**\n * Minimum presence ratio to consider a field required\n * (field must appear in at least 90% of files)\n */\nconst REQUIRED_THRESHOLD = 0.9;\n\n/**\n * Maximum unique values to consider a field as enum\n */\nconst ENUM_MAX_VALUES = 10;\n\n/**\n * Minimum ratio of unique values to total to NOT be an enum\n * (if uniqueValues / total < 0.3, it's likely an enum)\n */\nconst ENUM_RATIO_THRESHOLD = 0.3;\n\n/**\n * Image file extensions for detection\n */\nconst IMAGE_EXTENSIONS = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".webp\",\n \".avif\",\n \".svg\",\n];\n\n/**\n * URL pattern detection\n */\nconst URL_PATTERN = /^https?:\\/\\//;\n\n/**\n * Slug pattern detection (lowercase, hyphenated)\n */\nconst SLUG_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;\n\n/**\n * Datetime pattern detection (ISO datetime)\n */\nconst DATETIME_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}/;\n\n/**\n * Check if a string looks like a URL\n */\nfunction isUrlValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n return URL_PATTERN.test(value);\n}\n\n/**\n * Check if a string looks like a slug\n */\nfunction isSlugValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n if (value.length < 2 || value.length > 100) return false;\n return SLUG_PATTERN.test(value);\n}\n\n/**\n * Check if a string looks like a datetime\n */\nfunction isDatetimeValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n return DATETIME_PATTERN.test(value);\n}\n\n/**\n * Check if a string looks like a file path (non-image)\n */\nfunction isFilePath(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n if (isImagePath(value)) return false;\n return /\\.\\w{2,5}$/.test(value);\n}\n\n/**\n * Check if an array looks like a multiselect (array of strings from a small set)\n */\nfunction isMultiselectArray(values: unknown[]): boolean {\n if (values.length === 0) return false;\n const allStrings = values.every((v) => typeof v === \"string\" && v.length > 0);\n if (!allStrings) return false;\n const uniqueValues = [...new Set(values)];\n return (\n uniqueValues.length <= ENUM_MAX_VALUES &&\n values.length > uniqueValues.length\n );\n}\n\n/**\n * Field analysis data collected from samples\n */\ninterface FieldAnalysis {\n /** Number of files where this field appears */\n presentCount: number;\n /** Detected types for this field across samples */\n types: Set<string>;\n /** Sample values for enum detection */\n values: unknown[];\n /** Whether values look like image paths */\n hasImagePaths: boolean;\n /** Whether values look like dates */\n hasDateValues: boolean;\n /** Whether values look like URLs */\n hasUrlValues: boolean;\n /** Whether values look like slugs */\n hasSlugValues: boolean;\n /** Whether values look like datetimes */\n hasDatetimeValues: boolean;\n /** Whether values look like file paths */\n hasFilePaths: boolean;\n /** Whether all number values are integers */\n allIntegers: boolean;\n /** Whether array looks like multiselect */\n isMultiselect: boolean;\n /** For arrays, analysis of item types */\n arrayItemTypes: Set<string>;\n}\n\n/**\n * Result of schema detection\n */\nexport interface SchemaDetectionResult {\n /** The detected schema */\n schema: CollectionSchema;\n /** Number of files analyzed */\n samplesAnalyzed: number;\n /** Confidence score (0-1) based on sample consistency */\n confidence: number;\n /** Fields that had inconsistent types across samples */\n warnings: string[];\n}\n\n/**\n * Check if a string looks like an image path\n *\n * @param value - Value to check\n * @returns True if it looks like an image path\n */\nfunction isImagePath(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n\n const lowered = value.toLowerCase();\n return IMAGE_EXTENSIONS.some((ext) => lowered.endsWith(ext));\n}\n\n/**\n * Check if a value looks like a date\n *\n * @param value - Value to check\n * @returns True if it looks like a date\n */\nfunction isDateValue(value: unknown): boolean {\n // Already a Date object\n if (value instanceof Date) return true;\n\n // ISO date string (YYYY-MM-DD or full ISO)\n if (typeof value === \"string\") {\n // Full ISO format\n if (/^\\d{4}-\\d{2}-\\d{2}(T|\\s)/.test(value)) return true;\n // Simple date format\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return true;\n }\n\n return false;\n}\n\n/**\n * Detect the JavaScript type of a value\n *\n * @param value - Value to analyze\n * @returns Detected type string\n */\nfunction detectValueType(value: unknown): string {\n if (value === null || value === undefined) return \"null\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"string\") return \"string\";\n if (Array.isArray(value)) return \"array\";\n if (value instanceof Date) return \"date\";\n if (typeof value === \"object\") return \"object\";\n return \"unknown\";\n}\n\n/**\n * Convert detected type to schema field type\n *\n * @param analysis - Field analysis data\n * @returns The appropriate FieldType\n */\nfunction inferFieldType(analysis: FieldAnalysis): FieldType {\n // If it has image paths, it's an image field\n if (analysis.hasImagePaths) return \"image\";\n\n // If it has datetime values, it's a datetime field\n if (analysis.hasDatetimeValues) return \"datetime\";\n\n // If it has date values, it's a date field\n if (analysis.hasDateValues) return \"date\";\n\n // If it has file paths, it's a file field\n if (analysis.hasFilePaths) return \"file\";\n\n // If it has URL values, it's a url field\n if (analysis.hasUrlValues) return \"url\";\n\n // If it has slug values and is a single string type\n if (analysis.hasSlugValues && analysis.types.size === 1) {\n const typesArr = [...analysis.types];\n if (typesArr.length === 1 && typesArr[0] === \"string\") {\n return \"slug\";\n }\n }\n\n // Check for multiselect arrays\n if (analysis.isMultiselect) return \"multiselect\";\n\n // Check detected types (excluding null)\n const nonNullTypes = new Set([...analysis.types].filter((t) => t !== \"null\"));\n\n // Single type is easy\n if (nonNullTypes.size === 1) {\n const type = [...nonNullTypes][0];\n switch (type) {\n case \"boolean\":\n return \"boolean\";\n case \"number\":\n return analysis.allIntegers ? \"integer\" : \"number\";\n case \"array\":\n return \"array\";\n case \"object\":\n return \"object\";\n case \"date\":\n return \"date\";\n default:\n return \"string\";\n }\n }\n\n // Mixed types - default to string (most flexible)\n return \"string\";\n}\n\n/**\n * Detect if a field should be treated as an enum\n *\n * @param values - All values seen for this field\n * @param totalSamples - Total number of samples\n * @returns Array of enum values, or undefined if not an enum\n */\nfunction detectEnum(\n values: unknown[],\n totalSamples: number\n): string[] | undefined {\n // Filter to string values only\n const stringValues = values.filter(\n (v): v is string => typeof v === \"string\" && v.length > 0\n );\n\n if (stringValues.length === 0) return undefined;\n\n // Get unique values\n const uniqueValues = [...new Set(stringValues)];\n\n // Check if it's a good candidate for enum\n if (uniqueValues.length > ENUM_MAX_VALUES) return undefined;\n\n // Check ratio of unique to total\n const ratio = uniqueValues.length / totalSamples;\n if (ratio > ENUM_RATIO_THRESHOLD) return undefined;\n\n // Must have at least 2 unique values and appear multiple times\n if (uniqueValues.length < 2) return undefined;\n if (stringValues.length < totalSamples * 0.5) return undefined;\n\n return uniqueValues.sort();\n}\n\n/**\n * Detect item type for array fields\n *\n * @param analysis - Field analysis data\n * @returns The detected item type, or undefined\n */\nfunction detectArrayItemType(analysis: FieldAnalysis): string | undefined {\n if (analysis.arrayItemTypes.size === 0) return undefined;\n\n // Filter out null\n const types = [...analysis.arrayItemTypes].filter((t) => t !== \"null\");\n\n if (types.length === 0) return undefined;\n if (types.length === 1) return types[0];\n\n // Mixed types - default to string\n return \"string\";\n}\n\n/**\n * Analyze frontmatter from content items to detect schema\n *\n * @param collectionPath - Absolute path to the collection directory\n * @returns Schema detection result\n *\n * @example\n * ```typescript\n * const result = await detectSchema('/project/src/content/blog');\n * console.log(result.schema);\n * // {\n * // title: { type: 'string', required: true },\n * // pubDate: { type: 'date', required: true },\n * // draft: { type: 'boolean', required: false, default: false },\n * // tags: { type: 'array', required: false, items: 'string' },\n * // }\n * ```\n */\nexport async function detectSchema(\n collectionPath: string\n): Promise<SchemaDetectionResult> {\n const warnings: string[] = [];\n\n // Read sample content files\n const items = await readCollection(collectionPath, {\n includeDrafts: true,\n });\n\n // Limit to max samples\n const samples = items.slice(0, MAX_SAMPLE_FILES);\n\n if (samples.length === 0) {\n return {\n schema: {},\n samplesAnalyzed: 0,\n confidence: 0,\n warnings: [\"No content files found in collection\"],\n };\n }\n\n // Analyze each field across all samples\n const fieldAnalyses = new Map<string, FieldAnalysis>();\n\n for (const item of samples) {\n for (const [fieldName, value] of Object.entries(item.frontmatter)) {\n // Get or create field analysis\n let analysis = fieldAnalyses.get(fieldName);\n if (!analysis) {\n analysis = {\n presentCount: 0,\n types: new Set(),\n values: [],\n hasImagePaths: false,\n hasDateValues: false,\n hasUrlValues: false,\n hasSlugValues: false,\n hasDatetimeValues: false,\n hasFilePaths: false,\n allIntegers: true,\n isMultiselect: false,\n arrayItemTypes: new Set(),\n };\n fieldAnalyses.set(fieldName, analysis);\n }\n\n // Update analysis\n analysis.presentCount++;\n analysis.types.add(detectValueType(value));\n analysis.values.push(value);\n\n // Check for special types\n if (isImagePath(value)) {\n analysis.hasImagePaths = true;\n }\n if (isDateValue(value)) {\n analysis.hasDateValues = true;\n }\n if (isUrlValue(value)) {\n analysis.hasUrlValues = true;\n }\n if (isSlugValue(value)) {\n analysis.hasSlugValues = true;\n }\n if (isDatetimeValue(value)) {\n analysis.hasDatetimeValues = true;\n }\n if (isFilePath(value)) {\n analysis.hasFilePaths = true;\n }\n if (typeof value === \"number\" && !Number.isInteger(value)) {\n analysis.allIntegers = false;\n }\n\n // Analyze array items\n if (Array.isArray(value)) {\n for (const item of value) {\n analysis.arrayItemTypes.add(detectValueType(item));\n }\n if (isMultiselectArray(value)) {\n analysis.isMultiselect = true;\n }\n }\n }\n }\n\n // Generate schema from analysis\n const schema: CollectionSchema = {};\n const totalSamples = samples.length;\n\n for (const [fieldName, analysis] of fieldAnalyses) {\n const fieldType = inferFieldType(analysis);\n const isRequired =\n analysis.presentCount / totalSamples >= REQUIRED_THRESHOLD;\n\n const field: SchemaField = {\n type: fieldType,\n required: isRequired,\n };\n\n // Add array item type if applicable\n if (fieldType === \"array\") {\n const itemType = detectArrayItemType(analysis);\n if (itemType) {\n field.items = itemType;\n }\n }\n\n // Detect enum for string fields\n if (fieldType === \"string\") {\n const enumValues = detectEnum(analysis.values, totalSamples);\n if (enumValues) {\n // Store enum values in the field\n // Note: We use 'default' to store enum options since SchemaField\n // doesn't have an 'enum' property - this can be enhanced later\n field.description = `Options: ${enumValues.join(\", \")}`;\n }\n }\n\n // Detect default value for boolean fields\n if (fieldType === \"boolean\") {\n const boolValues = analysis.values.filter(\n (v): v is boolean => typeof v === \"boolean\"\n );\n if (boolValues.length > 0) {\n // Use most common value as default\n const trueCount = boolValues.filter((v) => v === true).length;\n const falseCount = boolValues.filter((v) => v === false).length;\n field.default = trueCount > falseCount ? true : false;\n }\n }\n\n // Check for type inconsistencies\n const nonNullTypes = [...analysis.types].filter((t) => t !== \"null\");\n if (nonNullTypes.length > 1) {\n warnings.push(\n `Field \"${fieldName}\" has inconsistent types: ${nonNullTypes.join(\", \")}`\n );\n }\n\n schema[fieldName] = field;\n }\n\n // Calculate confidence based on consistency\n const inconsistentFields = warnings.filter((w) =>\n w.includes(\"inconsistent\")\n ).length;\n const confidence = Math.max(\n 0,\n 1 - inconsistentFields / Math.max(1, fieldAnalyses.size)\n );\n\n return {\n schema,\n samplesAnalyzed: totalSamples,\n confidence,\n warnings,\n };\n}\n\n/**\n * Merge detected schema with user-provided schema\n *\n * User schema takes precedence over detected schema.\n *\n * @param detected - Auto-detected schema\n * @param userSchema - User-provided schema overrides\n * @returns Merged schema\n */\nexport function mergeSchema(\n detected: CollectionSchema,\n userSchema?: CollectionSchema\n): CollectionSchema {\n if (!userSchema) return detected;\n\n const merged: CollectionSchema = { ...detected };\n\n for (const [fieldName, userField] of Object.entries(userSchema)) {\n merged[fieldName] = {\n ...detected[fieldName],\n ...userField,\n };\n }\n\n return merged;\n}\n\n/**\n * Convert schema to a human-readable description\n *\n * @param schema - The schema to describe\n * @returns Human-readable description\n */\nexport function describeSchema(schema: CollectionSchema): string {\n const lines: string[] = [];\n\n for (const [fieldName, field] of Object.entries(schema)) {\n let desc = `- ${fieldName}: ${field.type}`;\n\n if (field.required) {\n desc += \" (required)\";\n }\n\n if (field.items) {\n desc += ` of ${field.items}`;\n }\n\n if (field.default !== undefined) {\n desc += ` [default: ${JSON.stringify(field.default)}]`;\n }\n\n if (field.description) {\n desc += ` - ${field.description}`;\n }\n\n lines.push(desc);\n }\n\n return lines.join(\"\\n\");\n}\n","/**\n * @fileoverview Collection discovery for Astro content collections\n *\n * This module provides functions to auto-discover content collections\n * from an Astro project's src/content directory.\n *\n * ## Discovery Process:\n * 1. Scan src/content/ for subdirectories\n * 2. Each subdirectory is treated as a collection\n * 3. Count content files in each collection\n * 4. Detect file patterns from existing files\n * 5. Auto-detect frontmatter schema from sample files\n *\n * @module @writenex/astro/discovery/collections\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { DEFAULT_FILE_PATTERN } from \"@/config/defaults\";\nimport { getCollectionCount } from \"@/filesystem/reader\";\nimport type { CollectionConfig, DiscoveredCollection } from \"@/types\";\nimport { detectFilePattern as detectPattern } from \"./patterns\";\nimport { detectSchema } from \"./schema\";\n\n/**\n * Default content directory path relative to project root\n */\nconst DEFAULT_CONTENT_DIR = \"src/content\";\n\n/**\n * Directories to ignore during discovery\n */\nconst IGNORED_DIRECTORIES = new Set([\"node_modules\", \".git\", \"_\", \".\"]);\n\n/**\n * Check if a directory should be ignored\n *\n * @param name - Directory name\n * @returns True if should be ignored\n */\nfunction shouldIgnore(name: string): boolean {\n return (\n IGNORED_DIRECTORIES.has(name) ||\n name.startsWith(\"_\") ||\n name.startsWith(\".\")\n );\n}\n\n/**\n * Discover all content collections in a project\n *\n * Scans the src/content directory for subdirectories and treats\n * each as a content collection.\n *\n * @param projectRoot - Absolute path to the project root\n * @param contentDir - Relative path to content directory (default: src/content)\n * @returns Array of discovered collections\n *\n * @example\n * ```typescript\n * const collections = await discoverCollections('/path/to/project');\n * // Returns: [\n * // { name: 'blog', path: 'src/content/blog', count: 10, ... },\n * // { name: 'docs', path: 'src/content/docs', count: 5, ... },\n * // ]\n * ```\n */\nexport async function discoverCollections(\n projectRoot: string,\n contentDir: string = DEFAULT_CONTENT_DIR\n): Promise<DiscoveredCollection[]> {\n const contentPath = join(projectRoot, contentDir);\n\n // Check if content directory exists\n if (!existsSync(contentPath)) {\n return [];\n }\n\n const collections: DiscoveredCollection[] = [];\n\n try {\n const entries = await readdir(contentPath, { withFileTypes: true });\n\n for (const entry of entries) {\n // Skip non-directories and ignored directories\n if (!entry.isDirectory() || shouldIgnore(entry.name)) {\n continue;\n }\n\n const collectionPath = join(contentPath, entry.name);\n const relativePath = join(contentDir, entry.name);\n\n // Count content files in this collection\n const count = await getCollectionCount(collectionPath);\n\n // Detect file pattern using pattern detection module\n const patternResult = await detectPattern(collectionPath);\n const filePattern = patternResult.pattern;\n\n // Auto-detect schema from sample files\n const schemaResult = await detectSchema(collectionPath);\n const schema =\n Object.keys(schemaResult.schema).length > 0\n ? schemaResult.schema\n : undefined;\n\n // Generate default preview URL pattern\n const previewUrl = `/${entry.name}/{slug}`;\n\n collections.push({\n name: entry.name,\n path: relativePath,\n filePattern,\n count,\n schema,\n previewUrl,\n });\n }\n } catch (error) {\n console.error(`[writenex] Failed to discover collections: ${error}`);\n }\n\n return collections;\n}\n\n/**\n * Merge discovered collections with configured collections\n *\n * Configured collections take precedence over discovered ones.\n * This allows users to override auto-discovered settings.\n *\n * @param discovered - Auto-discovered collections\n * @param configured - User-configured collections\n * @returns Merged collection list\n */\nexport function mergeCollections(\n discovered: DiscoveredCollection[],\n configured: CollectionConfig[]\n): DiscoveredCollection[] {\n const configuredNames = new Set(configured.map((c) => c.name));\n const result: DiscoveredCollection[] = [];\n\n // Add configured collections first (they take precedence)\n for (const config of configured) {\n const discoveredMatch = discovered.find((d) => d.name === config.name);\n\n result.push({\n name: config.name,\n path: config.path,\n filePattern:\n config.filePattern ??\n discoveredMatch?.filePattern ??\n DEFAULT_FILE_PATTERN,\n count: discoveredMatch?.count ?? 0,\n schema: config.schema ?? discoveredMatch?.schema,\n previewUrl:\n config.previewUrl ??\n discoveredMatch?.previewUrl ??\n `/${config.name}/{slug}`,\n });\n }\n\n // Add discovered collections that weren't configured\n for (const disc of discovered) {\n if (!configuredNames.has(disc.name)) {\n result.push(disc);\n }\n }\n\n return result;\n}\n\n/**\n * Get a single collection by name\n *\n * @param projectRoot - Absolute path to the project root\n * @param collectionName - Name of the collection\n * @param contentDir - Relative path to content directory\n * @returns The collection if found, undefined otherwise\n */\nexport async function getCollection(\n projectRoot: string,\n collectionName: string,\n contentDir: string = DEFAULT_CONTENT_DIR\n): Promise<DiscoveredCollection | undefined> {\n const collections = await discoverCollections(projectRoot, contentDir);\n return collections.find((c) => c.name === collectionName);\n}\n\n/**\n * Check if a collection exists\n *\n * @param projectRoot - Absolute path to the project root\n * @param collectionName - Name of the collection\n * @param contentDir - Relative path to content directory\n * @returns True if the collection exists\n */\nexport async function collectionExists(\n projectRoot: string,\n collectionName: string,\n contentDir: string = DEFAULT_CONTENT_DIR\n): Promise<boolean> {\n const collectionPath = join(projectRoot, contentDir, collectionName);\n\n if (!existsSync(collectionPath)) {\n return false;\n }\n\n try {\n const stats = await stat(collectionPath);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":["item"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-YRSIZLHE.js.map
|