@content-collections/core 0.11.0 → 0.11.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/dist/index.d.ts +20 -2
- package/dist/index.js +404 -390
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -259,6 +259,13 @@ declare class ConfigurationError extends Error {
|
|
|
259
259
|
type: ErrorType;
|
|
260
260
|
constructor(type: ErrorType, message: string);
|
|
261
261
|
}
|
|
262
|
+
type InternalConfiguration = {
|
|
263
|
+
collections: Array<AnyCollection>;
|
|
264
|
+
path: string;
|
|
265
|
+
inputPaths: Array<string>;
|
|
266
|
+
checksum: string;
|
|
267
|
+
generateTypes?: boolean;
|
|
268
|
+
};
|
|
262
269
|
type Options$1 = {
|
|
263
270
|
configName: string;
|
|
264
271
|
cacheDir?: string;
|
|
@@ -314,12 +321,23 @@ declare function createBuilder(configurationPath: string, options?: Options, emi
|
|
|
314
321
|
<TKey extends "_error" | "_all">(key: TKey, listener: (event: SystemEvents[TKey]) => void): void;
|
|
315
322
|
};
|
|
316
323
|
}>;
|
|
324
|
+
declare function createInternalBuilder(initialConfiguration: InternalConfiguration, baseDirectory: string, options: Options, emitter: Emitter): Promise<{
|
|
325
|
+
build: () => Promise<void>;
|
|
326
|
+
sync: (modification: Modification, filePath: string) => Promise<boolean>;
|
|
327
|
+
watch: () => Promise<{
|
|
328
|
+
unsubscribe: () => Promise<void>;
|
|
329
|
+
}>;
|
|
330
|
+
on: {
|
|
331
|
+
<TKey extends "builder:start" | "builder:end" | "builder:created" | "watcher:file-changed" | "watcher:config-changed" | "watcher:config-reload-error" | "collector:read-error" | "collector:parse-error" | "transformer:validation-error" | "transformer:result-error" | "transformer:error" | "transformer:document-skipped" | "watcher:subscribe-error" | "watcher:subscribed" | "watcher:unsubscribed">(key: TKey, listener: (event: Events[TKey]) => void): void;
|
|
332
|
+
<TKey extends "_error" | "_all">(key: TKey, listener: (event: SystemEvents[TKey]) => void): void;
|
|
333
|
+
};
|
|
334
|
+
}>;
|
|
317
335
|
type Builder = Awaited<ReturnType<typeof createBuilder>>;
|
|
318
336
|
|
|
319
337
|
declare const deprecations: {
|
|
320
338
|
legacySchema: string;
|
|
321
339
|
};
|
|
322
340
|
type Deprecation = keyof typeof deprecations;
|
|
323
|
-
declare function suppressDeprecatedWarnings(...
|
|
341
|
+
declare function suppressDeprecatedWarnings(...suppresses: Array<Deprecation | "all">): void;
|
|
324
342
|
|
|
325
|
-
export { type AnyCollection, type AnyConfiguration, type Builder, type BuilderEvents, CollectError, type Collection, type CollectionRequest, type Configuration, ConfigurationError, ConfigurationReloadError, type Context, type Document, type GetTypeByName, type Meta, type Modification, type Schema, type SkippedSignal, TransformError, type Watcher, createBuilder, createDefaultImport, createNamedImport, defineCollection, defineConfig, defineParser, skippedSymbol, suppressDeprecatedWarnings };
|
|
343
|
+
export { type AnyCollection, type AnyConfiguration, type Builder, type BuilderEvents, CollectError, type Collection, type CollectionRequest, type Configuration, ConfigurationError, ConfigurationReloadError, type Context, type Document, type GetTypeByName, type Meta, type Modification, type Schema, type SkippedSignal, TransformError, type Watcher, createBuilder, createDefaultImport, createInternalBuilder, createNamedImport, defineCollection, defineConfig, defineParser, skippedSymbol, suppressDeprecatedWarnings };
|
package/dist/index.js
CHANGED
|
@@ -102,18 +102,322 @@ async function createCacheManager(baseDirectory, configChecksum) {
|
|
|
102
102
|
|
|
103
103
|
// src/collector.ts
|
|
104
104
|
import { readFile as readFile2 } from "fs/promises";
|
|
105
|
-
import
|
|
105
|
+
import path3 from "node:path";
|
|
106
106
|
import { glob } from "tinyglobby";
|
|
107
107
|
|
|
108
108
|
// src/parser.ts
|
|
109
109
|
import matter from "gray-matter";
|
|
110
110
|
import { parse, stringify } from "yaml";
|
|
111
|
+
function parseYaml(content) {
|
|
112
|
+
return parse(content.trim());
|
|
113
|
+
}
|
|
114
|
+
function frontmatter(fileContent) {
|
|
115
|
+
return matter(fileContent, {
|
|
116
|
+
engines: {
|
|
117
|
+
yaml: {
|
|
118
|
+
parse: parseYaml,
|
|
119
|
+
stringify
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function frontmatterParser(fileContent) {
|
|
125
|
+
const { data, content } = frontmatter(fileContent);
|
|
126
|
+
return {
|
|
127
|
+
...data,
|
|
128
|
+
content: content.trim()
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function frontmatterOnlyParser(fileContent) {
|
|
132
|
+
const { data } = frontmatter(fileContent);
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
var parsers = {
|
|
136
|
+
frontmatter: {
|
|
137
|
+
hasContent: true,
|
|
138
|
+
parse: frontmatterParser
|
|
139
|
+
},
|
|
140
|
+
["frontmatter-only"]: {
|
|
141
|
+
hasContent: false,
|
|
142
|
+
parse: frontmatterOnlyParser
|
|
143
|
+
},
|
|
144
|
+
json: {
|
|
145
|
+
hasContent: false,
|
|
146
|
+
parse: JSON.parse
|
|
147
|
+
},
|
|
148
|
+
yaml: {
|
|
149
|
+
hasContent: false,
|
|
150
|
+
parse: parseYaml
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
function getParser(configuredParser) {
|
|
154
|
+
if (typeof configuredParser === "string") {
|
|
155
|
+
return parsers[configuredParser];
|
|
156
|
+
}
|
|
157
|
+
return configuredParser;
|
|
158
|
+
}
|
|
159
|
+
function defineParser(parser) {
|
|
160
|
+
if (typeof parser === "function") {
|
|
161
|
+
return {
|
|
162
|
+
hasContent: false,
|
|
163
|
+
parse: parser
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return parser;
|
|
167
|
+
}
|
|
168
|
+
function isValidParser(parser) {
|
|
169
|
+
if (typeof parser === "string") {
|
|
170
|
+
return parser in parsers;
|
|
171
|
+
}
|
|
172
|
+
return "hasContent" in parser && typeof parser.parse === "function";
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/utils.ts
|
|
176
|
+
import camelcase from "camelcase";
|
|
177
|
+
import pluralize from "pluralize";
|
|
178
|
+
import path2 from "node:path";
|
|
179
|
+
function generateTypeName(name) {
|
|
180
|
+
const singularName = pluralize.singular(name);
|
|
181
|
+
return camelcase(singularName, { pascalCase: true });
|
|
182
|
+
}
|
|
183
|
+
function isDefined(value) {
|
|
184
|
+
return value !== void 0 && value !== null;
|
|
185
|
+
}
|
|
186
|
+
function orderByPath(a, b) {
|
|
187
|
+
return a.path.localeCompare(b.path);
|
|
188
|
+
}
|
|
189
|
+
function removeChildPaths(paths) {
|
|
190
|
+
return Array.from(
|
|
191
|
+
new Set(
|
|
192
|
+
paths.filter((path10) => {
|
|
193
|
+
return !paths.some((otherPath) => {
|
|
194
|
+
if (path10 === otherPath) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
return path10.startsWith(otherPath);
|
|
198
|
+
});
|
|
199
|
+
})
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
function posixToNativePath(pathName) {
|
|
204
|
+
if (path2.sep !== path2.posix.sep) {
|
|
205
|
+
return pathName.replaceAll(path2.posix.sep, path2.sep);
|
|
206
|
+
}
|
|
207
|
+
return pathName;
|
|
208
|
+
}
|
|
209
|
+
function toError(error) {
|
|
210
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/collector.ts
|
|
214
|
+
var CollectError = class extends Error {
|
|
215
|
+
type;
|
|
216
|
+
constructor(type, message) {
|
|
217
|
+
super(message);
|
|
218
|
+
this.type = type;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
function createCollector(emitter, baseDirectory = ".") {
|
|
222
|
+
async function read(filePath) {
|
|
223
|
+
try {
|
|
224
|
+
return await readFile2(filePath, "utf-8");
|
|
225
|
+
} catch (error) {
|
|
226
|
+
emitter.emit("collector:read-error", {
|
|
227
|
+
filePath,
|
|
228
|
+
error: new CollectError("Read", String(error))
|
|
229
|
+
});
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function collectFile(collection, filePath) {
|
|
234
|
+
const absolutePath = path3.join(
|
|
235
|
+
baseDirectory,
|
|
236
|
+
collection.directory,
|
|
237
|
+
filePath
|
|
238
|
+
);
|
|
239
|
+
const file = await read(absolutePath);
|
|
240
|
+
if (!file) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const parser = getParser(collection.parser);
|
|
245
|
+
const data = await parser.parse(file);
|
|
246
|
+
return {
|
|
247
|
+
data,
|
|
248
|
+
path: filePath
|
|
249
|
+
};
|
|
250
|
+
} catch (error) {
|
|
251
|
+
emitter.emit("collector:parse-error", {
|
|
252
|
+
filePath: path3.join(collection.directory, filePath),
|
|
253
|
+
error: new CollectError("Parse", String(error))
|
|
254
|
+
});
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function createIgnorePattern(collection) {
|
|
259
|
+
if (collection.exclude) {
|
|
260
|
+
if (Array.isArray(collection.exclude)) {
|
|
261
|
+
return collection.exclude;
|
|
262
|
+
} else {
|
|
263
|
+
return [collection.exclude];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return void 0;
|
|
267
|
+
}
|
|
268
|
+
async function resolveCollection(collection) {
|
|
269
|
+
const collectionDirectory = path3.join(baseDirectory, collection.directory);
|
|
270
|
+
const include = Array.isArray(collection.include) ? collection.include : [collection.include];
|
|
271
|
+
const filePaths = await glob(include, {
|
|
272
|
+
cwd: collectionDirectory,
|
|
273
|
+
onlyFiles: true,
|
|
274
|
+
absolute: false,
|
|
275
|
+
ignore: createIgnorePattern(collection)
|
|
276
|
+
});
|
|
277
|
+
const promises = filePaths.map(
|
|
278
|
+
(filePath) => collectFile(collection, posixToNativePath(filePath))
|
|
279
|
+
);
|
|
280
|
+
const files = await Promise.all(promises);
|
|
281
|
+
return {
|
|
282
|
+
...collection,
|
|
283
|
+
files: files.filter(isDefined).sort(orderByPath)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
async function collect(unresolvedCollections) {
|
|
287
|
+
const promises = unresolvedCollections.map(
|
|
288
|
+
(collection) => resolveCollection(collection)
|
|
289
|
+
);
|
|
290
|
+
return await Promise.all(promises);
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
collect,
|
|
294
|
+
collectFile
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/synchronizer.ts
|
|
299
|
+
import path4 from "node:path";
|
|
300
|
+
import picomatch from "picomatch";
|
|
301
|
+
function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
|
|
302
|
+
function findCollections(filePath) {
|
|
303
|
+
const resolvedFilePath = path4.resolve(filePath);
|
|
304
|
+
return collections.filter((collection) => {
|
|
305
|
+
return resolvedFilePath.startsWith(
|
|
306
|
+
path4.resolve(baseDirectory, collection.directory)
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function createRelativePath(collectionPath, filePath) {
|
|
311
|
+
const resolvedCollectionPath = path4.resolve(baseDirectory, collectionPath);
|
|
312
|
+
const resolvedFilePath = path4.resolve(filePath);
|
|
313
|
+
let relativePath = resolvedFilePath.slice(resolvedCollectionPath.length);
|
|
314
|
+
if (relativePath.startsWith(path4.sep)) {
|
|
315
|
+
relativePath = relativePath.slice(path4.sep.length);
|
|
316
|
+
}
|
|
317
|
+
return relativePath;
|
|
318
|
+
}
|
|
319
|
+
function resolve2(filePath) {
|
|
320
|
+
const collections2 = findCollections(filePath);
|
|
321
|
+
return collections2.map((collection) => {
|
|
322
|
+
const relativePath = createRelativePath(collection.directory, filePath);
|
|
323
|
+
return {
|
|
324
|
+
collection,
|
|
325
|
+
relativePath
|
|
326
|
+
};
|
|
327
|
+
}).filter(({ collection, relativePath }) => {
|
|
328
|
+
return picomatch.isMatch(relativePath, collection.include, {
|
|
329
|
+
// @see https://github.com/sdorra/content-collections/issues/602
|
|
330
|
+
windows: process.platform === "win32",
|
|
331
|
+
ignore: collection.exclude
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function deleted(filePath) {
|
|
336
|
+
const resolvedCollections = resolve2(filePath);
|
|
337
|
+
if (resolvedCollections.length === 0) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
let changed2 = false;
|
|
341
|
+
for (const { collection, relativePath } of resolvedCollections) {
|
|
342
|
+
const index = collection.files.findIndex(
|
|
343
|
+
(file) => file.path === relativePath
|
|
344
|
+
);
|
|
345
|
+
const deleted2 = collection.files.splice(index, 1);
|
|
346
|
+
if (deleted2.length > 0) {
|
|
347
|
+
changed2 = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return changed2;
|
|
351
|
+
}
|
|
352
|
+
async function changed(filePath) {
|
|
353
|
+
const resolvedCollections = resolve2(filePath);
|
|
354
|
+
if (resolvedCollections.length === 0) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
let changed2 = false;
|
|
358
|
+
for (const { collection, relativePath } of resolvedCollections) {
|
|
359
|
+
const index = collection.files.findIndex(
|
|
360
|
+
(file2) => file2.path === relativePath
|
|
361
|
+
);
|
|
362
|
+
const file = await readCollectionFile(collection, relativePath);
|
|
363
|
+
if (file) {
|
|
364
|
+
changed2 = true;
|
|
365
|
+
if (index === -1) {
|
|
366
|
+
collection.files.push(file);
|
|
367
|
+
collection.files.sort(orderByPath);
|
|
368
|
+
} else {
|
|
369
|
+
collection.files[index] = file;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return changed2;
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
deleted,
|
|
377
|
+
changed
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/transformer.ts
|
|
382
|
+
import os from "node:os";
|
|
383
|
+
import { basename, dirname as dirname2, extname, join as join3 } from "node:path";
|
|
384
|
+
import pLimit from "p-limit";
|
|
385
|
+
|
|
386
|
+
// src/config.ts
|
|
387
|
+
import { z } from "zod";
|
|
388
|
+
|
|
389
|
+
// src/warn.ts
|
|
390
|
+
var deprecations = {
|
|
391
|
+
legacySchema: `The use of a function as a schema is deprecated.
|
|
392
|
+
Please use a StandardSchema compliant library directly.
|
|
393
|
+
For more information, see:
|
|
394
|
+
https://content-collections.dev/docs/deprecations/schema-as-function`
|
|
395
|
+
};
|
|
396
|
+
var _suppressDeprecatedWarnings = [];
|
|
397
|
+
function suppressDeprecatedWarnings(...suppresses) {
|
|
398
|
+
for (const deprecation of suppresses) {
|
|
399
|
+
if (deprecation === "all") {
|
|
400
|
+
_suppressDeprecatedWarnings.push(
|
|
401
|
+
...Object.keys(deprecations)
|
|
402
|
+
);
|
|
403
|
+
return;
|
|
404
|
+
} else {
|
|
405
|
+
_suppressDeprecatedWarnings.push(deprecation);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function warnDeprecated(deprecation, logger = console.warn) {
|
|
410
|
+
if (_suppressDeprecatedWarnings.includes(deprecation)) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
logger(`[CC DEPRECATED]: ${deprecations[deprecation]}`);
|
|
414
|
+
}
|
|
111
415
|
|
|
112
416
|
// src/configurationReader.ts
|
|
113
417
|
import { createHash as createHash2 } from "node:crypto";
|
|
114
418
|
import { existsSync as existsSync2 } from "node:fs";
|
|
115
419
|
import fs2 from "node:fs/promises";
|
|
116
|
-
import
|
|
420
|
+
import path6 from "node:path";
|
|
117
421
|
|
|
118
422
|
// ../../node_modules/.pnpm/bundle-require@5.0.0_esbuild@0.25.6/node_modules/bundle-require/dist/index.js
|
|
119
423
|
import {
|
|
@@ -122,7 +426,7 @@ import {
|
|
|
122
426
|
} from "esbuild";
|
|
123
427
|
|
|
124
428
|
// ../../node_modules/.pnpm/load-tsconfig@0.2.5/node_modules/load-tsconfig/dist/index.js
|
|
125
|
-
import
|
|
429
|
+
import path5 from "path";
|
|
126
430
|
import fs from "fs";
|
|
127
431
|
import { createRequire } from "module";
|
|
128
432
|
var singleComment = Symbol("singleComment");
|
|
@@ -219,10 +523,10 @@ function jsoncParse(data) {
|
|
|
219
523
|
}
|
|
220
524
|
}
|
|
221
525
|
var req = true ? createRequire(import.meta.url) : __require;
|
|
222
|
-
var findUp = (name, startDir, stopDir =
|
|
526
|
+
var findUp = (name, startDir, stopDir = path5.parse(startDir).root) => {
|
|
223
527
|
let dir = startDir;
|
|
224
528
|
while (dir !== stopDir) {
|
|
225
|
-
const file =
|
|
529
|
+
const file = path5.join(dir, name);
|
|
226
530
|
if (fs.existsSync(file))
|
|
227
531
|
return file;
|
|
228
532
|
if (!file.endsWith(".json")) {
|
|
@@ -230,17 +534,17 @@ var findUp = (name, startDir, stopDir = path2.parse(startDir).root) => {
|
|
|
230
534
|
if (fs.existsSync(fileWithExt))
|
|
231
535
|
return fileWithExt;
|
|
232
536
|
}
|
|
233
|
-
dir =
|
|
537
|
+
dir = path5.dirname(dir);
|
|
234
538
|
}
|
|
235
539
|
return null;
|
|
236
540
|
};
|
|
237
541
|
var resolveTsConfigFromFile = (cwd, filename) => {
|
|
238
|
-
if (
|
|
542
|
+
if (path5.isAbsolute(filename))
|
|
239
543
|
return fs.existsSync(filename) ? filename : null;
|
|
240
544
|
return findUp(filename, cwd);
|
|
241
545
|
};
|
|
242
546
|
var resolveTsConfigFromExtends = (cwd, name) => {
|
|
243
|
-
if (
|
|
547
|
+
if (path5.isAbsolute(name))
|
|
244
548
|
return fs.existsSync(name) ? name : null;
|
|
245
549
|
if (name.startsWith("."))
|
|
246
550
|
return findUp(name, cwd);
|
|
@@ -249,14 +553,14 @@ var resolveTsConfigFromExtends = (cwd, name) => {
|
|
|
249
553
|
};
|
|
250
554
|
var loadTsConfigInternal = (dir = process.cwd(), name = "tsconfig.json", isExtends = false) => {
|
|
251
555
|
var _a, _b;
|
|
252
|
-
dir =
|
|
556
|
+
dir = path5.resolve(dir);
|
|
253
557
|
const id = isExtends ? resolveTsConfigFromExtends(dir, name) : resolveTsConfigFromFile(dir, name);
|
|
254
558
|
if (!id)
|
|
255
559
|
return null;
|
|
256
560
|
const data = jsoncParse(fs.readFileSync(id, "utf-8"));
|
|
257
|
-
const configDir =
|
|
561
|
+
const configDir = path5.dirname(id);
|
|
258
562
|
if ((_a = data.compilerOptions) == null ? void 0 : _a.baseUrl) {
|
|
259
|
-
data.compilerOptions.baseUrl =
|
|
563
|
+
data.compilerOptions.baseUrl = path5.join(
|
|
260
564
|
configDir,
|
|
261
565
|
data.compilerOptions.baseUrl
|
|
262
566
|
);
|
|
@@ -326,406 +630,99 @@ function createExternalsPlugin(configPath) {
|
|
|
326
630
|
return {
|
|
327
631
|
name: "external-packages",
|
|
328
632
|
setup: (build4) => {
|
|
329
|
-
build4.onResolve({ filter: /.*/ }, ({ path: path10, kind }) => {
|
|
330
|
-
if (match(path10, resolvePatterns)) {
|
|
331
|
-
if (kind === "dynamic-import") {
|
|
332
|
-
return { path: path10, external: true };
|
|
333
|
-
}
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
if (!NON_NODE_MODULE_RE.test(path10)) {
|
|
337
|
-
return {
|
|
338
|
-
path: path10,
|
|
339
|
-
external: true
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
var importPathPlugin = {
|
|
347
|
-
name: "import-path",
|
|
348
|
-
setup(build4) {
|
|
349
|
-
build4.onResolve({ filter: /^\@content-collections\/core$/ }, () => {
|
|
350
|
-
return { path: join2(__dirname, "index.ts"), external: true };
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
async function compile(configurationPath, outfile) {
|
|
355
|
-
const plugins = [createExternalsPlugin(configurationPath)];
|
|
356
|
-
if (process.env.NODE_ENV === "test") {
|
|
357
|
-
plugins.push(importPathPlugin);
|
|
358
|
-
}
|
|
359
|
-
const result = await build2({
|
|
360
|
-
entryPoints: [configurationPath],
|
|
361
|
-
packages: "external",
|
|
362
|
-
bundle: true,
|
|
363
|
-
platform: "node",
|
|
364
|
-
format: "esm",
|
|
365
|
-
plugins,
|
|
366
|
-
outfile,
|
|
367
|
-
metafile: true
|
|
368
|
-
});
|
|
369
|
-
return Object.keys(result.metafile.inputs);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// src/configurationReader.ts
|
|
373
|
-
var ConfigurationError = class extends Error {
|
|
374
|
-
type;
|
|
375
|
-
constructor(type, message) {
|
|
376
|
-
super(message);
|
|
377
|
-
this.type = type;
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
var defaultConfigName = "content-collection-config.mjs";
|
|
381
|
-
function resolveCacheDir(config, options) {
|
|
382
|
-
if (options.cacheDir) {
|
|
383
|
-
return options.cacheDir;
|
|
384
|
-
}
|
|
385
|
-
return path3.join(path3.dirname(config), ".content-collections", "cache");
|
|
386
|
-
}
|
|
387
|
-
function createConfigurationReader() {
|
|
388
|
-
return async (configurationPath, options = {
|
|
389
|
-
configName: defaultConfigName
|
|
390
|
-
}) => {
|
|
391
|
-
if (!existsSync2(configurationPath)) {
|
|
392
|
-
throw new ConfigurationError(
|
|
393
|
-
"Read",
|
|
394
|
-
`configuration file ${configurationPath} does not exist`
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
const cacheDir = resolveCacheDir(configurationPath, options);
|
|
398
|
-
await fs2.mkdir(cacheDir, { recursive: true });
|
|
399
|
-
const outfile = path3.join(cacheDir, options.configName);
|
|
400
|
-
try {
|
|
401
|
-
const configurationPaths = await compile(configurationPath, outfile);
|
|
402
|
-
const module = await import(`file://${path3.resolve(outfile)}?x=${Date.now()}`);
|
|
403
|
-
const hash = createHash2("sha256");
|
|
404
|
-
hash.update(await fs2.readFile(outfile, "utf-8"));
|
|
405
|
-
const checksum = hash.digest("hex");
|
|
406
|
-
return {
|
|
407
|
-
...module.default,
|
|
408
|
-
path: configurationPath,
|
|
409
|
-
inputPaths: configurationPaths.map((p) => path3.resolve(p)),
|
|
410
|
-
generateTypes: true,
|
|
411
|
-
checksum
|
|
412
|
-
};
|
|
413
|
-
} catch (error) {
|
|
414
|
-
throw new ConfigurationError(
|
|
415
|
-
"Compile",
|
|
416
|
-
`configuration file ${configurationPath} is invalid: ${error}`
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// src/parser.ts
|
|
423
|
-
function parseYaml(content) {
|
|
424
|
-
return parse(content.trim());
|
|
425
|
-
}
|
|
426
|
-
function frontmatter(fileContent) {
|
|
427
|
-
return matter(fileContent, {
|
|
428
|
-
engines: {
|
|
429
|
-
yaml: {
|
|
430
|
-
parse: parseYaml,
|
|
431
|
-
stringify
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
function frontmatterParser(fileContent) {
|
|
437
|
-
const { data, content } = frontmatter(fileContent);
|
|
438
|
-
return {
|
|
439
|
-
...data,
|
|
440
|
-
content: content.trim()
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
function frontmatterOnlyParser(fileContent) {
|
|
444
|
-
const { data } = frontmatter(fileContent);
|
|
445
|
-
return data;
|
|
446
|
-
}
|
|
447
|
-
var parsers = {
|
|
448
|
-
frontmatter: {
|
|
449
|
-
hasContent: true,
|
|
450
|
-
parse: frontmatterParser
|
|
451
|
-
},
|
|
452
|
-
["frontmatter-only"]: {
|
|
453
|
-
hasContent: false,
|
|
454
|
-
parse: frontmatterOnlyParser
|
|
455
|
-
},
|
|
456
|
-
json: {
|
|
457
|
-
hasContent: false,
|
|
458
|
-
parse: JSON.parse
|
|
459
|
-
},
|
|
460
|
-
yaml: {
|
|
461
|
-
hasContent: false,
|
|
462
|
-
parse: parseYaml
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
function getParser(configuredParser) {
|
|
466
|
-
if (typeof configuredParser === "string") {
|
|
467
|
-
const parser = parsers[configuredParser];
|
|
468
|
-
if (!parser) {
|
|
469
|
-
throw new ConfigurationError(
|
|
470
|
-
"Read",
|
|
471
|
-
`Parser ${configuredParser} does not exist`
|
|
472
|
-
);
|
|
473
|
-
}
|
|
474
|
-
return parser;
|
|
475
|
-
}
|
|
476
|
-
return configuredParser;
|
|
477
|
-
}
|
|
478
|
-
function defineParser(parser) {
|
|
479
|
-
if (typeof parser === "function") {
|
|
480
|
-
return {
|
|
481
|
-
hasContent: false,
|
|
482
|
-
parse: parser
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
return parser;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// src/utils.ts
|
|
489
|
-
import camelcase from "camelcase";
|
|
490
|
-
import pluralize from "pluralize";
|
|
491
|
-
import path4 from "node:path";
|
|
492
|
-
function generateTypeName(name) {
|
|
493
|
-
const singularName = pluralize.singular(name);
|
|
494
|
-
return camelcase(singularName, { pascalCase: true });
|
|
495
|
-
}
|
|
496
|
-
function isDefined(value) {
|
|
497
|
-
return value !== void 0 && value !== null;
|
|
498
|
-
}
|
|
499
|
-
function orderByPath(a, b) {
|
|
500
|
-
return a.path.localeCompare(b.path);
|
|
501
|
-
}
|
|
502
|
-
function removeChildPaths(paths) {
|
|
503
|
-
return Array.from(
|
|
504
|
-
new Set(
|
|
505
|
-
paths.filter((path10) => {
|
|
506
|
-
return !paths.some((otherPath) => {
|
|
507
|
-
if (path10 === otherPath) {
|
|
508
|
-
return false;
|
|
633
|
+
build4.onResolve({ filter: /.*/ }, ({ path: path10, kind }) => {
|
|
634
|
+
if (match(path10, resolvePatterns)) {
|
|
635
|
+
if (kind === "dynamic-import") {
|
|
636
|
+
return { path: path10, external: true };
|
|
509
637
|
}
|
|
510
|
-
return
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (!NON_NODE_MODULE_RE.test(path10)) {
|
|
641
|
+
return {
|
|
642
|
+
path: path10,
|
|
643
|
+
external: true
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
};
|
|
515
649
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
650
|
+
var importPathPlugin = {
|
|
651
|
+
name: "import-path",
|
|
652
|
+
setup(build4) {
|
|
653
|
+
build4.onResolve({ filter: /^\@content-collections\/core$/ }, () => {
|
|
654
|
+
return { path: join2(__dirname, "index.ts"), external: true };
|
|
655
|
+
});
|
|
519
656
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
657
|
+
};
|
|
658
|
+
async function compile(configurationPath, outfile) {
|
|
659
|
+
const plugins = [createExternalsPlugin(configurationPath)];
|
|
660
|
+
if (process.env.NODE_ENV === "test") {
|
|
661
|
+
plugins.push(importPathPlugin);
|
|
662
|
+
}
|
|
663
|
+
const result = await build2({
|
|
664
|
+
entryPoints: [configurationPath],
|
|
665
|
+
packages: "external",
|
|
666
|
+
bundle: true,
|
|
667
|
+
platform: "node",
|
|
668
|
+
format: "esm",
|
|
669
|
+
plugins,
|
|
670
|
+
outfile,
|
|
671
|
+
metafile: true
|
|
672
|
+
});
|
|
673
|
+
return Object.keys(result.metafile.inputs);
|
|
524
674
|
}
|
|
525
675
|
|
|
526
|
-
// src/
|
|
527
|
-
var
|
|
676
|
+
// src/configurationReader.ts
|
|
677
|
+
var ConfigurationError = class extends Error {
|
|
528
678
|
type;
|
|
529
679
|
constructor(type, message) {
|
|
530
680
|
super(message);
|
|
531
681
|
this.type = type;
|
|
532
682
|
}
|
|
533
683
|
};
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
} catch (error) {
|
|
539
|
-
emitter.emit("collector:read-error", {
|
|
540
|
-
filePath,
|
|
541
|
-
error: new CollectError("Read", String(error))
|
|
542
|
-
});
|
|
543
|
-
return null;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
async function collectFile(collection, filePath) {
|
|
547
|
-
const absolutePath = path5.join(
|
|
548
|
-
baseDirectory,
|
|
549
|
-
collection.directory,
|
|
550
|
-
filePath
|
|
551
|
-
);
|
|
552
|
-
const file = await read(absolutePath);
|
|
553
|
-
if (!file) {
|
|
554
|
-
return null;
|
|
555
|
-
}
|
|
556
|
-
try {
|
|
557
|
-
const parser = getParser(collection.parser);
|
|
558
|
-
const data = await parser.parse(file);
|
|
559
|
-
return {
|
|
560
|
-
data,
|
|
561
|
-
path: filePath
|
|
562
|
-
};
|
|
563
|
-
} catch (error) {
|
|
564
|
-
emitter.emit("collector:parse-error", {
|
|
565
|
-
filePath: path5.join(collection.directory, filePath),
|
|
566
|
-
error: new CollectError("Parse", String(error))
|
|
567
|
-
});
|
|
568
|
-
return null;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
function createIgnorePattern(collection) {
|
|
572
|
-
if (collection.exclude) {
|
|
573
|
-
if (Array.isArray(collection.exclude)) {
|
|
574
|
-
return collection.exclude;
|
|
575
|
-
} else {
|
|
576
|
-
return [collection.exclude];
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
return void 0;
|
|
580
|
-
}
|
|
581
|
-
async function resolveCollection(collection) {
|
|
582
|
-
const collectionDirectory = path5.join(baseDirectory, collection.directory);
|
|
583
|
-
const include = Array.isArray(collection.include) ? collection.include : [collection.include];
|
|
584
|
-
const filePaths = await glob(include, {
|
|
585
|
-
cwd: collectionDirectory,
|
|
586
|
-
onlyFiles: true,
|
|
587
|
-
absolute: false,
|
|
588
|
-
ignore: createIgnorePattern(collection)
|
|
589
|
-
});
|
|
590
|
-
const promises = filePaths.map(
|
|
591
|
-
(filePath) => collectFile(collection, posixToNativePath(filePath))
|
|
592
|
-
);
|
|
593
|
-
const files = await Promise.all(promises);
|
|
594
|
-
return {
|
|
595
|
-
...collection,
|
|
596
|
-
files: files.filter(isDefined).sort(orderByPath)
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
async function collect(unresolvedCollections) {
|
|
600
|
-
const promises = unresolvedCollections.map(
|
|
601
|
-
(collection) => resolveCollection(collection)
|
|
602
|
-
);
|
|
603
|
-
return await Promise.all(promises);
|
|
684
|
+
var defaultConfigName = "content-collection-config.mjs";
|
|
685
|
+
function resolveCacheDir(config, options) {
|
|
686
|
+
if (options.cacheDir) {
|
|
687
|
+
return options.cacheDir;
|
|
604
688
|
}
|
|
605
|
-
return
|
|
606
|
-
collect,
|
|
607
|
-
collectFile
|
|
608
|
-
};
|
|
689
|
+
return path6.join(path6.dirname(config), ".content-collections", "cache");
|
|
609
690
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
return resolvedFilePath.startsWith(
|
|
619
|
-
path6.resolve(baseDirectory, collection.directory)
|
|
691
|
+
function createConfigurationReader() {
|
|
692
|
+
return async (configurationPath, options = {
|
|
693
|
+
configName: defaultConfigName
|
|
694
|
+
}) => {
|
|
695
|
+
if (!existsSync2(configurationPath)) {
|
|
696
|
+
throw new ConfigurationError(
|
|
697
|
+
"Read",
|
|
698
|
+
`configuration file ${configurationPath} does not exist`
|
|
620
699
|
);
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
function createRelativePath(collectionPath, filePath) {
|
|
624
|
-
const resolvedCollectionPath = path6.resolve(baseDirectory, collectionPath);
|
|
625
|
-
const resolvedFilePath = path6.resolve(filePath);
|
|
626
|
-
let relativePath = resolvedFilePath.slice(resolvedCollectionPath.length);
|
|
627
|
-
if (relativePath.startsWith(path6.sep)) {
|
|
628
|
-
relativePath = relativePath.slice(path6.sep.length);
|
|
629
700
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const
|
|
701
|
+
const cacheDir = resolveCacheDir(configurationPath, options);
|
|
702
|
+
await fs2.mkdir(cacheDir, { recursive: true });
|
|
703
|
+
const outfile = path6.join(cacheDir, options.configName);
|
|
704
|
+
try {
|
|
705
|
+
const configurationPaths = await compile(configurationPath, outfile);
|
|
706
|
+
const module = await import(`file://${path6.resolve(outfile)}?x=${Date.now()}`);
|
|
707
|
+
const hash = createHash2("sha256");
|
|
708
|
+
hash.update(await fs2.readFile(outfile, "utf-8"));
|
|
709
|
+
const checksum = hash.digest("hex");
|
|
636
710
|
return {
|
|
637
|
-
|
|
638
|
-
|
|
711
|
+
...module.default,
|
|
712
|
+
path: configurationPath,
|
|
713
|
+
inputPaths: configurationPaths.map((p) => path6.resolve(p)),
|
|
714
|
+
generateTypes: true,
|
|
715
|
+
checksum
|
|
639
716
|
};
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
ignore: collection.exclude
|
|
645
|
-
});
|
|
646
|
-
});
|
|
647
|
-
}
|
|
648
|
-
function deleted(filePath) {
|
|
649
|
-
const resolvedCollections = resolve2(filePath);
|
|
650
|
-
if (resolvedCollections.length === 0) {
|
|
651
|
-
return false;
|
|
652
|
-
}
|
|
653
|
-
let changed2 = false;
|
|
654
|
-
for (const { collection, relativePath } of resolvedCollections) {
|
|
655
|
-
const index = collection.files.findIndex(
|
|
656
|
-
(file) => file.path === relativePath
|
|
657
|
-
);
|
|
658
|
-
const deleted2 = collection.files.splice(index, 1);
|
|
659
|
-
if (deleted2.length > 0) {
|
|
660
|
-
changed2 = true;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return changed2;
|
|
664
|
-
}
|
|
665
|
-
async function changed(filePath) {
|
|
666
|
-
const resolvedCollections = resolve2(filePath);
|
|
667
|
-
if (resolvedCollections.length === 0) {
|
|
668
|
-
return false;
|
|
669
|
-
}
|
|
670
|
-
let changed2 = false;
|
|
671
|
-
for (const { collection, relativePath } of resolvedCollections) {
|
|
672
|
-
const index = collection.files.findIndex(
|
|
673
|
-
(file2) => file2.path === relativePath
|
|
717
|
+
} catch (error) {
|
|
718
|
+
throw new ConfigurationError(
|
|
719
|
+
"Compile",
|
|
720
|
+
`configuration file ${configurationPath} is invalid: ${error}`
|
|
674
721
|
);
|
|
675
|
-
const file = await readCollectionFile(collection, relativePath);
|
|
676
|
-
if (file) {
|
|
677
|
-
changed2 = true;
|
|
678
|
-
if (index === -1) {
|
|
679
|
-
collection.files.push(file);
|
|
680
|
-
collection.files.sort(orderByPath);
|
|
681
|
-
} else {
|
|
682
|
-
collection.files[index] = file;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
722
|
}
|
|
686
|
-
return changed2;
|
|
687
|
-
}
|
|
688
|
-
return {
|
|
689
|
-
deleted,
|
|
690
|
-
changed
|
|
691
723
|
};
|
|
692
724
|
}
|
|
693
725
|
|
|
694
|
-
// src/transformer.ts
|
|
695
|
-
import os from "node:os";
|
|
696
|
-
import { basename, dirname as dirname2, extname, join as join3 } from "node:path";
|
|
697
|
-
import pLimit from "p-limit";
|
|
698
|
-
|
|
699
|
-
// src/config.ts
|
|
700
|
-
import { z } from "zod";
|
|
701
|
-
|
|
702
|
-
// src/warn.ts
|
|
703
|
-
var deprecations = {
|
|
704
|
-
legacySchema: `The use of a function as a schema is deprecated.
|
|
705
|
-
Please use a StandardSchema compliant library directly.
|
|
706
|
-
For more information, see:
|
|
707
|
-
https://content-collections.dev/docs/deprecations/schema-as-function`
|
|
708
|
-
};
|
|
709
|
-
var _suppressDeprecatedWarnings = [];
|
|
710
|
-
function suppressDeprecatedWarnings(...deprecations2) {
|
|
711
|
-
for (const deprecation of deprecations2) {
|
|
712
|
-
if (deprecation === "all") {
|
|
713
|
-
_suppressDeprecatedWarnings.push(
|
|
714
|
-
...Object.keys(deprecations2)
|
|
715
|
-
);
|
|
716
|
-
return;
|
|
717
|
-
} else {
|
|
718
|
-
_suppressDeprecatedWarnings.push(deprecation);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
function warnDeprecated(deprecation, logger = console.warn) {
|
|
723
|
-
if (_suppressDeprecatedWarnings.includes(deprecation)) {
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
logger(`[CC DEPRECATED]: ${deprecations[deprecation]}`);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
726
|
// src/config.ts
|
|
730
727
|
var skippedSymbol = Symbol("skipped");
|
|
731
728
|
var InvalidReturnTypeSymbol = Symbol(`InvalidReturnType`);
|
|
@@ -737,6 +734,11 @@ function defineCollection(collection) {
|
|
|
737
734
|
let parser = collection.parser;
|
|
738
735
|
if (!parser) {
|
|
739
736
|
parser = "frontmatter";
|
|
737
|
+
} else if (!isValidParser(parser)) {
|
|
738
|
+
throw new ConfigurationError(
|
|
739
|
+
"Read",
|
|
740
|
+
`Parser ${parser} is not valid a parser`
|
|
741
|
+
);
|
|
740
742
|
}
|
|
741
743
|
let schema2 = collection.schema;
|
|
742
744
|
if (!schema2["~standard"]) {
|
|
@@ -1264,13 +1266,24 @@ async function createBuilder(configurationPath, options = {
|
|
|
1264
1266
|
}, emitter = createEmitter()) {
|
|
1265
1267
|
const readConfiguration = createConfigurationReader();
|
|
1266
1268
|
const baseDirectory = path9.dirname(configurationPath);
|
|
1269
|
+
const configuration = await readConfiguration(configurationPath, options);
|
|
1270
|
+
return createInternalBuilder(
|
|
1271
|
+
configuration,
|
|
1272
|
+
baseDirectory,
|
|
1273
|
+
options,
|
|
1274
|
+
emitter
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
async function createInternalBuilder(initialConfiguration, baseDirectory, options, emitter) {
|
|
1278
|
+
const readConfiguration = createConfigurationReader();
|
|
1279
|
+
const configurationPath = initialConfiguration.path;
|
|
1267
1280
|
const outputDirectory = resolveOutputDir(baseDirectory, options);
|
|
1268
1281
|
emitter.emit("builder:created", {
|
|
1269
1282
|
createdAt: Date.now(),
|
|
1270
1283
|
configurationPath,
|
|
1271
1284
|
outputDirectory
|
|
1272
1285
|
});
|
|
1273
|
-
let configuration =
|
|
1286
|
+
let configuration = initialConfiguration;
|
|
1274
1287
|
let watcher = null;
|
|
1275
1288
|
let context2 = await createBuildContext({
|
|
1276
1289
|
emitter,
|
|
@@ -1363,6 +1376,7 @@ export {
|
|
|
1363
1376
|
TransformError,
|
|
1364
1377
|
createBuilder,
|
|
1365
1378
|
createDefaultImport,
|
|
1379
|
+
createInternalBuilder,
|
|
1366
1380
|
createNamedImport,
|
|
1367
1381
|
defineCollection,
|
|
1368
1382
|
defineConfig,
|