@markuplint/parser-utils 5.1.0 → 5.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/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
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.2.0](https://github.com/markuplint/markuplint/compare/v5.1.1...v5.2.0) (2026-10-13)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **parser-utils:** do not enter a namespace by the name of an authored element ([40e4d2d](https://github.com/markuplint/markuplint/commit/40e4d2d5065a7831721495d9ef2672fdddb51d93))
11
+ - use caret ranges for third-party dependencies of published packages ([5fb5d2e](https://github.com/markuplint/markuplint/commit/5fb5d2ee81eaeea45fe7256a40dd41c95ff0d672))
12
+
13
+ ### Features
14
+
15
+ - **parser-utils:** add getChildNamespace and getNamespaceBelow ([88cbab7](https://github.com/markuplint/markuplint/commit/88cbab7755d4efcdc6ac8a0f6d61d209f80802e6))
16
+
17
+ ## [5.1.1](https://github.com/markuplint/markuplint/compare/v5.1.0...v5.1.1) (2026-10-09)
18
+
19
+ **Note:** Version bump only for package @markuplint/parser-utils
20
+
6
21
  # [5.1.0](https://github.com/markuplint/markuplint/compare/v5.0.1...v5.1.0) (2026-10-08)
7
22
 
8
23
  **Note:** Version bump only for package @markuplint/parser-utils
@@ -4,8 +4,33 @@ import type { MLASTParentNode, NamespaceURI } from '@markuplint/ml-ast';
4
4
  * Handles namespace transitions between HTML, SVG, and MathML
5
5
  * (e.g., entering `<svg>` switches to SVG namespace, `<foreignObject>` switches back to HTML).
6
6
  *
7
- * @param currentNodeName - The tag name of the current node, or null for anonymous nodes
7
+ * @param currentNodeName - The tag name of the current node, or null for anonymous nodes and
8
+ * for an authored element (a component), which does not enter a namespace by its name
8
9
  * @param parentNode - The parent node in the AST, or null for root-level nodes
9
10
  * @returns The resolved namespace URI for the node
10
11
  */
11
12
  export declare function getNamespace(currentNodeName: string | null, parentNode: MLASTParentNode | null): NamespaceURI;
13
+ /**
14
+ * Determines the namespace URI for an element from its tag name and its parent element,
15
+ * by the same transitions as {@link getNamespace}. For a caller that knows the parent's
16
+ * name and namespace but has no AST node for it.
17
+ *
18
+ * @param currentNodeName - The tag name of the element, or null to take the namespace its parent gives any element
19
+ * @param parentNamespace - The namespace URI of the parent element (HTML at the top level)
20
+ * @param parentNodeName - The tag name of the parent element, or null at the top level
21
+ * @returns The resolved namespace URI for the element
22
+ */
23
+ export declare function getChildNamespace(currentNodeName: string | null, parentNamespace: NamespaceURI, parentNodeName: string | null): NamespaceURI;
24
+ /**
25
+ * Determines the namespace URI of an element below an ancestor whose own namespace is not
26
+ * known, such as the root of a component, which takes the namespace of where it is used.
27
+ *
28
+ * It is known once the ancestor or the elements between them cross a transition: an `svg`
29
+ * or `math` is taken to enter its namespace, as it does from HTML, and an element below
30
+ * `foreignObject` is HTML whether the `foreignObject` is in SVG or in HTML.
31
+ *
32
+ * @param ancestorName - The tag name of the ancestor, or null for a component or fragment
33
+ * @param names - The tag names from the child of the ancestor down to the element, null for a component
34
+ * @returns The namespace URI of the element, or null when it depends on where the ancestor is
35
+ */
36
+ export declare function getNamespaceBelow(ancestorName: string | null, names: readonly (string | null)[]): NamespaceURI | null;
@@ -3,22 +3,69 @@
3
3
  * Handles namespace transitions between HTML, SVG, and MathML
4
4
  * (e.g., entering `<svg>` switches to SVG namespace, `<foreignObject>` switches back to HTML).
5
5
  *
6
- * @param currentNodeName - The tag name of the current node, or null for anonymous nodes
6
+ * @param currentNodeName - The tag name of the current node, or null for anonymous nodes and
7
+ * for an authored element (a component), which does not enter a namespace by its name
7
8
  * @param parentNode - The parent node in the AST, or null for root-level nodes
8
9
  * @returns The resolved namespace URI for the node
9
10
  */
10
11
  export function getNamespace(currentNodeName, parentNode) {
11
- const parentNS = getParentNamespace(parentNode);
12
- if (parentNS === 'http://www.w3.org/1999/xhtml' && currentNodeName?.toLowerCase() === 'svg') {
12
+ return getChildNamespace(currentNodeName, getParentNamespace(parentNode), parentNode?.nodeName ?? null);
13
+ }
14
+ /**
15
+ * Determines the namespace URI for an element from its tag name and its parent element,
16
+ * by the same transitions as {@link getNamespace}. For a caller that knows the parent's
17
+ * name and namespace but has no AST node for it.
18
+ *
19
+ * @param currentNodeName - The tag name of the element, or null to take the namespace its parent gives any element
20
+ * @param parentNamespace - The namespace URI of the parent element (HTML at the top level)
21
+ * @param parentNodeName - The tag name of the parent element, or null at the top level
22
+ * @returns The resolved namespace URI for the element
23
+ */
24
+ export function getChildNamespace(currentNodeName, parentNamespace, parentNodeName) {
25
+ if (parentNamespace === 'http://www.w3.org/1999/xhtml' && currentNodeName?.toLowerCase() === 'svg') {
13
26
  return 'http://www.w3.org/2000/svg';
14
27
  }
15
- else if (parentNS === 'http://www.w3.org/2000/svg' && parentNode?.nodeName === 'foreignObject') {
28
+ else if (parentNamespace === 'http://www.w3.org/2000/svg' && parentNodeName === 'foreignObject') {
16
29
  return 'http://www.w3.org/1999/xhtml';
17
30
  }
18
- else if (parentNS === 'http://www.w3.org/1999/xhtml' && currentNodeName?.toLowerCase() === 'math') {
31
+ else if (parentNamespace === 'http://www.w3.org/1999/xhtml' && currentNodeName?.toLowerCase() === 'math') {
19
32
  return 'http://www.w3.org/1998/Math/MathML';
20
33
  }
21
- return parentNS;
34
+ return parentNamespace;
35
+ }
36
+ /**
37
+ * Determines the namespace URI of an element below an ancestor whose own namespace is not
38
+ * known, such as the root of a component, which takes the namespace of where it is used.
39
+ *
40
+ * It is known once the ancestor or the elements between them cross a transition: an `svg`
41
+ * or `math` is taken to enter its namespace, as it does from HTML, and an element below
42
+ * `foreignObject` is HTML whether the `foreignObject` is in SVG or in HTML.
43
+ *
44
+ * @param ancestorName - The tag name of the ancestor, or null for a component or fragment
45
+ * @param names - The tag names from the child of the ancestor down to the element, null for a component
46
+ * @returns The namespace URI of the element, or null when it depends on where the ancestor is
47
+ */
48
+ export function getNamespaceBelow(ancestorName, names) {
49
+ let namespace = getEnteredNamespace(ancestorName);
50
+ let parentName = ancestorName;
51
+ for (const name of names) {
52
+ if (namespace) {
53
+ namespace = getChildNamespace(name, namespace, parentName);
54
+ }
55
+ else {
56
+ namespace =
57
+ getEnteredNamespace(name) ?? (parentName === 'foreignObject' ? 'http://www.w3.org/1999/xhtml' : null);
58
+ }
59
+ parentName = name;
60
+ }
61
+ return namespace;
62
+ }
63
+ /**
64
+ * The namespace an element enters by its name from HTML, or null if it enters none.
65
+ */
66
+ function getEnteredNamespace(name) {
67
+ const entered = getChildNamespace(name, 'http://www.w3.org/1999/xhtml', null);
68
+ return entered === 'http://www.w3.org/1999/xhtml' ? null : entered;
22
69
  }
23
70
  function getParentNamespace(parentNode) {
24
71
  if (!parentNode) {
package/lib/parser.js CHANGED
@@ -1357,6 +1357,7 @@ export class Parser {
1357
1357
  }
1358
1358
  const tagToken = this.createToken(rawCodeFragment, tagStartOffset, tagStartLine, tagStartCol);
1359
1359
  const isFragment = tagName === '';
1360
+ const elementType = this.detectElementType(tagName);
1360
1361
  const commons = {
1361
1362
  depth,
1362
1363
  nodeName: isFragment ? '#jsx-fragment' : tagName,
@@ -1368,10 +1369,13 @@ export class Parser {
1368
1369
  ...tagToken,
1369
1370
  ...commons,
1370
1371
  type: 'starttag',
1371
- elementType: this.detectElementType(tagName),
1372
+ elementType,
1373
+ // What a component renders is not known from its name, so an authored
1374
+ // element is not given the name: `<Svg>` and `<Math>` would enter
1375
+ // their namespaces, as `getNamespace` compares names in lowercase.
1372
1376
  namespace: 'namespace' in token
1373
1377
  ? token.namespace
1374
- : getNamespace(tagName, token.parentNode),
1378
+ : getNamespace(elementType === 'authored' ? null : tagName, token.parentNode),
1375
1379
  attributes: attrs,
1376
1380
  childNodes: [],
1377
1381
  pairNode: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/parser-utils",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "Utility module for markuplint parser plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,16 +35,16 @@
35
35
  "clean": "tsc --build --clean tsconfig.build.json"
36
36
  },
37
37
  "dependencies": {
38
- "@markuplint/ml-ast": "5.1.0",
39
- "@markuplint/ml-spec": "5.1.0",
40
- "@markuplint/shared": "5.1.0",
41
- "@markuplint/types": "5.1.0",
42
- "debug": "4.4.3",
43
- "espree": "11.2.0",
44
- "type-fest": "5.6.0"
38
+ "@markuplint/ml-ast": "5.1.1",
39
+ "@markuplint/ml-spec": "5.2.0",
40
+ "@markuplint/shared": "5.2.0",
41
+ "@markuplint/types": "5.2.0",
42
+ "debug": "^4.4.3",
43
+ "espree": "^11.2.0",
44
+ "type-fest": "^5.10.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@typescript-eslint/typescript-estree": "8.59.0"
47
+ "@typescript-eslint/typescript-estree": "8.71.1"
48
48
  },
49
- "gitHead": "3a061784a8211034ad0c1cbd64798c0213414f65"
49
+ "gitHead": "d8b2feab77c9c862513615bea6b80d2817431878"
50
50
  }