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.js CHANGED
@@ -41,7 +41,6 @@ __export(index_exports, {
41
41
  IGNORED_ATTRIBUTES: () => IGNORED_ATTRIBUTES,
42
42
  IGNORED_ATTRIBUTES_STARTS_WITH: () => IGNORED_ATTRIBUTES_STARTS_WITH,
43
43
  IGNORED_ELEMENT_SELECTORS: () => IGNORED_ELEMENT_SELECTORS,
44
- IGNORED_VALIDATION_ELEMENT_SELECTORS: () => IGNORED_VALIDATION_ELEMENT_SELECTORS,
45
44
  INDENT_TYPE_ATTRIBUTE: () => INDENT_TYPE_ATTRIBUTE,
46
45
  INLINE_ELEMENT_SCHEMAS: () => INLINE_ELEMENT_SCHEMAS,
47
46
  LAYOUT_ATTRIBUTES: () => LAYOUT_ATTRIBUTES,
@@ -50,6 +49,7 @@ __export(index_exports, {
50
49
  LAYOUT_TABLE_PLACEMENT_ATTRIBUTE: () => LAYOUT_TABLE_PLACEMENT_ATTRIBUTE,
51
50
  LAYOUT_USER_ATTRIBUTE: () => LAYOUT_USER_ATTRIBUTE,
52
51
  LEFT_INDENT_ATTRIBUTE: () => LEFT_INDENT_ATTRIBUTE,
52
+ LINKEND_ATTRIBUTE: () => LINKEND_ATTRIBUTE,
53
53
  RIGHT_INDENT_ATTRIBUTE: () => RIGHT_INDENT_ATTRIBUTE,
54
54
  SCHEMAS: () => SCHEMAS,
55
55
  SPACE_ABOVE_ATTRIBUTE: () => SPACE_ABOVE_ATTRIBUTE,
@@ -62,15 +62,20 @@ __export(index_exports, {
62
62
  TRACK_CHANGES_ATTR_DATA_TIME: () => TRACK_CHANGES_ATTR_DATA_TIME,
63
63
  TRACK_CHANGES_ATTR_DATA_USERID: () => TRACK_CHANGES_ATTR_DATA_USERID,
64
64
  TRACK_CHANGES_ATTR_DATA_USERNAME: () => TRACK_CHANGES_ATTR_DATA_USERNAME,
65
+ XMLID_ATTRIBUTE: () => XMLID_ATTRIBUTE,
66
+ closestElementBySchema: () => closestElementBySchema,
65
67
  createElement: () => createElement,
66
68
  findAttributeDefinitionByName: () => findAttributeDefinitionByName,
67
69
  findSchemaByCode: () => findSchemaByCode,
68
70
  findSchemaByElement: () => findSchemaByElement,
71
+ getAdjacentElement: () => getAdjacentElement,
69
72
  getAttributeName: () => getAttributeName,
73
+ getElementLinks: () => getElementLinks,
74
+ getStore: () => getStore,
70
75
  isAttributeRestricted: () => isAttributeRestricted,
76
+ isDeletedElement: () => isDeletedElement,
71
77
  isIgnoredAttribute: () => isIgnoredAttribute,
72
78
  isIgnoredElement: () => isIgnoredElement,
73
- isIgnoredValidation: () => isIgnoredValidation,
74
79
  isTrackChangesSchema: () => isTrackChangesSchema,
75
80
  queryAllElementsBySchema: () => queryAllElementsBySchema,
76
81
  queryElementBySchema: () => queryElementBySchema,
@@ -78,7 +83,7 @@ __export(index_exports, {
78
83
  });
79
84
  module.exports = __toCommonJS(index_exports);
80
85
 
81
- // src/schema/utils/createSchema.ts
86
+ // src/schema/helpers/createSchema.ts
82
87
  var createSchema = (params) => {
83
88
  return params;
84
89
  };
@@ -120,10 +125,13 @@ var TRACK_CHANGES_ATTRS = [
120
125
  ];
121
126
  var ELE_ID_ATTRIBUTE = "ele-id";
122
127
  var STORE_ATTRIBUTE = "store";
128
+ var XMLID_ATTRIBUTE = "xmlid";
129
+ var LINKEND_ATTRIBUTE = "linkend";
123
130
  var ID_ATTRS = [STORE_ATTRIBUTE, ELE_ID_ATTRIBUTE];
124
131
 
125
132
  // src/schema/shared/allowedAtomsChildren.ts
126
133
  var ATOM_CODES_ALLOWED_CHILDREN = [
134
+ { code: "mark", required: false },
127
135
  { code: "indexterm", required: false },
128
136
  { code: "b", required: false },
129
137
  { code: "i", required: false },
@@ -167,6 +175,7 @@ var QUATERNARY_TAG = "QUATERNARY";
167
175
  var BOOKMARK_TAG = "BOOKMARK";
168
176
  var SEE_TAG = "SEE";
169
177
  var REFERENCE_MARK_TAG = "REFERENCE";
178
+ var MARK_TAG = "MARK";
170
179
 
171
180
  // src/schema/elementSchemas/atoms/b.ts
172
181
  var B_SCHEMA = createSchema({
@@ -608,6 +617,23 @@ var ABBR_SCHEMA = createSchema({
608
617
  allowedChildrenCodes: [...ATOM_CODES_ALLOWED_CHILDREN]
609
618
  });
610
619
 
620
+ // src/schema/elementSchemas/atoms/mark.ts
621
+ var MARK_SCHEMA = createSchema({
622
+ code: "mark",
623
+ kind: "atom",
624
+ tag: MARK_TAG,
625
+ requiredAttributes: ["id"],
626
+ optionalAttributes: [
627
+ "data-markjs",
628
+ {
629
+ name: "data-replaceable",
630
+ values: ["true", "false"],
631
+ defaultValue: "true"
632
+ }
633
+ ],
634
+ allowedChildrenCodes: [...ATOM_CODES_ALLOWED_CHILDREN]
635
+ });
636
+
611
637
  // src/schema/elementSchemas/atoms/index.ts
612
638
  var ATOM_SCHEMAS = {
613
639
  indexterm: INDEXTERM_SCHEMA,
@@ -635,7 +661,8 @@ var ATOM_SCHEMAS = {
635
661
  comment: COMMENT_SCHEMA,
636
662
  query: QUERY_SCHEMA,
637
663
  reply: REPLY_SCHEMA,
638
- abbreviation: ABBR_SCHEMA
664
+ abbreviation: ABBR_SCHEMA,
665
+ mark: MARK_SCHEMA
639
666
  };
640
667
 
641
668
  // src/schema/elementSchemas/elements/elementsTags.ts
@@ -702,7 +729,7 @@ var EPIGRAPH_TAG = "EPIGRAPH";
702
729
  var INFO_TAG = "INFO1";
703
730
  var POEM_TAG = "POEM";
704
731
  var BIBLIOMIXED_TAG = "BIBLIOMIXED";
705
- var REFERENCE_BIBLIOGRAPHY_TAG = "REFERENCE_BIBLIOGRAPHY";
732
+ var REFERENCE_BIBLIOGRAPHY_TAG = "BIBLIOGRAPHY";
706
733
  var BIBLIODIV_TAG = "BIBLIODIV";
707
734
  var MATHPHRASE_TAG = "MATHPHRASE";
708
735
  var MATH_TAG = "MATH";
@@ -2061,7 +2088,7 @@ var FOOTNOTE_SECTION_SCHEMA = createSchema({
2061
2088
  });
2062
2089
 
2063
2090
  // src/schema/elementSchemas/elements/heading.ts
2064
- var HEADING_LEVEL = ["H1", "H2", "H3", "H4", "H5", "H6"];
2091
+ var HEADING_LEVEL = ["H0", "H1", "H2", "H3", "H4", "H5", "H6"];
2065
2092
  var HEADING_ROLES = [...HEADING_LEVEL, "vignette_group"];
2066
2093
  var HEADING_SCHEMA = createSchema({
2067
2094
  code: "heading",
@@ -2132,6 +2159,7 @@ var POEM_SCHEMA = createSchema({
2132
2159
  optionalAttributes: [...TRACK_CHANGES_ATTRS, "role", "trackmsg"],
2133
2160
  defaultChildCode: "line",
2134
2161
  allowedChildrenCodes: [
2162
+ { code: "title1", required: false },
2135
2163
  { code: "line", required: false },
2136
2164
  { code: "linegroup", required: false },
2137
2165
  { code: "source1", required: false }
@@ -2427,55 +2455,10 @@ var SCHEMAS = {
2427
2455
  ...INLINE_ELEMENT_SCHEMAS
2428
2456
  };
2429
2457
 
2430
- // src/schema/shared/ignoredElements.ts
2431
- var IGNORED_ELEMENT_SELECTORS = [
2432
- "span.rhlabel",
2433
- "span.printlabel",
2434
- "span.refIcon",
2435
- "span.missLink",
2436
- "span.ref-drag",
2437
- "span#dummySpan"
2438
- ];
2439
- var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
2440
- "referenceBibliomixed"
2441
- ];
2442
-
2443
- // src/schema/shared/ignoredAttributes.ts
2444
- var IGNORED_ATTRIBUTES = [
2445
- // Styling & layout
2446
- "class",
2447
- "style",
2448
- // Editor state
2449
- "contenteditable",
2450
- "draggable",
2451
- "data-prevpos",
2452
- "tabindex",
2453
- // Browser behaviour
2454
- "spellcheck",
2455
- "translate",
2456
- "lang",
2457
- "dir",
2458
- "hidden",
2459
- "data-gramm"
2460
- ];
2461
- var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
2462
-
2463
- // src/schema/utils/utils.ts
2464
- var isTrackChangesSchema = (schema) => schema.code === "insertion" || schema.code === "deletion" || schema.code === "lineGroupRemoval";
2465
- var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
2466
- (startsWith) => attribute.startsWith(startsWith)
2467
- );
2468
- var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
2469
- var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
2470
- var findSchemaByCode = (code) => SCHEMAS[code];
2471
- var findSchemaByElement = (element) => {
2472
- const schema = Object.values(SCHEMAS).find(
2473
- (schema2) => schema2.tag == element.tagName && (!schema2.matchesElement || schema2.matchesElement(element))
2474
- );
2475
- return schema;
2476
- };
2477
- var isAttributeRestricted = (attr) => typeof attr !== "string";
2458
+ // src/schema/helpers/getAttributeName.ts
2478
2459
  var getAttributeName = (attribute) => typeof attribute === "string" ? attribute.toLowerCase() : attribute.name.toLowerCase();
2460
+
2461
+ // src/schema/helpers/findAttributeDefinitionByName.ts
2479
2462
  var findAttributeDefinitionByName = (definitions, name) => {
2480
2463
  for (const def of definitions) {
2481
2464
  if (getAttributeName(def) === name.toLowerCase()) {
@@ -2485,47 +2468,29 @@ var findAttributeDefinitionByName = (definitions, name) => {
2485
2468
  return void 0;
2486
2469
  };
2487
2470
 
2488
- // src/schema/utils/createElement.ts
2489
- var createElement = ({
2490
- schemaCode,
2491
- attributes
2492
- }) => {
2493
- const schema = findSchemaByCode(schemaCode);
2494
- const element = document.createElement(schema.tag.toLowerCase());
2495
- for (const [name, value] of Object.entries(attributes)) {
2496
- if (!value) continue;
2497
- element.setAttribute(name, String(value));
2498
- }
2499
- return element;
2500
- };
2471
+ // src/schema/helpers/findSchemaByCode.ts
2472
+ var findSchemaByCode = (code) => SCHEMAS[code];
2501
2473
 
2502
- // src/schema/utils/queryElementBySchema.ts
2503
- var queryElementBySchema = (content, schemaCode) => {
2504
- const schema = findSchemaByCode(schemaCode);
2505
- const element = content.querySelector(schema.tag.toLowerCase());
2506
- if (!element) return void 0;
2507
- if (schema.matchesElement && !schema.matchesElement(element)) {
2508
- return void 0;
2509
- }
2510
- return element;
2511
- };
2512
- var queryAllElementsBySchema = (content, schemaCode) => {
2513
- const schema = findSchemaByCode(schemaCode);
2514
- const elements = content.querySelectorAll(
2515
- schema.tag.toLowerCase()
2474
+ // src/schema/helpers/matchesSchemaTag.ts
2475
+ var matchesSchemaTag = (element, tag) => element.tagName.toUpperCase() === tag.toUpperCase();
2476
+
2477
+ // src/schema/helpers/findSchemaByElement.ts
2478
+ var findSchemaByElement = (element) => {
2479
+ const schema = Object.values(SCHEMAS).find(
2480
+ (schema2) => matchesSchemaTag(element, schema2.tag) && (!schema2.matchesElement || schema2.matchesElement(element))
2516
2481
  );
2517
- const matchingElements = [];
2518
- for (const element of elements) {
2519
- if (schema.matchesElement && !schema.matchesElement(element)) {
2520
- continue;
2521
- }
2522
- matchingElements.push(element);
2523
- }
2524
- return matchingElements;
2482
+ return schema;
2525
2483
  };
2526
2484
 
2485
+ // src/schema/helpers/isAttributeRestricted.ts
2486
+ var isAttributeRestricted = (attr) => typeof attr !== "string";
2487
+
2488
+ // src/schema/helpers/isTrackChangesSchema.ts
2489
+ var isTrackChangesSchema = (schema) => schema.code === "insertion" || schema.code === "deletion" || schema.code === "lineGroupRemoval";
2490
+
2527
2491
  // src/schema/shared/labelElements.ts
2528
2492
  var ElementLabel = {
2493
+ mark: "Mark",
2529
2494
  referenceBibliomixed: "Reference Bibliomixed",
2530
2495
  referenceBibliography: "Reference Bibliography",
2531
2496
  bibliodiv: "Bibliodiv",
@@ -2660,40 +2625,54 @@ var DEPENDENT_FORBIDDEN_ELEMENTS = [
2660
2625
  }
2661
2626
  ];
2662
2627
 
2663
- // src/validation/utils/generateValidationIssueId.ts
2664
- var generateValidationIssueId = () => {
2665
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2666
- return crypto.randomUUID();
2667
- }
2668
- return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2669
- };
2670
-
2671
- // src/validation/utils/addValidationIssue.ts
2672
- var createValidationIssue = (issue) => ({
2673
- id: generateValidationIssueId(),
2674
- ...issue
2675
- });
2676
- var addValidationIssue = (errors, issue) => {
2677
- errors.push(createValidationIssue(issue));
2678
- };
2628
+ // src/helpers/isIgnoredElement.ts
2629
+ var IGNORED_ELEMENT_SELECTORS = [
2630
+ "span.rhlabel",
2631
+ "span.printlabel",
2632
+ "span.refIcon",
2633
+ "span.missLink",
2634
+ "span.ref-drag",
2635
+ "span#dummySpan"
2636
+ ];
2637
+ var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
2679
2638
 
2680
- // src/validation/utils/getStore.ts
2681
- var getStore = (element) => {
2682
- return element.getAttribute("store") || "";
2683
- };
2639
+ // src/validation/helpers/isIgnoredValidation.ts
2640
+ var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
2641
+ "referenceBibliomixed"
2642
+ ];
2643
+ var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
2684
2644
 
2685
- // src/validation/utils/retrieveTextIgnoringNodesWithSelector.ts
2686
- var retrieveTextIgnoringNodesWithSelector = (element, selector = ".del") => {
2687
- const clonedElement = element.cloneNode(true);
2688
- for (const delElement of clonedElement.querySelectorAll(selector)) {
2689
- delElement.remove();
2645
+ // src/helpers/closestElementBySchema.ts
2646
+ var closestElementBySchema = ({
2647
+ element,
2648
+ code,
2649
+ ignoreDeletedElements = false
2650
+ }) => {
2651
+ const schema = findSchemaByCode(code);
2652
+ if (!schema) return;
2653
+ const closestElement = element.closest(
2654
+ schema.tag.toLowerCase()
2655
+ );
2656
+ if (!closestElement) return;
2657
+ if (schema.matchesElement && !schema.matchesElement(closestElement)) {
2658
+ return;
2690
2659
  }
2691
- return clonedElement.textContent || "";
2660
+ if (ignoreDeletedElements && isDeletedElement(closestElement)) {
2661
+ return closestElementBySchema({
2662
+ element: closestElement,
2663
+ code,
2664
+ ignoreDeletedElements
2665
+ });
2666
+ }
2667
+ return closestElement;
2692
2668
  };
2693
2669
 
2694
- // src/validation/utils/isDeletedElement.ts
2670
+ // src/helpers/isDeletedElement.ts
2695
2671
  var isDeletedElement = (element) => {
2696
- return !!element.closest(".del");
2672
+ return !!closestElementBySchema({
2673
+ element,
2674
+ code: "deletion"
2675
+ });
2697
2676
  };
2698
2677
 
2699
2678
  // src/validation/utils/getElementsSelector.ts
@@ -2709,63 +2688,35 @@ var getElementsSelector = ({
2709
2688
  return elements;
2710
2689
  };
2711
2690
 
2712
- // src/validation/validateLinkend.ts
2713
- var findElementLinkedTo = (linkend, elementsToLink) => {
2714
- return elementsToLink.includes(linkend);
2715
- };
2716
- var LINK_TO_CROSS_CHECK = [
2717
- TABLE_LINK_ROLE,
2718
- FIGURE_LINK_ROLE,
2719
- EQUATION_LINK_ROLE,
2720
- FOOTNOTE_LINK_ROLE,
2721
- REFERENCE_LINK_ROLE
2722
- ];
2723
- var LINK_BLOCKER_ROLES = [
2724
- TABLE_LINK_ROLE,
2725
- FIGURE_LINK_ROLE,
2726
- EQUATION_LINK_ROLE,
2727
- FOOTNOTE_LINK_ROLE
2728
- ];
2729
- var validateLinkend = (linkElement, elementsToLink) => {
2730
- const linkend = linkElement.getAttribute("linkend");
2731
- if (!linkend) {
2732
- return [];
2733
- }
2734
- const isLinkFootnoteCue = linkElement.tagName.toUpperCase() === FOOTNOTE_LINK_SCHEMA.tag;
2735
- if (isLinkFootnoteCue) {
2736
- if (findElementLinkedTo(linkend, elementsToLink)) {
2737
- return [];
2738
- }
2739
- return [
2740
- createValidationIssue({
2741
- store: getStore(linkElement),
2742
- title: "Unlinked footnote cue",
2743
- kind: "unlinked",
2744
- description: "This footnote cue is not referenced to any footnote in this chapter. Please link it again manually.",
2745
- level: "blocker"
2746
- })
2747
- ];
2748
- }
2749
- const role = linkElement.getAttribute("role");
2750
- if (!role) {
2751
- return [];
2752
- }
2753
- if (!LINK_TO_CROSS_CHECK.includes(role)) {
2754
- return [];
2691
+ // src/validation/utils/retrieveTextIgnoringNodesWithSelector.ts
2692
+ var retrieveTextIgnoringNodesWithSelector = (element, selector = ".del") => {
2693
+ const clonedElement = element.cloneNode(true);
2694
+ for (const delElement of clonedElement.querySelectorAll(selector)) {
2695
+ delElement.remove();
2755
2696
  }
2756
- if (findElementLinkedTo(linkend, elementsToLink)) {
2757
- return [];
2697
+ return clonedElement.textContent || "";
2698
+ };
2699
+
2700
+ // src/helpers/getStore.ts
2701
+ var getStore = (element) => {
2702
+ return element.getAttribute(STORE_ATTRIBUTE) || "";
2703
+ };
2704
+
2705
+ // src/validation/helpers/generateValidationIssueId.ts
2706
+ var generateValidationIssueId = () => {
2707
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2708
+ return crypto.randomUUID();
2758
2709
  }
2759
- const isBlocker = LINK_BLOCKER_ROLES.includes(role.toLowerCase());
2760
- return [
2761
- createValidationIssue({
2762
- store: getStore(linkElement),
2763
- title: "Unlinked element",
2764
- kind: "unlinked",
2765
- description: "This link is not referenced to any element in the current chapter or any other chapter. Please link it again manually.",
2766
- level: isBlocker ? "blocker" : "warning"
2767
- })
2768
- ];
2710
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2711
+ };
2712
+
2713
+ // src/validation/helpers/addValidationIssue.ts
2714
+ var createValidationIssue = (issue) => ({
2715
+ id: generateValidationIssueId(),
2716
+ ...issue
2717
+ });
2718
+ var addValidationIssue = (errors, issue) => {
2719
+ errors.push(createValidationIssue(issue));
2769
2720
  };
2770
2721
 
2771
2722
  // src/validation/validateFootnotes.ts
@@ -2778,15 +2729,11 @@ var extractFootnoteNumber = (footnote) => {
2778
2729
  }
2779
2730
  return footnoteNumber;
2780
2731
  };
2781
- var validateFootnoteCue = (footnoteElement, linkElements) => {
2732
+ var validateFootnoteNumber = (footnoteElement) => {
2782
2733
  const errors = [];
2783
- const linkend = footnoteElement.getAttribute("xmlid") || "";
2784
2734
  const footnoteNumber = footnoteElement.querySelector(
2785
2735
  FOOTNOTE_NUMBER_SCHEMA.tag
2786
2736
  );
2787
- if (findElementLinkedTo(linkend, linkElements)) {
2788
- return errors;
2789
- }
2790
2737
  if (!footnoteNumber) {
2791
2738
  addValidationIssue(errors, {
2792
2739
  store: getStore(footnoteElement),
@@ -2796,14 +2743,6 @@ var validateFootnoteCue = (footnoteElement, linkElements) => {
2796
2743
  level: "blocker"
2797
2744
  });
2798
2745
  }
2799
- const label = extractFootnoteNumber(footnoteNumber);
2800
- addValidationIssue(errors, {
2801
- store: getStore(footnoteElement),
2802
- title: "Unreferenced footnote",
2803
- kind: "unlinked",
2804
- description: `The footnote ${label} is not referenced to any footnote cue in this chapter. Please reference it in the chapter.`,
2805
- level: "blocker"
2806
- });
2807
2746
  return errors;
2808
2747
  };
2809
2748
  var validateConsecutiveFootnotes = (root) => {
@@ -2888,6 +2827,92 @@ var validateConsecutiveFootnoteCues = (root) => {
2888
2827
  return errors;
2889
2828
  };
2890
2829
 
2830
+ // src/validation/validateLinkend.ts
2831
+ var findElementLinkedTo = (linkend, elementsToLink) => {
2832
+ return elementsToLink.includes(linkend);
2833
+ };
2834
+ var LINK_TO_CROSS_CHECK = [
2835
+ TABLE_LINK_ROLE,
2836
+ FIGURE_LINK_ROLE,
2837
+ EQUATION_LINK_ROLE,
2838
+ FOOTNOTE_LINK_ROLE,
2839
+ REFERENCE_LINK_ROLE
2840
+ ];
2841
+ var LINK_BLOCKER_ROLES = [
2842
+ TABLE_LINK_ROLE,
2843
+ FIGURE_LINK_ROLE,
2844
+ EQUATION_LINK_ROLE,
2845
+ FOOTNOTE_LINK_ROLE
2846
+ ];
2847
+ var validateLinkend = (linkElement, elementsToLink) => {
2848
+ const linkend = linkElement.getAttribute("linkend");
2849
+ if (!linkend) {
2850
+ return [];
2851
+ }
2852
+ if (findElementLinkedTo(linkend, elementsToLink)) {
2853
+ return [];
2854
+ }
2855
+ const isLinkFootnoteCue = matchesSchemaTag(
2856
+ linkElement,
2857
+ FOOTNOTE_LINK_SCHEMA.tag
2858
+ );
2859
+ if (isLinkFootnoteCue) {
2860
+ return [
2861
+ createValidationIssue({
2862
+ store: getStore(linkElement),
2863
+ title: "Unlinked footnote cue",
2864
+ kind: "unlinked",
2865
+ description: "This footnote cue is not referenced to any footnote in this chapter. Please link it again manually.",
2866
+ level: "blocker"
2867
+ })
2868
+ ];
2869
+ }
2870
+ const isLink = matchesSchemaTag(linkElement, LINK_SCHEMA.tag);
2871
+ if (!isLink) {
2872
+ return [];
2873
+ }
2874
+ const role = linkElement.getAttribute("role");
2875
+ if (!role) {
2876
+ return [];
2877
+ }
2878
+ if (!LINK_TO_CROSS_CHECK.includes(role)) {
2879
+ return [];
2880
+ }
2881
+ const isBlocker = LINK_BLOCKER_ROLES.includes(role.toLowerCase());
2882
+ return [
2883
+ createValidationIssue({
2884
+ store: getStore(linkElement),
2885
+ title: "Unlinked element",
2886
+ kind: "unlinked",
2887
+ description: "This link is not referenced to any element in the current chapter or any other chapter. Please link it again manually.",
2888
+ level: isBlocker ? "blocker" : "warning"
2889
+ })
2890
+ ];
2891
+ };
2892
+
2893
+ // src/helpers/isIgnoredAttribute.ts
2894
+ var IGNORED_ATTRIBUTES = [
2895
+ // Styling & layout
2896
+ "class",
2897
+ "style",
2898
+ // Editor state
2899
+ "contenteditable",
2900
+ "draggable",
2901
+ "data-prevpos",
2902
+ "tabindex",
2903
+ // Browser behaviour
2904
+ "spellcheck",
2905
+ "translate",
2906
+ "lang",
2907
+ "dir",
2908
+ "hidden",
2909
+ "data-gramm"
2910
+ ];
2911
+ var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
2912
+ var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
2913
+ (startsWith) => attribute.startsWith(startsWith)
2914
+ );
2915
+
2891
2916
  // src/validation/validateAttributes.ts
2892
2917
  var validateAttributes = (element, schema) => {
2893
2918
  const errors = [];
@@ -2931,7 +2956,7 @@ var validateAttributes = (element, schema) => {
2931
2956
  // src/validation/validateChildren.ts
2932
2957
  var validateElementAgainstSchema = (element, schema) => {
2933
2958
  const errors = [];
2934
- if (element.tagName.toUpperCase() !== schema.tag) {
2959
+ if (!matchesSchemaTag(element, schema.tag)) {
2935
2960
  addValidationIssue(errors, {
2936
2961
  store: getStore(element),
2937
2962
  title: `Expected ${schema.tag}, got ${element.tagName}`,
@@ -3032,31 +3057,83 @@ var getExtraInstruction = (schema, childSchema) => {
3032
3057
  return "";
3033
3058
  };
3034
3059
 
3035
- // src/validation/validateReferences.ts
3060
+ // src/validation/validateElementToLinkTo.ts
3036
3061
  var findElementLinkedTo2 = (xmlid, linkElements) => {
3037
3062
  return linkElements.includes(xmlid);
3038
3063
  };
3039
- var validateReferenceCited = (referenceElement, linkElements) => {
3040
- const xmlid = referenceElement.getAttribute("xmlid");
3064
+ var isFootnote = (element) => {
3065
+ return matchesSchemaTag(element, FOOTNOTE_SCHEMA.tag);
3066
+ };
3067
+ var isReference = (element) => {
3068
+ return matchesSchemaTag(element, BIBLIOMIXED_SCHEMA.tag) || !!closestElementBySchema({
3069
+ element,
3070
+ code: "referenceBibliography"
3071
+ });
3072
+ };
3073
+ var isTable = (element) => {
3074
+ return matchesSchemaTag(element, TABLE_SCHEMA.tag);
3075
+ };
3076
+ var isFigure = (element) => {
3077
+ return matchesSchemaTag(element, FIGURE_SCHEMA.tag);
3078
+ };
3079
+ var validateElementToLinkTo = (element, linkElements) => {
3080
+ const xmlid = element.getAttribute("xmlid");
3041
3081
  if (!xmlid) {
3042
3082
  return [];
3043
3083
  }
3044
3084
  if (findElementLinkedTo2(xmlid, linkElements)) {
3045
3085
  return [];
3046
3086
  }
3047
- return [
3048
- createValidationIssue({
3049
- store: getStore(referenceElement),
3050
- title: "Unlinked element",
3051
- kind: "unlinked",
3052
- description: "This reference is not cited in this chapter or any other chapter. Please add a link to this reference or delete the reference.",
3053
- level: "warning"
3054
- })
3055
- ];
3087
+ if (isFootnote(element)) {
3088
+ const label = extractFootnoteNumber(element);
3089
+ return [
3090
+ createValidationIssue({
3091
+ store: getStore(element),
3092
+ title: "Uncited footnote",
3093
+ kind: "uncited",
3094
+ description: `The footnote ${label} is not cited to any footnote cue in this chapter. Please reference it in the chapter.`,
3095
+ level: "blocker"
3096
+ })
3097
+ ];
3098
+ }
3099
+ if (isReference(element)) {
3100
+ return [
3101
+ createValidationIssue({
3102
+ store: getStore(element),
3103
+ title: "Uncited reference",
3104
+ kind: "uncited",
3105
+ description: "This reference is not cited in this chapter or any other chapter. Please add a link to this reference or delete it.",
3106
+ level: "warning"
3107
+ })
3108
+ ];
3109
+ }
3110
+ if (isTable(element)) {
3111
+ return [
3112
+ createValidationIssue({
3113
+ store: getStore(element),
3114
+ title: "Uncited table",
3115
+ kind: "uncited",
3116
+ description: "This table is not cited in this chapter or any other chapter. Please add a link to this table or delete it.",
3117
+ level: "warning"
3118
+ })
3119
+ ];
3120
+ }
3121
+ if (isFigure(element)) {
3122
+ return [
3123
+ createValidationIssue({
3124
+ store: getStore(element),
3125
+ title: "Uncited figure",
3126
+ kind: "uncited",
3127
+ description: "This figure is not cited in this chapter or any other chapter. Please add a link to this figure or delete it.",
3128
+ level: "warning"
3129
+ })
3130
+ ];
3131
+ }
3132
+ return [];
3056
3133
  };
3057
3134
 
3058
3135
  // src/validation/validateWeblink.ts
3059
- var import_mark = __toESM(require("mark.js"));
3136
+ var import_mark2 = __toESM(require("mark.js"));
3060
3137
  var EDGE_PUNCTUATION = `:;.,\\-\u2013\u2014\u2012_(){}[\\]!'"+=\xAB\xBB\u2039\u203A\u201C\u201D\u2018\u2019<>`;
3061
3138
  var WEB_URI_PATTERN = `(?:(?:https?):\\/\\/|www\\.)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}(?::\\d{1,5})?(?:\\/(?:[^\\s]*[^\\s${EDGE_PUNCTUATION}])?)?`;
3062
3139
  var WEB_URI_IN_TEXT_REGEX = new RegExp(WEB_URI_PATTERN, "gi");
@@ -3076,7 +3153,7 @@ var POSSIBLE_WEBLINK_EXCLUDE_SELECTORS = [
3076
3153
  var collectPossibleWebLinks = (content) => {
3077
3154
  const clone = content.cloneNode(true);
3078
3155
  const possibleWebLinks = /* @__PURE__ */ new Set();
3079
- const instance = new import_mark.default(clone);
3156
+ const instance = new import_mark2.default(clone);
3080
3157
  instance.markRegExp(WEB_URI_IN_TEXT_REGEX, {
3081
3158
  acrossElements: false,
3082
3159
  exclude: POSSIBLE_WEBLINK_EXCLUDE_SELECTORS,
@@ -3104,30 +3181,20 @@ var validatePossibleWeblinks = (root) => {
3104
3181
  return errors;
3105
3182
  };
3106
3183
 
3107
- // src/validation/utils/getParentElement.ts
3108
- var getParentElement = ({
3109
- element,
3110
- schemaCode,
3111
- filterDeletedNodes
3112
- }) => {
3113
- let current = element.parentElement;
3114
- while (current) {
3115
- const isValidParent = findSchemaByElement(current)?.code === schemaCode;
3116
- const isFilterDeleted = filterDeletedNodes && isDeletedElement(current);
3117
- if (isValidParent || isFilterDeleted) {
3118
- return current;
3119
- }
3120
- current = current.parentElement;
3121
- }
3122
- return void 0;
3123
- };
3124
-
3125
3184
  // src/validation/validateHeadingHierarchy.ts
3185
+ var shouldSuppressWarning = (element) => {
3186
+ const closestBox = closestElementBySchema({
3187
+ element,
3188
+ code: BOX_SCHEMA.code,
3189
+ ignoreDeletedElements: true
3190
+ });
3191
+ return !!closestBox;
3192
+ };
3126
3193
  var getHierarchyLevel = (element) => {
3127
3194
  const role = element.getAttribute("role");
3128
3195
  if (!role) return void 0;
3129
- const validHeadingLevel = HEADING_LEVEL.indexOf(role) + 1;
3130
- if (!validHeadingLevel) return void 0;
3196
+ const validHeadingLevel = HEADING_LEVEL.indexOf(role);
3197
+ if (validHeadingLevel === -1) return void 0;
3131
3198
  return validHeadingLevel;
3132
3199
  };
3133
3200
  var validateHeadingHierarchy = (element) => {
@@ -3135,17 +3202,23 @@ var validateHeadingHierarchy = (element) => {
3135
3202
  if (isDeletedElement(element)) {
3136
3203
  return errors;
3137
3204
  }
3205
+ if (shouldSuppressWarning(element)) {
3206
+ return errors;
3207
+ }
3138
3208
  const level = getHierarchyLevel(element);
3139
3209
  if (level === void 0) {
3140
3210
  return errors;
3141
3211
  }
3142
- const parentHeading = getParentElement({
3143
- element,
3144
- schemaCode: HEADING_SCHEMA.code,
3145
- filterDeletedNodes: true
3212
+ if (!element.parentElement) {
3213
+ return errors;
3214
+ }
3215
+ const parentHeading = closestElementBySchema({
3216
+ element: element.parentElement,
3217
+ code: HEADING_SCHEMA.code,
3218
+ ignoreDeletedElements: true
3146
3219
  });
3147
3220
  if (!parentHeading) {
3148
- if (level !== 1) {
3221
+ if (level > 1) {
3149
3222
  addValidationIssue(errors, {
3150
3223
  store: getStore(element),
3151
3224
  title: "Missing heading H1",
@@ -3175,7 +3248,7 @@ var validateHeadingHierarchy = (element) => {
3175
3248
  };
3176
3249
 
3177
3250
  // src/validation/validateOlink.ts
3178
- var ORCID_PATTERN = /^\d{4}-\d{4}-\d{4}-\d{4}$/;
3251
+ var ORCID_PATTERN = /^\d{4}-\d{4}-\d{4}-\d{3}[\dX]$/;
3179
3252
  var validateOlink = (element) => {
3180
3253
  const errors = [];
3181
3254
  if (isDeletedElement(element)) {
@@ -3208,14 +3281,8 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
3208
3281
  if (schemasToValidateAgainst.includes(schema.code)) {
3209
3282
  errors.push(...validateElementAgainstSchema(element, schema));
3210
3283
  }
3211
- if (schema.tag === LINK_SCHEMA.tag || schema.tag === FOOTNOTE_LINK_SCHEMA.tag) {
3212
- errors.push(...validateLinkend(element, elementsToLink));
3213
- }
3214
- if (schema.tag === BIBLIOMIXED_SCHEMA.tag) {
3215
- errors.push(...validateReferenceCited(element, linkElements));
3216
- }
3217
3284
  if (schema.tag === FOOTNOTE_SCHEMA.tag) {
3218
- errors.push(...validateFootnoteCue(element, linkElements));
3285
+ errors.push(...validateFootnoteNumber(element));
3219
3286
  }
3220
3287
  if (schema.code === HEADING_SCHEMA.code) {
3221
3288
  errors.push(...validateHeadingHierarchy(element));
@@ -3223,6 +3290,8 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
3223
3290
  if (schema.code === OLINK_SCHEMA.code) {
3224
3291
  errors.push(...validateOlink(element));
3225
3292
  }
3293
+ errors.push(...validateLinkend(element, elementsToLink));
3294
+ errors.push(...validateElementToLinkTo(element, linkElements));
3226
3295
  if (isIgnoredValidation(schema.code)) {
3227
3296
  return errors;
3228
3297
  }
@@ -3258,6 +3327,84 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3258
3327
  }
3259
3328
  return errors;
3260
3329
  };
3330
+
3331
+ // src/helpers/getElementLinks.ts
3332
+ var getElementLinks = (contentChaptersToValidate) => {
3333
+ const elementsToLink = [];
3334
+ const linkedElements = [];
3335
+ for (const chapter of contentChaptersToValidate) {
3336
+ const parser = new DOMParser();
3337
+ const content = parser.parseFromString(chapter, "text/html");
3338
+ const elementsXMLID = content.querySelectorAll(`[${XMLID_ATTRIBUTE}]`);
3339
+ for (const elementWithXMLID of elementsXMLID) {
3340
+ const linkValue = elementWithXMLID.getAttribute(XMLID_ATTRIBUTE);
3341
+ if (!linkValue) continue;
3342
+ elementsToLink.push(linkValue);
3343
+ }
3344
+ const elementsLinkend = content.querySelectorAll(`[${LINKEND_ATTRIBUTE}]`);
3345
+ for (const elementWithLinkend of elementsLinkend) {
3346
+ const linkendValue = elementWithLinkend.getAttribute(LINKEND_ATTRIBUTE);
3347
+ if (!linkendValue) continue;
3348
+ linkedElements.push(linkendValue);
3349
+ }
3350
+ }
3351
+ return { elementsToLink, linkedElements };
3352
+ };
3353
+
3354
+ // src/helpers/createElement.ts
3355
+ var createElement = ({
3356
+ schemaCode,
3357
+ attributes
3358
+ }) => {
3359
+ const schema = findSchemaByCode(schemaCode);
3360
+ const element = document.createElement(schema.tag.toLowerCase());
3361
+ for (const [name, value] of Object.entries(attributes)) {
3362
+ if (!value) continue;
3363
+ element.setAttribute(name, String(value));
3364
+ }
3365
+ return element;
3366
+ };
3367
+
3368
+ // src/helpers/queryElementBySchema.ts
3369
+ var queryElementBySchema = (content, schemaCode) => {
3370
+ const schema = findSchemaByCode(schemaCode);
3371
+ const element = content.querySelector(schema.tag.toLowerCase());
3372
+ if (!element) return void 0;
3373
+ if (schema.matchesElement && !schema.matchesElement(element)) {
3374
+ return void 0;
3375
+ }
3376
+ return element;
3377
+ };
3378
+ var queryAllElementsBySchema = (content, schemaCode) => {
3379
+ const schema = findSchemaByCode(schemaCode);
3380
+ const elements = content.querySelectorAll(
3381
+ schema.tag.toLowerCase()
3382
+ );
3383
+ const matchingElements = [];
3384
+ for (const element of elements) {
3385
+ if (schema.matchesElement && !schema.matchesElement(element)) {
3386
+ continue;
3387
+ }
3388
+ matchingElements.push(element);
3389
+ }
3390
+ return matchingElements;
3391
+ };
3392
+
3393
+ // src/helpers/getAdjacentElement.ts
3394
+ var getAdjacentElement = ({
3395
+ element,
3396
+ direction,
3397
+ code
3398
+ }) => {
3399
+ let current = element;
3400
+ while (current) {
3401
+ const sibling = direction === "next" ? current.nextElementSibling : current.previousElementSibling;
3402
+ if (sibling instanceof HTMLElement) {
3403
+ return closestElementBySchema({ element: sibling, code }) || queryElementBySchema(sibling, code);
3404
+ }
3405
+ current = current.parentElement;
3406
+ }
3407
+ };
3261
3408
  // Annotate the CommonJS export names for ESM import in node:
3262
3409
  0 && (module.exports = {
3263
3410
  ALIGNMENT_ATTRIBUTE,
@@ -3271,7 +3418,6 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3271
3418
  IGNORED_ATTRIBUTES,
3272
3419
  IGNORED_ATTRIBUTES_STARTS_WITH,
3273
3420
  IGNORED_ELEMENT_SELECTORS,
3274
- IGNORED_VALIDATION_ELEMENT_SELECTORS,
3275
3421
  INDENT_TYPE_ATTRIBUTE,
3276
3422
  INLINE_ELEMENT_SCHEMAS,
3277
3423
  LAYOUT_ATTRIBUTES,
@@ -3280,6 +3426,7 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3280
3426
  LAYOUT_TABLE_PLACEMENT_ATTRIBUTE,
3281
3427
  LAYOUT_USER_ATTRIBUTE,
3282
3428
  LEFT_INDENT_ATTRIBUTE,
3429
+ LINKEND_ATTRIBUTE,
3283
3430
  RIGHT_INDENT_ATTRIBUTE,
3284
3431
  SCHEMAS,
3285
3432
  SPACE_ABOVE_ATTRIBUTE,
@@ -3292,15 +3439,20 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3292
3439
  TRACK_CHANGES_ATTR_DATA_TIME,
3293
3440
  TRACK_CHANGES_ATTR_DATA_USERID,
3294
3441
  TRACK_CHANGES_ATTR_DATA_USERNAME,
3442
+ XMLID_ATTRIBUTE,
3443
+ closestElementBySchema,
3295
3444
  createElement,
3296
3445
  findAttributeDefinitionByName,
3297
3446
  findSchemaByCode,
3298
3447
  findSchemaByElement,
3448
+ getAdjacentElement,
3299
3449
  getAttributeName,
3450
+ getElementLinks,
3451
+ getStore,
3300
3452
  isAttributeRestricted,
3453
+ isDeletedElement,
3301
3454
  isIgnoredAttribute,
3302
3455
  isIgnoredElement,
3303
- isIgnoredValidation,
3304
3456
  isTrackChangesSchema,
3305
3457
  queryAllElementsBySchema,
3306
3458
  queryElementBySchema,