• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

markuplint / markuplint / #3730

pending completion
#3730

push

yusukehirao
Publish

 - markuplint@3.8.0
 - @markuplint/config-presets@3.6.0
 - @markuplint/create-rule-helper@3.8.0
 - @markuplint/file-resolver@3.8.0
 - @markuplint/html-spec@3.7.0
 - @markuplint/ml-config@3.7.0
 - @markuplint/ml-core@3.8.0
 - @markuplint/ml-spec@3.7.0
 - @markuplint/react-spec@3.7.0
 - @markuplint/rule-textlint@3.8.0
 - @markuplint/rules@3.8.0
 - @markuplint/selector@3.7.0
 - @markuplint/test-tools@3.2.0
 - @markuplint/vue-spec@3.7.0
 - @markuplint/playground@2.1.0-alpha.10

4489 of 6591 branches covered (68.11%)

Branch coverage included in aggregate %.

7069 of 9801 relevant lines covered (72.13%)

669.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.48
/packages/@markuplint/ml-spec/src/specs/schema-to-spec.ts
1
import type { ElementSpec, ExtendedSpec, MLMLSpec, Attribute } from '../types';
2

3
import { mergeArray } from '../utils/merge-array';
1✔
4

5
/**
6
 * Merging HTML-spec schema and extended spec schemas
7
 *
8
 * Ex: `@markuplint/html-spec` + `{ specs: { "\\.vue$": "@markuplint/vue-spec" } }` in configure files.
9
 *
10
 * @param schemas `MLDocument.schemas`
11
 */
12
export function schemaToSpec(schemas: readonly [MLMLSpec, ...ExtendedSpec[]]) {
1✔
13
        const [main, ...extendedSpecs] = schemas;
2✔
14
        const result = { ...main };
2✔
15
        for (const extendedSpec of extendedSpecs) {
2✔
16
                if (extendedSpec.cites) {
3!
17
                        result.cites = [...result.cites, ...extendedSpec.cites];
×
18
                }
19
                if (extendedSpec.def) {
3✔
20
                        const def = { ...result.def };
1✔
21
                        if (extendedSpec.def['#globalAttrs']?.['#extends']) {
1!
22
                                const gAttrs = { ...def['#globalAttrs'] };
1✔
23
                                gAttrs['#HTMLGlobalAttrs'] = {
1✔
24
                                        ...(def['#globalAttrs']?.['#HTMLGlobalAttrs'] ?? {}),
6!
25
                                        ...(extendedSpec.def['#globalAttrs']?.['#extends'] ?? {}),
6!
26
                                };
27
                                def['#globalAttrs'] = gAttrs;
1✔
28
                        }
29
                        if (extendedSpec.def['#aria']) {
1!
30
                                def['#aria'] = {
×
31
                                        '1.1': {
32
                                                roles: mergeArray(def['#aria']['1.1'].roles, extendedSpec.def['#aria']['1.1'].roles),
33
                                                props: mergeArray(def['#aria']['1.1'].props, extendedSpec.def['#aria']['1.1'].props),
34
                                                graphicsRoles: mergeArray(
35
                                                        def['#aria']['1.1'].graphicsRoles,
36
                                                        extendedSpec.def['#aria']['1.1'].graphicsRoles,
37
                                                ),
38
                                        },
39
                                        '1.2': {
40
                                                roles: mergeArray(def['#aria']['1.2'].roles, extendedSpec.def['#aria']['1.2'].roles),
41
                                                props: mergeArray(def['#aria']['1.2'].props, extendedSpec.def['#aria']['1.2'].props),
42
                                                graphicsRoles: mergeArray(
43
                                                        def['#aria']['1.2'].graphicsRoles,
44
                                                        extendedSpec.def['#aria']['1.2'].graphicsRoles,
45
                                                ),
46
                                        },
47
                                        '1.3': {
48
                                                roles: mergeArray(def['#aria']['1.3'].roles, extendedSpec.def['#aria']['1.3'].roles),
49
                                                props: mergeArray(def['#aria']['1.3'].props, extendedSpec.def['#aria']['1.3'].props),
50
                                                graphicsRoles: mergeArray(
51
                                                        def['#aria']['1.3'].graphicsRoles,
52
                                                        extendedSpec.def['#aria']['1.3'].graphicsRoles,
53
                                                ),
54
                                        },
55
                                };
56
                        }
57
                        if (extendedSpec.def['#contentModels']) {
1!
58
                                const models = { ...def['#contentModels'] };
×
59
                                const keys = new Set([
×
60
                                        ...Object.keys(def['#contentModels']),
61
                                        ...Object.keys(extendedSpec.def['#contentModels']),
62
                                ]) as Set<keyof (typeof def)['#contentModels']>;
63
                                for (const modelName of keys) {
×
64
                                        const mainModel = def['#contentModels'][modelName];
×
65
                                        const exModel = extendedSpec.def['#contentModels'][modelName];
×
66
                                        models[modelName] = [...(mainModel ?? []), ...(exModel ?? [])];
×
67
                                }
68
                                def['#contentModels'] = models;
×
69
                        }
70
                        result.def = def;
1✔
71
                }
72
                if (extendedSpec.specs) {
3✔
73
                        const exSpecs = extendedSpec.specs.slice();
2✔
74
                        const specs: ElementSpec[] = [];
2✔
75
                        for (const elSpec of result.specs) {
2✔
76
                                const tagName = elSpec.name.toLowerCase();
446✔
77
                                const index = exSpecs.findIndex(spec => spec.name.toLowerCase() === tagName);
446✔
78
                                if (index === -1) {
446✔
79
                                        specs.push(elSpec);
444✔
80
                                        continue;
444✔
81
                                }
82
                                const exSpec = exSpecs.splice(index, 1)[0];
2✔
83
                                specs.push({
2✔
84
                                        ...elSpec,
85
                                        ...exSpec,
86
                                        globalAttrs: {
87
                                                ...elSpec.globalAttrs,
88
                                                ...exSpec?.globalAttrs,
6!
89
                                        },
90
                                        attributes: mergeAttrSpec(elSpec.attributes, exSpec?.attributes),
6!
91
                                        categories: mergeArray(elSpec.categories, exSpec?.categories),
6!
92
                                });
93
                        }
94

95
                        result.specs = specs;
2✔
96
                }
97
        }
98

99
        return result;
2✔
100
}
101

102
function mergeAttrSpec(
103
        std: Readonly<Record<string, Attribute>>,
104
        ex: Readonly<Record<string, Partial<Attribute>>> = {},
×
105
): Record<string, Readonly<Attribute>> {
106
        const result: Record<string, Attribute> = {};
2✔
107
        const keys = Array.from(new Set([...Object.keys(std), ...Object.keys(ex)]));
2✔
108
        for (const key of keys) {
2✔
109
                const _std = std[key]!;
28✔
110
                const _ex = ex[key];
28✔
111
                result[key] = {
28✔
112
                        ..._std,
113
                        ..._ex,
114
                };
115
        }
116
        return result;
2✔
117
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc