pro-editor-schema 0.1.200 → 0.2.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/README.md +98 -44
- package/dist/index.d.mts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +143 -171
- package/dist/index.mjs +141 -170
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -7,41 +7,64 @@ TypeScript library that defines XML/HTML schema rules used by the editor and pro
|
|
|
7
7
|
- Schema definitions for supported tags and schema codes.
|
|
8
8
|
- Shared schema constants and attribute helpers.
|
|
9
9
|
- Runtime schema lookup utilities.
|
|
10
|
-
- XML validation utilities (`validateXml
|
|
10
|
+
- XML validation utilities (`validateXml` and related validators).
|
|
11
11
|
- Type-safe element factory (`createElement`) based on schema definitions.
|
|
12
12
|
|
|
13
|
-
## Install
|
|
13
|
+
## Install
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm install
|
|
17
|
-
npm run typecheck
|
|
18
|
-
npm run test
|
|
19
|
-
npm run build
|
|
20
17
|
```
|
|
21
18
|
|
|
19
|
+
## Scripts
|
|
20
|
+
|
|
21
|
+
| Command | Description |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `npm run dev` | Build in watch mode |
|
|
24
|
+
| `npm run build` | Build CJS, ESM, and type declarations |
|
|
25
|
+
| `npm run typecheck` | Run TypeScript without emitting files |
|
|
26
|
+
| `npm run lint` | Run ESLint on `src/` |
|
|
27
|
+
| `npm run test` | Run tests once with Vitest |
|
|
28
|
+
| `npm run test:watch` | Run tests in watch mode |
|
|
29
|
+
| `npm run check` | Run the full verification pipeline (`npm ci`, `typecheck`, `lint`, `test`, `build`) |
|
|
30
|
+
|
|
31
|
+
For local development, `npm run check` is the fastest way to verify everything before pushing.
|
|
32
|
+
|
|
33
|
+
## CI
|
|
34
|
+
|
|
35
|
+
GitHub Actions runs on push and pull requests to `main` / `master`:
|
|
36
|
+
|
|
37
|
+
- **Typecheck** — `npm run typecheck`
|
|
38
|
+
- **Lint** — `npm run lint`
|
|
39
|
+
- **Test** — `npm test`
|
|
40
|
+
|
|
41
|
+
Workflow file: `.github/workflows/ci.yml`
|
|
42
|
+
|
|
22
43
|
## Project structure
|
|
23
44
|
|
|
24
|
-
- `src/index.ts
|
|
25
|
-
- `src/schema/schema.types.ts
|
|
26
|
-
- `src/schema/schemas.ts
|
|
27
|
-
- `src/schema/elementSchemas/elements
|
|
28
|
-
- `src/schema/elementSchemas/atoms
|
|
29
|
-
- `src/schema/elementSchemas/inlineElements
|
|
30
|
-
- `src/schema/shared
|
|
31
|
-
- `src/schema/utils
|
|
32
|
-
- `src/validation
|
|
45
|
+
- `src/index.ts` — public exports for schemas, types, shared constants, and validation.
|
|
46
|
+
- `src/schema/schema.types.ts` — core schema and validation-related types.
|
|
47
|
+
- `src/schema/schemas.ts` — central `SCHEMAS` map (`code -> schema`).
|
|
48
|
+
- `src/schema/elementSchemas/elements` — element schema definitions and `ELEMENT_SCHEMAS`.
|
|
49
|
+
- `src/schema/elementSchemas/atoms` — atom schema definitions and `ATOM_SCHEMAS`.
|
|
50
|
+
- `src/schema/elementSchemas/inlineElements` — inline schema definitions and `INLINE_ELEMENT_SCHEMAS`.
|
|
51
|
+
- `src/schema/shared` — shared attribute and ignored-node constants.
|
|
52
|
+
- `src/schema/utils` — schema lookup, element creation, and label helpers.
|
|
53
|
+
- `src/validation` — document validation entrypoint and validation modules.
|
|
54
|
+
- `src/**/*.test.ts` — Vitest test files (run with `happy-dom`).
|
|
33
55
|
|
|
34
56
|
## Schema model
|
|
35
57
|
|
|
36
58
|
Each schema defines:
|
|
37
59
|
|
|
38
|
-
- `code
|
|
39
|
-
- `kind
|
|
40
|
-
- `tag
|
|
41
|
-
- `requiredAttributes
|
|
42
|
-
- `optionalAttributes
|
|
43
|
-
- `
|
|
44
|
-
- `
|
|
60
|
+
- `code` — internal schema identifier.
|
|
61
|
+
- `kind` — schema category (`element`, `atom`, `inline`).
|
|
62
|
+
- `tag` — uppercase XML tag name used in documents.
|
|
63
|
+
- `requiredAttributes` — required attributes (free or restricted values).
|
|
64
|
+
- `optionalAttributes` — optional attributes (free or restricted values).
|
|
65
|
+
- `defaultChildCode` — preferred child tag (optional, used by some block-like schemas).
|
|
66
|
+
- `allowedChildrenCodes` — allowed child tags and whether each child is required.
|
|
67
|
+
- `matchesElement` — optional predicate to resolve elements that share the same tag (for example `SPAN`, `SECTION1`).
|
|
45
68
|
|
|
46
69
|
Schemas are combined in `SCHEMAS` from:
|
|
47
70
|
|
|
@@ -49,15 +72,29 @@ Schemas are combined in `SCHEMAS` from:
|
|
|
49
72
|
- `ATOM_SCHEMAS`
|
|
50
73
|
- `INLINE_ELEMENT_SCHEMAS`
|
|
51
74
|
|
|
75
|
+
### Resolving schemas from DOM elements
|
|
76
|
+
|
|
77
|
+
`findSchemaByElement` matches by tag name. When multiple schemas share a tag, the first schema with a matching `matchesElement` predicate wins.
|
|
78
|
+
|
|
79
|
+
Examples:
|
|
80
|
+
|
|
81
|
+
- `SPAN` with class `ins` → `insertion`
|
|
82
|
+
- `SPAN` with class `del` → `deletion`
|
|
83
|
+
- `SPAN` with class `cmtQurySection` → `commentQuerySection`
|
|
84
|
+
- `SECTION1` with `role="H1"` → `heading`
|
|
85
|
+
- `SECTION1` with `role="ch"` or a `FOOTNOTE` child → `footnoteSection`
|
|
86
|
+
|
|
87
|
+
When adding a new schema that reuses an existing tag, define `matchesElement` on every schema that shares that tag.
|
|
88
|
+
|
|
52
89
|
## Public API highlights
|
|
53
90
|
|
|
54
91
|
From `src/index.ts`, consumers can import:
|
|
55
92
|
|
|
56
|
-
- Types
|
|
57
|
-
- Maps
|
|
58
|
-
- Utilities
|
|
59
|
-
-
|
|
60
|
-
- Shared constants
|
|
93
|
+
- **Types:** `Schema`, `SchemaCode`, `ElementSchemaCode`, `AtomSchemaCode`, `InlineSchemaCode`, `ValidationError`
|
|
94
|
+
- **Maps:** `SCHEMAS`, `ELEMENT_SCHEMAS`, `ATOM_SCHEMAS`, `INLINE_ELEMENT_SCHEMAS`
|
|
95
|
+
- **Utilities:** `findSchemaByCode`, `findSchemaByElement`, `createElement`, `ElementLabel`
|
|
96
|
+
- **Validation:** `validateXml`
|
|
97
|
+
- **Shared constants:** ignored elements/attributes, global attribute constants, dependents forbidden elements
|
|
61
98
|
|
|
62
99
|
## Usage examples
|
|
63
100
|
|
|
@@ -79,7 +116,6 @@ const para = createElement({
|
|
|
79
116
|
attributes: {
|
|
80
117
|
store: "body",
|
|
81
118
|
"ele-id": "p-1",
|
|
82
|
-
role: "body",
|
|
83
119
|
},
|
|
84
120
|
});
|
|
85
121
|
```
|
|
@@ -89,23 +125,41 @@ const para = createElement({
|
|
|
89
125
|
```ts
|
|
90
126
|
import { validateXml } from "pro-editor-schema";
|
|
91
127
|
|
|
92
|
-
const errors = validateXml(
|
|
128
|
+
const errors = validateXml(
|
|
129
|
+
rootElement,
|
|
130
|
+
elementsToLink,
|
|
131
|
+
linkElements,
|
|
132
|
+
["para", "heading"],
|
|
133
|
+
);
|
|
93
134
|
```
|
|
94
135
|
|
|
95
|
-
`validateXml`
|
|
136
|
+
`validateXml` parameters:
|
|
137
|
+
|
|
138
|
+
- `xml` — root element to validate.
|
|
139
|
+
- `elementsToLink` — IDs available as `linkend` targets.
|
|
140
|
+
- `linkElements` — IDs cited by links (used for reference validation).
|
|
141
|
+
- `schemasToValidateAgainst` — schema codes to run attribute/child validation against.
|
|
142
|
+
|
|
143
|
+
`validateXml` always runs:
|
|
144
|
+
|
|
145
|
+
- Consecutive footnote number checks
|
|
146
|
+
- Consecutive footnote cue checks
|
|
147
|
+
|
|
148
|
+
It also runs per-element checks for:
|
|
149
|
+
|
|
150
|
+
- Link targets (`linkend`) on linkable elements
|
|
151
|
+
- Uncited bibliographic references
|
|
152
|
+
- Unreferenced footnotes
|
|
96
153
|
|
|
97
|
-
-
|
|
98
|
-
- Footnote cue sequence checks
|
|
99
|
-
- Link target checks (`linkend`)
|
|
100
|
-
- Optional schema-based attribute and child validation when enabled
|
|
154
|
+
Schema-based attribute and child validation only runs for codes listed in `schemasToValidateAgainst`.
|
|
101
155
|
|
|
102
156
|
## How validation works
|
|
103
157
|
|
|
104
158
|
- `validateXml` traverses the XML tree and delegates checks per element.
|
|
105
|
-
- `findSchemaByElement` resolves schema from
|
|
106
|
-
- `validateAttributes`
|
|
159
|
+
- `findSchemaByElement` resolves schema from tag and optional `matchesElement`.
|
|
160
|
+
- `validateAttributes` validates restricted attribute values.
|
|
107
161
|
- `validateChildren` ensures child tags are allowed and required children exist.
|
|
108
|
-
- `validateFootnotes` and `
|
|
162
|
+
- `validateFootnotes`, `validateLinkend`, and `validateReferenceCited` provide cross-reference integrity checks.
|
|
109
163
|
|
|
110
164
|
Validation results use `ValidationError`:
|
|
111
165
|
|
|
@@ -118,23 +172,23 @@ Validation results use `ValidationError`:
|
|
|
118
172
|
|
|
119
173
|
## Adding or updating a schema
|
|
120
174
|
|
|
121
|
-
1. Create or update schema file in one of:
|
|
175
|
+
1. Create or update a schema file in one of:
|
|
122
176
|
- `src/schema/elementSchemas/elements`
|
|
123
177
|
- `src/schema/elementSchemas/atoms`
|
|
124
178
|
- `src/schema/elementSchemas/inlineElements`
|
|
125
|
-
2. Define schema with `createSchema(...)`.
|
|
126
|
-
3.
|
|
179
|
+
2. Define the schema with `createSchema(...)`.
|
|
180
|
+
3. If the tag is already used by another schema, add a `matchesElement` predicate.
|
|
181
|
+
4. Register it in the corresponding map:
|
|
127
182
|
- `ELEMENT_SCHEMAS`
|
|
128
183
|
- `ATOM_SCHEMAS`
|
|
129
184
|
- `INLINE_ELEMENT_SCHEMAS`
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
- `npm run typecheck`
|
|
134
|
-
- `npm run test`
|
|
185
|
+
5. Ensure the schema code exists in the matching union type in `schema.types.ts`.
|
|
186
|
+
6. Add or update tests for any new validation or utility behavior.
|
|
187
|
+
7. Run `npm run check`.
|
|
135
188
|
|
|
136
189
|
## Notes
|
|
137
190
|
|
|
138
191
|
- Tag matching is done in uppercase in schema definitions and validation.
|
|
139
192
|
- Some schema codes represent block/group-like structures while still being typed as `kind: "element"` in the current model.
|
|
140
193
|
- Ignored attributes and ignored UI helper elements are excluded from strict validation by design.
|
|
194
|
+
- Track-changes atoms (`insertion`, `deletion`) are unwrapped when validating required children.
|
package/dist/index.d.mts
CHANGED
|
@@ -17,21 +17,21 @@ type Schema<TRequiredAttributes = readonly AttributeDefinition[], TOptionalAttri
|
|
|
17
17
|
requiredAttributes: TRequiredAttributes;
|
|
18
18
|
optionalAttributes: TOptionalAttributes;
|
|
19
19
|
defaultChildCode?: SchemaCode;
|
|
20
|
-
allowedChildrenCodes:
|
|
20
|
+
allowedChildrenCodes: AllowedChildren[];
|
|
21
|
+
matchesElement?: (element: Element) => boolean;
|
|
21
22
|
};
|
|
22
23
|
type SchemaCode = ElementSchemaCode | InlineSchemaCode | AtomSchemaCode;
|
|
23
24
|
type ElementSchemaCode = "referenceBibliomixed" | "referenceBibliography" | "bibliodiv" | "degrees" | "email" | "equation" | "fignote" | "figsource" | "firstname" | "footnote" | "footnoteno" | "honorific" | "img" | "informalfigure" | "keyword" | "label1" | "li" | "line" | "lrh" | "math" | "mathphrase" | "merror" | "mfrac" | "mi" | "mmultiscripts" | "mn" | "mo" | "mover" | "mpadded" | "mphantom" | "mprescripts" | "mroot" | "mrow" | "ms" | "mspace" | "msqrt" | "mstyle" | "msub" | "msubsup" | "msup" | "mtable" | "mtd" | "mtext" | "mtr" | "munder" | "munderover" | "olink" | "org" | "orgname" | "para" | "punc" | "rrh" | "source1" | "speaker" | "subtitle1" | "surname" | "tag" | "tblfn" | "tblsource" | "thead" | "title1" | "token" | "tp" | "abstract1" | "affiliation" | "alttext" | "appendix" | "author" | "authorgroup" | "blockquote" | "caption1" | "chapter" | "dialogue" | "epigraph" | "figure1" | "footnoteSection" | "heading" | "imageobject" | "info1" | "keywordset" | "mediaobject" | "ol" | "personname" | "poem" | "sidebar" | "table" | "table1" | "tbody" | "td" | "tgroup" | "tr" | "ul";
|
|
24
25
|
type AtomSchemaCode = "indexterm" | "primary" | "secondary" | "tertiary" | "quaternary" | "bookmark" | "see" | "commentQuerySection" | "comment" | "content" | "query" | "reply" | "deletion" | "emphasis" | "highlightmark" | "i" | "insertion" | "sc" | "strike" | "sub" | "sup" | "u" | "b" | "referenceMark";
|
|
25
26
|
type InlineSchemaCode = "footnote1" | "inlineequation" | "link" | "uri" | "phrase";
|
|
26
|
-
declare const ElementLabel: Record<SchemaCode, string>;
|
|
27
27
|
|
|
28
28
|
declare const SCHEMAS: Record<SchemaCode, Schema>;
|
|
29
29
|
|
|
30
|
+
declare const isTrackChangesSchema: (schema: Schema) => boolean;
|
|
30
31
|
declare const isIgnoredAttribute: (attribute: string) => boolean;
|
|
31
32
|
declare const isIgnoredElement: (element: Element) => boolean;
|
|
32
33
|
declare const isIgnoredValidation: (code: SchemaCode) => boolean;
|
|
33
|
-
declare const findSchemaByCode: (code: SchemaCode) => Schema
|
|
34
|
-
declare const findSchemaByTagName: (tagName: string) => Schema[];
|
|
34
|
+
declare const findSchemaByCode: (code: SchemaCode) => Schema;
|
|
35
35
|
declare const findSchemaByElement: (element: Element) => Schema | undefined;
|
|
36
36
|
declare const isAttributeRestricted: (attr: AttributeDefinition) => attr is RestrictedAttribute;
|
|
37
37
|
declare const getAttributeName: (attribute: AttributeDefinition) => string;
|
|
@@ -49,12 +49,20 @@ type CreateElementParams<TSchema extends Schema> = {
|
|
|
49
49
|
};
|
|
50
50
|
declare const createElement: <TSchema extends Schema>({ schemaCode, attributes, }: CreateElementParams<TSchema>) => HTMLElement;
|
|
51
51
|
|
|
52
|
+
declare const ElementLabel: Record<SchemaCode, string>;
|
|
53
|
+
|
|
52
54
|
declare const IGNORED_ELEMENT_SELECTORS: string[];
|
|
53
55
|
declare const IGNORED_VALIDATION_ELEMENT_SELECTORS: SchemaCode[];
|
|
54
56
|
|
|
55
57
|
declare const IGNORED_ATTRIBUTES: string[];
|
|
56
58
|
declare const IGNORED_ATTRIBUTES_STARTS_WITH: string[];
|
|
57
59
|
|
|
60
|
+
type DependentForbiddenElement = {
|
|
61
|
+
code: SchemaCode;
|
|
62
|
+
dependentElements: SchemaCode[];
|
|
63
|
+
};
|
|
64
|
+
declare const DEPENDENT_FORBIDDEN_ELEMENTS: DependentForbiddenElement[];
|
|
65
|
+
|
|
58
66
|
declare const ALIGNMENT_ATTRIBUTE = "data-alignment";
|
|
59
67
|
declare const LEFT_INDENT_ATTRIBUTE = "data-left-indent";
|
|
60
68
|
declare const RIGHT_INDENT_ATTRIBUTE = "data-right-indent";
|
|
@@ -105,6 +113,6 @@ type ValidationError = {
|
|
|
105
113
|
* * ValidateConsecutiveFootnotes and ValidateConsecutiveFootnoteCues are default validations.
|
|
106
114
|
* @returns The validation errors.
|
|
107
115
|
*/
|
|
108
|
-
declare const validateXml: (xml: Element, elementsToLink:
|
|
116
|
+
declare const validateXml: (xml: Element, elementsToLink: string[], linkElements: string[], schemasToValidateAgainst: SchemaCode[]) => ValidationError[];
|
|
109
117
|
|
|
110
|
-
export { ALIGNMENT_ATTRIBUTE, ATOM_SCHEMAS, type AllowedChildren, type AtomSchemaCode, type AttributeDefinition, ELEMENT_SCHEMAS, ELE_ID_ATTRIBUTE, ElementLabel, type ElementSchemaCode, FIGURE_PLACEMENT_ATTRIBUTE, type FreeAttribute, ID_ATTRS, IGNORED_ATTRIBUTES, IGNORED_ATTRIBUTES_STARTS_WITH, IGNORED_ELEMENT_SELECTORS, IGNORED_VALIDATION_ELEMENT_SELECTORS, INDENT_TYPE_ATTRIBUTE, INLINE_ELEMENT_SCHEMAS, type InlineSchemaCode, LAYOUT_ATTRIBUTES, LAYOUT_CELL_WIDTH_ATTRIBUTE, LAYOUT_TABLE_ORIENTATION_ATTRIBUTE, LAYOUT_TABLE_PLACEMENT_ATTRIBUTE, LAYOUT_USER_ATTRIBUTE, LEFT_INDENT_ATTRIBUTE, RIGHT_INDENT_ATTRIBUTE, type RestrictedAttribute, SCHEMAS, SPACE_ABOVE_ATTRIBUTE, SPACE_BELOW_ATTRIBUTE, SPECIAL_INDENT_ATTRIBUTE, STORE_ATTRIBUTE, STYLE_NAME_ATTRIBUTE, type Schema, type SchemaCode, type SchemaKind, TRACK_CHANGES_ATTRS, TRACK_CHANGES_ATTR_DATA_DATE, TRACK_CHANGES_ATTR_DATA_TIME, TRACK_CHANGES_ATTR_DATA_USERID, TRACK_CHANGES_ATTR_DATA_USERNAME, type ValidationError, type ValidationErrorKind, type ValidationErrorLevel, createElement, findAttributeDefinitionByName, findSchemaByCode, findSchemaByElement,
|
|
118
|
+
export { ALIGNMENT_ATTRIBUTE, ATOM_SCHEMAS, type AllowedChildren, type AtomSchemaCode, type AttributeDefinition, DEPENDENT_FORBIDDEN_ELEMENTS, ELEMENT_SCHEMAS, ELE_ID_ATTRIBUTE, ElementLabel, type ElementSchemaCode, FIGURE_PLACEMENT_ATTRIBUTE, type FreeAttribute, ID_ATTRS, IGNORED_ATTRIBUTES, IGNORED_ATTRIBUTES_STARTS_WITH, IGNORED_ELEMENT_SELECTORS, IGNORED_VALIDATION_ELEMENT_SELECTORS, INDENT_TYPE_ATTRIBUTE, INLINE_ELEMENT_SCHEMAS, type InlineSchemaCode, LAYOUT_ATTRIBUTES, LAYOUT_CELL_WIDTH_ATTRIBUTE, LAYOUT_TABLE_ORIENTATION_ATTRIBUTE, LAYOUT_TABLE_PLACEMENT_ATTRIBUTE, LAYOUT_USER_ATTRIBUTE, LEFT_INDENT_ATTRIBUTE, RIGHT_INDENT_ATTRIBUTE, type RestrictedAttribute, SCHEMAS, SPACE_ABOVE_ATTRIBUTE, SPACE_BELOW_ATTRIBUTE, SPECIAL_INDENT_ATTRIBUTE, STORE_ATTRIBUTE, STYLE_NAME_ATTRIBUTE, type Schema, type SchemaCode, type SchemaKind, TRACK_CHANGES_ATTRS, TRACK_CHANGES_ATTR_DATA_DATE, TRACK_CHANGES_ATTR_DATA_TIME, TRACK_CHANGES_ATTR_DATA_USERID, TRACK_CHANGES_ATTR_DATA_USERNAME, type ValidationError, type ValidationErrorKind, type ValidationErrorLevel, createElement, findAttributeDefinitionByName, findSchemaByCode, findSchemaByElement, getAttributeName, isAttributeRestricted, isIgnoredAttribute, isIgnoredElement, isIgnoredValidation, isTrackChangesSchema, validateXml };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,21 +17,21 @@ type Schema<TRequiredAttributes = readonly AttributeDefinition[], TOptionalAttri
|
|
|
17
17
|
requiredAttributes: TRequiredAttributes;
|
|
18
18
|
optionalAttributes: TOptionalAttributes;
|
|
19
19
|
defaultChildCode?: SchemaCode;
|
|
20
|
-
allowedChildrenCodes:
|
|
20
|
+
allowedChildrenCodes: AllowedChildren[];
|
|
21
|
+
matchesElement?: (element: Element) => boolean;
|
|
21
22
|
};
|
|
22
23
|
type SchemaCode = ElementSchemaCode | InlineSchemaCode | AtomSchemaCode;
|
|
23
24
|
type ElementSchemaCode = "referenceBibliomixed" | "referenceBibliography" | "bibliodiv" | "degrees" | "email" | "equation" | "fignote" | "figsource" | "firstname" | "footnote" | "footnoteno" | "honorific" | "img" | "informalfigure" | "keyword" | "label1" | "li" | "line" | "lrh" | "math" | "mathphrase" | "merror" | "mfrac" | "mi" | "mmultiscripts" | "mn" | "mo" | "mover" | "mpadded" | "mphantom" | "mprescripts" | "mroot" | "mrow" | "ms" | "mspace" | "msqrt" | "mstyle" | "msub" | "msubsup" | "msup" | "mtable" | "mtd" | "mtext" | "mtr" | "munder" | "munderover" | "olink" | "org" | "orgname" | "para" | "punc" | "rrh" | "source1" | "speaker" | "subtitle1" | "surname" | "tag" | "tblfn" | "tblsource" | "thead" | "title1" | "token" | "tp" | "abstract1" | "affiliation" | "alttext" | "appendix" | "author" | "authorgroup" | "blockquote" | "caption1" | "chapter" | "dialogue" | "epigraph" | "figure1" | "footnoteSection" | "heading" | "imageobject" | "info1" | "keywordset" | "mediaobject" | "ol" | "personname" | "poem" | "sidebar" | "table" | "table1" | "tbody" | "td" | "tgroup" | "tr" | "ul";
|
|
24
25
|
type AtomSchemaCode = "indexterm" | "primary" | "secondary" | "tertiary" | "quaternary" | "bookmark" | "see" | "commentQuerySection" | "comment" | "content" | "query" | "reply" | "deletion" | "emphasis" | "highlightmark" | "i" | "insertion" | "sc" | "strike" | "sub" | "sup" | "u" | "b" | "referenceMark";
|
|
25
26
|
type InlineSchemaCode = "footnote1" | "inlineequation" | "link" | "uri" | "phrase";
|
|
26
|
-
declare const ElementLabel: Record<SchemaCode, string>;
|
|
27
27
|
|
|
28
28
|
declare const SCHEMAS: Record<SchemaCode, Schema>;
|
|
29
29
|
|
|
30
|
+
declare const isTrackChangesSchema: (schema: Schema) => boolean;
|
|
30
31
|
declare const isIgnoredAttribute: (attribute: string) => boolean;
|
|
31
32
|
declare const isIgnoredElement: (element: Element) => boolean;
|
|
32
33
|
declare const isIgnoredValidation: (code: SchemaCode) => boolean;
|
|
33
|
-
declare const findSchemaByCode: (code: SchemaCode) => Schema
|
|
34
|
-
declare const findSchemaByTagName: (tagName: string) => Schema[];
|
|
34
|
+
declare const findSchemaByCode: (code: SchemaCode) => Schema;
|
|
35
35
|
declare const findSchemaByElement: (element: Element) => Schema | undefined;
|
|
36
36
|
declare const isAttributeRestricted: (attr: AttributeDefinition) => attr is RestrictedAttribute;
|
|
37
37
|
declare const getAttributeName: (attribute: AttributeDefinition) => string;
|
|
@@ -49,12 +49,20 @@ type CreateElementParams<TSchema extends Schema> = {
|
|
|
49
49
|
};
|
|
50
50
|
declare const createElement: <TSchema extends Schema>({ schemaCode, attributes, }: CreateElementParams<TSchema>) => HTMLElement;
|
|
51
51
|
|
|
52
|
+
declare const ElementLabel: Record<SchemaCode, string>;
|
|
53
|
+
|
|
52
54
|
declare const IGNORED_ELEMENT_SELECTORS: string[];
|
|
53
55
|
declare const IGNORED_VALIDATION_ELEMENT_SELECTORS: SchemaCode[];
|
|
54
56
|
|
|
55
57
|
declare const IGNORED_ATTRIBUTES: string[];
|
|
56
58
|
declare const IGNORED_ATTRIBUTES_STARTS_WITH: string[];
|
|
57
59
|
|
|
60
|
+
type DependentForbiddenElement = {
|
|
61
|
+
code: SchemaCode;
|
|
62
|
+
dependentElements: SchemaCode[];
|
|
63
|
+
};
|
|
64
|
+
declare const DEPENDENT_FORBIDDEN_ELEMENTS: DependentForbiddenElement[];
|
|
65
|
+
|
|
58
66
|
declare const ALIGNMENT_ATTRIBUTE = "data-alignment";
|
|
59
67
|
declare const LEFT_INDENT_ATTRIBUTE = "data-left-indent";
|
|
60
68
|
declare const RIGHT_INDENT_ATTRIBUTE = "data-right-indent";
|
|
@@ -105,6 +113,6 @@ type ValidationError = {
|
|
|
105
113
|
* * ValidateConsecutiveFootnotes and ValidateConsecutiveFootnoteCues are default validations.
|
|
106
114
|
* @returns The validation errors.
|
|
107
115
|
*/
|
|
108
|
-
declare const validateXml: (xml: Element, elementsToLink:
|
|
116
|
+
declare const validateXml: (xml: Element, elementsToLink: string[], linkElements: string[], schemasToValidateAgainst: SchemaCode[]) => ValidationError[];
|
|
109
117
|
|
|
110
|
-
export { ALIGNMENT_ATTRIBUTE, ATOM_SCHEMAS, type AllowedChildren, type AtomSchemaCode, type AttributeDefinition, ELEMENT_SCHEMAS, ELE_ID_ATTRIBUTE, ElementLabel, type ElementSchemaCode, FIGURE_PLACEMENT_ATTRIBUTE, type FreeAttribute, ID_ATTRS, IGNORED_ATTRIBUTES, IGNORED_ATTRIBUTES_STARTS_WITH, IGNORED_ELEMENT_SELECTORS, IGNORED_VALIDATION_ELEMENT_SELECTORS, INDENT_TYPE_ATTRIBUTE, INLINE_ELEMENT_SCHEMAS, type InlineSchemaCode, LAYOUT_ATTRIBUTES, LAYOUT_CELL_WIDTH_ATTRIBUTE, LAYOUT_TABLE_ORIENTATION_ATTRIBUTE, LAYOUT_TABLE_PLACEMENT_ATTRIBUTE, LAYOUT_USER_ATTRIBUTE, LEFT_INDENT_ATTRIBUTE, RIGHT_INDENT_ATTRIBUTE, type RestrictedAttribute, SCHEMAS, SPACE_ABOVE_ATTRIBUTE, SPACE_BELOW_ATTRIBUTE, SPECIAL_INDENT_ATTRIBUTE, STORE_ATTRIBUTE, STYLE_NAME_ATTRIBUTE, type Schema, type SchemaCode, type SchemaKind, TRACK_CHANGES_ATTRS, TRACK_CHANGES_ATTR_DATA_DATE, TRACK_CHANGES_ATTR_DATA_TIME, TRACK_CHANGES_ATTR_DATA_USERID, TRACK_CHANGES_ATTR_DATA_USERNAME, type ValidationError, type ValidationErrorKind, type ValidationErrorLevel, createElement, findAttributeDefinitionByName, findSchemaByCode, findSchemaByElement,
|
|
118
|
+
export { ALIGNMENT_ATTRIBUTE, ATOM_SCHEMAS, type AllowedChildren, type AtomSchemaCode, type AttributeDefinition, DEPENDENT_FORBIDDEN_ELEMENTS, ELEMENT_SCHEMAS, ELE_ID_ATTRIBUTE, ElementLabel, type ElementSchemaCode, FIGURE_PLACEMENT_ATTRIBUTE, type FreeAttribute, ID_ATTRS, IGNORED_ATTRIBUTES, IGNORED_ATTRIBUTES_STARTS_WITH, IGNORED_ELEMENT_SELECTORS, IGNORED_VALIDATION_ELEMENT_SELECTORS, INDENT_TYPE_ATTRIBUTE, INLINE_ELEMENT_SCHEMAS, type InlineSchemaCode, LAYOUT_ATTRIBUTES, LAYOUT_CELL_WIDTH_ATTRIBUTE, LAYOUT_TABLE_ORIENTATION_ATTRIBUTE, LAYOUT_TABLE_PLACEMENT_ATTRIBUTE, LAYOUT_USER_ATTRIBUTE, LEFT_INDENT_ATTRIBUTE, RIGHT_INDENT_ATTRIBUTE, type RestrictedAttribute, SCHEMAS, SPACE_ABOVE_ATTRIBUTE, SPACE_BELOW_ATTRIBUTE, SPECIAL_INDENT_ATTRIBUTE, STORE_ATTRIBUTE, STYLE_NAME_ATTRIBUTE, type Schema, type SchemaCode, type SchemaKind, TRACK_CHANGES_ATTRS, TRACK_CHANGES_ATTR_DATA_DATE, TRACK_CHANGES_ATTR_DATA_TIME, TRACK_CHANGES_ATTR_DATA_USERID, TRACK_CHANGES_ATTR_DATA_USERNAME, type ValidationError, type ValidationErrorKind, type ValidationErrorLevel, createElement, findAttributeDefinitionByName, findSchemaByCode, findSchemaByElement, getAttributeName, isAttributeRestricted, isIgnoredAttribute, isIgnoredElement, isIgnoredValidation, isTrackChangesSchema, validateXml };
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
ALIGNMENT_ATTRIBUTE: () => ALIGNMENT_ATTRIBUTE,
|
|
24
24
|
ATOM_SCHEMAS: () => ATOM_SCHEMAS,
|
|
25
|
+
DEPENDENT_FORBIDDEN_ELEMENTS: () => DEPENDENT_FORBIDDEN_ELEMENTS,
|
|
25
26
|
ELEMENT_SCHEMAS: () => ELEMENT_SCHEMAS,
|
|
26
27
|
ELE_ID_ATTRIBUTE: () => ELE_ID_ATTRIBUTE,
|
|
27
28
|
ElementLabel: () => ElementLabel,
|
|
@@ -55,35 +56,19 @@ __export(index_exports, {
|
|
|
55
56
|
findAttributeDefinitionByName: () => findAttributeDefinitionByName,
|
|
56
57
|
findSchemaByCode: () => findSchemaByCode,
|
|
57
58
|
findSchemaByElement: () => findSchemaByElement,
|
|
58
|
-
findSchemaByTagName: () => findSchemaByTagName,
|
|
59
59
|
getAttributeName: () => getAttributeName,
|
|
60
60
|
isAttributeRestricted: () => isAttributeRestricted,
|
|
61
61
|
isIgnoredAttribute: () => isIgnoredAttribute,
|
|
62
62
|
isIgnoredElement: () => isIgnoredElement,
|
|
63
63
|
isIgnoredValidation: () => isIgnoredValidation,
|
|
64
|
+
isTrackChangesSchema: () => isTrackChangesSchema,
|
|
64
65
|
validateXml: () => validateXml
|
|
65
66
|
});
|
|
66
67
|
module.exports = __toCommonJS(index_exports);
|
|
67
68
|
|
|
68
69
|
// src/schema/utils/createSchema.ts
|
|
69
|
-
var createSchema = ({
|
|
70
|
-
|
|
71
|
-
kind,
|
|
72
|
-
tag,
|
|
73
|
-
requiredAttributes,
|
|
74
|
-
optionalAttributes,
|
|
75
|
-
defaultChildCode,
|
|
76
|
-
allowedChildrenCodes
|
|
77
|
-
}) => {
|
|
78
|
-
return {
|
|
79
|
-
code,
|
|
80
|
-
kind,
|
|
81
|
-
tag,
|
|
82
|
-
requiredAttributes,
|
|
83
|
-
optionalAttributes,
|
|
84
|
-
defaultChildCode,
|
|
85
|
-
allowedChildrenCodes: new Set(allowedChildrenCodes)
|
|
86
|
-
};
|
|
70
|
+
var createSchema = (params) => {
|
|
71
|
+
return params;
|
|
87
72
|
};
|
|
88
73
|
|
|
89
74
|
// src/schema/shared/globalAttributes.ts
|
|
@@ -184,6 +169,7 @@ var COMMENT_QUERY_SECTION_SCHEMA = createSchema({
|
|
|
184
169
|
kind: "atom",
|
|
185
170
|
tag: SPAN_TAG,
|
|
186
171
|
code: "commentQuerySection",
|
|
172
|
+
matchesElement: (element) => element.classList.contains("cmtQurySection"),
|
|
187
173
|
requiredAttributes: [...ID_ATTRS, "id"],
|
|
188
174
|
optionalAttributes: [...TRACK_CHANGES_ATTRS, "title"],
|
|
189
175
|
allowedChildrenCodes: [...ATOM_CODES_ALLOWED_CHILDREN]
|
|
@@ -203,6 +189,7 @@ var DELETION_SCHEMA = createSchema({
|
|
|
203
189
|
code: "deletion",
|
|
204
190
|
kind: "atom",
|
|
205
191
|
tag: SPAN_TAG,
|
|
192
|
+
matchesElement: (element) => element.classList.contains("del"),
|
|
206
193
|
requiredAttributes: [...TRACK_CHANGES_ATTRS, ...ID_ATTRS],
|
|
207
194
|
optionalAttributes: [],
|
|
208
195
|
allowedChildrenCodes: [
|
|
@@ -253,6 +240,7 @@ var INSERTION_SCHEMA = createSchema({
|
|
|
253
240
|
code: "insertion",
|
|
254
241
|
kind: "atom",
|
|
255
242
|
tag: SPAN_TAG,
|
|
243
|
+
matchesElement: (element) => element.classList.contains("ins"),
|
|
256
244
|
requiredAttributes: [...TRACK_CHANGES_ATTRS, ...ID_ATTRS],
|
|
257
245
|
optionalAttributes: [],
|
|
258
246
|
allowedChildrenCodes: [
|
|
@@ -1974,15 +1962,21 @@ var EPIGRAPH_SCHEMA = createSchema({
|
|
|
1974
1962
|
});
|
|
1975
1963
|
|
|
1976
1964
|
// src/schema/elementSchemas/elements/footnoteSection.ts
|
|
1965
|
+
var FOOTNOTE_SECTION_ROLES = ["ch", "bk"];
|
|
1977
1966
|
var FOOTNOTE_SECTION_SCHEMA = createSchema({
|
|
1978
1967
|
code: "footnoteSection",
|
|
1979
1968
|
kind: "element",
|
|
1980
1969
|
tag: SECTION_TAG,
|
|
1970
|
+
matchesElement: (element) => {
|
|
1971
|
+
const role = element.getAttribute("role");
|
|
1972
|
+
if (role && FOOTNOTE_SECTION_ROLES.includes(role)) return true;
|
|
1973
|
+
return element.querySelector(FOOTNOTE_TAG) !== null;
|
|
1974
|
+
},
|
|
1981
1975
|
requiredAttributes: [
|
|
1982
1976
|
...ID_ATTRS,
|
|
1983
1977
|
{
|
|
1984
1978
|
name: "role",
|
|
1985
|
-
values:
|
|
1979
|
+
values: FOOTNOTE_SECTION_ROLES,
|
|
1986
1980
|
defaultValue: "ch"
|
|
1987
1981
|
}
|
|
1988
1982
|
],
|
|
@@ -1995,16 +1989,22 @@ var FOOTNOTE_SECTION_SCHEMA = createSchema({
|
|
|
1995
1989
|
});
|
|
1996
1990
|
|
|
1997
1991
|
// src/schema/elementSchemas/elements/heading.ts
|
|
1992
|
+
var HEADING_ROLES = ["H1", "H2", "H3", "H4", "H5", "H6", "vignette_group"];
|
|
1998
1993
|
var HEADING_SCHEMA = createSchema({
|
|
1999
1994
|
code: "heading",
|
|
2000
1995
|
kind: "element",
|
|
2001
1996
|
tag: SECTION_TAG,
|
|
1997
|
+
matchesElement: (element) => {
|
|
1998
|
+
const role = element.getAttribute("role");
|
|
1999
|
+
if (!role) return false;
|
|
2000
|
+
return HEADING_ROLES.includes(role);
|
|
2001
|
+
},
|
|
2002
2002
|
requiredAttributes: [
|
|
2003
2003
|
...ID_ATTRS,
|
|
2004
2004
|
"xmlid",
|
|
2005
2005
|
{
|
|
2006
2006
|
name: "role",
|
|
2007
|
-
values:
|
|
2007
|
+
values: HEADING_ROLES,
|
|
2008
2008
|
defaultValue: "H1"
|
|
2009
2009
|
}
|
|
2010
2010
|
],
|
|
@@ -2071,17 +2071,7 @@ var MATHPHRASE_SCHEMA = createSchema({
|
|
|
2071
2071
|
tag: MATHPHRASE_TAG,
|
|
2072
2072
|
requiredAttributes: [ELE_ID_ATTRIBUTE],
|
|
2073
2073
|
optionalAttributes: [],
|
|
2074
|
-
allowedChildrenCodes: [
|
|
2075
|
-
{ code: MATH_SCHEMA.code, required: true },
|
|
2076
|
-
{
|
|
2077
|
-
code: INSERTION_SCHEMA.code,
|
|
2078
|
-
required: false
|
|
2079
|
-
},
|
|
2080
|
-
{
|
|
2081
|
-
code: DELETION_SCHEMA.code,
|
|
2082
|
-
required: false
|
|
2083
|
-
}
|
|
2084
|
-
]
|
|
2074
|
+
allowedChildrenCodes: [{ code: MATH_SCHEMA.code, required: true }]
|
|
2085
2075
|
});
|
|
2086
2076
|
|
|
2087
2077
|
// src/schema/elementSchemas/elements/reference/bibliodiv.ts
|
|
@@ -2339,7 +2329,78 @@ var SCHEMAS = {
|
|
|
2339
2329
|
...INLINE_ELEMENT_SCHEMAS
|
|
2340
2330
|
};
|
|
2341
2331
|
|
|
2342
|
-
// src/schema/
|
|
2332
|
+
// src/schema/shared/ignoredElements.ts
|
|
2333
|
+
var IGNORED_ELEMENT_SELECTORS = [
|
|
2334
|
+
"span.rhlabel",
|
|
2335
|
+
"span.printlabel",
|
|
2336
|
+
"span.refIcon",
|
|
2337
|
+
"span.missLink",
|
|
2338
|
+
"span.ref-drag"
|
|
2339
|
+
];
|
|
2340
|
+
var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
|
|
2341
|
+
"referenceBibliomixed"
|
|
2342
|
+
];
|
|
2343
|
+
|
|
2344
|
+
// src/schema/shared/ignoredAttributes.ts
|
|
2345
|
+
var IGNORED_ATTRIBUTES = [
|
|
2346
|
+
// Styling & layout
|
|
2347
|
+
"class",
|
|
2348
|
+
"style",
|
|
2349
|
+
// Editor state
|
|
2350
|
+
"contenteditable",
|
|
2351
|
+
"draggable",
|
|
2352
|
+
"data-prevpos",
|
|
2353
|
+
"tabindex",
|
|
2354
|
+
// Browser behaviour
|
|
2355
|
+
"spellcheck",
|
|
2356
|
+
"translate",
|
|
2357
|
+
"lang",
|
|
2358
|
+
"dir",
|
|
2359
|
+
"hidden",
|
|
2360
|
+
"data-gramm"
|
|
2361
|
+
];
|
|
2362
|
+
var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
|
|
2363
|
+
|
|
2364
|
+
// src/schema/utils/utils.ts
|
|
2365
|
+
var isTrackChangesSchema = (schema) => schema.code === "insertion" || schema.code === "deletion";
|
|
2366
|
+
var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
|
|
2367
|
+
(startsWith) => attribute.startsWith(startsWith)
|
|
2368
|
+
);
|
|
2369
|
+
var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
|
|
2370
|
+
var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
|
|
2371
|
+
var findSchemaByCode = (code) => SCHEMAS[code];
|
|
2372
|
+
var findSchemaByElement = (element) => {
|
|
2373
|
+
const schema = Object.values(SCHEMAS).find(
|
|
2374
|
+
(schema2) => schema2.tag == element.tagName && (!schema2.matchesElement || schema2.matchesElement(element))
|
|
2375
|
+
);
|
|
2376
|
+
return schema;
|
|
2377
|
+
};
|
|
2378
|
+
var isAttributeRestricted = (attr) => typeof attr !== "string";
|
|
2379
|
+
var getAttributeName = (attribute) => typeof attribute === "string" ? attribute.toLowerCase() : attribute.name.toLowerCase();
|
|
2380
|
+
var findAttributeDefinitionByName = (definitions, name) => {
|
|
2381
|
+
for (const def of definitions) {
|
|
2382
|
+
if (getAttributeName(def) === name.toLowerCase()) {
|
|
2383
|
+
return def;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
return void 0;
|
|
2387
|
+
};
|
|
2388
|
+
|
|
2389
|
+
// src/schema/utils/createElement.ts
|
|
2390
|
+
var createElement = ({
|
|
2391
|
+
schemaCode,
|
|
2392
|
+
attributes
|
|
2393
|
+
}) => {
|
|
2394
|
+
const schema = findSchemaByCode(schemaCode);
|
|
2395
|
+
const element = document.createElement(schema.tag.toLowerCase());
|
|
2396
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
2397
|
+
if (!value) continue;
|
|
2398
|
+
element.setAttribute(name, String(value));
|
|
2399
|
+
}
|
|
2400
|
+
return element;
|
|
2401
|
+
};
|
|
2402
|
+
|
|
2403
|
+
// src/schema/shared/labelElements.ts
|
|
2343
2404
|
var ElementLabel = {
|
|
2344
2405
|
referenceBibliomixed: "Reference Bibliomixed",
|
|
2345
2406
|
referenceBibliography: "Reference Bibliography",
|
|
@@ -2464,111 +2525,13 @@ var ElementLabel = {
|
|
|
2464
2525
|
phrase: "Phrase"
|
|
2465
2526
|
};
|
|
2466
2527
|
|
|
2467
|
-
// src/schema/shared/
|
|
2468
|
-
var
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
"span.missLink",
|
|
2473
|
-
"span.ref-drag"
|
|
2474
|
-
];
|
|
2475
|
-
var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
|
|
2476
|
-
"referenceBibliomixed"
|
|
2477
|
-
];
|
|
2478
|
-
|
|
2479
|
-
// src/schema/shared/ignoredAttributes.ts
|
|
2480
|
-
var IGNORED_ATTRIBUTES = [
|
|
2481
|
-
// Styling & layout
|
|
2482
|
-
"class",
|
|
2483
|
-
"style",
|
|
2484
|
-
// Editor state
|
|
2485
|
-
"contenteditable",
|
|
2486
|
-
"draggable",
|
|
2487
|
-
"data-prevpos",
|
|
2488
|
-
"tabindex",
|
|
2489
|
-
// Browser behaviour
|
|
2490
|
-
"spellcheck",
|
|
2491
|
-
"translate",
|
|
2492
|
-
"lang",
|
|
2493
|
-
"dir",
|
|
2494
|
-
"hidden",
|
|
2495
|
-
"data-gramm"
|
|
2496
|
-
];
|
|
2497
|
-
var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
|
|
2498
|
-
|
|
2499
|
-
// src/schema/utils/utils.ts
|
|
2500
|
-
var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
|
|
2501
|
-
(startsWith) => attribute.startsWith(startsWith)
|
|
2502
|
-
);
|
|
2503
|
-
var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
|
|
2504
|
-
var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
|
|
2505
|
-
var findSchemaByCode = (code) => SCHEMAS[code];
|
|
2506
|
-
var findSchemaByTagName = (tagName) => Object.values(SCHEMAS).filter(
|
|
2507
|
-
(schema) => schema.tag === tagName.toUpperCase()
|
|
2508
|
-
);
|
|
2509
|
-
var findSchemaByElement = (element) => {
|
|
2510
|
-
const tagName = element.tagName.toUpperCase();
|
|
2511
|
-
const isInsertion = element.classList.contains("ins");
|
|
2512
|
-
const isDeletion = element.classList.contains("del");
|
|
2513
|
-
const isQueryComment = element.classList.contains("cmtQurySection");
|
|
2514
|
-
const role = element.getAttribute("role");
|
|
2515
|
-
if (tagName === SPAN_TAG) {
|
|
2516
|
-
if (isQueryComment) {
|
|
2517
|
-
return findSchemaByCode("commentQuerySection");
|
|
2518
|
-
}
|
|
2519
|
-
if (isInsertion) {
|
|
2520
|
-
return findSchemaByCode("insertion");
|
|
2521
|
-
}
|
|
2522
|
-
if (isDeletion) {
|
|
2523
|
-
return findSchemaByCode("deletion");
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
if (tagName === SECTION_TAG) {
|
|
2527
|
-
if (role) {
|
|
2528
|
-
if (role.startsWith("H")) {
|
|
2529
|
-
return findSchemaByCode("heading");
|
|
2530
|
-
}
|
|
2531
|
-
if (role === "ch" || role === "bk") {
|
|
2532
|
-
return findSchemaByCode("footnoteSection");
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
const isFootnoteSectionWithoutRole = element.querySelector(FOOTNOTE_TAG);
|
|
2536
|
-
if (isFootnoteSectionWithoutRole) {
|
|
2537
|
-
return findSchemaByCode("footnoteSection");
|
|
2538
|
-
}
|
|
2539
|
-
}
|
|
2540
|
-
const candidates = findSchemaByTagName(tagName);
|
|
2541
|
-
return candidates[0];
|
|
2542
|
-
};
|
|
2543
|
-
var isAttributeRestricted = (attr) => typeof attr !== "string";
|
|
2544
|
-
var getAttributeName = (attribute) => typeof attribute === "string" ? attribute.toLowerCase() : attribute.name.toLowerCase();
|
|
2545
|
-
var findAttributeDefinitionByName = (definitions, name) => {
|
|
2546
|
-
for (const def of definitions) {
|
|
2547
|
-
if (getAttributeName(def) === name.toLowerCase()) {
|
|
2548
|
-
return def;
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
return void 0;
|
|
2552
|
-
};
|
|
2553
|
-
|
|
2554
|
-
// src/schema/utils/createElement.ts
|
|
2555
|
-
var createElement = ({
|
|
2556
|
-
schemaCode,
|
|
2557
|
-
attributes
|
|
2558
|
-
}) => {
|
|
2559
|
-
const schema = findSchemaByCode(schemaCode);
|
|
2560
|
-
if (!schema) {
|
|
2561
|
-
throw new Error(`Schema not found for code: ${schemaCode}`);
|
|
2562
|
-
}
|
|
2563
|
-
const element = document.createElement(schema.tag.toLowerCase());
|
|
2564
|
-
for (const [name, value] of Object.entries(attributes)) {
|
|
2565
|
-
if (value === void 0) {
|
|
2566
|
-
continue;
|
|
2567
|
-
}
|
|
2568
|
-
element.setAttribute(name, String(value));
|
|
2528
|
+
// src/schema/shared/dependentsForbiddenElements.ts
|
|
2529
|
+
var DEPENDENT_FORBIDDEN_ELEMENTS = [
|
|
2530
|
+
{
|
|
2531
|
+
code: "commentQuerySection",
|
|
2532
|
+
dependentElements: ["query", "comment", "reply", "content"]
|
|
2569
2533
|
}
|
|
2570
|
-
|
|
2571
|
-
};
|
|
2534
|
+
];
|
|
2572
2535
|
|
|
2573
2536
|
// src/validation/utils/generateValidationIssueId.ts
|
|
2574
2537
|
var generateValidationIssueId = () => {
|
|
@@ -2791,12 +2754,47 @@ var validateElementAgainstSchema = (element, schema) => {
|
|
|
2791
2754
|
errors.push(...validateChildren(element, schema));
|
|
2792
2755
|
return errors;
|
|
2793
2756
|
};
|
|
2794
|
-
var
|
|
2757
|
+
var validateRequiredChildren = (element, schema, childElements) => {
|
|
2795
2758
|
const errors = [];
|
|
2759
|
+
for (const allowedChild of schema.allowedChildrenCodes) {
|
|
2760
|
+
if (!allowedChild.required) {
|
|
2761
|
+
continue;
|
|
2762
|
+
}
|
|
2763
|
+
const hasChild = childElements.some((child) => {
|
|
2764
|
+
const childSchema = findSchemaByElement(child);
|
|
2765
|
+
return childSchema?.code === allowedChild.code;
|
|
2766
|
+
});
|
|
2767
|
+
if (!hasChild) {
|
|
2768
|
+
const requiredChildrenTag = findSchemaByCode(allowedChild.code).tag;
|
|
2769
|
+
addValidationIssue(errors, {
|
|
2770
|
+
store: getStore(element),
|
|
2771
|
+
title: `Missing required child element ${requiredChildrenTag}`,
|
|
2772
|
+
level: "warning",
|
|
2773
|
+
kind: "missing",
|
|
2774
|
+
description: `The child element ${requiredChildrenTag} is required but not present.`
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
return errors;
|
|
2779
|
+
};
|
|
2780
|
+
var getEffectiveChildElements = (element) => {
|
|
2781
|
+
const effectiveChildren = [];
|
|
2796
2782
|
const childElements = [...element.children].filter(
|
|
2797
2783
|
(child) => !isIgnoredElement(child)
|
|
2798
2784
|
);
|
|
2799
|
-
const
|
|
2785
|
+
for (const child of childElements) {
|
|
2786
|
+
const childSchema = findSchemaByElement(child);
|
|
2787
|
+
if (childSchema && isTrackChangesSchema(childSchema)) {
|
|
2788
|
+
effectiveChildren.push(...getEffectiveChildElements(child));
|
|
2789
|
+
continue;
|
|
2790
|
+
}
|
|
2791
|
+
effectiveChildren.push(child);
|
|
2792
|
+
}
|
|
2793
|
+
return effectiveChildren;
|
|
2794
|
+
};
|
|
2795
|
+
var validateChildren = (element, schema) => {
|
|
2796
|
+
const errors = [];
|
|
2797
|
+
const childElements = getEffectiveChildElements(element);
|
|
2800
2798
|
if (schema.kind === "atom") {
|
|
2801
2799
|
return errors;
|
|
2802
2800
|
}
|
|
@@ -2812,7 +2810,7 @@ var validateChildren = (element, schema) => {
|
|
|
2812
2810
|
});
|
|
2813
2811
|
continue;
|
|
2814
2812
|
}
|
|
2815
|
-
const allowedChild =
|
|
2813
|
+
const allowedChild = schema.allowedChildrenCodes.find(
|
|
2816
2814
|
(candidate) => candidate.code === childSchema.code
|
|
2817
2815
|
);
|
|
2818
2816
|
if (!allowedChild) {
|
|
@@ -2827,34 +2825,7 @@ var validateChildren = (element, schema) => {
|
|
|
2827
2825
|
}
|
|
2828
2826
|
errors.push(...validateElementAgainstSchema(child, childSchema));
|
|
2829
2827
|
}
|
|
2830
|
-
|
|
2831
|
-
if (!allowedChild.required) {
|
|
2832
|
-
continue;
|
|
2833
|
-
}
|
|
2834
|
-
const hasChild = childElements.some((child) => {
|
|
2835
|
-
const childSchema = findSchemaByElement(child);
|
|
2836
|
-
return childSchema?.code === allowedChild.code;
|
|
2837
|
-
});
|
|
2838
|
-
if (!hasChild) {
|
|
2839
|
-
const requiredChildLabel = ElementLabel[allowedChild.code];
|
|
2840
|
-
addValidationIssue(errors, {
|
|
2841
|
-
store: getStore(element),
|
|
2842
|
-
title: `Missing required child element ${requiredChildLabel}`,
|
|
2843
|
-
level: "warning",
|
|
2844
|
-
kind: "missing",
|
|
2845
|
-
description: `The child element ${requiredChildLabel} is required but not present.`
|
|
2846
|
-
});
|
|
2847
|
-
}
|
|
2848
|
-
}
|
|
2849
|
-
if (schema.allowedChildrenCodes.size === 0 && childElements.length > 0) {
|
|
2850
|
-
addValidationIssue(errors, {
|
|
2851
|
-
store: getStore(element),
|
|
2852
|
-
title: "Atom element cannot contain child elements",
|
|
2853
|
-
level: "warning",
|
|
2854
|
-
kind: "forbidden",
|
|
2855
|
-
description: `The element is an atom element and cannot contain child elements.`
|
|
2856
|
-
});
|
|
2857
|
-
}
|
|
2828
|
+
errors.push(...validateRequiredChildren(element, schema, childElements));
|
|
2858
2829
|
return errors;
|
|
2859
2830
|
};
|
|
2860
2831
|
|
|
@@ -2907,9 +2878,9 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
|
|
|
2907
2878
|
if (schemasToValidateAgainst.includes(schema.code)) {
|
|
2908
2879
|
errors.push(...validateElementAgainstSchema(element, schema));
|
|
2909
2880
|
}
|
|
2910
|
-
const role = element.getAttribute("role")
|
|
2881
|
+
const role = element.getAttribute("role");
|
|
2911
2882
|
const linkableRoles = getLinkableRoles();
|
|
2912
|
-
if (schema.tag === LINK_SCHEMA.tag && linkableRoles.includes(role) || schema.tag === FOOTNOTE_LINK_SCHEMA.tag) {
|
|
2883
|
+
if (schema.tag === LINK_SCHEMA.tag && role && linkableRoles.includes(role) || schema.tag === FOOTNOTE_LINK_SCHEMA.tag) {
|
|
2913
2884
|
errors.push(...validateLinkend(element, elementsToLink));
|
|
2914
2885
|
}
|
|
2915
2886
|
if (schema.tag === BIBLIOMIXED_SCHEMA.tag) {
|
|
@@ -2956,6 +2927,7 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
|
|
|
2956
2927
|
0 && (module.exports = {
|
|
2957
2928
|
ALIGNMENT_ATTRIBUTE,
|
|
2958
2929
|
ATOM_SCHEMAS,
|
|
2930
|
+
DEPENDENT_FORBIDDEN_ELEMENTS,
|
|
2959
2931
|
ELEMENT_SCHEMAS,
|
|
2960
2932
|
ELE_ID_ATTRIBUTE,
|
|
2961
2933
|
ElementLabel,
|
|
@@ -2989,11 +2961,11 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
|
|
|
2989
2961
|
findAttributeDefinitionByName,
|
|
2990
2962
|
findSchemaByCode,
|
|
2991
2963
|
findSchemaByElement,
|
|
2992
|
-
findSchemaByTagName,
|
|
2993
2964
|
getAttributeName,
|
|
2994
2965
|
isAttributeRestricted,
|
|
2995
2966
|
isIgnoredAttribute,
|
|
2996
2967
|
isIgnoredElement,
|
|
2997
2968
|
isIgnoredValidation,
|
|
2969
|
+
isTrackChangesSchema,
|
|
2998
2970
|
validateXml
|
|
2999
2971
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
// src/schema/utils/createSchema.ts
|
|
2
|
-
var createSchema = ({
|
|
3
|
-
|
|
4
|
-
kind,
|
|
5
|
-
tag,
|
|
6
|
-
requiredAttributes,
|
|
7
|
-
optionalAttributes,
|
|
8
|
-
defaultChildCode,
|
|
9
|
-
allowedChildrenCodes
|
|
10
|
-
}) => {
|
|
11
|
-
return {
|
|
12
|
-
code,
|
|
13
|
-
kind,
|
|
14
|
-
tag,
|
|
15
|
-
requiredAttributes,
|
|
16
|
-
optionalAttributes,
|
|
17
|
-
defaultChildCode,
|
|
18
|
-
allowedChildrenCodes: new Set(allowedChildrenCodes)
|
|
19
|
-
};
|
|
2
|
+
var createSchema = (params) => {
|
|
3
|
+
return params;
|
|
20
4
|
};
|
|
21
5
|
|
|
22
6
|
// src/schema/shared/globalAttributes.ts
|
|
@@ -117,6 +101,7 @@ var COMMENT_QUERY_SECTION_SCHEMA = createSchema({
|
|
|
117
101
|
kind: "atom",
|
|
118
102
|
tag: SPAN_TAG,
|
|
119
103
|
code: "commentQuerySection",
|
|
104
|
+
matchesElement: (element) => element.classList.contains("cmtQurySection"),
|
|
120
105
|
requiredAttributes: [...ID_ATTRS, "id"],
|
|
121
106
|
optionalAttributes: [...TRACK_CHANGES_ATTRS, "title"],
|
|
122
107
|
allowedChildrenCodes: [...ATOM_CODES_ALLOWED_CHILDREN]
|
|
@@ -136,6 +121,7 @@ var DELETION_SCHEMA = createSchema({
|
|
|
136
121
|
code: "deletion",
|
|
137
122
|
kind: "atom",
|
|
138
123
|
tag: SPAN_TAG,
|
|
124
|
+
matchesElement: (element) => element.classList.contains("del"),
|
|
139
125
|
requiredAttributes: [...TRACK_CHANGES_ATTRS, ...ID_ATTRS],
|
|
140
126
|
optionalAttributes: [],
|
|
141
127
|
allowedChildrenCodes: [
|
|
@@ -186,6 +172,7 @@ var INSERTION_SCHEMA = createSchema({
|
|
|
186
172
|
code: "insertion",
|
|
187
173
|
kind: "atom",
|
|
188
174
|
tag: SPAN_TAG,
|
|
175
|
+
matchesElement: (element) => element.classList.contains("ins"),
|
|
189
176
|
requiredAttributes: [...TRACK_CHANGES_ATTRS, ...ID_ATTRS],
|
|
190
177
|
optionalAttributes: [],
|
|
191
178
|
allowedChildrenCodes: [
|
|
@@ -1907,15 +1894,21 @@ var EPIGRAPH_SCHEMA = createSchema({
|
|
|
1907
1894
|
});
|
|
1908
1895
|
|
|
1909
1896
|
// src/schema/elementSchemas/elements/footnoteSection.ts
|
|
1897
|
+
var FOOTNOTE_SECTION_ROLES = ["ch", "bk"];
|
|
1910
1898
|
var FOOTNOTE_SECTION_SCHEMA = createSchema({
|
|
1911
1899
|
code: "footnoteSection",
|
|
1912
1900
|
kind: "element",
|
|
1913
1901
|
tag: SECTION_TAG,
|
|
1902
|
+
matchesElement: (element) => {
|
|
1903
|
+
const role = element.getAttribute("role");
|
|
1904
|
+
if (role && FOOTNOTE_SECTION_ROLES.includes(role)) return true;
|
|
1905
|
+
return element.querySelector(FOOTNOTE_TAG) !== null;
|
|
1906
|
+
},
|
|
1914
1907
|
requiredAttributes: [
|
|
1915
1908
|
...ID_ATTRS,
|
|
1916
1909
|
{
|
|
1917
1910
|
name: "role",
|
|
1918
|
-
values:
|
|
1911
|
+
values: FOOTNOTE_SECTION_ROLES,
|
|
1919
1912
|
defaultValue: "ch"
|
|
1920
1913
|
}
|
|
1921
1914
|
],
|
|
@@ -1928,16 +1921,22 @@ var FOOTNOTE_SECTION_SCHEMA = createSchema({
|
|
|
1928
1921
|
});
|
|
1929
1922
|
|
|
1930
1923
|
// src/schema/elementSchemas/elements/heading.ts
|
|
1924
|
+
var HEADING_ROLES = ["H1", "H2", "H3", "H4", "H5", "H6", "vignette_group"];
|
|
1931
1925
|
var HEADING_SCHEMA = createSchema({
|
|
1932
1926
|
code: "heading",
|
|
1933
1927
|
kind: "element",
|
|
1934
1928
|
tag: SECTION_TAG,
|
|
1929
|
+
matchesElement: (element) => {
|
|
1930
|
+
const role = element.getAttribute("role");
|
|
1931
|
+
if (!role) return false;
|
|
1932
|
+
return HEADING_ROLES.includes(role);
|
|
1933
|
+
},
|
|
1935
1934
|
requiredAttributes: [
|
|
1936
1935
|
...ID_ATTRS,
|
|
1937
1936
|
"xmlid",
|
|
1938
1937
|
{
|
|
1939
1938
|
name: "role",
|
|
1940
|
-
values:
|
|
1939
|
+
values: HEADING_ROLES,
|
|
1941
1940
|
defaultValue: "H1"
|
|
1942
1941
|
}
|
|
1943
1942
|
],
|
|
@@ -2004,17 +2003,7 @@ var MATHPHRASE_SCHEMA = createSchema({
|
|
|
2004
2003
|
tag: MATHPHRASE_TAG,
|
|
2005
2004
|
requiredAttributes: [ELE_ID_ATTRIBUTE],
|
|
2006
2005
|
optionalAttributes: [],
|
|
2007
|
-
allowedChildrenCodes: [
|
|
2008
|
-
{ code: MATH_SCHEMA.code, required: true },
|
|
2009
|
-
{
|
|
2010
|
-
code: INSERTION_SCHEMA.code,
|
|
2011
|
-
required: false
|
|
2012
|
-
},
|
|
2013
|
-
{
|
|
2014
|
-
code: DELETION_SCHEMA.code,
|
|
2015
|
-
required: false
|
|
2016
|
-
}
|
|
2017
|
-
]
|
|
2006
|
+
allowedChildrenCodes: [{ code: MATH_SCHEMA.code, required: true }]
|
|
2018
2007
|
});
|
|
2019
2008
|
|
|
2020
2009
|
// src/schema/elementSchemas/elements/reference/bibliodiv.ts
|
|
@@ -2272,7 +2261,78 @@ var SCHEMAS = {
|
|
|
2272
2261
|
...INLINE_ELEMENT_SCHEMAS
|
|
2273
2262
|
};
|
|
2274
2263
|
|
|
2275
|
-
// src/schema/
|
|
2264
|
+
// src/schema/shared/ignoredElements.ts
|
|
2265
|
+
var IGNORED_ELEMENT_SELECTORS = [
|
|
2266
|
+
"span.rhlabel",
|
|
2267
|
+
"span.printlabel",
|
|
2268
|
+
"span.refIcon",
|
|
2269
|
+
"span.missLink",
|
|
2270
|
+
"span.ref-drag"
|
|
2271
|
+
];
|
|
2272
|
+
var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
|
|
2273
|
+
"referenceBibliomixed"
|
|
2274
|
+
];
|
|
2275
|
+
|
|
2276
|
+
// src/schema/shared/ignoredAttributes.ts
|
|
2277
|
+
var IGNORED_ATTRIBUTES = [
|
|
2278
|
+
// Styling & layout
|
|
2279
|
+
"class",
|
|
2280
|
+
"style",
|
|
2281
|
+
// Editor state
|
|
2282
|
+
"contenteditable",
|
|
2283
|
+
"draggable",
|
|
2284
|
+
"data-prevpos",
|
|
2285
|
+
"tabindex",
|
|
2286
|
+
// Browser behaviour
|
|
2287
|
+
"spellcheck",
|
|
2288
|
+
"translate",
|
|
2289
|
+
"lang",
|
|
2290
|
+
"dir",
|
|
2291
|
+
"hidden",
|
|
2292
|
+
"data-gramm"
|
|
2293
|
+
];
|
|
2294
|
+
var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
|
|
2295
|
+
|
|
2296
|
+
// src/schema/utils/utils.ts
|
|
2297
|
+
var isTrackChangesSchema = (schema) => schema.code === "insertion" || schema.code === "deletion";
|
|
2298
|
+
var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
|
|
2299
|
+
(startsWith) => attribute.startsWith(startsWith)
|
|
2300
|
+
);
|
|
2301
|
+
var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
|
|
2302
|
+
var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
|
|
2303
|
+
var findSchemaByCode = (code) => SCHEMAS[code];
|
|
2304
|
+
var findSchemaByElement = (element) => {
|
|
2305
|
+
const schema = Object.values(SCHEMAS).find(
|
|
2306
|
+
(schema2) => schema2.tag == element.tagName && (!schema2.matchesElement || schema2.matchesElement(element))
|
|
2307
|
+
);
|
|
2308
|
+
return schema;
|
|
2309
|
+
};
|
|
2310
|
+
var isAttributeRestricted = (attr) => typeof attr !== "string";
|
|
2311
|
+
var getAttributeName = (attribute) => typeof attribute === "string" ? attribute.toLowerCase() : attribute.name.toLowerCase();
|
|
2312
|
+
var findAttributeDefinitionByName = (definitions, name) => {
|
|
2313
|
+
for (const def of definitions) {
|
|
2314
|
+
if (getAttributeName(def) === name.toLowerCase()) {
|
|
2315
|
+
return def;
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
return void 0;
|
|
2319
|
+
};
|
|
2320
|
+
|
|
2321
|
+
// src/schema/utils/createElement.ts
|
|
2322
|
+
var createElement = ({
|
|
2323
|
+
schemaCode,
|
|
2324
|
+
attributes
|
|
2325
|
+
}) => {
|
|
2326
|
+
const schema = findSchemaByCode(schemaCode);
|
|
2327
|
+
const element = document.createElement(schema.tag.toLowerCase());
|
|
2328
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
2329
|
+
if (!value) continue;
|
|
2330
|
+
element.setAttribute(name, String(value));
|
|
2331
|
+
}
|
|
2332
|
+
return element;
|
|
2333
|
+
};
|
|
2334
|
+
|
|
2335
|
+
// src/schema/shared/labelElements.ts
|
|
2276
2336
|
var ElementLabel = {
|
|
2277
2337
|
referenceBibliomixed: "Reference Bibliomixed",
|
|
2278
2338
|
referenceBibliography: "Reference Bibliography",
|
|
@@ -2397,111 +2457,13 @@ var ElementLabel = {
|
|
|
2397
2457
|
phrase: "Phrase"
|
|
2398
2458
|
};
|
|
2399
2459
|
|
|
2400
|
-
// src/schema/shared/
|
|
2401
|
-
var
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
"span.missLink",
|
|
2406
|
-
"span.ref-drag"
|
|
2407
|
-
];
|
|
2408
|
-
var IGNORED_VALIDATION_ELEMENT_SELECTORS = [
|
|
2409
|
-
"referenceBibliomixed"
|
|
2410
|
-
];
|
|
2411
|
-
|
|
2412
|
-
// src/schema/shared/ignoredAttributes.ts
|
|
2413
|
-
var IGNORED_ATTRIBUTES = [
|
|
2414
|
-
// Styling & layout
|
|
2415
|
-
"class",
|
|
2416
|
-
"style",
|
|
2417
|
-
// Editor state
|
|
2418
|
-
"contenteditable",
|
|
2419
|
-
"draggable",
|
|
2420
|
-
"data-prevpos",
|
|
2421
|
-
"tabindex",
|
|
2422
|
-
// Browser behaviour
|
|
2423
|
-
"spellcheck",
|
|
2424
|
-
"translate",
|
|
2425
|
-
"lang",
|
|
2426
|
-
"dir",
|
|
2427
|
-
"hidden",
|
|
2428
|
-
"data-gramm"
|
|
2429
|
-
];
|
|
2430
|
-
var IGNORED_ATTRIBUTES_STARTS_WITH = ["er-", "er_", "drop", "drag"];
|
|
2431
|
-
|
|
2432
|
-
// src/schema/utils/utils.ts
|
|
2433
|
-
var isIgnoredAttribute = (attribute) => IGNORED_ATTRIBUTES.includes(attribute) || IGNORED_ATTRIBUTES_STARTS_WITH.some(
|
|
2434
|
-
(startsWith) => attribute.startsWith(startsWith)
|
|
2435
|
-
);
|
|
2436
|
-
var isIgnoredElement = (element) => IGNORED_ELEMENT_SELECTORS.some((selector) => element.matches(selector));
|
|
2437
|
-
var isIgnoredValidation = (code) => IGNORED_VALIDATION_ELEMENT_SELECTORS.includes(code);
|
|
2438
|
-
var findSchemaByCode = (code) => SCHEMAS[code];
|
|
2439
|
-
var findSchemaByTagName = (tagName) => Object.values(SCHEMAS).filter(
|
|
2440
|
-
(schema) => schema.tag === tagName.toUpperCase()
|
|
2441
|
-
);
|
|
2442
|
-
var findSchemaByElement = (element) => {
|
|
2443
|
-
const tagName = element.tagName.toUpperCase();
|
|
2444
|
-
const isInsertion = element.classList.contains("ins");
|
|
2445
|
-
const isDeletion = element.classList.contains("del");
|
|
2446
|
-
const isQueryComment = element.classList.contains("cmtQurySection");
|
|
2447
|
-
const role = element.getAttribute("role");
|
|
2448
|
-
if (tagName === SPAN_TAG) {
|
|
2449
|
-
if (isQueryComment) {
|
|
2450
|
-
return findSchemaByCode("commentQuerySection");
|
|
2451
|
-
}
|
|
2452
|
-
if (isInsertion) {
|
|
2453
|
-
return findSchemaByCode("insertion");
|
|
2454
|
-
}
|
|
2455
|
-
if (isDeletion) {
|
|
2456
|
-
return findSchemaByCode("deletion");
|
|
2457
|
-
}
|
|
2458
|
-
}
|
|
2459
|
-
if (tagName === SECTION_TAG) {
|
|
2460
|
-
if (role) {
|
|
2461
|
-
if (role.startsWith("H")) {
|
|
2462
|
-
return findSchemaByCode("heading");
|
|
2463
|
-
}
|
|
2464
|
-
if (role === "ch" || role === "bk") {
|
|
2465
|
-
return findSchemaByCode("footnoteSection");
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
const isFootnoteSectionWithoutRole = element.querySelector(FOOTNOTE_TAG);
|
|
2469
|
-
if (isFootnoteSectionWithoutRole) {
|
|
2470
|
-
return findSchemaByCode("footnoteSection");
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
const candidates = findSchemaByTagName(tagName);
|
|
2474
|
-
return candidates[0];
|
|
2475
|
-
};
|
|
2476
|
-
var isAttributeRestricted = (attr) => typeof attr !== "string";
|
|
2477
|
-
var getAttributeName = (attribute) => typeof attribute === "string" ? attribute.toLowerCase() : attribute.name.toLowerCase();
|
|
2478
|
-
var findAttributeDefinitionByName = (definitions, name) => {
|
|
2479
|
-
for (const def of definitions) {
|
|
2480
|
-
if (getAttributeName(def) === name.toLowerCase()) {
|
|
2481
|
-
return def;
|
|
2482
|
-
}
|
|
2483
|
-
}
|
|
2484
|
-
return void 0;
|
|
2485
|
-
};
|
|
2486
|
-
|
|
2487
|
-
// src/schema/utils/createElement.ts
|
|
2488
|
-
var createElement = ({
|
|
2489
|
-
schemaCode,
|
|
2490
|
-
attributes
|
|
2491
|
-
}) => {
|
|
2492
|
-
const schema = findSchemaByCode(schemaCode);
|
|
2493
|
-
if (!schema) {
|
|
2494
|
-
throw new Error(`Schema not found for code: ${schemaCode}`);
|
|
2495
|
-
}
|
|
2496
|
-
const element = document.createElement(schema.tag.toLowerCase());
|
|
2497
|
-
for (const [name, value] of Object.entries(attributes)) {
|
|
2498
|
-
if (value === void 0) {
|
|
2499
|
-
continue;
|
|
2500
|
-
}
|
|
2501
|
-
element.setAttribute(name, String(value));
|
|
2460
|
+
// src/schema/shared/dependentsForbiddenElements.ts
|
|
2461
|
+
var DEPENDENT_FORBIDDEN_ELEMENTS = [
|
|
2462
|
+
{
|
|
2463
|
+
code: "commentQuerySection",
|
|
2464
|
+
dependentElements: ["query", "comment", "reply", "content"]
|
|
2502
2465
|
}
|
|
2503
|
-
|
|
2504
|
-
};
|
|
2466
|
+
];
|
|
2505
2467
|
|
|
2506
2468
|
// src/validation/utils/generateValidationIssueId.ts
|
|
2507
2469
|
var generateValidationIssueId = () => {
|
|
@@ -2724,12 +2686,47 @@ var validateElementAgainstSchema = (element, schema) => {
|
|
|
2724
2686
|
errors.push(...validateChildren(element, schema));
|
|
2725
2687
|
return errors;
|
|
2726
2688
|
};
|
|
2727
|
-
var
|
|
2689
|
+
var validateRequiredChildren = (element, schema, childElements) => {
|
|
2728
2690
|
const errors = [];
|
|
2691
|
+
for (const allowedChild of schema.allowedChildrenCodes) {
|
|
2692
|
+
if (!allowedChild.required) {
|
|
2693
|
+
continue;
|
|
2694
|
+
}
|
|
2695
|
+
const hasChild = childElements.some((child) => {
|
|
2696
|
+
const childSchema = findSchemaByElement(child);
|
|
2697
|
+
return childSchema?.code === allowedChild.code;
|
|
2698
|
+
});
|
|
2699
|
+
if (!hasChild) {
|
|
2700
|
+
const requiredChildrenTag = findSchemaByCode(allowedChild.code).tag;
|
|
2701
|
+
addValidationIssue(errors, {
|
|
2702
|
+
store: getStore(element),
|
|
2703
|
+
title: `Missing required child element ${requiredChildrenTag}`,
|
|
2704
|
+
level: "warning",
|
|
2705
|
+
kind: "missing",
|
|
2706
|
+
description: `The child element ${requiredChildrenTag} is required but not present.`
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
return errors;
|
|
2711
|
+
};
|
|
2712
|
+
var getEffectiveChildElements = (element) => {
|
|
2713
|
+
const effectiveChildren = [];
|
|
2729
2714
|
const childElements = [...element.children].filter(
|
|
2730
2715
|
(child) => !isIgnoredElement(child)
|
|
2731
2716
|
);
|
|
2732
|
-
const
|
|
2717
|
+
for (const child of childElements) {
|
|
2718
|
+
const childSchema = findSchemaByElement(child);
|
|
2719
|
+
if (childSchema && isTrackChangesSchema(childSchema)) {
|
|
2720
|
+
effectiveChildren.push(...getEffectiveChildElements(child));
|
|
2721
|
+
continue;
|
|
2722
|
+
}
|
|
2723
|
+
effectiveChildren.push(child);
|
|
2724
|
+
}
|
|
2725
|
+
return effectiveChildren;
|
|
2726
|
+
};
|
|
2727
|
+
var validateChildren = (element, schema) => {
|
|
2728
|
+
const errors = [];
|
|
2729
|
+
const childElements = getEffectiveChildElements(element);
|
|
2733
2730
|
if (schema.kind === "atom") {
|
|
2734
2731
|
return errors;
|
|
2735
2732
|
}
|
|
@@ -2745,7 +2742,7 @@ var validateChildren = (element, schema) => {
|
|
|
2745
2742
|
});
|
|
2746
2743
|
continue;
|
|
2747
2744
|
}
|
|
2748
|
-
const allowedChild =
|
|
2745
|
+
const allowedChild = schema.allowedChildrenCodes.find(
|
|
2749
2746
|
(candidate) => candidate.code === childSchema.code
|
|
2750
2747
|
);
|
|
2751
2748
|
if (!allowedChild) {
|
|
@@ -2760,34 +2757,7 @@ var validateChildren = (element, schema) => {
|
|
|
2760
2757
|
}
|
|
2761
2758
|
errors.push(...validateElementAgainstSchema(child, childSchema));
|
|
2762
2759
|
}
|
|
2763
|
-
|
|
2764
|
-
if (!allowedChild.required) {
|
|
2765
|
-
continue;
|
|
2766
|
-
}
|
|
2767
|
-
const hasChild = childElements.some((child) => {
|
|
2768
|
-
const childSchema = findSchemaByElement(child);
|
|
2769
|
-
return childSchema?.code === allowedChild.code;
|
|
2770
|
-
});
|
|
2771
|
-
if (!hasChild) {
|
|
2772
|
-
const requiredChildLabel = ElementLabel[allowedChild.code];
|
|
2773
|
-
addValidationIssue(errors, {
|
|
2774
|
-
store: getStore(element),
|
|
2775
|
-
title: `Missing required child element ${requiredChildLabel}`,
|
|
2776
|
-
level: "warning",
|
|
2777
|
-
kind: "missing",
|
|
2778
|
-
description: `The child element ${requiredChildLabel} is required but not present.`
|
|
2779
|
-
});
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
if (schema.allowedChildrenCodes.size === 0 && childElements.length > 0) {
|
|
2783
|
-
addValidationIssue(errors, {
|
|
2784
|
-
store: getStore(element),
|
|
2785
|
-
title: "Atom element cannot contain child elements",
|
|
2786
|
-
level: "warning",
|
|
2787
|
-
kind: "forbidden",
|
|
2788
|
-
description: `The element is an atom element and cannot contain child elements.`
|
|
2789
|
-
});
|
|
2790
|
-
}
|
|
2760
|
+
errors.push(...validateRequiredChildren(element, schema, childElements));
|
|
2791
2761
|
return errors;
|
|
2792
2762
|
};
|
|
2793
2763
|
|
|
@@ -2840,9 +2810,9 @@ var validateElement = (element, root, elementsToLink, linkElements, schemasToVal
|
|
|
2840
2810
|
if (schemasToValidateAgainst.includes(schema.code)) {
|
|
2841
2811
|
errors.push(...validateElementAgainstSchema(element, schema));
|
|
2842
2812
|
}
|
|
2843
|
-
const role = element.getAttribute("role")
|
|
2813
|
+
const role = element.getAttribute("role");
|
|
2844
2814
|
const linkableRoles = getLinkableRoles();
|
|
2845
|
-
if (schema.tag === LINK_SCHEMA.tag && linkableRoles.includes(role) || schema.tag === FOOTNOTE_LINK_SCHEMA.tag) {
|
|
2815
|
+
if (schema.tag === LINK_SCHEMA.tag && role && linkableRoles.includes(role) || schema.tag === FOOTNOTE_LINK_SCHEMA.tag) {
|
|
2846
2816
|
errors.push(...validateLinkend(element, elementsToLink));
|
|
2847
2817
|
}
|
|
2848
2818
|
if (schema.tag === BIBLIOMIXED_SCHEMA.tag) {
|
|
@@ -2888,6 +2858,7 @@ var validateXml = (xml, elementsToLink, linkElements, schemasToValidateAgainst)
|
|
|
2888
2858
|
export {
|
|
2889
2859
|
ALIGNMENT_ATTRIBUTE,
|
|
2890
2860
|
ATOM_SCHEMAS,
|
|
2861
|
+
DEPENDENT_FORBIDDEN_ELEMENTS,
|
|
2891
2862
|
ELEMENT_SCHEMAS,
|
|
2892
2863
|
ELE_ID_ATTRIBUTE,
|
|
2893
2864
|
ElementLabel,
|
|
@@ -2921,11 +2892,11 @@ export {
|
|
|
2921
2892
|
findAttributeDefinitionByName,
|
|
2922
2893
|
findSchemaByCode,
|
|
2923
2894
|
findSchemaByElement,
|
|
2924
|
-
findSchemaByTagName,
|
|
2925
2895
|
getAttributeName,
|
|
2926
2896
|
isAttributeRestricted,
|
|
2927
2897
|
isIgnoredAttribute,
|
|
2928
2898
|
isIgnoredElement,
|
|
2929
2899
|
isIgnoredValidation,
|
|
2900
|
+
isTrackChangesSchema,
|
|
2930
2901
|
validateXml
|
|
2931
2902
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pro-editor-schema",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Pro Editor XML schemas",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -19,13 +19,18 @@
|
|
|
19
19
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
20
20
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
21
21
|
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "eslint src",
|
|
22
23
|
"test": "vitest run",
|
|
23
|
-
"test:watch": "vitest"
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"check": "npm ci && npm run typecheck && npm run lint && npm run test && npm run build"
|
|
24
26
|
},
|
|
25
27
|
"devDependencies": {
|
|
28
|
+
"@eslint/js": "^10.0.1",
|
|
29
|
+
"eslint": "^10.6.0",
|
|
26
30
|
"happy-dom": "^20.0.10",
|
|
27
31
|
"tsup": "^8.0.0",
|
|
28
32
|
"typescript": "^5.0.0",
|
|
33
|
+
"typescript-eslint": "^8.62.1",
|
|
29
34
|
"vitest": "^3.2.4"
|
|
30
35
|
}
|
|
31
36
|
}
|