@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 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(...deprecations: Array<Deprecation | "all">): void;
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 path5 from "node:path";
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 path3 from "node:path";
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 path2 from "path";
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 = path2.parse(startDir).root) => {
526
+ var findUp = (name, startDir, stopDir = path5.parse(startDir).root) => {
223
527
  let dir = startDir;
224
528
  while (dir !== stopDir) {
225
- const file = path2.join(dir, name);
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 = path2.dirname(dir);
537
+ dir = path5.dirname(dir);
234
538
  }
235
539
  return null;
236
540
  };
237
541
  var resolveTsConfigFromFile = (cwd, filename) => {
238
- if (path2.isAbsolute(filename))
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 (path2.isAbsolute(name))
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 = path2.resolve(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 = path2.dirname(id);
561
+ const configDir = path5.dirname(id);
258
562
  if ((_a = data.compilerOptions) == null ? void 0 : _a.baseUrl) {
259
- data.compilerOptions.baseUrl = path2.join(
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 path10.startsWith(otherPath);
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
- function posixToNativePath(pathName) {
517
- if (path4.sep !== path4.posix.sep) {
518
- return pathName.replaceAll(path4.posix.sep, path4.sep);
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
- return pathName;
521
- }
522
- function toError(error) {
523
- return error instanceof Error ? error : new Error(String(error));
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/collector.ts
527
- var CollectError = class extends Error {
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
- function createCollector(emitter, baseDirectory = ".") {
535
- async function read(filePath) {
536
- try {
537
- return await readFile2(filePath, "utf-8");
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
- // src/synchronizer.ts
612
- import path6 from "node:path";
613
- import picomatch from "picomatch";
614
- function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
615
- function findCollections(filePath) {
616
- const resolvedFilePath = path6.resolve(filePath);
617
- return collections.filter((collection) => {
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
- return relativePath;
631
- }
632
- function resolve2(filePath) {
633
- const collections2 = findCollections(filePath);
634
- return collections2.map((collection) => {
635
- const relativePath = createRelativePath(collection.directory, filePath);
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
- collection,
638
- relativePath
711
+ ...module.default,
712
+ path: configurationPath,
713
+ inputPaths: configurationPaths.map((p) => path6.resolve(p)),
714
+ generateTypes: true,
715
+ checksum
639
716
  };
640
- }).filter(({ collection, relativePath }) => {
641
- return picomatch.isMatch(relativePath, collection.include, {
642
- // @see https://github.com/sdorra/content-collections/issues/602
643
- windows: process.platform === "win32",
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 = await readConfiguration(configurationPath, options);
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,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@content-collections/core",
3
3
  "type": "module",
4
- "version": "0.11.0",
4
+ "version": "0.11.1",
5
5
  "description": "Core of Content Collections",
6
6
  "author": "Sebastian Sdorra <s.sdorra@gmail.com>",
7
7
  "license": "MIT",