pro-editor-schema 1.3.0 → 1.4.0

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,12 @@ 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
3126
3185
  var getHierarchyLevel = (element) => {
3127
3186
  const role = element.getAttribute("role");
3128
3187
  if (!role) return void 0;
3129
- const validHeadingLevel = HEADING_LEVEL.indexOf(role) + 1;
3130
- if (!validHeadingLevel) return void 0;
3188
+ const validHeadingLevel = HEADING_LEVEL.indexOf(role);
3189
+ if (validHeadingLevel === -1) return void 0;
3131
3190
  return validHeadingLevel;
3132
3191
  };
3133
3192
  var validateHeadingHierarchy = (element) => {
@@ -3139,13 +3198,16 @@ var validateHeadingHierarchy = (element) => {
3139
3198
  if (level === void 0) {
3140
3199
  return errors;
3141
3200
  }
3142
- const parentHeading = getParentElement({
3143
- element,
3144
- schemaCode: HEADING_SCHEMA.code,
3145
- filterDeletedNodes: true
3201
+ if (!element.parentElement) {
3202
+ return errors;
3203
+ }
3204
+ const parentHeading = closestElementBySchema({
3205
+ element: element.parentElement,
3206
+ code: HEADING_SCHEMA.code,
3207
+ ignoreDeletedElements: true
3146
3208
  });
3147
3209
  if (!parentHeading) {
3148
- if (level !== 1) {
3210
+ if (level > 1) {
3149
3211
  addValidationIssue(errors, {
3150
3212
  store: getStore(element),
3151
3213
  title: "Missing heading H1",
@@ -3175,7 +3237,7 @@ var validateHeadingHierarchy = (element) => {
3175
3237
  };
3176
3238
 
3177
3239
  // src/validation/validateOlink.ts
3178
- var ORCID_PATTERN = /^\d{4}-\d{4}-\d{4}-\d{4}$/;
3240
+ var ORCID_PATTERN = /^\d{4}-\d{4}-\d{4}-\d{3}[\dX]$/;
3179
3241
  var validateOlink = (element) => {
3180
3242
  const errors = [];
3181
3243
  if (isDeletedElement(element)) {
@@ -3208,14 +3270,8 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
3208
3270
  if (schemasToValidateAgainst.includes(schema.code)) {
3209
3271
  errors.push(...validateElementAgainstSchema(element, schema));
3210
3272
  }
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
3273
  if (schema.tag === FOOTNOTE_SCHEMA.tag) {
3218
- errors.push(...validateFootnoteCue(element, linkElements));
3274
+ errors.push(...validateFootnoteNumber(element));
3219
3275
  }
3220
3276
  if (schema.code === HEADING_SCHEMA.code) {
3221
3277
  errors.push(...validateHeadingHierarchy(element));
@@ -3223,6 +3279,8 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
3223
3279
  if (schema.code === OLINK_SCHEMA.code) {
3224
3280
  errors.push(...validateOlink(element));
3225
3281
  }
3282
+ errors.push(...validateLinkend(element, elementsToLink));
3283
+ errors.push(...validateElementToLinkTo(element, linkElements));
3226
3284
  if (isIgnoredValidation(schema.code)) {
3227
3285
  return errors;
3228
3286
  }
@@ -3258,6 +3316,84 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3258
3316
  }
3259
3317
  return errors;
3260
3318
  };
3319
+
3320
+ // src/helpers/getElementLinks.ts
3321
+ var getElementLinks = (contentChaptersToValidate) => {
3322
+ const elementsToLink = [];
3323
+ const linkedElements = [];
3324
+ for (const chapter of contentChaptersToValidate) {
3325
+ const parser = new DOMParser();
3326
+ const content = parser.parseFromString(chapter, "text/html");
3327
+ const elementsXMLID = content.querySelectorAll(`[${XMLID_ATTRIBUTE}]`);
3328
+ for (const elementWithXMLID of elementsXMLID) {
3329
+ const linkValue = elementWithXMLID.getAttribute(XMLID_ATTRIBUTE);
3330
+ if (!linkValue) continue;
3331
+ elementsToLink.push(linkValue);
3332
+ }
3333
+ const elementsLinkend = content.querySelectorAll(`[${LINKEND_ATTRIBUTE}]`);
3334
+ for (const elementWithLinkend of elementsLinkend) {
3335
+ const linkendValue = elementWithLinkend.getAttribute(LINKEND_ATTRIBUTE);
3336
+ if (!linkendValue) continue;
3337
+ linkedElements.push(linkendValue);
3338
+ }
3339
+ }
3340
+ return { elementsToLink, linkedElements };
3341
+ };
3342
+
3343
+ // src/helpers/createElement.ts
3344
+ var createElement = ({
3345
+ schemaCode,
3346
+ attributes
3347
+ }) => {
3348
+ const schema = findSchemaByCode(schemaCode);
3349
+ const element = document.createElement(schema.tag.toLowerCase());
3350
+ for (const [name, value] of Object.entries(attributes)) {
3351
+ if (!value) continue;
3352
+ element.setAttribute(name, String(value));
3353
+ }
3354
+ return element;
3355
+ };
3356
+
3357
+ // src/helpers/queryElementBySchema.ts
3358
+ var queryElementBySchema = (content, schemaCode) => {
3359
+ const schema = findSchemaByCode(schemaCode);
3360
+ const element = content.querySelector(schema.tag.toLowerCase());
3361
+ if (!element) return void 0;
3362
+ if (schema.matchesElement && !schema.matchesElement(element)) {
3363
+ return void 0;
3364
+ }
3365
+ return element;
3366
+ };
3367
+ var queryAllElementsBySchema = (content, schemaCode) => {
3368
+ const schema = findSchemaByCode(schemaCode);
3369
+ const elements = content.querySelectorAll(
3370
+ schema.tag.toLowerCase()
3371
+ );
3372
+ const matchingElements = [];
3373
+ for (const element of elements) {
3374
+ if (schema.matchesElement && !schema.matchesElement(element)) {
3375
+ continue;
3376
+ }
3377
+ matchingElements.push(element);
3378
+ }
3379
+ return matchingElements;
3380
+ };
3381
+
3382
+ // src/helpers/getAdjacentElement.ts
3383
+ var getAdjacentElement = ({
3384
+ element,
3385
+ direction,
3386
+ code
3387
+ }) => {
3388
+ let current = element;
3389
+ while (current) {
3390
+ const sibling = direction === "next" ? current.nextElementSibling : current.previousElementSibling;
3391
+ if (sibling instanceof HTMLElement) {
3392
+ return closestElementBySchema({ element: sibling, code }) || queryElementBySchema(sibling, code);
3393
+ }
3394
+ current = current.parentElement;
3395
+ }
3396
+ };
3261
3397
  // Annotate the CommonJS export names for ESM import in node:
3262
3398
  0 && (module.exports = {
3263
3399
  ALIGNMENT_ATTRIBUTE,
@@ -3271,7 +3407,6 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3271
3407
  IGNORED_ATTRIBUTES,
3272
3408
  IGNORED_ATTRIBUTES_STARTS_WITH,
3273
3409
  IGNORED_ELEMENT_SELECTORS,
3274
- IGNORED_VALIDATION_ELEMENT_SELECTORS,
3275
3410
  INDENT_TYPE_ATTRIBUTE,
3276
3411
  INLINE_ELEMENT_SCHEMAS,
3277
3412
  LAYOUT_ATTRIBUTES,
@@ -3280,6 +3415,7 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3280
3415
  LAYOUT_TABLE_PLACEMENT_ATTRIBUTE,
3281
3416
  LAYOUT_USER_ATTRIBUTE,
3282
3417
  LEFT_INDENT_ATTRIBUTE,
3418
+ LINKEND_ATTRIBUTE,
3283
3419
  RIGHT_INDENT_ATTRIBUTE,
3284
3420
  SCHEMAS,
3285
3421
  SPACE_ABOVE_ATTRIBUTE,
@@ -3292,15 +3428,20 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
3292
3428
  TRACK_CHANGES_ATTR_DATA_TIME,
3293
3429
  TRACK_CHANGES_ATTR_DATA_USERID,
3294
3430
  TRACK_CHANGES_ATTR_DATA_USERNAME,
3431
+ XMLID_ATTRIBUTE,
3432
+ closestElementBySchema,
3295
3433
  createElement,
3296
3434
  findAttributeDefinitionByName,
3297
3435
  findSchemaByCode,
3298
3436
  findSchemaByElement,
3437
+ getAdjacentElement,
3299
3438
  getAttributeName,
3439
+ getElementLinks,
3440
+ getStore,
3300
3441
  isAttributeRestricted,
3442
+ isDeletedElement,
3301
3443
  isIgnoredAttribute,
3302
3444
  isIgnoredElement,
3303
- isIgnoredValidation,
3304
3445
  isTrackChangesSchema,
3305
3446
  queryAllElementsBySchema,
3306
3447
  queryElementBySchema,