pro-editor-schema 1.1.9 → 1.2.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/README.md +2 -0
- package/dist/index.js +83 -10
- package/dist/index.mjs +83 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -197,12 +197,14 @@ const errors = validateXml(rootElement, elementsToLink, linkElements, [
|
|
|
197
197
|
|
|
198
198
|
- Consecutive footnote number checks
|
|
199
199
|
- Consecutive footnote cue checks
|
|
200
|
+
- Possible weblink checks
|
|
200
201
|
|
|
201
202
|
It also runs per-element checks for:
|
|
202
203
|
|
|
203
204
|
- Link targets (`linkend`) on linkable elements
|
|
204
205
|
- Uncited bibliographic references
|
|
205
206
|
- Unreferenced footnotes
|
|
207
|
+
- Heading hierarchy
|
|
206
208
|
|
|
207
209
|
Schema-based attribute and child validation only runs for codes listed in `schemasToValidateAgainst`.
|
|
208
210
|
|
package/dist/index.js
CHANGED
|
@@ -2030,7 +2030,8 @@ var FOOTNOTE_SECTION_SCHEMA = createSchema({
|
|
|
2030
2030
|
});
|
|
2031
2031
|
|
|
2032
2032
|
// src/schema/elementSchemas/elements/heading.ts
|
|
2033
|
-
var
|
|
2033
|
+
var HEADING_LEVEL = ["H1", "H2", "H3", "H4", "H5", "H6"];
|
|
2034
|
+
var HEADING_ROLES = [...HEADING_LEVEL, "vignette_group"];
|
|
2034
2035
|
var HEADING_SCHEMA = createSchema({
|
|
2035
2036
|
code: "heading",
|
|
2036
2037
|
kind: "element",
|
|
@@ -2655,23 +2656,22 @@ var retrieveTextIgnoringNodesWithSelector = (element, selector = ".del") => {
|
|
|
2655
2656
|
return clonedElement.textContent || "";
|
|
2656
2657
|
};
|
|
2657
2658
|
|
|
2659
|
+
// src/validation/utils/isDeletedElement.ts
|
|
2660
|
+
var isDeletedElement = (element) => {
|
|
2661
|
+
return !!element.closest(".del");
|
|
2662
|
+
};
|
|
2663
|
+
|
|
2658
2664
|
// src/validation/utils/getElementsSelector.ts
|
|
2659
2665
|
var getElementsSelector = ({
|
|
2660
2666
|
element,
|
|
2661
2667
|
selector,
|
|
2662
2668
|
filterDeletedNodes
|
|
2663
2669
|
}) => {
|
|
2664
|
-
const elements = element.querySelectorAll(selector);
|
|
2670
|
+
const elements = Array.from(element.querySelectorAll(selector));
|
|
2665
2671
|
if (filterDeletedNodes) {
|
|
2666
|
-
return
|
|
2667
|
-
const hasDeletedParent = element2.closest(".del") !== null;
|
|
2668
|
-
if (hasDeletedParent) {
|
|
2669
|
-
return false;
|
|
2670
|
-
}
|
|
2671
|
-
return true;
|
|
2672
|
-
});
|
|
2672
|
+
return elements.filter((element2) => !isDeletedElement(element2));
|
|
2673
2673
|
}
|
|
2674
|
-
return
|
|
2674
|
+
return elements;
|
|
2675
2675
|
};
|
|
2676
2676
|
|
|
2677
2677
|
// src/validation/validateLinkend.ts
|
|
@@ -3056,6 +3056,76 @@ var validatePossibleWeblinks = (root) => {
|
|
|
3056
3056
|
return errors;
|
|
3057
3057
|
};
|
|
3058
3058
|
|
|
3059
|
+
// src/validation/utils/getParentElement.ts
|
|
3060
|
+
var getParentElement = ({
|
|
3061
|
+
element,
|
|
3062
|
+
schemaCode,
|
|
3063
|
+
filterDeletedNodes
|
|
3064
|
+
}) => {
|
|
3065
|
+
let current = element.parentElement;
|
|
3066
|
+
while (current) {
|
|
3067
|
+
const isValidParent = findSchemaByElement(current)?.code === schemaCode;
|
|
3068
|
+
const isFilterDeleted = filterDeletedNodes && isDeletedElement(current);
|
|
3069
|
+
if (isValidParent || isFilterDeleted) {
|
|
3070
|
+
return current;
|
|
3071
|
+
}
|
|
3072
|
+
current = current.parentElement;
|
|
3073
|
+
}
|
|
3074
|
+
return void 0;
|
|
3075
|
+
};
|
|
3076
|
+
|
|
3077
|
+
// src/validation/validateHeadingHierarchy.ts
|
|
3078
|
+
var getHierarchyLevel = (element) => {
|
|
3079
|
+
const role = element.getAttribute("role");
|
|
3080
|
+
if (!role) return void 0;
|
|
3081
|
+
const validHeadingLevel = HEADING_LEVEL.indexOf(role) + 1;
|
|
3082
|
+
if (!validHeadingLevel) return void 0;
|
|
3083
|
+
return validHeadingLevel;
|
|
3084
|
+
};
|
|
3085
|
+
var validateHeadingHierarchy = (element) => {
|
|
3086
|
+
const errors = [];
|
|
3087
|
+
if (isDeletedElement(element)) {
|
|
3088
|
+
return errors;
|
|
3089
|
+
}
|
|
3090
|
+
const level = getHierarchyLevel(element);
|
|
3091
|
+
if (level === void 0) {
|
|
3092
|
+
return errors;
|
|
3093
|
+
}
|
|
3094
|
+
const parentHeading = getParentElement({
|
|
3095
|
+
element,
|
|
3096
|
+
schemaCode: HEADING_SCHEMA.code,
|
|
3097
|
+
filterDeletedNodes: true
|
|
3098
|
+
});
|
|
3099
|
+
if (!parentHeading) {
|
|
3100
|
+
if (level !== 1) {
|
|
3101
|
+
addValidationIssue(errors, {
|
|
3102
|
+
store: getStore(element),
|
|
3103
|
+
title: "Missing heading H1",
|
|
3104
|
+
kind: "missing",
|
|
3105
|
+
description: `H${level} is not under an H1. Please check the heading hierarchy.`,
|
|
3106
|
+
level: "warning"
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
3109
|
+
return errors;
|
|
3110
|
+
}
|
|
3111
|
+
const parentLevel = getHierarchyLevel(parentHeading);
|
|
3112
|
+
if (parentLevel === void 0) {
|
|
3113
|
+
return errors;
|
|
3114
|
+
}
|
|
3115
|
+
const expectedLevel = parentLevel + 1;
|
|
3116
|
+
if (level === expectedLevel) {
|
|
3117
|
+
return errors;
|
|
3118
|
+
}
|
|
3119
|
+
addValidationIssue(errors, {
|
|
3120
|
+
store: getStore(element),
|
|
3121
|
+
title: "Invalid heading hierarchy",
|
|
3122
|
+
kind: "forbidden",
|
|
3123
|
+
description: `H${level} cannot follow H${parentLevel} directly. Please check the heading hierarchy.`,
|
|
3124
|
+
level: "warning"
|
|
3125
|
+
});
|
|
3126
|
+
return errors;
|
|
3127
|
+
};
|
|
3128
|
+
|
|
3059
3129
|
// src/validation/validateXml.ts
|
|
3060
3130
|
var validateElement = (element, root, elementsToLink, linkElements, schemasToValidateAgainst) => {
|
|
3061
3131
|
if (isIgnoredElement(element)) {
|
|
@@ -3076,6 +3146,9 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
|
|
|
3076
3146
|
if (schema.tag === FOOTNOTE_SCHEMA.tag) {
|
|
3077
3147
|
errors.push(...validateFootnoteCue(element, linkElements));
|
|
3078
3148
|
}
|
|
3149
|
+
if (schema.code === HEADING_SCHEMA.code) {
|
|
3150
|
+
errors.push(...validateHeadingHierarchy(element));
|
|
3151
|
+
}
|
|
3079
3152
|
if (isIgnoredValidation(schema.code)) {
|
|
3080
3153
|
return errors;
|
|
3081
3154
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1950,7 +1950,8 @@ var FOOTNOTE_SECTION_SCHEMA = createSchema({
|
|
|
1950
1950
|
});
|
|
1951
1951
|
|
|
1952
1952
|
// src/schema/elementSchemas/elements/heading.ts
|
|
1953
|
-
var
|
|
1953
|
+
var HEADING_LEVEL = ["H1", "H2", "H3", "H4", "H5", "H6"];
|
|
1954
|
+
var HEADING_ROLES = [...HEADING_LEVEL, "vignette_group"];
|
|
1954
1955
|
var HEADING_SCHEMA = createSchema({
|
|
1955
1956
|
code: "heading",
|
|
1956
1957
|
kind: "element",
|
|
@@ -2575,23 +2576,22 @@ var retrieveTextIgnoringNodesWithSelector = (element, selector = ".del") => {
|
|
|
2575
2576
|
return clonedElement.textContent || "";
|
|
2576
2577
|
};
|
|
2577
2578
|
|
|
2579
|
+
// src/validation/utils/isDeletedElement.ts
|
|
2580
|
+
var isDeletedElement = (element) => {
|
|
2581
|
+
return !!element.closest(".del");
|
|
2582
|
+
};
|
|
2583
|
+
|
|
2578
2584
|
// src/validation/utils/getElementsSelector.ts
|
|
2579
2585
|
var getElementsSelector = ({
|
|
2580
2586
|
element,
|
|
2581
2587
|
selector,
|
|
2582
2588
|
filterDeletedNodes
|
|
2583
2589
|
}) => {
|
|
2584
|
-
const elements = element.querySelectorAll(selector);
|
|
2590
|
+
const elements = Array.from(element.querySelectorAll(selector));
|
|
2585
2591
|
if (filterDeletedNodes) {
|
|
2586
|
-
return
|
|
2587
|
-
const hasDeletedParent = element2.closest(".del") !== null;
|
|
2588
|
-
if (hasDeletedParent) {
|
|
2589
|
-
return false;
|
|
2590
|
-
}
|
|
2591
|
-
return true;
|
|
2592
|
-
});
|
|
2592
|
+
return elements.filter((element2) => !isDeletedElement(element2));
|
|
2593
2593
|
}
|
|
2594
|
-
return
|
|
2594
|
+
return elements;
|
|
2595
2595
|
};
|
|
2596
2596
|
|
|
2597
2597
|
// src/validation/validateLinkend.ts
|
|
@@ -2976,6 +2976,76 @@ var validatePossibleWeblinks = (root) => {
|
|
|
2976
2976
|
return errors;
|
|
2977
2977
|
};
|
|
2978
2978
|
|
|
2979
|
+
// src/validation/utils/getParentElement.ts
|
|
2980
|
+
var getParentElement = ({
|
|
2981
|
+
element,
|
|
2982
|
+
schemaCode,
|
|
2983
|
+
filterDeletedNodes
|
|
2984
|
+
}) => {
|
|
2985
|
+
let current = element.parentElement;
|
|
2986
|
+
while (current) {
|
|
2987
|
+
const isValidParent = findSchemaByElement(current)?.code === schemaCode;
|
|
2988
|
+
const isFilterDeleted = filterDeletedNodes && isDeletedElement(current);
|
|
2989
|
+
if (isValidParent || isFilterDeleted) {
|
|
2990
|
+
return current;
|
|
2991
|
+
}
|
|
2992
|
+
current = current.parentElement;
|
|
2993
|
+
}
|
|
2994
|
+
return void 0;
|
|
2995
|
+
};
|
|
2996
|
+
|
|
2997
|
+
// src/validation/validateHeadingHierarchy.ts
|
|
2998
|
+
var getHierarchyLevel = (element) => {
|
|
2999
|
+
const role = element.getAttribute("role");
|
|
3000
|
+
if (!role) return void 0;
|
|
3001
|
+
const validHeadingLevel = HEADING_LEVEL.indexOf(role) + 1;
|
|
3002
|
+
if (!validHeadingLevel) return void 0;
|
|
3003
|
+
return validHeadingLevel;
|
|
3004
|
+
};
|
|
3005
|
+
var validateHeadingHierarchy = (element) => {
|
|
3006
|
+
const errors = [];
|
|
3007
|
+
if (isDeletedElement(element)) {
|
|
3008
|
+
return errors;
|
|
3009
|
+
}
|
|
3010
|
+
const level = getHierarchyLevel(element);
|
|
3011
|
+
if (level === void 0) {
|
|
3012
|
+
return errors;
|
|
3013
|
+
}
|
|
3014
|
+
const parentHeading = getParentElement({
|
|
3015
|
+
element,
|
|
3016
|
+
schemaCode: HEADING_SCHEMA.code,
|
|
3017
|
+
filterDeletedNodes: true
|
|
3018
|
+
});
|
|
3019
|
+
if (!parentHeading) {
|
|
3020
|
+
if (level !== 1) {
|
|
3021
|
+
addValidationIssue(errors, {
|
|
3022
|
+
store: getStore(element),
|
|
3023
|
+
title: "Missing heading H1",
|
|
3024
|
+
kind: "missing",
|
|
3025
|
+
description: `H${level} is not under an H1. Please check the heading hierarchy.`,
|
|
3026
|
+
level: "warning"
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3029
|
+
return errors;
|
|
3030
|
+
}
|
|
3031
|
+
const parentLevel = getHierarchyLevel(parentHeading);
|
|
3032
|
+
if (parentLevel === void 0) {
|
|
3033
|
+
return errors;
|
|
3034
|
+
}
|
|
3035
|
+
const expectedLevel = parentLevel + 1;
|
|
3036
|
+
if (level === expectedLevel) {
|
|
3037
|
+
return errors;
|
|
3038
|
+
}
|
|
3039
|
+
addValidationIssue(errors, {
|
|
3040
|
+
store: getStore(element),
|
|
3041
|
+
title: "Invalid heading hierarchy",
|
|
3042
|
+
kind: "forbidden",
|
|
3043
|
+
description: `H${level} cannot follow H${parentLevel} directly. Please check the heading hierarchy.`,
|
|
3044
|
+
level: "warning"
|
|
3045
|
+
});
|
|
3046
|
+
return errors;
|
|
3047
|
+
};
|
|
3048
|
+
|
|
2979
3049
|
// src/validation/validateXml.ts
|
|
2980
3050
|
var validateElement = (element, root, elementsToLink, linkElements, schemasToValidateAgainst) => {
|
|
2981
3051
|
if (isIgnoredElement(element)) {
|
|
@@ -2996,6 +3066,9 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
|
|
|
2996
3066
|
if (schema.tag === FOOTNOTE_SCHEMA.tag) {
|
|
2997
3067
|
errors.push(...validateFootnoteCue(element, linkElements));
|
|
2998
3068
|
}
|
|
3069
|
+
if (schema.code === HEADING_SCHEMA.code) {
|
|
3070
|
+
errors.push(...validateHeadingHierarchy(element));
|
|
3071
|
+
}
|
|
2999
3072
|
if (isIgnoredValidation(schema.code)) {
|
|
3000
3073
|
return errors;
|
|
3001
3074
|
}
|