@jxsuite/parser 4.2.0 → 4.3.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/content-loader.js +226 -153
- package/dist/content.js +3 -0
- package/dist/markdown.js +199 -145
- package/dist/serialize.js +7 -1
- package/package.json +4 -4
- package/schemas/project.fragment.schema.json +223 -4
- package/src/Content.class.json +4 -0
- package/src/content-loader.ts +64 -17
- package/src/content-rules.ts +8 -220
- package/src/serialize.ts +10 -1
- package/src/types.ts +5 -0
package/dist/content-loader.js
CHANGED
|
@@ -80,6 +80,9 @@ function isRef(value) {
|
|
|
80
80
|
function isNodeObject(value) {
|
|
81
81
|
return isJsonObject(value);
|
|
82
82
|
}
|
|
83
|
+
function isTemplateString(value) {
|
|
84
|
+
return typeof value === "string" && value.includes("${");
|
|
85
|
+
}
|
|
83
86
|
function isPlainTagName(tagName) {
|
|
84
87
|
return typeof tagName === "string";
|
|
85
88
|
}
|
|
@@ -272,6 +275,195 @@ var init_alerts = __esm(() => {
|
|
|
272
275
|
LINE_END = /\r?\n/;
|
|
273
276
|
});
|
|
274
277
|
|
|
278
|
+
// ../../packages/schema/src/content-query.ts
|
|
279
|
+
function isPlainObject(value) {
|
|
280
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
281
|
+
}
|
|
282
|
+
function comparable(value) {
|
|
283
|
+
if (value instanceof Date) {
|
|
284
|
+
if (Number.isNaN(value.getTime())) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const iso = value.toISOString();
|
|
288
|
+
return iso.endsWith("T00:00:00.000Z") ? iso.slice(0, 10) : iso.replace(/\.\d{3}Z$/, "Z");
|
|
289
|
+
}
|
|
290
|
+
return value;
|
|
291
|
+
}
|
|
292
|
+
function deepEqual(a, b) {
|
|
293
|
+
if (a === b) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
297
|
+
return a.length === b.length && a.every((item, i) => deepEqual(comparable(item), comparable(b[i])));
|
|
298
|
+
}
|
|
299
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
300
|
+
const keys = Object.keys(a);
|
|
301
|
+
return keys.length === Object.keys(b).length && keys.every((key) => (key in b) && deepEqual(comparable(a[key]), comparable(b[key])));
|
|
302
|
+
}
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
function sameValue(actual, expected) {
|
|
306
|
+
const a = comparable(actual);
|
|
307
|
+
if (Array.isArray(expected) || isPlainObject(expected)) {
|
|
308
|
+
return deepEqual(a, expected);
|
|
309
|
+
}
|
|
310
|
+
if (Array.isArray(a)) {
|
|
311
|
+
return a.some((item) => comparable(item) === expected);
|
|
312
|
+
}
|
|
313
|
+
return a === expected;
|
|
314
|
+
}
|
|
315
|
+
function readField(data, key) {
|
|
316
|
+
if (Object.hasOwn(data, key)) {
|
|
317
|
+
return data[key];
|
|
318
|
+
}
|
|
319
|
+
if (!key.includes(".")) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
return readPath(data, key.split("."));
|
|
323
|
+
}
|
|
324
|
+
function readPath(holder, [part, ...rest]) {
|
|
325
|
+
if (part === undefined || !isPlainObject(holder) || !Object.hasOwn(holder, part)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const value = holder[part];
|
|
329
|
+
return rest.length === 0 ? value : readPath(value, rest);
|
|
330
|
+
}
|
|
331
|
+
function order(actual, operand) {
|
|
332
|
+
const a = comparable(actual);
|
|
333
|
+
if (isNumber(a) && isNumber(operand)) {
|
|
334
|
+
return a - operand;
|
|
335
|
+
}
|
|
336
|
+
if (isString(a) && isString(operand)) {
|
|
337
|
+
return a < operand ? -1 : a > operand ? 1 : 0;
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
function isNowOperand(operand) {
|
|
342
|
+
return isPlainObject(operand) && operand.$now === true && Object.keys(operand).length === 1;
|
|
343
|
+
}
|
|
344
|
+
function timeOf(value) {
|
|
345
|
+
const time = value instanceof Date ? value.getTime() : isString(value) ? Date.parse(value) : Number.NaN;
|
|
346
|
+
return Number.isNaN(time) ? undefined : time;
|
|
347
|
+
}
|
|
348
|
+
function operatorTest(where, op, operand, ctx) {
|
|
349
|
+
switch (op) {
|
|
350
|
+
case "$eq": {
|
|
351
|
+
return (actual) => sameValue(actual, operand);
|
|
352
|
+
}
|
|
353
|
+
case "$ne": {
|
|
354
|
+
return (actual) => !sameValue(actual, operand);
|
|
355
|
+
}
|
|
356
|
+
case "$in":
|
|
357
|
+
case "$nin": {
|
|
358
|
+
if (!Array.isArray(operand)) {
|
|
359
|
+
throw new TypeError(`${where}.${op}: expected an array, got ${JSON.stringify(operand)}`);
|
|
360
|
+
}
|
|
361
|
+
const hit = (actual) => operand.some((candidate) => sameValue(actual, candidate));
|
|
362
|
+
return op === "$in" ? hit : (actual) => !hit(actual);
|
|
363
|
+
}
|
|
364
|
+
case "$exists": {
|
|
365
|
+
if (!isBoolean(operand)) {
|
|
366
|
+
throw new TypeError(`${where}.$exists: expected true or false, got ${JSON.stringify(operand)}`);
|
|
367
|
+
}
|
|
368
|
+
return (actual) => (actual !== undefined && actual !== null) === operand;
|
|
369
|
+
}
|
|
370
|
+
default: {
|
|
371
|
+
const test = (diff) => op === "$gt" ? diff > 0 : op === "$gte" ? diff >= 0 : op === "$lt" ? diff < 0 : diff <= 0;
|
|
372
|
+
if (isNowOperand(operand)) {
|
|
373
|
+
return (actual) => {
|
|
374
|
+
if (actual === undefined || actual === null) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
const time = timeOf(actual);
|
|
378
|
+
return time === undefined ? ctx.onBadDate : test(time - ctx.now().getTime());
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if (!isString(operand) && !isNumber(operand)) {
|
|
382
|
+
throw new TypeError(`${where}.${op}: expected a string or number, got ${JSON.stringify(operand)}`);
|
|
383
|
+
}
|
|
384
|
+
return (actual) => {
|
|
385
|
+
const diff = order(actual, operand);
|
|
386
|
+
return diff !== undefined && test(diff);
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function operatorKeys(condition) {
|
|
392
|
+
const keys = Object.keys(condition);
|
|
393
|
+
const dollars = keys.filter((key) => key.startsWith("$"));
|
|
394
|
+
if (dollars.length === 0) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return dollars.length === keys.length ? keys : [];
|
|
398
|
+
}
|
|
399
|
+
function compileCondition(key, condition, ctx) {
|
|
400
|
+
const where = `${ctx.name}.${key}`;
|
|
401
|
+
if (!isPlainObject(condition)) {
|
|
402
|
+
return (actual) => sameValue(actual, condition);
|
|
403
|
+
}
|
|
404
|
+
const ops = operatorKeys(condition);
|
|
405
|
+
if (ops === null) {
|
|
406
|
+
return (actual) => deepEqual(comparable(actual), condition);
|
|
407
|
+
}
|
|
408
|
+
if (ops.length === 0) {
|
|
409
|
+
throw new TypeError(`${where}: cannot mix $operators with plain keys in one condition`);
|
|
410
|
+
}
|
|
411
|
+
const tests = ops.map((op) => {
|
|
412
|
+
if (!OPERATORS.has(op)) {
|
|
413
|
+
throw new TypeError(`${where}: unknown operator "${op}" (use ${[...OPERATORS].join(", ")})`);
|
|
414
|
+
}
|
|
415
|
+
return operatorTest(where, op, condition[op], ctx);
|
|
416
|
+
});
|
|
417
|
+
return (actual) => tests.every((test) => test(actual));
|
|
418
|
+
}
|
|
419
|
+
function compileFields(query, ctx) {
|
|
420
|
+
return Object.entries(query).map(([key, condition]) => {
|
|
421
|
+
if (key.startsWith("$")) {
|
|
422
|
+
throw new TypeError(`${ctx.name}.${key}: top-level operators are not supported, conditions on different fields already combine with AND`);
|
|
423
|
+
}
|
|
424
|
+
return { key, test: compileCondition(key, condition, ctx) };
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function compileWhere(where, options = {}) {
|
|
428
|
+
if (where === undefined) {
|
|
429
|
+
return Object.assign(() => true, { why: nothing });
|
|
430
|
+
}
|
|
431
|
+
if (!isPlainObject(where)) {
|
|
432
|
+
throw new TypeError(`"where" must be an object mapping frontmatter fields to conditions`);
|
|
433
|
+
}
|
|
434
|
+
const ctx = { name: "where", now: options.now ?? realClock, onBadDate: false };
|
|
435
|
+
const tests = compileFields(where, ctx);
|
|
436
|
+
return Object.assign((data) => tests.every(({ key, test }) => test(readField(data, key))), {
|
|
437
|
+
why: (data) => tests.find(({ key, test }) => !test(readField(data, key)))?.key
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
function compileHold(hold, options = {}) {
|
|
441
|
+
if (hold === undefined) {
|
|
442
|
+
return nothing;
|
|
443
|
+
}
|
|
444
|
+
if (!Array.isArray(hold)) {
|
|
445
|
+
throw new TypeError(`"hold" must be an array of { "label", "when" } rules`);
|
|
446
|
+
}
|
|
447
|
+
const now = options.now ?? realClock;
|
|
448
|
+
const rules = hold.map((rule, index) => {
|
|
449
|
+
const at = `hold[${index}]`;
|
|
450
|
+
if (!isPlainObject(rule) || !isString(rule.label) || rule.label.trim() === "") {
|
|
451
|
+
throw new TypeError(`${at}: expected a non-empty "label"`);
|
|
452
|
+
}
|
|
453
|
+
if (!isPlainObject(rule.when) || Object.keys(rule.when).length === 0) {
|
|
454
|
+
throw new TypeError(`${at}: expected "when" to name at least one frontmatter field`);
|
|
455
|
+
}
|
|
456
|
+
const ctx = { name: `${at}.when`, now, onBadDate: true };
|
|
457
|
+
return { label: rule.label, tests: compileFields(rule.when, ctx) };
|
|
458
|
+
});
|
|
459
|
+
return (data) => rules.find(({ tests }) => tests.every(({ key, test }) => test(readField(data, key))))?.label;
|
|
460
|
+
}
|
|
461
|
+
var OPERATORS, nothing = () => {}, realClock = () => new Date;
|
|
462
|
+
var init_content_query = __esm(() => {
|
|
463
|
+
init_guards();
|
|
464
|
+
OPERATORS = new Set(["$eq", "$ne", "$in", "$nin", "$exists", "$gt", "$gte", "$lt", "$lte"]);
|
|
465
|
+
});
|
|
466
|
+
|
|
275
467
|
// src/content-rules.ts
|
|
276
468
|
function escapeRegExp(text) {
|
|
277
469
|
return text.replaceAll(REGEXP_SPECIAL, String.raw`\$&`);
|
|
@@ -397,7 +589,7 @@ function mayNameDirectory(pattern) {
|
|
|
397
589
|
}
|
|
398
590
|
function compileExclude(patterns) {
|
|
399
591
|
if (patterns === undefined) {
|
|
400
|
-
return { empty: true, excludedBy:
|
|
592
|
+
return { empty: true, excludedBy: nothing2, excludesDir: () => false };
|
|
401
593
|
}
|
|
402
594
|
if (!Array.isArray(patterns)) {
|
|
403
595
|
throw new TypeError(`"exclude" must be an array of glob patterns`);
|
|
@@ -437,152 +629,11 @@ function compileExclude(patterns) {
|
|
|
437
629
|
excludedBy: (path) => files.find((f) => f.re.test(path))?.pattern
|
|
438
630
|
};
|
|
439
631
|
}
|
|
440
|
-
|
|
441
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
442
|
-
}
|
|
443
|
-
function comparable(value) {
|
|
444
|
-
if (value instanceof Date) {
|
|
445
|
-
if (Number.isNaN(value.getTime())) {
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
const iso = value.toISOString();
|
|
449
|
-
return iso.endsWith("T00:00:00.000Z") ? iso.slice(0, 10) : iso.replace(/\.\d{3}Z$/, "Z");
|
|
450
|
-
}
|
|
451
|
-
return value;
|
|
452
|
-
}
|
|
453
|
-
function deepEqual(a, b) {
|
|
454
|
-
if (a === b) {
|
|
455
|
-
return true;
|
|
456
|
-
}
|
|
457
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
458
|
-
return a.length === b.length && a.every((item, i) => deepEqual(comparable(item), comparable(b[i])));
|
|
459
|
-
}
|
|
460
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
461
|
-
const keys = Object.keys(a);
|
|
462
|
-
return keys.length === Object.keys(b).length && keys.every((key) => (key in b) && deepEqual(comparable(a[key]), comparable(b[key])));
|
|
463
|
-
}
|
|
464
|
-
return false;
|
|
465
|
-
}
|
|
466
|
-
function sameValue(actual, expected) {
|
|
467
|
-
const a = comparable(actual);
|
|
468
|
-
if (Array.isArray(expected) || isPlainObject(expected)) {
|
|
469
|
-
return deepEqual(a, expected);
|
|
470
|
-
}
|
|
471
|
-
if (Array.isArray(a)) {
|
|
472
|
-
return a.some((item) => comparable(item) === expected);
|
|
473
|
-
}
|
|
474
|
-
return a === expected;
|
|
475
|
-
}
|
|
476
|
-
function readField(data, key) {
|
|
477
|
-
if (Object.hasOwn(data, key)) {
|
|
478
|
-
return data[key];
|
|
479
|
-
}
|
|
480
|
-
if (!key.includes(".")) {
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
return readPath(data, key.split("."));
|
|
484
|
-
}
|
|
485
|
-
function readPath(holder, [part, ...rest]) {
|
|
486
|
-
if (part === undefined || !isPlainObject(holder) || !Object.hasOwn(holder, part)) {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
const value = holder[part];
|
|
490
|
-
return rest.length === 0 ? value : readPath(value, rest);
|
|
491
|
-
}
|
|
492
|
-
function order(actual, operand) {
|
|
493
|
-
const a = comparable(actual);
|
|
494
|
-
if (isNumber(a) && isNumber(operand)) {
|
|
495
|
-
return a - operand;
|
|
496
|
-
}
|
|
497
|
-
if (isString(a) && isString(operand)) {
|
|
498
|
-
return a < operand ? -1 : a > operand ? 1 : 0;
|
|
499
|
-
}
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
function operatorTest(where, op, operand) {
|
|
503
|
-
switch (op) {
|
|
504
|
-
case "$eq": {
|
|
505
|
-
return (actual) => sameValue(actual, operand);
|
|
506
|
-
}
|
|
507
|
-
case "$ne": {
|
|
508
|
-
return (actual) => !sameValue(actual, operand);
|
|
509
|
-
}
|
|
510
|
-
case "$in":
|
|
511
|
-
case "$nin": {
|
|
512
|
-
if (!Array.isArray(operand)) {
|
|
513
|
-
throw new TypeError(`${where}.${op}: expected an array, got ${JSON.stringify(operand)}`);
|
|
514
|
-
}
|
|
515
|
-
const hit = (actual) => operand.some((candidate) => sameValue(actual, candidate));
|
|
516
|
-
return op === "$in" ? hit : (actual) => !hit(actual);
|
|
517
|
-
}
|
|
518
|
-
case "$exists": {
|
|
519
|
-
if (!isBoolean(operand)) {
|
|
520
|
-
throw new TypeError(`${where}.$exists: expected true or false, got ${JSON.stringify(operand)}`);
|
|
521
|
-
}
|
|
522
|
-
return (actual) => (actual !== undefined && actual !== null) === operand;
|
|
523
|
-
}
|
|
524
|
-
default: {
|
|
525
|
-
if (!isString(operand) && !isNumber(operand)) {
|
|
526
|
-
throw new TypeError(`${where}.${op}: expected a string or number, got ${JSON.stringify(operand)}`);
|
|
527
|
-
}
|
|
528
|
-
const test = (diff) => op === "$gt" ? diff > 0 : op === "$gte" ? diff >= 0 : op === "$lt" ? diff < 0 : diff <= 0;
|
|
529
|
-
return (actual) => {
|
|
530
|
-
const diff = order(actual, operand);
|
|
531
|
-
return diff !== undefined && test(diff);
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
function operatorKeys(condition) {
|
|
537
|
-
const keys = Object.keys(condition);
|
|
538
|
-
const dollars = keys.filter((key) => key.startsWith("$"));
|
|
539
|
-
if (dollars.length === 0) {
|
|
540
|
-
return null;
|
|
541
|
-
}
|
|
542
|
-
return dollars.length === keys.length ? keys : [];
|
|
543
|
-
}
|
|
544
|
-
function compileCondition(key, condition) {
|
|
545
|
-
const where = `where.${key}`;
|
|
546
|
-
if (!isPlainObject(condition)) {
|
|
547
|
-
return (actual) => sameValue(actual, condition);
|
|
548
|
-
}
|
|
549
|
-
const ops = operatorKeys(condition);
|
|
550
|
-
if (ops === null) {
|
|
551
|
-
return (actual) => deepEqual(comparable(actual), condition);
|
|
552
|
-
}
|
|
553
|
-
if (ops.length === 0) {
|
|
554
|
-
throw new TypeError(`${where}: cannot mix $operators with plain keys in one condition`);
|
|
555
|
-
}
|
|
556
|
-
const tests = ops.map((op) => {
|
|
557
|
-
if (!OPERATORS.has(op)) {
|
|
558
|
-
throw new TypeError(`${where}: unknown operator "${op}" (use ${[...OPERATORS].join(", ")})`);
|
|
559
|
-
}
|
|
560
|
-
return operatorTest(where, op, condition[op]);
|
|
561
|
-
});
|
|
562
|
-
return (actual) => tests.every((test) => test(actual));
|
|
563
|
-
}
|
|
564
|
-
function compileWhere(where) {
|
|
565
|
-
if (where === undefined) {
|
|
566
|
-
return Object.assign(() => true, { why: nothing });
|
|
567
|
-
}
|
|
568
|
-
if (!isPlainObject(where)) {
|
|
569
|
-
throw new TypeError(`"where" must be an object mapping frontmatter fields to conditions`);
|
|
570
|
-
}
|
|
571
|
-
const tests = Object.entries(where).map(([key, condition]) => {
|
|
572
|
-
if (key.startsWith("$")) {
|
|
573
|
-
throw new TypeError(`where.${key}: top-level operators are not supported, conditions on different fields already combine with AND`);
|
|
574
|
-
}
|
|
575
|
-
return { key, test: compileCondition(key, condition) };
|
|
576
|
-
});
|
|
577
|
-
return Object.assign((data) => tests.every(({ key, test }) => test(readField(data, key))), {
|
|
578
|
-
why: (data) => tests.find(({ key, test }) => !test(readField(data, key)))?.key
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
var nothing = () => {}, REGEXP_SPECIAL, MAX_STAR_RUNS = 4, OPERATORS;
|
|
632
|
+
var nothing2 = () => {}, REGEXP_SPECIAL, MAX_STAR_RUNS = 4;
|
|
582
633
|
var init_content_rules = __esm(() => {
|
|
583
634
|
init_guards();
|
|
635
|
+
init_content_query();
|
|
584
636
|
REGEXP_SPECIAL = /[$()*+.?[\\\]^{|}]/g;
|
|
585
|
-
OPERATORS = new Set(["$eq", "$ne", "$in", "$nin", "$exists", "$gt", "$gte", "$lt", "$lte"]);
|
|
586
637
|
});
|
|
587
638
|
|
|
588
639
|
// ../../node_modules/bail/index.js
|
|
@@ -34647,7 +34698,7 @@ function isNonRelativeRef(value) {
|
|
|
34647
34698
|
}
|
|
34648
34699
|
var DOCUMENT_EXTENSIONS = new Set([".md", ".markdown", ".mdx"]);
|
|
34649
34700
|
function mountFilterFor(def) {
|
|
34650
|
-
if (!def || def.exclude === undefined && def.where === undefined && def.route === undefined) {
|
|
34701
|
+
if (!def || def.exclude === undefined && def.where === undefined && def.hold === undefined && def.route === undefined) {
|
|
34651
34702
|
return;
|
|
34652
34703
|
}
|
|
34653
34704
|
let exclude;
|
|
@@ -34799,11 +34850,11 @@ function loadContentConfig(projectRoot, projectConfig) {
|
|
|
34799
34850
|
const config = { content: projectConfig?.content ?? {} };
|
|
34800
34851
|
return { config, contentDir };
|
|
34801
34852
|
}
|
|
34802
|
-
async function loadContentSection(section, root, formats, projectConfig) {
|
|
34853
|
+
async function loadContentSection(section, root, formats, projectConfig, includeHeld) {
|
|
34803
34854
|
const contentTypes = new Map;
|
|
34804
34855
|
const mounts = sectionMounts(section, root, projectConfig);
|
|
34805
34856
|
for (const name of Object.keys(section)) {
|
|
34806
|
-
contentTypes.set(name, await loadSectionType(name, { formats, mounts, projectConfig, root, section }));
|
|
34857
|
+
contentTypes.set(name, await loadSectionType(name, { formats, includeHeld, mounts, projectConfig, root, section }));
|
|
34807
34858
|
}
|
|
34808
34859
|
return contentTypes;
|
|
34809
34860
|
}
|
|
@@ -34814,7 +34865,7 @@ function sectionMounts(section, root, projectConfig) {
|
|
|
34814
34865
|
]));
|
|
34815
34866
|
}
|
|
34816
34867
|
async function loadSectionType(name, source) {
|
|
34817
|
-
const { section, root, formats, projectConfig, mounts, onDeferred } = source;
|
|
34868
|
+
const { section, root, formats, projectConfig, mounts, onDeferred, includeHeld } = source;
|
|
34818
34869
|
const contentTypeDef = section[name];
|
|
34819
34870
|
if (!contentTypeDef) {
|
|
34820
34871
|
return [];
|
|
@@ -34823,6 +34874,7 @@ async function loadSectionType(name, source) {
|
|
|
34823
34874
|
const typeSource = contentTypeDef.source;
|
|
34824
34875
|
if (!isString(typeSource) || !typeSource.includes(LOCALE_PLACEHOLDER)) {
|
|
34825
34876
|
return await loadContentType(name, contentTypeDef, root, formats, {
|
|
34877
|
+
includeHeld,
|
|
34826
34878
|
mount: mounts.get(name),
|
|
34827
34879
|
projectConfig,
|
|
34828
34880
|
...deferral
|
|
@@ -34837,6 +34889,7 @@ async function loadSectionType(name, source) {
|
|
|
34837
34889
|
for (const locale of locales) {
|
|
34838
34890
|
const localized = { ...contentTypeDef, source: localeSource(root, typeSource, locale) };
|
|
34839
34891
|
const entries = await loadContentType(name, localized, root, formats, {
|
|
34892
|
+
includeHeld,
|
|
34840
34893
|
locale,
|
|
34841
34894
|
mount: mounts.get(`${name}/${locale}`),
|
|
34842
34895
|
projectConfig,
|
|
@@ -34863,6 +34916,7 @@ var KNOWN_TYPE_KEYS = [
|
|
|
34863
34916
|
"alerts",
|
|
34864
34917
|
"exclude",
|
|
34865
34918
|
"format",
|
|
34919
|
+
"hold",
|
|
34866
34920
|
"idField",
|
|
34867
34921
|
"indexRoute",
|
|
34868
34922
|
"links",
|
|
@@ -34922,7 +34976,8 @@ function compileTypeRules(name, def) {
|
|
|
34922
34976
|
idField: def.idField,
|
|
34923
34977
|
links,
|
|
34924
34978
|
route: parseRouteConfig(def.route, def.indexRoute, name),
|
|
34925
|
-
where: def.where === undefined ? null : compileWhere(def.where)
|
|
34979
|
+
where: def.where === undefined ? null : compileWhere(def.where),
|
|
34980
|
+
hold: def.hold === undefined ? null : compileHold(def.hold)
|
|
34926
34981
|
};
|
|
34927
34982
|
} catch (error) {
|
|
34928
34983
|
const message = errorMessage(error);
|
|
@@ -34937,6 +34992,7 @@ function finishEntries(files, ctx) {
|
|
|
34937
34992
|
const { name, rules } = ctx;
|
|
34938
34993
|
const kept = [];
|
|
34939
34994
|
const unpublished = new Map;
|
|
34995
|
+
const held = [];
|
|
34940
34996
|
let loadedCount = 0;
|
|
34941
34997
|
for (const file of files) {
|
|
34942
34998
|
const keep = [];
|
|
@@ -34946,8 +35002,19 @@ function finishEntries(files, ctx) {
|
|
|
34946
35002
|
if (file.rel !== null && file.entries.length === 1) {
|
|
34947
35003
|
unpublished.set(file.rel, `left out by where.${rules.where.why(entry.data) ?? "filter"}`);
|
|
34948
35004
|
}
|
|
34949
|
-
|
|
35005
|
+
continue;
|
|
35006
|
+
}
|
|
35007
|
+
const hold = rules.hold?.(entry.data);
|
|
35008
|
+
if (hold === undefined) {
|
|
35009
|
+
keep.push(entry);
|
|
35010
|
+
} else if (ctx.includeHeld === true) {
|
|
35011
|
+
entry._meta = { ...entry._meta, hold };
|
|
34950
35012
|
keep.push(entry);
|
|
35013
|
+
} else {
|
|
35014
|
+
held.push(`${file.rel ?? entry.id} (${hold})`);
|
|
35015
|
+
if (file.rel !== null && file.entries.length === 1) {
|
|
35016
|
+
unpublished.set(file.rel, `held: ${hold}`);
|
|
35017
|
+
}
|
|
34951
35018
|
}
|
|
34952
35019
|
}
|
|
34953
35020
|
if (keep.length > 0) {
|
|
@@ -34958,6 +35025,9 @@ function finishEntries(files, ctx) {
|
|
|
34958
35025
|
const [first] = files.flatMap((file) => file.entries);
|
|
34959
35026
|
console.warn(`Content type "${name}": "where" left out all ${loadedCount} entries, so the collection is ` + `empty (it failed on "${first ? rules.where.why(first.data) ?? "?" : "?"}" for the first one). ` + `Check the field names and the value types: YAML \`true\` is a boolean, "true" is text.`);
|
|
34960
35027
|
}
|
|
35028
|
+
if (held.length > 0) {
|
|
35029
|
+
console.info(`Content type "${name}": holding ${held.length} from this build: ${held.join(", ")}`);
|
|
35030
|
+
}
|
|
34961
35031
|
for (const file of kept) {
|
|
34962
35032
|
for (const entry of file.entries) {
|
|
34963
35033
|
if (file.rel !== null) {
|
|
@@ -35225,12 +35295,13 @@ async function loadContentType(name, contentTypeDef, projectRoot, registry, opti
|
|
|
35225
35295
|
if (!source) {
|
|
35226
35296
|
return [];
|
|
35227
35297
|
}
|
|
35228
|
-
const { mount, projectConfig, locale, deferBody, onDeferred } = options;
|
|
35298
|
+
const { mount, projectConfig, locale, deferBody, onDeferred, includeHeld } = options;
|
|
35229
35299
|
const { schema } = contentTypeDef;
|
|
35230
35300
|
const rules = compileTypeRules(name, contentTypeDef);
|
|
35231
35301
|
const finishContext = (extra) => ({
|
|
35232
35302
|
coerceDates: false,
|
|
35233
35303
|
entryExtensions: new Set,
|
|
35304
|
+
includeHeld,
|
|
35234
35305
|
locale,
|
|
35235
35306
|
mount,
|
|
35236
35307
|
name,
|
|
@@ -35519,7 +35590,7 @@ class ContentStore extends Map {
|
|
|
35519
35590
|
}
|
|
35520
35591
|
static async whole(source) {
|
|
35521
35592
|
const store = new ContentStore(source);
|
|
35522
|
-
const loaded = await loadContentSection(source.section, source.root, source.formats, source.projectConfig);
|
|
35593
|
+
const loaded = await loadContentSection(source.section, source.root, source.formats, source.projectConfig, source.includeHeld);
|
|
35523
35594
|
for (const [name, entries] of loaded) {
|
|
35524
35595
|
store.#adopt(name, entries);
|
|
35525
35596
|
store.#loads.set(name, Promise.resolve());
|
|
@@ -35594,8 +35665,9 @@ class ContentStore extends Map {
|
|
|
35594
35665
|
#loadType(name) {
|
|
35595
35666
|
let load = this.#loads.get(name);
|
|
35596
35667
|
if (!load) {
|
|
35597
|
-
const { section, root, formats, projectConfig } = this.#source;
|
|
35668
|
+
const { section, root, formats, projectConfig, includeHeld } = this.#source;
|
|
35598
35669
|
load = loadSectionType(name, {
|
|
35670
|
+
includeHeld,
|
|
35599
35671
|
formats,
|
|
35600
35672
|
mounts: this.#mounts,
|
|
35601
35673
|
onDeferred: (entry, completeBody) => {
|
|
@@ -35646,6 +35718,7 @@ class Content {
|
|
|
35646
35718
|
static async projectData(sectionValue, ctx) {
|
|
35647
35719
|
const source = {
|
|
35648
35720
|
formats: ctx.registry.formats,
|
|
35721
|
+
includeHeld: ctx.includeHeld,
|
|
35649
35722
|
projectConfig: ctx.projectConfig,
|
|
35650
35723
|
root: ctx.root,
|
|
35651
35724
|
section: sectionValue ?? {}
|
package/dist/content.js
CHANGED
|
@@ -80,6 +80,9 @@ function isRef(value) {
|
|
|
80
80
|
function isNodeObject(value) {
|
|
81
81
|
return isJsonObject(value);
|
|
82
82
|
}
|
|
83
|
+
function isTemplateString(value) {
|
|
84
|
+
return typeof value === "string" && value.includes("${");
|
|
85
|
+
}
|
|
83
86
|
function isPlainTagName(tagName) {
|
|
84
87
|
return typeof tagName === "string";
|
|
85
88
|
}
|