pro-editor-schema 1.3.0 → 1.4.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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // src/schema/utils/createSchema.ts
1
+ // src/schema/helpers/createSchema.ts
2
2
  var createSchema = (params) => {
3
3
  return params;
4
4
  };
@@ -40,10 +40,13 @@ var TRACK_CHANGES_ATTRS = [
40
40
  ];
41
41
  var ELE_ID_ATTRIBUTE = "ele-id";
42
42
  var STORE_ATTRIBUTE = "store";
43
+ var XMLID_ATTRIBUTE = "xmlid";
44
+ var LINKEND_ATTRIBUTE = "linkend";
43
45
  var ID_ATTRS = [STORE_ATTRIBUTE, ELE_ID_ATTRIBUTE];
44
46
 
45
47
  // src/schema/shared/allowedAtomsChildren.ts
46
48
  var ATOM_CODES_ALLOWED_CHILDREN = [
49
+ { code: "mark", required: false },
47
50
  { code: "indexterm", required: false },
48
51
  { code: "b", required: false },
49
52
  { code: "i", required: false },
@@ -87,6 +90,7 @@ var QUATERNARY_TAG = "QUATERNARY";
87
90
  var BOOKMARK_TAG = "BOOKMARK";
88
91
  var SEE_TAG = "SEE";
89
92
  var REFERENCE_MARK_TAG = "REFERENCE";
93
+ var MARK_TAG = "MARK";
90
94
 
91
95
  // src/schema/elementSchemas/atoms/b.ts
92
96
  var B_SCHEMA = createSchema({
@@ -528,6 +532,23 @@ var ABBR_SCHEMA = createSchema({
528
532
  allowedChildrenCodes: [...ATOM_CODES_ALLOWED_CHILDREN]
529
533
  });
530
534
 
535
+ // src/schema/elementSchemas/atoms/mark.ts
536
+ var MARK_SCHEMA = createSchema({
537
+ code: "mark",
538
+ kind: "atom",
539
+ tag: MARK_TAG,
540
+ requiredAttributes: ["id"],
541
+ optionalAttributes: [
542
+ "data-markjs",
543
+ {
544
+ name: "data-replaceable",
545
+ values: ["true", "false"],
546
+ defaultValue: "true"
547
+ }
548
+ ],
549
+ allowedChildrenCodes: [...ATOM_CODES_ALLOWED_CHILDREN]
550
+ });
551
+
531
552
  // src/schema/elementSchemas/atoms/index.ts
532
553
  var ATOM_SCHEMAS = {
533
554
  indexterm: INDEXTERM_SCHEMA,
@@ -555,7 +576,8 @@ var ATOM_SCHEMAS = {
555
576
  comment: COMMENT_SCHEMA,
556
577
  query: QUERY_SCHEMA,
557
578
  reply: REPLY_SCHEMA,
558
- abbreviation: ABBR_SCHEMA
579
+ abbreviation: ABBR_SCHEMA,
580
+ mark: MARK_SCHEMA
559
581
  };
560
582
 
561
583
  // src/schema/elementSchemas/elements/elementsTags.ts
@@ -622,7 +644,7 @@ var EPIGRAPH_TAG = "EPIGRAPH";
622
644
  var INFO_TAG = "INFO1";
623
645
  var POEM_TAG = "POEM";
624
646
  var BIBLIOMIXED_TAG = "BIBLIOMIXED";
625
- var REFERENCE_BIBLIOGRAPHY_TAG = "REFERENCE_BIBLIOGRAPHY";
647
+ var REFERENCE_BIBLIOGRAPHY_TAG = "BIBLIOGRAPHY";
626
648
  var BIBLIODIV_TAG = "BIBLIODIV";
627
649
  var MATHPHRASE_TAG = "MATHPHRASE";
628
650
  var MATH_TAG = "MATH";
@@ -1981,7 +2003,7 @@ var FOOTNOTE_SECTION_SCHEMA = createSchema({
1981
2003
  });
1982
2004
 
1983
2005
  // src/schema/elementSchemas/elements/heading.ts
1984
- var HEADING_LEVEL = ["H1", "H2", "H3", "H4", "H5", "H6"];
2006
+ var HEADING_LEVEL = ["H0", "H1", "H2", "H3", "H4", "H5", "H6"];
1985
2007
  var HEADING_ROLES = [...HEADING_LEVEL, "vignette_group"];
1986
2008
  var HEADING_SCHEMA = createSchema({
1987
2009
  code: "heading",
@@ -2052,6 +2074,7 @@ var POEM_SCHEMA = createSchema({
2052
2074
  optionalAttributes: [...TRACK_CHANGES_ATTRS, "role", "trackmsg"],
2053
2075
  defaultChildCode: "line",
2054
2076
  allowedChildrenCodes: [
2077
+ { code: "title1", required: false },
2055
2078
  { code: "line", required: false },
2056
2079
  { code: "linegroup", required: false },
2057
2080
  { code: "source1", required: false }
@@ -2347,55 +2370,10 @@ var SCHEMAS = {
2347
2370
  ...INLINE_ELEMENT_SCHEMAS
2348
2371
  };
2349
2372
 
2350
- // src/schema/shared/ignoredElements.ts
2351
- var IGNORED_ELEMENT_SELECTORS = [
2352
- "span.rhlabel",
2353
- "span.printlabel",
2354
- "span.refIcon",
2355
- "span.missLink",
2356
- "span.ref-drag",
2357
- "span#dummySpan"
2358
- ];
2359
- var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
2360
- "referenceBibliomixed"
2361
- ];
2362
-
2363
- // src/schema/shared/ignoredAttributes.ts
2364
- var IGNORED_ATTRIBUTES = [
2365
- // Styling & layout
2366
- "class",
2367
- "style",
2368
- // Editor state
2369
- "contenteditable",
2370
- "draggable",
2371
- "data-prevpos",
2372
- "tabindex",
2373
- // Browser behaviour
2374
- "spellcheck",
2375
- "translate",
2376
- "lang",
2377
- "dir",
2378
- "hidden",
2379
- "data-gramm"
2380
- ];
2381
- var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
2382
-
2383
- // src/schema/utils/utils.ts
2384
- var isTrackChangesSchema = (schema) => schema.code === "insertion" || schema.code === "deletion" || schema.code === "lineGroupRemoval";
2385
- var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
2386
- (startsWith) => attribute.startsWith(startsWith)
2387
- );
2388
- var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
2389
- var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
2390
- var findSchemaByCode = (code) => SCHEMAS[code];
2391
- var findSchemaByElement = (element) => {
2392
- const schema = Object.values(SCHEMAS).find(
2393
- (schema2) => schema2.tag == element.tagName && (!schema2.matchesElement || schema2.matchesElement(element))
2394
- );
2395
- return schema;
2396
- };
2397
- var isAttributeRestricted = (attr) => typeof attr !== "string";
2373
+ // src/schema/helpers/getAttributeName.ts
2398
2374
  var getAttributeName = (attribute) => typeof attribute === "string" ? attribute.toLowerCase() : attribute.name.toLowerCase();
2375
+
2376
+ // src/schema/helpers/findAttributeDefinitionByName.ts
2399
2377
  var findAttributeDefinitionByName = (definitions, name) => {
2400
2378
  for (const def of definitions) {
2401
2379
  if (getAttributeName(def) === name.toLowerCase()) {
@@ -2405,47 +2383,29 @@ var findAttributeDefinitionByName = (definitions, name) => {
2405
2383
  return void 0;
2406
2384
  };
2407
2385
 
2408
- // src/schema/utils/createElement.ts
2409
- var createElement = ({
2410
- schemaCode,
2411
- attributes
2412
- }) => {
2413
- const schema = findSchemaByCode(schemaCode);
2414
- const element = document.createElement(schema.tag.toLowerCase());
2415
- for (const [name, value] of Object.entries(attributes)) {
2416
- if (!value) continue;
2417
- element.setAttribute(name, String(value));
2418
- }
2419
- return element;
2420
- };
2386
+ // src/schema/helpers/findSchemaByCode.ts
2387
+ var findSchemaByCode = (code) => SCHEMAS[code];
2421
2388
 
2422
- // src/schema/utils/queryElementBySchema.ts
2423
- var queryElementBySchema = (content, schemaCode) => {
2424
- const schema = findSchemaByCode(schemaCode);
2425
- const element = content.querySelector(schema.tag.toLowerCase());
2426
- if (!element) return void 0;
2427
- if (schema.matchesElement && !schema.matchesElement(element)) {
2428
- return void 0;
2429
- }
2430
- return element;
2431
- };
2432
- var queryAllElementsBySchema = (content, schemaCode) => {
2433
- const schema = findSchemaByCode(schemaCode);
2434
- const elements = content.querySelectorAll(
2435
- schema.tag.toLowerCase()
2389
+ // src/schema/helpers/matchesSchemaTag.ts
2390
+ var matchesSchemaTag = (element, tag) => element.tagName.toUpperCase() === tag.toUpperCase();
2391
+
2392
+ // src/schema/helpers/findSchemaByElement.ts
2393
+ var findSchemaByElement = (element) => {
2394
+ const schema = Object.values(SCHEMAS).find(
2395
+ (schema2) => matchesSchemaTag(element, schema2.tag) && (!schema2.matchesElement || schema2.matchesElement(element))
2436
2396
  );
2437
- const matchingElements = [];
2438
- for (const element of elements) {
2439
- if (schema.matchesElement && !schema.matchesElement(element)) {
2440
- continue;
2441
- }
2442
- matchingElements.push(element);
2443
- }
2444
- return matchingElements;
2397
+ return schema;
2445
2398
  };
2446
2399
 
2400
+ // src/schema/helpers/isAttributeRestricted.ts
2401
+ var isAttributeRestricted = (attr) => typeof attr !== "string";
2402
+
2403
+ // src/schema/helpers/isTrackChangesSchema.ts
2404
+ var isTrackChangesSchema = (schema) => schema.code === "insertion" || schema.code === "deletion" || schema.code === "lineGroupRemoval";
2405
+
2447
2406
  // src/schema/shared/labelElements.ts
2448
2407
  var ElementLabel = {
2408
+ mark: "Mark",
2449
2409
  referenceBibliomixed: "Reference Bibliomixed",
2450
2410
  referenceBibliography: "Reference Bibliography",
2451
2411
  bibliodiv: "Bibliodiv",
@@ -2580,40 +2540,54 @@ var DEPENDENT_FORBIDDEN_ELEMENTS = [
2580
2540
  }
2581
2541
  ];
2582
2542
 
2583
- // src/validation/utils/generateValidationIssueId.ts
2584
- var generateValidationIssueId = () => {
2585
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2586
- return crypto.randomUUID();
2587
- }
2588
- return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2589
- };
2590
-
2591
- // src/validation/utils/addValidationIssue.ts
2592
- var createValidationIssue = (issue) => ({
2593
- id: generateValidationIssueId(),
2594
- ...issue
2595
- });
2596
- var addValidationIssue = (errors, issue) => {
2597
- errors.push(createValidationIssue(issue));
2598
- };
2543
+ // src/helpers/isIgnoredElement.ts
2544
+ var IGNORED_ELEMENT_SELECTORS = [
2545
+ "span.rhlabel",
2546
+ "span.printlabel",
2547
+ "span.refIcon",
2548
+ "span.missLink",
2549
+ "span.ref-drag",
2550
+ "span#dummySpan"
2551
+ ];
2552
+ var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
2599
2553
 
2600
- // src/validation/utils/getStore.ts
2601
- var getStore = (element) => {
2602
- return element.getAttribute("store") || "";
2603
- };
2554
+ // src/validation/helpers/isIgnoredValidation.ts
2555
+ var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
2556
+ "referenceBibliomixed"
2557
+ ];
2558
+ var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
2604
2559
 
2605
- // src/validation/utils/retrieveTextIgnoringNodesWithSelector.ts
2606
- var retrieveTextIgnoringNodesWithSelector = (element, selector = ".del") => {
2607
- const clonedElement = element.cloneNode(true);
2608
- for (const delElement of clonedElement.querySelectorAll(selector)) {
2609
- delElement.remove();
2560
+ // src/helpers/closestElementBySchema.ts
2561
+ var closestElementBySchema = ({
2562
+ element,
2563
+ code,
2564
+ ignoreDeletedElements = false
2565
+ }) => {
2566
+ const schema = findSchemaByCode(code);
2567
+ if (!schema) return;
2568
+ const closestElement = element.closest(
2569
+ schema.tag.toLowerCase()
2570
+ );
2571
+ if (!closestElement) return;
2572
+ if (schema.matchesElement && !schema.matchesElement(closestElement)) {
2573
+ return;
2610
2574
  }
2611
- return clonedElement.textContent || "";
2575
+ if (ignoreDeletedElements && isDeletedElement(closestElement)) {
2576
+ return closestElementBySchema({
2577
+ element: closestElement,
2578
+ code,
2579
+ ignoreDeletedElements
2580
+ });
2581
+ }
2582
+ return closestElement;
2612
2583
  };
2613
2584
 
2614
- // src/validation/utils/isDeletedElement.ts
2585
+ // src/helpers/isDeletedElement.ts
2615
2586
  var isDeletedElement = (element) => {
2616
- return !!element.closest(".del");
2587
+ return !!closestElementBySchema({
2588
+ element,
2589
+ code: "deletion"
2590
+ });
2617
2591
  };
2618
2592
 
2619
2593
  // src/validation/utils/getElementsSelector.ts
@@ -2629,63 +2603,35 @@ var getElementsSelector = ({
2629
2603
  return elements;
2630
2604
  };
2631
2605
 
2632
- // src/validation/validateLinkend.ts
2633
- var findElementLinkedTo = (linkend, elementsToLink) => {
2634
- return elementsToLink.includes(linkend);
2635
- };
2636
- var LINK_TO_CROSS_CHECK = [
2637
- TABLE_LINK_ROLE,
2638
- FIGURE_LINK_ROLE,
2639
- EQUATION_LINK_ROLE,
2640
- FOOTNOTE_LINK_ROLE,
2641
- REFERENCE_LINK_ROLE
2642
- ];
2643
- var LINK_BLOCKER_ROLES = [
2644
- TABLE_LINK_ROLE,
2645
- FIGURE_LINK_ROLE,
2646
- EQUATION_LINK_ROLE,
2647
- FOOTNOTE_LINK_ROLE
2648
- ];
2649
- var validateLinkend = (linkElement, elementsToLink) => {
2650
- const linkend = linkElement.getAttribute("linkend");
2651
- if (!linkend) {
2652
- return [];
2653
- }
2654
- const isLinkFootnoteCue = linkElement.tagName.toUpperCase() === FOOTNOTE_LINK_SCHEMA.tag;
2655
- if (isLinkFootnoteCue) {
2656
- if (findElementLinkedTo(linkend, elementsToLink)) {
2657
- return [];
2658
- }
2659
- return [
2660
- createValidationIssue({
2661
- store: getStore(linkElement),
2662
- title: "Unlinked footnote cue",
2663
- kind: "unlinked",
2664
- description: "This footnote cue is not referenced to any footnote in this chapter. Please link it again manually.",
2665
- level: "blocker"
2666
- })
2667
- ];
2668
- }
2669
- const role = linkElement.getAttribute("role");
2670
- if (!role) {
2671
- return [];
2672
- }
2673
- if (!LINK_TO_CROSS_CHECK.includes(role)) {
2674
- return [];
2606
+ // src/validation/utils/retrieveTextIgnoringNodesWithSelector.ts
2607
+ var retrieveTextIgnoringNodesWithSelector = (element, selector = ".del") => {
2608
+ const clonedElement = element.cloneNode(true);
2609
+ for (const delElement of clonedElement.querySelectorAll(selector)) {
2610
+ delElement.remove();
2675
2611
  }
2676
- if (findElementLinkedTo(linkend, elementsToLink)) {
2677
- return [];
2612
+ return clonedElement.textContent || "";
2613
+ };
2614
+
2615
+ // src/helpers/getStore.ts
2616
+ var getStore = (element) => {
2617
+ return element.getAttribute(STORE_ATTRIBUTE) || "";
2618
+ };
2619
+
2620
+ // src/validation/helpers/generateValidationIssueId.ts
2621
+ var generateValidationIssueId = () => {
2622
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2623
+ return crypto.randomUUID();
2678
2624
  }
2679
- const isBlocker = LINK_BLOCKER_ROLES.includes(role.toLowerCase());
2680
- return [
2681
- createValidationIssue({
2682
- store: getStore(linkElement),
2683
- title: "Unlinked element",
2684
- kind: "unlinked",
2685
- description: "This link is not referenced to any element in the current chapter or any other chapter. Please link it again manually.",
2686
- level: isBlocker ? "blocker" : "warning"
2687
- })
2688
- ];
2625
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2626
+ };
2627
+
2628
+ // src/validation/helpers/addValidationIssue.ts
2629
+ var createValidationIssue = (issue) => ({
2630
+ id: generateValidationIssueId(),
2631
+ ...issue
2632
+ });
2633
+ var addValidationIssue = (errors, issue) => {
2634
+ errors.push(createValidationIssue(issue));
2689
2635
  };
2690
2636
 
2691
2637
  // src/validation/validateFootnotes.ts
@@ -2698,15 +2644,11 @@ var extractFootnoteNumber = (footnote) => {
2698
2644
  }
2699
2645
  return footnoteNumber;
2700
2646
  };
2701
- var validateFootnoteCue = (footnoteElement, linkElements) => {
2647
+ var validateFootnoteNumber = (footnoteElement) => {
2702
2648
  const errors = [];
2703
- const linkend = footnoteElement.getAttribute("xmlid") || "";
2704
2649
  const footnoteNumber = footnoteElement.querySelector(
2705
2650
  FOOTNOTE_NUMBER_SCHEMA.tag
2706
2651
  );
2707
- if (findElementLinkedTo(linkend, linkElements)) {
2708
- return errors;
2709
- }
2710
2652
  if (!footnoteNumber) {
2711
2653
  addValidationIssue(errors, {
2712
2654
  store: getStore(footnoteElement),
@@ -2716,14 +2658,6 @@ var validateFootnoteCue = (footnoteElement, linkElements) => {
2716
2658
  level: "blocker"
2717
2659
  });
2718
2660
  }
2719
- const label = extractFootnoteNumber(footnoteNumber);
2720
- addValidationIssue(errors, {
2721
- store: getStore(footnoteElement),
2722
- title: "Unreferenced footnote",
2723
- kind: "unlinked",
2724
- description: `The footnote ${label} is not referenced to any footnote cue in this chapter. Please reference it in the chapter.`,
2725
- level: "blocker"
2726
- });
2727
2661
  return errors;
2728
2662
  };
2729
2663
  var validateConsecutiveFootnotes = (root) => {
@@ -2808,6 +2742,92 @@ var validateConsecutiveFootnoteCues = (root) => {
2808
2742
  return errors;
2809
2743
  };
2810
2744
 
2745
+ // src/validation/validateLinkend.ts
2746
+ var findElementLinkedTo = (linkend, elementsToLink) => {
2747
+ return elementsToLink.includes(linkend);
2748
+ };
2749
+ var LINK_TO_CROSS_CHECK = [
2750
+ TABLE_LINK_ROLE,
2751
+ FIGURE_LINK_ROLE,
2752
+ EQUATION_LINK_ROLE,
2753
+ FOOTNOTE_LINK_ROLE,
2754
+ REFERENCE_LINK_ROLE
2755
+ ];
2756
+ var LINK_BLOCKER_ROLES = [
2757
+ TABLE_LINK_ROLE,
2758
+ FIGURE_LINK_ROLE,
2759
+ EQUATION_LINK_ROLE,
2760
+ FOOTNOTE_LINK_ROLE
2761
+ ];
2762
+ var validateLinkend = (linkElement, elementsToLink) => {
2763
+ const linkend = linkElement.getAttribute("linkend");
2764
+ if (!linkend) {
2765
+ return [];
2766
+ }
2767
+ if (findElementLinkedTo(linkend, elementsToLink)) {
2768
+ return [];
2769
+ }
2770
+ const isLinkFootnoteCue = matchesSchemaTag(
2771
+ linkElement,
2772
+ FOOTNOTE_LINK_SCHEMA.tag
2773
+ );
2774
+ if (isLinkFootnoteCue) {
2775
+ return [
2776
+ createValidationIssue({
2777
+ store: getStore(linkElement),
2778
+ title: "Unlinked footnote cue",
2779
+ kind: "unlinked",
2780
+ description: "This footnote cue is not referenced to any footnote in this chapter. Please link it again manually.",
2781
+ level: "blocker"
2782
+ })
2783
+ ];
2784
+ }
2785
+ const isLink = matchesSchemaTag(linkElement, LINK_SCHEMA.tag);
2786
+ if (!isLink) {
2787
+ return [];
2788
+ }
2789
+ const role = linkElement.getAttribute("role");
2790
+ if (!role) {
2791
+ return [];
2792
+ }
2793
+ if (!LINK_TO_CROSS_CHECK.includes(role)) {
2794
+ return [];
2795
+ }
2796
+ const isBlocker = LINK_BLOCKER_ROLES.includes(role.toLowerCase());
2797
+ return [
2798
+ createValidationIssue({
2799
+ store: getStore(linkElement),
2800
+ title: "Unlinked element",
2801
+ kind: "unlinked",
2802
+ description: "This link is not referenced to any element in the current chapter or any other chapter. Please link it again manually.",
2803
+ level: isBlocker ? "blocker" : "warning"
2804
+ })
2805
+ ];
2806
+ };
2807
+
2808
+ // src/helpers/isIgnoredAttribute.ts
2809
+ var IGNORED_ATTRIBUTES = [
2810
+ // Styling & layout
2811
+ "class",
2812
+ "style",
2813
+ // Editor state
2814
+ "contenteditable",
2815
+ "draggable",
2816
+ "data-prevpos",
2817
+ "tabindex",
2818
+ // Browser behaviour
2819
+ "spellcheck",
2820
+ "translate",
2821
+ "lang",
2822
+ "dir",
2823
+ "hidden",
2824
+ "data-gramm"
2825
+ ];
2826
+ var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
2827
+ var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
2828
+ (startsWith) => attribute.startsWith(startsWith)
2829
+ );
2830
+
2811
2831
  // src/validation/validateAttributes.ts
2812
2832
  var validateAttributes = (element, schema) => {
2813
2833
  const errors = [];
@@ -2851,7 +2871,7 @@ var validateAttributes = (element, schema) => {
2851
2871
  // src/validation/validateChildren.ts
2852
2872
  var validateElementAgainstSchema = (element, schema) => {
2853
2873
  const errors = [];
2854
- if (element.tagName.toUpperCase() !== schema.tag) {
2874
+ if (!matchesSchemaTag(element, schema.tag)) {
2855
2875
  addValidationIssue(errors, {
2856
2876
  store: getStore(element),
2857
2877
  title: `Expected ${schema.tag}, got ${element.tagName}`,
@@ -2952,27 +2972,79 @@ var getExtraInstruction = (schema, childSchema) => {
2952
2972
  return "";
2953
2973
  };
2954
2974
 
2955
- // src/validation/validateReferences.ts
2975
+ // src/validation/validateElementToLinkTo.ts
2956
2976
  var findElementLinkedTo2 = (xmlid, linkElements) => {
2957
2977
  return linkElements.includes(xmlid);
2958
2978
  };
2959
- var validateReferenceCited = (referenceElement, linkElements) => {
2960
- const xmlid = referenceElement.getAttribute("xmlid");
2979
+ var isFootnote = (element) => {
2980
+ return matchesSchemaTag(element, FOOTNOTE_SCHEMA.tag);
2981
+ };
2982
+ var isReference = (element) => {
2983
+ return matchesSchemaTag(element, BIBLIOMIXED_SCHEMA.tag) || !!closestElementBySchema({
2984
+ element,
2985
+ code: "referenceBibliography"
2986
+ });
2987
+ };
2988
+ var isTable = (element) => {
2989
+ return matchesSchemaTag(element, TABLE_SCHEMA.tag);
2990
+ };
2991
+ var isFigure = (element) => {
2992
+ return matchesSchemaTag(element, FIGURE_SCHEMA.tag);
2993
+ };
2994
+ var validateElementToLinkTo = (element, linkElements) => {
2995
+ const xmlid = element.getAttribute("xmlid");
2961
2996
  if (!xmlid) {
2962
2997
  return [];
2963
2998
  }
2964
2999
  if (findElementLinkedTo2(xmlid, linkElements)) {
2965
3000
  return [];
2966
3001
  }
2967
- return [
2968
- createValidationIssue({
2969
- store: getStore(referenceElement),
2970
- title: "Unlinked element",
2971
- kind: "unlinked",
2972
- description: "This reference is not cited in this chapter or any other chapter. Please add a link to this reference or delete the reference.",
2973
- level: "warning"
2974
- })
2975
- ];
3002
+ if (isFootnote(element)) {
3003
+ const label = extractFootnoteNumber(element);
3004
+ return [
3005
+ createValidationIssue({
3006
+ store: getStore(element),
3007
+ title: "Uncited footnote",
3008
+ kind: "uncited",
3009
+ description: `The footnote ${label} is not cited to any footnote cue in this chapter. Please reference it in the chapter.`,
3010
+ level: "blocker"
3011
+ })
3012
+ ];
3013
+ }
3014
+ if (isReference(element)) {
3015
+ return [
3016
+ createValidationIssue({
3017
+ store: getStore(element),
3018
+ title: "Uncited reference",
3019
+ kind: "uncited",
3020
+ description: "This reference is not cited in this chapter or any other chapter. Please add a link to this reference or delete it.",
3021
+ level: "warning"
3022
+ })
3023
+ ];
3024
+ }
3025
+ if (isTable(element)) {
3026
+ return [
3027
+ createValidationIssue({
3028
+ store: getStore(element),
3029
+ title: "Uncited table",
3030
+ kind: "uncited",
3031
+ description: "This table is not cited in this chapter or any other chapter. Please add a link to this table or delete it.",
3032
+ level: "warning"
3033
+ })
3034
+ ];
3035
+ }
3036
+ if (isFigure(element)) {
3037
+ return [
3038
+ createValidationIssue({
3039
+ store: getStore(element),
3040
+ title: "Uncited figure",
3041
+ kind: "uncited",
3042
+ description: "This figure is not cited in this chapter or any other chapter. Please add a link to this figure or delete it.",
3043
+ level: "warning"
3044
+ })
3045
+ ];
3046
+ }
3047
+ return [];
2976
3048
  };
2977
3049
 
2978
3050
  // src/validation/validateWeblink.ts
@@ -3024,30 +3096,20 @@ var validatePossibleWeblinks = (root) => {
3024
3096
  return errors;
3025
3097
  };
3026
3098
 
3027
- // src/validation/utils/getParentElement.ts
3028
- var getParentElement = ({
3029
- element,
3030
- schemaCode,
3031
- filterDeletedNodes
3032
- }) => {
3033
- let current = element.parentElement;
3034
- while (current) {
3035
- const isValidParent = findSchemaByElement(current)?.code === schemaCode;
3036
- const isFilterDeleted = filterDeletedNodes && isDeletedElement(current);
3037
- if (isValidParent || isFilterDeleted) {
3038
- return current;
3039
- }
3040
- current = current.parentElement;
3041
- }
3042
- return void 0;
3043
- };
3044
-
3045
3099
  // src/validation/validateHeadingHierarchy.ts
3100
+ var shouldSuppressWarning = (element) => {
3101
+ const closestBox = closestElementBySchema({
3102
+ element,
3103
+ code: BOX_SCHEMA.code,
3104
+ ignoreDeletedElements: true
3105
+ });
3106
+ return !!closestBox;
3107
+ };
3046
3108
  var getHierarchyLevel = (element) => {
3047
3109
  const role = element.getAttribute("role");
3048
3110
  if (!role) return void 0;
3049
- const validHeadingLevel = HEADING_LEVEL.indexOf(role) + 1;
3050
- if (!validHeadingLevel) return void 0;
3111
+ const validHeadingLevel = HEADING_LEVEL.indexOf(role);
3112
+ if (validHeadingLevel === -1) return void 0;
3051
3113
  return validHeadingLevel;
3052
3114
  };
3053
3115
  var validateHeadingHierarchy = (element) => {
@@ -3055,17 +3117,23 @@ var validateHeadingHierarchy = (element) => {
3055
3117
  if (isDeletedElement(element)) {
3056
3118
  return errors;
3057
3119
  }
3120
+ if (shouldSuppressWarning(element)) {
3121
+ return errors;
3122
+ }
3058
3123
  const level = getHierarchyLevel(element);
3059
3124
  if (level === void 0) {
3060
3125
  return errors;
3061
3126
  }
3062
- const parentHeading = getParentElement({
3063
- element,
3064
- schemaCode: HEADING_SCHEMA.code,
3065
- filterDeletedNodes: true
3127
+ if (!element.parentElement) {
3128
+ return errors;
3129
+ }
3130
+ const parentHeading = closestElementBySchema({
3131
+ element: element.parentElement,
3132
+ code: HEADING_SCHEMA.code,
3133
+ ignoreDeletedElements: true
3066
3134
  });
3067
3135
  if (!parentHeading) {
3068
- if (level !== 1) {
3136
+ if (level > 1) {
3069
3137
  addValidationIssue(errors, {
3070
3138
  store: getStore(element),
3071
3139
  title: "Missing heading H1",
@@ -3095,7 +3163,7 @@ var validateHeadingHierarchy = (element) => {
3095
3163
  };
3096
3164
 
3097
3165
  // src/validation/validateOlink.ts
3098
- var ORCID_PATTERN = /^\d{4}-\d{4}-\d{4}-\d{4}$/;
3166
+ var ORCID_PATTERN = /^\d{4}-\d{4}-\d{4}-\d{3}[\dX]$/;
3099
3167
  var validateOlink = (element) => {
3100
3168
  const errors = [];
3101
3169
  if (isDeletedElement(element)) {
@@ -3128,14 +3196,8 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
3128
3196
  if (schemasToValidateAgainst.includes(schema.code)) {
3129
3197
  errors.push(...validateElementAgainstSchema(element, schema));
3130
3198
  }
3131
- if (schema.tag === LINK_SCHEMA.tag || schema.tag === FOOTNOTE_LINK_SCHEMA.tag) {
3132
- errors.push(...validateLinkend(element, elementsToLink));
3133
- }
3134
- if (schema.tag === BIBLIOMIXED_SCHEMA.tag) {
3135
- errors.push(...validateReferenceCited(element, linkElements));
3136
- }
3137
3199
  if (schema.tag === FOOTNOTE_SCHEMA.tag) {
3138
- errors.push(...validateFootnoteCue(element, linkElements));
3200
+ errors.push(...validateFootnoteNumber(element));
3139
3201
  }
3140
3202
  if (schema.code === HEADING_SCHEMA.code) {
3141
3203
  errors.push(...validateHeadingHierarchy(element));
@@ -3143,6 +3205,8 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
3143
3205
  if (schema.code === OLINK_SCHEMA.code) {
3144
3206
  errors.push(...validateOlink(element));
3145
3207
  }
3208
+ errors.push(...validateLinkend(element, elementsToLink));
3209
+ errors.push(...validateElementToLinkTo(element, linkElements));
3146
3210
  if (isIgnoredValidation(schema.code)) {
3147
3211
  return errors;
3148
3212
  }
@@ -3178,6 +3242,84 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3178
3242
  }
3179
3243
  return errors;
3180
3244
  };
3245
+
3246
+ // src/helpers/getElementLinks.ts
3247
+ var getElementLinks = (contentChaptersToValidate) => {
3248
+ const elementsToLink = [];
3249
+ const linkedElements = [];
3250
+ for (const chapter of contentChaptersToValidate) {
3251
+ const parser = new DOMParser();
3252
+ const content = parser.parseFromString(chapter, "text/html");
3253
+ const elementsXMLID = content.querySelectorAll(`[${XMLID_ATTRIBUTE}]`);
3254
+ for (const elementWithXMLID of elementsXMLID) {
3255
+ const linkValue = elementWithXMLID.getAttribute(XMLID_ATTRIBUTE);
3256
+ if (!linkValue) continue;
3257
+ elementsToLink.push(linkValue);
3258
+ }
3259
+ const elementsLinkend = content.querySelectorAll(`[${LINKEND_ATTRIBUTE}]`);
3260
+ for (const elementWithLinkend of elementsLinkend) {
3261
+ const linkendValue = elementWithLinkend.getAttribute(LINKEND_ATTRIBUTE);
3262
+ if (!linkendValue) continue;
3263
+ linkedElements.push(linkendValue);
3264
+ }
3265
+ }
3266
+ return { elementsToLink, linkedElements };
3267
+ };
3268
+
3269
+ // src/helpers/createElement.ts
3270
+ var createElement = ({
3271
+ schemaCode,
3272
+ attributes
3273
+ }) => {
3274
+ const schema = findSchemaByCode(schemaCode);
3275
+ const element = document.createElement(schema.tag.toLowerCase());
3276
+ for (const [name, value] of Object.entries(attributes)) {
3277
+ if (!value) continue;
3278
+ element.setAttribute(name, String(value));
3279
+ }
3280
+ return element;
3281
+ };
3282
+
3283
+ // src/helpers/queryElementBySchema.ts
3284
+ var queryElementBySchema = (content, schemaCode) => {
3285
+ const schema = findSchemaByCode(schemaCode);
3286
+ const element = content.querySelector(schema.tag.toLowerCase());
3287
+ if (!element) return void 0;
3288
+ if (schema.matchesElement && !schema.matchesElement(element)) {
3289
+ return void 0;
3290
+ }
3291
+ return element;
3292
+ };
3293
+ var queryAllElementsBySchema = (content, schemaCode) => {
3294
+ const schema = findSchemaByCode(schemaCode);
3295
+ const elements = content.querySelectorAll(
3296
+ schema.tag.toLowerCase()
3297
+ );
3298
+ const matchingElements = [];
3299
+ for (const element of elements) {
3300
+ if (schema.matchesElement && !schema.matchesElement(element)) {
3301
+ continue;
3302
+ }
3303
+ matchingElements.push(element);
3304
+ }
3305
+ return matchingElements;
3306
+ };
3307
+
3308
+ // src/helpers/getAdjacentElement.ts
3309
+ var getAdjacentElement = ({
3310
+ element,
3311
+ direction,
3312
+ code
3313
+ }) => {
3314
+ let current = element;
3315
+ while (current) {
3316
+ const sibling = direction === "next" ? current.nextElementSibling : current.previousElementSibling;
3317
+ if (sibling instanceof HTMLElement) {
3318
+ return closestElementBySchema({ element: sibling, code }) || queryElementBySchema(sibling, code);
3319
+ }
3320
+ current = current.parentElement;
3321
+ }
3322
+ };
3181
3323
  export {
3182
3324
  ALIGNMENT_ATTRIBUTE,
3183
3325
  ATOM_SCHEMAS,
@@ -3190,7 +3332,6 @@ export {
3190
3332
  IGNORED_ATTRIBUTES,
3191
3333
  IGNORED_ATTRIBUTES_STARTS_WITH,
3192
3334
  IGNORED_ELEMENT_SELECTORS,
3193
- IGNORED_VALIDATION_ELEMENT_SELECTORS,
3194
3335
  INDENT_TYPE_ATTRIBUTE,
3195
3336
  INLINE_ELEMENT_SCHEMAS,
3196
3337
  LAYOUT_ATTRIBUTES,
@@ -3199,6 +3340,7 @@ export {
3199
3340
  LAYOUT_TABLE_PLACEMENT_ATTRIBUTE,
3200
3341
  LAYOUT_USER_ATTRIBUTE,
3201
3342
  LEFT_INDENT_ATTRIBUTE,
3343
+ LINKEND_ATTRIBUTE,
3202
3344
  RIGHT_INDENT_ATTRIBUTE,
3203
3345
  SCHEMAS,
3204
3346
  SPACE_ABOVE_ATTRIBUTE,
@@ -3211,15 +3353,20 @@ export {
3211
3353
  TRACK_CHANGES_ATTR_DATA_TIME,
3212
3354
  TRACK_CHANGES_ATTR_DATA_USERID,
3213
3355
  TRACK_CHANGES_ATTR_DATA_USERNAME,
3356
+ XMLID_ATTRIBUTE,
3357
+ closestElementBySchema,
3214
3358
  createElement,
3215
3359
  findAttributeDefinitionByName,
3216
3360
  findSchemaByCode,
3217
3361
  findSchemaByElement,
3362
+ getAdjacentElement,
3218
3363
  getAttributeName,
3364
+ getElementLinks,
3365
+ getStore,
3219
3366
  isAttributeRestricted,
3367
+ isDeletedElement,
3220
3368
  isIgnoredAttribute,
3221
3369
  isIgnoredElement,
3222
- isIgnoredValidation,
3223
3370
  isTrackChangesSchema,
3224
3371
  queryAllElementsBySchema,
3225
3372
  queryElementBySchema,