@markuplint/ml-spec 5.0.0-alpha.1 → 5.0.0-alpha.3
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/ARCHITECTURE.ja.md +8 -8
- package/ARCHITECTURE.md +8 -8
- package/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/lib/algorithm/aria/has-required-owned-elements.js +3 -1
- package/lib/algorithm/aria/is-exposed.js +10 -2
- package/lib/algorithm/html/content-model-category-to-tag-names.js +11 -1
- package/lib/types/permitted-structures.d.ts +1 -1
- package/lib/utils/get-attr-specs-spec.js +2 -2
- package/lib/utils/get-spec-by-tag-name.d.ts +1 -1
- package/lib/utils/get-spec.d.ts +1 -1
- package/package.json +5 -5
package/ARCHITECTURE.ja.md
CHANGED
|
@@ -146,16 +146,16 @@ flowchart TD
|
|
|
146
146
|
|
|
147
147
|
型システムは、マークアップ言語仕様・要素仕様・ARIA ロール・属性の構造を定義します。
|
|
148
148
|
|
|
149
|
-
| ファイル | 役割
|
|
150
|
-
| ------------------------------- |
|
|
151
|
-
| `types/index.ts` | 手書き型: `MLMLSpec`, `ElementSpec`, `ExtendedSpec`, `ARIARole`, `ComputedRole` 等
|
|
152
|
-
| `types/aria.ts` | 生成型: `ARIA`, `PermittedRoles`, `ImplicitRole`, `PermittedARIAProperties`, `ImplicitProperties`
|
|
153
|
-
| `types/attributes.ts` | 生成型: `AttributeType`, `GlobalAttributes`, `AttributeJSON`, `List`, `Enum`, `Number`
|
|
154
|
-
| `types/permitted-structures.ts` | 生成型: `PermittedContentPattern`, `ContentModel`, `Category`(HTML 13 + SVG 19 カテゴリ)
|
|
149
|
+
| ファイル | 役割 |
|
|
150
|
+
| ------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
151
|
+
| `types/index.ts` | 手書き型: `MLMLSpec`, `ElementSpec`, `ExtendedSpec`, `ARIARole`, `ComputedRole` 等 |
|
|
152
|
+
| `types/aria.ts` | 生成型: `ARIA`, `PermittedRoles`, `ImplicitRole`, `PermittedARIAProperties`, `ImplicitProperties` |
|
|
153
|
+
| `types/attributes.ts` | 生成型: `AttributeType`, `GlobalAttributes`, `AttributeJSON`, `List`, `Enum`, `Number` |
|
|
154
|
+
| `types/permitted-structures.ts` | 生成型: `PermittedContentPattern`, `ContentModel`, `Category`(HTML 13 + SVG 19 + MathML 3 カテゴリ) |
|
|
155
155
|
|
|
156
156
|
### 2. ARIA アルゴリズム
|
|
157
157
|
|
|
158
|
-
ARIA アルゴリズムは WAI-ARIA, HTML-AAM, SVG-AAM, AccName 1.2 仕様に基づくロール計算とアクセシビリティツリー管理を実装します。
|
|
158
|
+
ARIA アルゴリズムは WAI-ARIA, HTML-AAM, SVG-AAM, MathML-AAM, AccName 1.2 仕様に基づくロール計算とアクセシビリティツリー管理を実装します。
|
|
159
159
|
|
|
160
160
|
| ファイル | 役割 |
|
|
161
161
|
| -------------------------------- | ------------------------------------------------------------------------------- |
|
|
@@ -183,7 +183,7 @@ HTML アルゴリズムは HTML Living Standard に基づくコンテンツモ
|
|
|
183
183
|
| `get-content-model.ts` | 条件付きパターン評価を含むコンテンツモデルの取得 |
|
|
184
184
|
| `content-model-category-to-tag-names.ts` | コンテンツモデルカテゴリをソート済みタグ名配列に変換 |
|
|
185
185
|
| `get-selectors-by-content-model-category.ts` | コンテンツモデルカテゴリを CSS セレクタにマッピング |
|
|
186
|
-
| `is-palpable-elements.ts` | SVG/露出可能要素拡張付きパルパブルコンテンツ検出
|
|
186
|
+
| `is-palpable-elements.ts` | SVG/MathML/露出可能要素拡張付きパルパブルコンテンツ検出 |
|
|
187
187
|
| `is-void-element.ts` | ボイド要素判定(13 の HTML ボイド要素) |
|
|
188
188
|
| `is-nothing-content-model.ts` | 「Nothing」コンテンツモデル判定(void + iframe + template) |
|
|
189
189
|
| `may-be-focusable.ts` | フォーカス可能性ヒューリスティック(interactive + tabindex + contenteditable) |
|
package/ARCHITECTURE.md
CHANGED
|
@@ -146,16 +146,16 @@ flowchart TD
|
|
|
146
146
|
|
|
147
147
|
The type system defines the structure of markup language specifications, element specs, ARIA roles, and attributes.
|
|
148
148
|
|
|
149
|
-
| File | Purpose
|
|
150
|
-
| ------------------------------- |
|
|
151
|
-
| `types/index.ts` | Hand-written types: `MLMLSpec`, `ElementSpec`, `ExtendedSpec`, `ARIARole`, `ComputedRole`, etc.
|
|
152
|
-
| `types/aria.ts` | Generated: `ARIA`, `PermittedRoles`, `ImplicitRole`, `PermittedARIAProperties`, `ImplicitProperties`
|
|
153
|
-
| `types/attributes.ts` | Generated: `AttributeType`, `GlobalAttributes`, `AttributeJSON`, `List`, `Enum`, `Number`
|
|
154
|
-
| `types/permitted-structures.ts` | Generated: `PermittedContentPattern`, `ContentModel`, `Category` (HTML 13 + SVG 19 categories)
|
|
149
|
+
| File | Purpose |
|
|
150
|
+
| ------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
151
|
+
| `types/index.ts` | Hand-written types: `MLMLSpec`, `ElementSpec`, `ExtendedSpec`, `ARIARole`, `ComputedRole`, etc. |
|
|
152
|
+
| `types/aria.ts` | Generated: `ARIA`, `PermittedRoles`, `ImplicitRole`, `PermittedARIAProperties`, `ImplicitProperties` |
|
|
153
|
+
| `types/attributes.ts` | Generated: `AttributeType`, `GlobalAttributes`, `AttributeJSON`, `List`, `Enum`, `Number` |
|
|
154
|
+
| `types/permitted-structures.ts` | Generated: `PermittedContentPattern`, `ContentModel`, `Category` (HTML 13 + SVG 19 + MathML 3 categories) |
|
|
155
155
|
|
|
156
156
|
### 2. ARIA Algorithms
|
|
157
157
|
|
|
158
|
-
ARIA algorithms implement WAI-ARIA, HTML-AAM, SVG-AAM, and AccName 1.2 specifications for role computation and accessibility tree management.
|
|
158
|
+
ARIA algorithms implement WAI-ARIA, HTML-AAM, SVG-AAM, MathML-AAM, and AccName 1.2 specifications for role computation and accessibility tree management.
|
|
159
159
|
|
|
160
160
|
| File | Purpose |
|
|
161
161
|
| -------------------------------- | --------------------------------------------------------------------------------- |
|
|
@@ -183,7 +183,7 @@ HTML algorithms implement content model evaluation and element classification fr
|
|
|
183
183
|
| `get-content-model.ts` | Retrieves content model with conditional pattern evaluation |
|
|
184
184
|
| `content-model-category-to-tag-names.ts` | Converts content model category to sorted tag name array |
|
|
185
185
|
| `get-selectors-by-content-model-category.ts` | Maps content model category to CSS selectors |
|
|
186
|
-
| `is-palpable-elements.ts` | Palpable content detection with SVG/exposable extensions
|
|
186
|
+
| `is-palpable-elements.ts` | Palpable content detection with SVG/MathML/exposable extensions |
|
|
187
187
|
| `is-void-element.ts` | Void element check (13 HTML void elements) |
|
|
188
188
|
| `is-nothing-content-model.ts` | "Nothing" content model check (void + iframe + template) |
|
|
189
189
|
| `may-be-focusable.ts` | Focusability heuristic (interactive + tabindex + contenteditable) |
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [5.0.0-alpha.3](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.2...v5.0.0-alpha.3) (2026-02-26)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @markuplint/ml-spec
|
|
9
|
+
|
|
10
|
+
# [5.0.0-alpha.2](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.1...v5.0.0-alpha.2) (2026-02-23)
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- **ml-spec:** add MathML content model categories and namespace support ([80f0945](https://github.com/markuplint/markuplint/commit/80f0945595aed48c9766423e83e8cd2b1c454a54))
|
|
15
|
+
|
|
6
16
|
# [5.0.0-alpha.1](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.0...v5.0.0-alpha.1) (2026-02-22)
|
|
7
17
|
|
|
8
18
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
This package serves as the foundational layer for markuplint's specification system, providing:
|
|
8
8
|
|
|
9
|
-
- **Type definitions** for markup language specifications (HTML, ARIA, SVG)
|
|
9
|
+
- **Type definitions** for markup language specifications (HTML, ARIA, SVG, MathML)
|
|
10
10
|
- **W3C specification algorithms** (HTML Standard, WAI-ARIA 1.1/1.2/1.3 compliance)
|
|
11
11
|
- **JSON schemas** that define the structure of element specifications
|
|
12
12
|
- **Runtime utilities** for specification resolution, attribute validation, and content model checking
|
|
@@ -23,7 +23,9 @@ el, specs, version) {
|
|
|
23
23
|
* THIS CONDITION IS PARTIAL SUPPORT.
|
|
24
24
|
*/
|
|
25
25
|
if (el.hasAttribute('aria-owns')) {
|
|
26
|
-
// FIXME
|
|
26
|
+
// FIXME: Partial support — assumes aria-owns always provides required owned elements.
|
|
27
|
+
// A complete implementation would resolve the ID references in the aria-owns value
|
|
28
|
+
// and verify that the referenced elements actually have the required roles.
|
|
27
29
|
return true;
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
@@ -153,6 +153,9 @@ el, specs, version) {
|
|
|
153
153
|
* - Elements that are a valid target of an aria-activedescendant attribute.
|
|
154
154
|
*/
|
|
155
155
|
// TODO: Compute aria-activedescendant.
|
|
156
|
+
// To implement this, we need to find all elements with `aria-activedescendant`
|
|
157
|
+
// in the document and check if any of them reference this element's ID.
|
|
158
|
+
// This requires cross-element analysis that is not yet supported.
|
|
156
159
|
// results.push(true);
|
|
157
160
|
/**
|
|
158
161
|
* Elements that have an explicit role or a global WAI-ARIA attribute and
|
|
@@ -179,7 +182,10 @@ el, specs, version) {
|
|
|
179
182
|
* Elements that are not hidden and have an ID that is referenced
|
|
180
183
|
* by another element via a WAI-ARIA property.
|
|
181
184
|
*/
|
|
182
|
-
// TODO: Compute
|
|
185
|
+
// TODO: Compute referring ID.
|
|
186
|
+
// To implement this, we need to find all ARIA relationship attributes
|
|
187
|
+
// (e.g., aria-labelledby, aria-describedby, aria-owns, aria-controls)
|
|
188
|
+
// across the document that reference this element's ID.
|
|
183
189
|
// results.push(true);
|
|
184
190
|
return results.includes(true);
|
|
185
191
|
}
|
|
@@ -190,7 +196,9 @@ el) {
|
|
|
190
196
|
if (!style) {
|
|
191
197
|
return false;
|
|
192
198
|
}
|
|
193
|
-
// TODO: Improve accuracy
|
|
199
|
+
// TODO: Improve accuracy by using a proper CSS parser instead of regex.
|
|
200
|
+
// This regex does not handle shorthand properties, `!important`, or values
|
|
201
|
+
// inside comments/strings. A CSS declaration parser would be more reliable.
|
|
194
202
|
return /display\s*:\s*none|visibility\s*:\s*hidden/i.test(style);
|
|
195
203
|
}
|
|
196
204
|
function isExposedElement(
|
|
@@ -13,7 +13,17 @@ export function contentModelCategoryToTagNames(contentModel, def) {
|
|
|
13
13
|
if (cached) {
|
|
14
14
|
return cached;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
let tags = def['#contentModels'][contentModel];
|
|
17
|
+
if (!tags) {
|
|
18
|
+
// Case-insensitive fallback for mixed-case categories (e.g., #MathMLPresentation, #SVGAnimation)
|
|
19
|
+
const lowerKey = contentModel.toLowerCase();
|
|
20
|
+
for (const key of Object.keys(def['#contentModels'])) {
|
|
21
|
+
if (key.toLowerCase() === lowerKey) {
|
|
22
|
+
tags = def['#contentModels'][key];
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
17
27
|
const sortedTag = Object.freeze(tags && Array.isArray(tags) ? tags.toSorted() : []);
|
|
18
28
|
cache.set(contentModel, sortedTag);
|
|
19
29
|
return sortedTag;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export type PermittedContentPattern = PermittedContentRequire | PermittedContentOptional | PermittedContentOneOrMore | PermittedContentZeroOrMore | PermittedContentChoice | PermittedContentTransparent;
|
|
7
7
|
export type Model = ContentType | ContentType[];
|
|
8
8
|
export type ContentType = string | Category;
|
|
9
|
-
export type Category = '#text' | '#phrasing' | '#flow' | '#interactive' | '#heading' | '#sectioning' | '#metadata' | '#embedded' | '#palpable' | '#script-supporting' | '#SVGAnimation' | '#SVGBasicShapes' | '#SVGContainer' | '#SVGDescriptive' | '#SVGFilterPrimitive' | '#SVGFont' | '#SVGGradient' | '#SVGGraphics' | '#SVGGraphicsReferencing' | '#SVGLightSource' | '#SVGNeverRendered' | '#SVGNone' | '#SVGPaintServer' | '#SVGRenderable' | '#SVGShape' | '#SVGStructural' | '#SVGStructurallyExternal' | '#SVGTextContent' | '#SVGTextContentChild';
|
|
9
|
+
export type Category = '#text' | '#phrasing' | '#flow' | '#interactive' | '#heading' | '#sectioning' | '#metadata' | '#embedded' | '#palpable' | '#script-supporting' | '#SVGAnimation' | '#SVGBasicShapes' | '#SVGContainer' | '#SVGDescriptive' | '#SVGFilterPrimitive' | '#SVGFont' | '#SVGGradient' | '#SVGGraphics' | '#SVGGraphicsReferencing' | '#SVGLightSource' | '#SVGNeverRendered' | '#SVGNone' | '#SVGPaintServer' | '#SVGRenderable' | '#SVGShape' | '#SVGStructural' | '#SVGStructurallyExternal' | '#SVGTextContent' | '#SVGTextContentChild' | '#MathMLPresentation' | '#MathMLScript' | '#MathMLTabular';
|
|
10
10
|
export interface ContentModelsSchema {
|
|
11
11
|
__contentModel?: ContentModel;
|
|
12
12
|
}
|
|
@@ -28,7 +28,7 @@ export function getAttrSpecs(localName, namespace, schema) {
|
|
|
28
28
|
}
|
|
29
29
|
const globalAttrs = schema.def['#globalAttrs'];
|
|
30
30
|
let attrs = {};
|
|
31
|
-
for (const catName
|
|
31
|
+
for (const catName of Object.keys(elSpec.globalAttrs)) {
|
|
32
32
|
// @ts-ignore
|
|
33
33
|
const catAttrs = elSpec.globalAttrs[catName];
|
|
34
34
|
if (catAttrs === false) {
|
|
@@ -57,7 +57,7 @@ export function getAttrSpecs(localName, namespace, schema) {
|
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
for (const attrName
|
|
60
|
+
for (const attrName of Object.keys(elSpec.attributes)) {
|
|
61
61
|
const attr = elSpec.attributes[attrName];
|
|
62
62
|
if (!attr) {
|
|
63
63
|
continue;
|
|
@@ -10,4 +10,4 @@ import type { ElementSpec } from '../types/index.js';
|
|
|
10
10
|
* @param namespace - The namespace URI string, or null for HTML namespace
|
|
11
11
|
* @returns The matching element specification, or null if not found
|
|
12
12
|
*/
|
|
13
|
-
export declare function getSpecByTagName<K extends keyof ElementSpec = keyof ElementSpec>(specs: readonly Pick<ElementSpec, 'name' | K>[], localName: string, namespace: string | null): Pick<ElementSpec,
|
|
13
|
+
export declare function getSpecByTagName<K extends keyof ElementSpec = keyof ElementSpec>(specs: readonly Pick<ElementSpec, 'name' | K>[], localName: string, namespace: string | null): Pick<ElementSpec, "name" | K> | null;
|
package/lib/utils/get-spec.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ import type { ElementSpec } from '../types/index.js';
|
|
|
9
9
|
* @param specs - The array of element specifications to search
|
|
10
10
|
* @returns The matching element specification, or null if not found
|
|
11
11
|
*/
|
|
12
|
-
export declare function getSpec<K extends keyof ElementSpec>(el: Element, specs: readonly Pick<ElementSpec, 'name' | K>[]): Pick<ElementSpec,
|
|
12
|
+
export declare function getSpec<K extends keyof ElementSpec>(el: Element, specs: readonly Pick<ElementSpec, 'name' | K>[]): Pick<ElementSpec, "name" | K> | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/ml-spec",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.3",
|
|
4
4
|
"description": "Types and schema that specs of the Markup languages for markuplint",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"schema:prettier": "npx prettier --write \"./schemas/*.json\" \"./src/types/*.ts\" --log-level warn"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@markuplint/ml-ast": "5.0.0-alpha.
|
|
38
|
-
"@markuplint/types": "5.0.0-alpha.
|
|
37
|
+
"@markuplint/ml-ast": "5.0.0-alpha.3",
|
|
38
|
+
"@markuplint/types": "5.0.0-alpha.3",
|
|
39
39
|
"is-plain-object": "5.0.0",
|
|
40
40
|
"type-fest": "5.4.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@markuplint/test-tools": "5.0.0-alpha.
|
|
43
|
+
"@markuplint/test-tools": "5.0.0-alpha.3",
|
|
44
44
|
"json-schema-to-typescript": "15.0.4"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "2fbdf26daa3d021ac628ccc2f59f0eeae6ddd53d"
|
|
47
47
|
}
|