@transferwise/components 0.0.0-experimental-c388243 → 0.0.0-experimental-18063d6

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.
Files changed (75) hide show
  1. package/build/chips/Chip.js.map +1 -1
  2. package/build/chips/Chip.mjs.map +1 -1
  3. package/build/chips/Chips.js.map +1 -1
  4. package/build/chips/Chips.mjs.map +1 -1
  5. package/build/index.js +0 -2
  6. package/build/index.js.map +1 -1
  7. package/build/index.mjs +0 -1
  8. package/build/index.mjs.map +1 -1
  9. package/build/main.css +0 -35
  10. package/build/styles/main.css +0 -35
  11. package/build/types/body/Body.d.ts +2 -2
  12. package/build/types/chips/Chip.d.ts +3 -3
  13. package/build/types/chips/Chip.d.ts.map +1 -1
  14. package/build/types/chips/Chips.d.ts +10 -9
  15. package/build/types/chips/Chips.d.ts.map +1 -1
  16. package/build/types/iconButton/IconButton.d.ts +1 -1
  17. package/build/types/index.d.ts +0 -2
  18. package/build/types/index.d.ts.map +1 -1
  19. package/build/types/title/Title.d.ts +2 -2
  20. package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts +1 -1
  21. package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts +1 -1
  22. package/package.json +3 -3
  23. package/src/chips/Chip.tsx +4 -4
  24. package/src/chips/Chips.tsx +13 -18
  25. package/src/index.ts +0 -2
  26. package/src/main.css +0 -35
  27. package/src/main.less +0 -1
  28. package/build/markup/Markup.js +0 -128
  29. package/build/markup/Markup.js.map +0 -1
  30. package/build/markup/Markup.mjs +0 -126
  31. package/build/markup/Markup.mjs.map +0 -1
  32. package/build/markup/constants.js +0 -36
  33. package/build/markup/constants.js.map +0 -1
  34. package/build/markup/constants.mjs +0 -29
  35. package/build/markup/constants.mjs.map +0 -1
  36. package/build/markup/utils/parseMarkup.js +0 -226
  37. package/build/markup/utils/parseMarkup.js.map +0 -1
  38. package/build/markup/utils/parseMarkup.mjs +0 -223
  39. package/build/markup/utils/parseMarkup.mjs.map +0 -1
  40. package/build/markup/utils/sanitise.js +0 -91
  41. package/build/markup/utils/sanitise.js.map +0 -1
  42. package/build/markup/utils/sanitise.mjs +0 -89
  43. package/build/markup/utils/sanitise.mjs.map +0 -1
  44. package/build/styles/markup/Markup.css +0 -28
  45. package/build/styles/markup/_stories/Vulnerability/Vulnerability.css +0 -70
  46. package/build/types/markup/Markup.d.ts +0 -4
  47. package/build/types/markup/Markup.d.ts.map +0 -1
  48. package/build/types/markup/Markup.types.d.ts +0 -63
  49. package/build/types/markup/Markup.types.d.ts.map +0 -1
  50. package/build/types/markup/_stories/Vulnerability/Vulnerability.d.ts +0 -12
  51. package/build/types/markup/_stories/Vulnerability/Vulnerability.d.ts.map +0 -1
  52. package/build/types/markup/constants.d.ts +0 -20
  53. package/build/types/markup/constants.d.ts.map +0 -1
  54. package/build/types/markup/index.d.ts +0 -3
  55. package/build/types/markup/index.d.ts.map +0 -1
  56. package/build/types/markup/utils/parseMarkup.d.ts +0 -6
  57. package/build/types/markup/utils/parseMarkup.d.ts.map +0 -1
  58. package/build/types/markup/utils/sanitise.d.ts +0 -2
  59. package/build/types/markup/utils/sanitise.d.ts.map +0 -1
  60. package/src/markup/Markup.css +0 -28
  61. package/src/markup/Markup.less +0 -29
  62. package/src/markup/Markup.test.tsx +0 -330
  63. package/src/markup/Markup.tsx +0 -144
  64. package/src/markup/Markup.types.ts +0 -48
  65. package/src/markup/_stories/Markup.docs.mdx +0 -75
  66. package/src/markup/_stories/Markup.security.docs.mdx +0 -256
  67. package/src/markup/_stories/Markup.story.tsx +0 -198
  68. package/src/markup/_stories/Vulnerability/Vulnerability.css +0 -70
  69. package/src/markup/_stories/Vulnerability/Vulnerability.tsx +0 -30
  70. package/src/markup/constants.ts +0 -41
  71. package/src/markup/index.ts +0 -2
  72. package/src/markup/utils/parseMarkup.test.ts +0 -658
  73. package/src/markup/utils/parseMarkup.ts +0 -228
  74. package/src/markup/utils/sanitise.test.ts +0 -375
  75. package/src/markup/utils/sanitise.ts +0 -107
@@ -1,128 +0,0 @@
1
- 'use strict';
2
-
3
- var React = require('react');
4
- var Link = require('../link/Link.js');
5
- var parseMarkup = require('./utils/parseMarkup.js');
6
- var sanitise = require('./utils/sanitise.js');
7
- var jsxRuntime = require('react/jsx-runtime');
8
-
9
- function renderNodes(nodes, actions) {
10
- return nodes.map((node, index) => renderNode(node, actions, index));
11
- }
12
- function renderLinkNode(node, actions, key) {
13
- const children = renderNodes(node.children, actions);
14
- if (node.action && actions?.[node.action]) {
15
- return (
16
- /*#__PURE__*/
17
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events
18
- jsxRuntime.jsx(Link.default, {
19
- "aria-label": node.accessibilityLabel,
20
- onClick: actions[node.action],
21
- children: children
22
- }, key)
23
- );
24
- }
25
- if (node.href && sanitise.isAllowedHref(node.href)) {
26
- return /*#__PURE__*/jsxRuntime.jsx(Link.default, {
27
- href: node.href,
28
- target: node.target,
29
- "aria-label": node.accessibilityLabel,
30
- children: children
31
- }, key);
32
- }
33
- return /*#__PURE__*/jsxRuntime.jsx(React.Fragment, {
34
- children: children
35
- }, key);
36
- }
37
- function renderNode(node, actions, key) {
38
- switch (node.type) {
39
- case 'text':
40
- return /*#__PURE__*/jsxRuntime.jsx(React.Fragment, {
41
- children: node.content
42
- }, key);
43
- case 'newline':
44
- return /*#__PURE__*/jsxRuntime.jsx("br", {}, key);
45
- case 'important':
46
- case 'positive':
47
- case 'negative':
48
- return /*#__PURE__*/jsxRuntime.jsx("em", {
49
- className: `wds-markup-emphasis wds-markup-emphasis--${node.type}`,
50
- "aria-label": node.accessibilityLabel,
51
- children: renderNodes(node.children, actions)
52
- }, key);
53
- case 'strong':
54
- return /*#__PURE__*/jsxRuntime.jsx("strong", {
55
- className: "wds-markup-strong",
56
- "aria-label": node.accessibilityLabel,
57
- children: renderNodes(node.children, actions)
58
- }, key);
59
- case 'strikethrough':
60
- return /*#__PURE__*/jsxRuntime.jsx("del", {
61
- className: "wds-markup-strikethrough",
62
- "aria-label": node.accessibilityLabel,
63
- children: renderNodes(node.children, actions)
64
- }, key);
65
- case 'paragraph':
66
- return /*#__PURE__*/jsxRuntime.jsx("p", {
67
- className: "wds-markup-paragraph",
68
- children: renderNodes(node.children, actions)
69
- }, key);
70
- case 'link':
71
- return renderLinkNode(node, actions, key);
72
- }
73
- }
74
- /**
75
- * Parses a markup string and renders it as React elements. Supports `<important>`,
76
- * `<positive>`, `<negative>`, `<strong>`, `<strikethrough>`, `<paragraph>` (alias `<p>`),
77
- * and `<link>` (alias `<a>`) with secure href validation.
78
- *
79
- * It only processes `string` input, while `ReactNode` is passed-through without processing.
80
- *
81
- * > The component supersedes [Emphasis](?path=/docs/typography-emphasis--docs), which will be
82
- * eventually deprecated.
83
- *
84
- * @see http://storybook.wise.design/?path=/docs/typography-markup--docs
85
- * @link ../emphasis/Emphasis | Emphasis
86
- */
87
- function hasParagraph(nodes) {
88
- for (const node of nodes) {
89
- if (node.type === 'paragraph') {
90
- return true;
91
- }
92
- if ('children' in node && hasParagraph(node.children)) {
93
- return true;
94
- }
95
- }
96
- return false;
97
- }
98
- const Markup = ({
99
- children,
100
- actions,
101
- as,
102
- className,
103
- 'data-testid': testId
104
- }) => {
105
- const tree = React.useMemo(() => typeof children === 'string' ? parseMarkup.parseMarkup(children) : [], [children]);
106
- if (typeof children !== 'string') {
107
- if (children == null) {
108
- return null;
109
- }
110
- return /*#__PURE__*/jsxRuntime.jsx("span", {
111
- className: className,
112
- "data-testid": testId,
113
- children: children
114
- });
115
- }
116
- if (tree.length === 0) {
117
- return null;
118
- }
119
- const Element = as ?? (hasParagraph(tree) ? 'div' : 'span');
120
- return /*#__PURE__*/jsxRuntime.jsx(Element, {
121
- className: className,
122
- "data-testid": testId,
123
- children: renderNodes(tree, actions)
124
- });
125
- };
126
-
127
- exports.Markup = Markup;
128
- //# sourceMappingURL=Markup.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Markup.js","sources":["../../src/markup/Markup.tsx"],"sourcesContent":["import React, { Fragment, useMemo } from 'react';\n\nimport Link from '../link';\n\nimport { parseMarkup } from './utils/parseMarkup';\nimport { isAllowedHref } from './utils/sanitise';\nimport type { MarkupActions, MarkupNode, MarkupProps } from './Markup.types';\n\nfunction renderNodes(nodes: MarkupNode[], actions?: MarkupActions): React.ReactNode[] {\n return nodes.map((node, index) => renderNode(node, actions, index));\n}\n\nfunction renderLinkNode(\n node: Extract<MarkupNode, { type: 'link' }>,\n actions: MarkupActions | undefined,\n key: number,\n): React.ReactNode {\n const children = renderNodes(node.children, actions);\n\n if (node.action && actions?.[node.action]) {\n return (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <Link key={key} aria-label={node.accessibilityLabel} onClick={actions[node.action]}>\n {children}\n </Link>\n );\n }\n\n if (node.href && isAllowedHref(node.href)) {\n return (\n <Link key={key} href={node.href} target={node.target} aria-label={node.accessibilityLabel}>\n {children}\n </Link>\n );\n }\n\n return <Fragment key={key}>{children}</Fragment>;\n}\n\nfunction renderNode(\n node: MarkupNode,\n actions: MarkupActions | undefined,\n key: number,\n): React.ReactNode {\n switch (node.type) {\n case 'text':\n return <Fragment key={key}>{node.content}</Fragment>;\n case 'newline':\n return <br key={key} />;\n case 'important':\n case 'positive':\n case 'negative':\n return (\n <em\n key={key}\n className={`wds-markup-emphasis wds-markup-emphasis--${node.type}`}\n aria-label={node.accessibilityLabel}\n >\n {renderNodes(node.children, actions)}\n </em>\n );\n case 'strong':\n return (\n <strong key={key} className=\"wds-markup-strong\" aria-label={node.accessibilityLabel}>\n {renderNodes(node.children, actions)}\n </strong>\n );\n case 'strikethrough':\n return (\n <del key={key} className=\"wds-markup-strikethrough\" aria-label={node.accessibilityLabel}>\n {renderNodes(node.children, actions)}\n </del>\n );\n case 'paragraph':\n return (\n <p key={key} className=\"wds-markup-paragraph\">\n {renderNodes(node.children, actions)}\n </p>\n );\n case 'link':\n return renderLinkNode(node, actions, key);\n }\n}\n\n/**\n * Parses a markup string and renders it as React elements. Supports `<important>`,\n * `<positive>`, `<negative>`, `<strong>`, `<strikethrough>`, `<paragraph>` (alias `<p>`),\n * and `<link>` (alias `<a>`) with secure href validation.\n *\n * It only processes `string` input, while `ReactNode` is passed-through without processing.\n *\n * > The component supersedes [Emphasis](?path=/docs/typography-emphasis--docs), which will be\n * eventually deprecated.\n *\n * @see http://storybook.wise.design/?path=/docs/typography-markup--docs\n * @link ../emphasis/Emphasis | Emphasis\n */\nfunction hasParagraph(nodes: MarkupNode[]): boolean {\n for (const node of nodes) {\n if (node.type === 'paragraph') {\n return true;\n }\n if ('children' in node && hasParagraph(node.children)) {\n return true;\n }\n }\n return false;\n}\n\nexport const Markup: React.FC<MarkupProps> = ({\n children,\n actions,\n as,\n className,\n 'data-testid': testId,\n}) => {\n const tree = useMemo(\n () => (typeof children === 'string' ? parseMarkup(children) : []),\n [children],\n );\n\n if (typeof children !== 'string') {\n if (children == null) {\n return null;\n }\n return (\n <span className={className} data-testid={testId}>\n {children}\n </span>\n );\n }\n\n if (tree.length === 0) {\n return null;\n }\n\n const Element = as ?? (hasParagraph(tree) ? 'div' : 'span');\n\n return (\n <Element className={className} data-testid={testId}>\n {renderNodes(tree, actions)}\n </Element>\n );\n};\n"],"names":["renderNodes","nodes","actions","map","node","index","renderNode","renderLinkNode","key","children","action","_jsx","Link","accessibilityLabel","onClick","href","isAllowedHref","target","Fragment","type","content","className","hasParagraph","Markup","as","testId","tree","useMemo","parseMarkup","length","Element"],"mappings":"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"}
@@ -1,126 +0,0 @@
1
- import { useMemo, Fragment } from 'react';
2
- import Link from '../link/Link.mjs';
3
- import { parseMarkup } from './utils/parseMarkup.mjs';
4
- import { isAllowedHref } from './utils/sanitise.mjs';
5
- import { jsx } from 'react/jsx-runtime';
6
-
7
- function renderNodes(nodes, actions) {
8
- return nodes.map((node, index) => renderNode(node, actions, index));
9
- }
10
- function renderLinkNode(node, actions, key) {
11
- const children = renderNodes(node.children, actions);
12
- if (node.action && actions?.[node.action]) {
13
- return (
14
- /*#__PURE__*/
15
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events
16
- jsx(Link, {
17
- "aria-label": node.accessibilityLabel,
18
- onClick: actions[node.action],
19
- children: children
20
- }, key)
21
- );
22
- }
23
- if (node.href && isAllowedHref(node.href)) {
24
- return /*#__PURE__*/jsx(Link, {
25
- href: node.href,
26
- target: node.target,
27
- "aria-label": node.accessibilityLabel,
28
- children: children
29
- }, key);
30
- }
31
- return /*#__PURE__*/jsx(Fragment, {
32
- children: children
33
- }, key);
34
- }
35
- function renderNode(node, actions, key) {
36
- switch (node.type) {
37
- case 'text':
38
- return /*#__PURE__*/jsx(Fragment, {
39
- children: node.content
40
- }, key);
41
- case 'newline':
42
- return /*#__PURE__*/jsx("br", {}, key);
43
- case 'important':
44
- case 'positive':
45
- case 'negative':
46
- return /*#__PURE__*/jsx("em", {
47
- className: `wds-markup-emphasis wds-markup-emphasis--${node.type}`,
48
- "aria-label": node.accessibilityLabel,
49
- children: renderNodes(node.children, actions)
50
- }, key);
51
- case 'strong':
52
- return /*#__PURE__*/jsx("strong", {
53
- className: "wds-markup-strong",
54
- "aria-label": node.accessibilityLabel,
55
- children: renderNodes(node.children, actions)
56
- }, key);
57
- case 'strikethrough':
58
- return /*#__PURE__*/jsx("del", {
59
- className: "wds-markup-strikethrough",
60
- "aria-label": node.accessibilityLabel,
61
- children: renderNodes(node.children, actions)
62
- }, key);
63
- case 'paragraph':
64
- return /*#__PURE__*/jsx("p", {
65
- className: "wds-markup-paragraph",
66
- children: renderNodes(node.children, actions)
67
- }, key);
68
- case 'link':
69
- return renderLinkNode(node, actions, key);
70
- }
71
- }
72
- /**
73
- * Parses a markup string and renders it as React elements. Supports `<important>`,
74
- * `<positive>`, `<negative>`, `<strong>`, `<strikethrough>`, `<paragraph>` (alias `<p>`),
75
- * and `<link>` (alias `<a>`) with secure href validation.
76
- *
77
- * It only processes `string` input, while `ReactNode` is passed-through without processing.
78
- *
79
- * > The component supersedes [Emphasis](?path=/docs/typography-emphasis--docs), which will be
80
- * eventually deprecated.
81
- *
82
- * @see http://storybook.wise.design/?path=/docs/typography-markup--docs
83
- * @link ../emphasis/Emphasis | Emphasis
84
- */
85
- function hasParagraph(nodes) {
86
- for (const node of nodes) {
87
- if (node.type === 'paragraph') {
88
- return true;
89
- }
90
- if ('children' in node && hasParagraph(node.children)) {
91
- return true;
92
- }
93
- }
94
- return false;
95
- }
96
- const Markup = ({
97
- children,
98
- actions,
99
- as,
100
- className,
101
- 'data-testid': testId
102
- }) => {
103
- const tree = useMemo(() => typeof children === 'string' ? parseMarkup(children) : [], [children]);
104
- if (typeof children !== 'string') {
105
- if (children == null) {
106
- return null;
107
- }
108
- return /*#__PURE__*/jsx("span", {
109
- className: className,
110
- "data-testid": testId,
111
- children: children
112
- });
113
- }
114
- if (tree.length === 0) {
115
- return null;
116
- }
117
- const Element = as ?? (hasParagraph(tree) ? 'div' : 'span');
118
- return /*#__PURE__*/jsx(Element, {
119
- className: className,
120
- "data-testid": testId,
121
- children: renderNodes(tree, actions)
122
- });
123
- };
124
-
125
- export { Markup };
126
- //# sourceMappingURL=Markup.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Markup.mjs","sources":["../../src/markup/Markup.tsx"],"sourcesContent":["import React, { Fragment, useMemo } from 'react';\n\nimport Link from '../link';\n\nimport { parseMarkup } from './utils/parseMarkup';\nimport { isAllowedHref } from './utils/sanitise';\nimport type { MarkupActions, MarkupNode, MarkupProps } from './Markup.types';\n\nfunction renderNodes(nodes: MarkupNode[], actions?: MarkupActions): React.ReactNode[] {\n return nodes.map((node, index) => renderNode(node, actions, index));\n}\n\nfunction renderLinkNode(\n node: Extract<MarkupNode, { type: 'link' }>,\n actions: MarkupActions | undefined,\n key: number,\n): React.ReactNode {\n const children = renderNodes(node.children, actions);\n\n if (node.action && actions?.[node.action]) {\n return (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <Link key={key} aria-label={node.accessibilityLabel} onClick={actions[node.action]}>\n {children}\n </Link>\n );\n }\n\n if (node.href && isAllowedHref(node.href)) {\n return (\n <Link key={key} href={node.href} target={node.target} aria-label={node.accessibilityLabel}>\n {children}\n </Link>\n );\n }\n\n return <Fragment key={key}>{children}</Fragment>;\n}\n\nfunction renderNode(\n node: MarkupNode,\n actions: MarkupActions | undefined,\n key: number,\n): React.ReactNode {\n switch (node.type) {\n case 'text':\n return <Fragment key={key}>{node.content}</Fragment>;\n case 'newline':\n return <br key={key} />;\n case 'important':\n case 'positive':\n case 'negative':\n return (\n <em\n key={key}\n className={`wds-markup-emphasis wds-markup-emphasis--${node.type}`}\n aria-label={node.accessibilityLabel}\n >\n {renderNodes(node.children, actions)}\n </em>\n );\n case 'strong':\n return (\n <strong key={key} className=\"wds-markup-strong\" aria-label={node.accessibilityLabel}>\n {renderNodes(node.children, actions)}\n </strong>\n );\n case 'strikethrough':\n return (\n <del key={key} className=\"wds-markup-strikethrough\" aria-label={node.accessibilityLabel}>\n {renderNodes(node.children, actions)}\n </del>\n );\n case 'paragraph':\n return (\n <p key={key} className=\"wds-markup-paragraph\">\n {renderNodes(node.children, actions)}\n </p>\n );\n case 'link':\n return renderLinkNode(node, actions, key);\n }\n}\n\n/**\n * Parses a markup string and renders it as React elements. Supports `<important>`,\n * `<positive>`, `<negative>`, `<strong>`, `<strikethrough>`, `<paragraph>` (alias `<p>`),\n * and `<link>` (alias `<a>`) with secure href validation.\n *\n * It only processes `string` input, while `ReactNode` is passed-through without processing.\n *\n * > The component supersedes [Emphasis](?path=/docs/typography-emphasis--docs), which will be\n * eventually deprecated.\n *\n * @see http://storybook.wise.design/?path=/docs/typography-markup--docs\n * @link ../emphasis/Emphasis | Emphasis\n */\nfunction hasParagraph(nodes: MarkupNode[]): boolean {\n for (const node of nodes) {\n if (node.type === 'paragraph') {\n return true;\n }\n if ('children' in node && hasParagraph(node.children)) {\n return true;\n }\n }\n return false;\n}\n\nexport const Markup: React.FC<MarkupProps> = ({\n children,\n actions,\n as,\n className,\n 'data-testid': testId,\n}) => {\n const tree = useMemo(\n () => (typeof children === 'string' ? parseMarkup(children) : []),\n [children],\n );\n\n if (typeof children !== 'string') {\n if (children == null) {\n return null;\n }\n return (\n <span className={className} data-testid={testId}>\n {children}\n </span>\n );\n }\n\n if (tree.length === 0) {\n return null;\n }\n\n const Element = as ?? (hasParagraph(tree) ? 'div' : 'span');\n\n return (\n <Element className={className} data-testid={testId}>\n {renderNodes(tree, actions)}\n </Element>\n );\n};\n"],"names":["renderNodes","nodes","actions","map","node","index","renderNode","renderLinkNode","key","children","action","_jsx","Link","accessibilityLabel","onClick","href","isAllowedHref","target","Fragment","type","content","className","hasParagraph","Markup","as","testId","tree","useMemo","parseMarkup","length","Element"],"mappings":"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"}
@@ -1,36 +0,0 @@
1
- 'use strict';
2
-
3
- // Only these tags are recognised — anything else is treated as plain text (security allow-list)
4
- const ALLOWED_TAGS = ['important', 'positive', 'negative', 'strong', 'strikethrough', 'paragraph', 'p', 'link', 'a'];
5
- /**
6
- * Matches opening and closing tags from the ALLOWED_TAGS allow-list.
7
- *
8
- * Capture groups:
9
- * 1. `/` if this is a closing tag, undefined otherwise
10
- * 2. Tag name
11
- * 3. Raw attribute string between the tag name and `>` (empty for closing tags)
12
- *
13
- * The lookahead `(?=[\s>/])` after the tag name ensures we don't match partial
14
- * words — e.g. `<stronger>` won't be matched as `<strong>`.
15
- *
16
- * Global flag (`g`) allows iterative matching via `exec()`.
17
- */
18
- const TAG_REGEX = new RegExp(`<(\\/)?(${ALLOWED_TAGS.join('|')})(?=[\\s>/])((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>`, 'g');
19
- const TAG_ALIASES = {
20
- p: 'paragraph',
21
- a: 'link'
22
- };
23
- // Maximum recursive nesting before the parser emits tags as literal text (DoS protection)
24
- const MAX_NESTING_DEPTH = 32;
25
- // Only these link targets are allowed — others are stripped to prevent iframe breakout
26
- const ALLOWED_TARGETS = ['_blank', '_self'];
27
- // Only these protocols pass href validation — all others are blocked
28
- const ALLOWED_PROTOCOLS = ['https:', 'mailto:'];
29
-
30
- exports.ALLOWED_PROTOCOLS = ALLOWED_PROTOCOLS;
31
- exports.ALLOWED_TAGS = ALLOWED_TAGS;
32
- exports.ALLOWED_TARGETS = ALLOWED_TARGETS;
33
- exports.MAX_NESTING_DEPTH = MAX_NESTING_DEPTH;
34
- exports.TAG_ALIASES = TAG_ALIASES;
35
- exports.TAG_REGEX = TAG_REGEX;
36
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","sources":["../../src/markup/constants.ts"],"sourcesContent":["// Only these tags are recognised — anything else is treated as plain text (security allow-list)\nexport const ALLOWED_TAGS = [\n 'important',\n 'positive',\n 'negative',\n 'strong',\n 'strikethrough',\n 'paragraph',\n 'p',\n 'link',\n 'a',\n] as const;\n\n/**\n * Matches opening and closing tags from the ALLOWED_TAGS allow-list.\n *\n * Capture groups:\n * 1. `/` if this is a closing tag, undefined otherwise\n * 2. Tag name\n * 3. Raw attribute string between the tag name and `>` (empty for closing tags)\n *\n * The lookahead `(?=[\\s>/])` after the tag name ensures we don't match partial\n * words — e.g. `<stronger>` won't be matched as `<strong>`.\n *\n * Global flag (`g`) allows iterative matching via `exec()`.\n */\nexport const TAG_REGEX = new RegExp(\n `<(\\\\/)?(${ALLOWED_TAGS.join('|')})(?=[\\\\s>/])((?:[^>\"']*(?:\"[^\"]*\"|'[^']*'))*[^>\"']*)>`,\n 'g',\n);\n\nexport const TAG_ALIASES: Record<string, string> = { p: 'paragraph', a: 'link' };\n\n// Maximum recursive nesting before the parser emits tags as literal text (DoS protection)\nexport const MAX_NESTING_DEPTH = 32;\n\n// Only these link targets are allowed — others are stripped to prevent iframe breakout\nexport const ALLOWED_TARGETS = ['_blank', '_self'];\n\n// Only these protocols pass href validation — all others are blocked\nexport const ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n"],"names":["ALLOWED_TAGS","TAG_REGEX","RegExp","join","TAG_ALIASES","p","a","MAX_NESTING_DEPTH","ALLOWED_TARGETS","ALLOWED_PROTOCOLS"],"mappings":";;AAAA;AACO,MAAMA,YAAY,GAAG,CAC1B,WAAW,EACX,UAAU,EACV,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,GAAG,EACH,MAAM,EACN,GAAG;AAGL;;;;;;;;;;;;AAYG;MACUC,SAAS,GAAG,IAAIC,MAAM,CACjC,CAAA,QAAA,EAAWF,YAAY,CAACG,IAAI,CAAC,GAAG,CAAC,CAAA,qDAAA,CAAuD,EACxF,GAAG;AAGE,MAAMC,WAAW,GAA2B;AAAEC,EAAAA,CAAC,EAAE,WAAW;AAAEC,EAAAA,CAAC,EAAE;;AAExE;AACO,MAAMC,iBAAiB,GAAG;AAEjC;MACaC,eAAe,GAAG,CAAC,QAAQ,EAAE,OAAO;AAEjD;MACaC,iBAAiB,GAAG,CAAC,QAAQ,EAAE,SAAS;;;;;;;;;"}
@@ -1,29 +0,0 @@
1
- // Only these tags are recognised — anything else is treated as plain text (security allow-list)
2
- const ALLOWED_TAGS = ['important', 'positive', 'negative', 'strong', 'strikethrough', 'paragraph', 'p', 'link', 'a'];
3
- /**
4
- * Matches opening and closing tags from the ALLOWED_TAGS allow-list.
5
- *
6
- * Capture groups:
7
- * 1. `/` if this is a closing tag, undefined otherwise
8
- * 2. Tag name
9
- * 3. Raw attribute string between the tag name and `>` (empty for closing tags)
10
- *
11
- * The lookahead `(?=[\s>/])` after the tag name ensures we don't match partial
12
- * words — e.g. `<stronger>` won't be matched as `<strong>`.
13
- *
14
- * Global flag (`g`) allows iterative matching via `exec()`.
15
- */
16
- const TAG_REGEX = new RegExp(`<(\\/)?(${ALLOWED_TAGS.join('|')})(?=[\\s>/])((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>`, 'g');
17
- const TAG_ALIASES = {
18
- p: 'paragraph',
19
- a: 'link'
20
- };
21
- // Maximum recursive nesting before the parser emits tags as literal text (DoS protection)
22
- const MAX_NESTING_DEPTH = 32;
23
- // Only these link targets are allowed — others are stripped to prevent iframe breakout
24
- const ALLOWED_TARGETS = ['_blank', '_self'];
25
- // Only these protocols pass href validation — all others are blocked
26
- const ALLOWED_PROTOCOLS = ['https:', 'mailto:'];
27
-
28
- export { ALLOWED_PROTOCOLS, ALLOWED_TAGS, ALLOWED_TARGETS, MAX_NESTING_DEPTH, TAG_ALIASES, TAG_REGEX };
29
- //# sourceMappingURL=constants.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.mjs","sources":["../../src/markup/constants.ts"],"sourcesContent":["// Only these tags are recognised — anything else is treated as plain text (security allow-list)\nexport const ALLOWED_TAGS = [\n 'important',\n 'positive',\n 'negative',\n 'strong',\n 'strikethrough',\n 'paragraph',\n 'p',\n 'link',\n 'a',\n] as const;\n\n/**\n * Matches opening and closing tags from the ALLOWED_TAGS allow-list.\n *\n * Capture groups:\n * 1. `/` if this is a closing tag, undefined otherwise\n * 2. Tag name\n * 3. Raw attribute string between the tag name and `>` (empty for closing tags)\n *\n * The lookahead `(?=[\\s>/])` after the tag name ensures we don't match partial\n * words — e.g. `<stronger>` won't be matched as `<strong>`.\n *\n * Global flag (`g`) allows iterative matching via `exec()`.\n */\nexport const TAG_REGEX = new RegExp(\n `<(\\\\/)?(${ALLOWED_TAGS.join('|')})(?=[\\\\s>/])((?:[^>\"']*(?:\"[^\"]*\"|'[^']*'))*[^>\"']*)>`,\n 'g',\n);\n\nexport const TAG_ALIASES: Record<string, string> = { p: 'paragraph', a: 'link' };\n\n// Maximum recursive nesting before the parser emits tags as literal text (DoS protection)\nexport const MAX_NESTING_DEPTH = 32;\n\n// Only these link targets are allowed — others are stripped to prevent iframe breakout\nexport const ALLOWED_TARGETS = ['_blank', '_self'];\n\n// Only these protocols pass href validation — all others are blocked\nexport const ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n"],"names":["ALLOWED_TAGS","TAG_REGEX","RegExp","join","TAG_ALIASES","p","a","MAX_NESTING_DEPTH","ALLOWED_TARGETS","ALLOWED_PROTOCOLS"],"mappings":"AAAA;AACO,MAAMA,YAAY,GAAG,CAC1B,WAAW,EACX,UAAU,EACV,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,GAAG,EACH,MAAM,EACN,GAAG;AAGL;;;;;;;;;;;;AAYG;MACUC,SAAS,GAAG,IAAIC,MAAM,CACjC,CAAA,QAAA,EAAWF,YAAY,CAACG,IAAI,CAAC,GAAG,CAAC,CAAA,qDAAA,CAAuD,EACxF,GAAG;AAGE,MAAMC,WAAW,GAA2B;AAAEC,EAAAA,CAAC,EAAE,WAAW;AAAEC,EAAAA,CAAC,EAAE;;AAExE;AACO,MAAMC,iBAAiB,GAAG;AAEjC;MACaC,eAAe,GAAG,CAAC,QAAQ,EAAE,OAAO;AAEjD;MACaC,iBAAiB,GAAG,CAAC,QAAQ,EAAE,SAAS;;;;"}
@@ -1,226 +0,0 @@
1
- 'use strict';
2
-
3
- var constants = require('../constants.js');
4
-
5
- const OBJECT_PROTOTYPE_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));
6
- // eslint-disable-next-line regexp/no-control-character
7
- const CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
8
- const HTML_METACHAR = /[<>"']/g;
9
- /**
10
- * Splits the input string into a flat list of tokens by scanning for known tags.
11
- * Text between tags is emitted as text/newline tokens. Unrecognised tags are never
12
- * tokenised — they remain part of the surrounding text content.
13
- */
14
- function tokenise(input) {
15
- const tokens = [];
16
- let lastIndex = 0;
17
- constants.TAG_REGEX.lastIndex = 0;
18
- let match = constants.TAG_REGEX.exec(input);
19
- while (match !== null) {
20
- if (match.index > lastIndex) {
21
- pushTextWithNewlines(tokens, input.slice(lastIndex, match.index));
22
- }
23
- const isClose = match[1] === '/';
24
- const tag = match[2];
25
- const attrs = match[3] || '';
26
- if (isClose) {
27
- tokens.push({
28
- type: 'close',
29
- tag
30
- });
31
- } else {
32
- tokens.push({
33
- type: 'open',
34
- tag,
35
- attrs
36
- });
37
- }
38
- lastIndex = constants.TAG_REGEX.lastIndex;
39
- match = constants.TAG_REGEX.exec(input);
40
- }
41
- if (lastIndex < input.length) {
42
- pushTextWithNewlines(tokens, input.slice(lastIndex));
43
- }
44
- return tokens;
45
- }
46
- /** Splits a text fragment on newline characters, interleaving newline tokens between parts. */
47
- function pushTextWithNewlines(tokens, text) {
48
- const parts = text.split('\n');
49
- for (let index = 0; index < parts.length; index += 1) {
50
- if (index > 0) {
51
- tokens.push({
52
- type: 'newline'
53
- });
54
- }
55
- if (parts[index]) {
56
- tokens.push({
57
- type: 'text',
58
- content: parts[index]
59
- });
60
- }
61
- }
62
- }
63
- /**
64
- * Recursive descent parser that consumes tokens and builds a MarkupNode tree.
65
- *
66
- * When `untilTag` is provided, the function collects nodes until it finds a matching
67
- * close token — returning `{ closed: true }`. If it exhausts all tokens without finding
68
- * the close, it returns `{ closed: false }` so the caller can fall back to plain text
69
- * (graceful degradation for malformed input).
70
- *
71
- * The shared `position` object acts as a cursor across recursive calls, avoiding the
72
- * need to slice or copy the token array.
73
- */
74
- function parse(tokens, position, untilTag, depth = 0) {
75
- const nodes = [];
76
- while (position.index < tokens.length) {
77
- const token = tokens[position.index];
78
- if (token.type === 'text') {
79
- nodes.push({
80
- type: 'text',
81
- content: token.content
82
- });
83
- position.index += 1;
84
- } else if (token.type === 'newline') {
85
- nodes.push({
86
- type: 'newline'
87
- });
88
- position.index += 1;
89
- } else if (token.type === 'close') {
90
- if (token.tag === untilTag) {
91
- position.index += 1;
92
- return {
93
- closed: true,
94
- nodes
95
- };
96
- }
97
- // Mismatched close tag — render as literal text
98
- nodes.push({
99
- type: 'text',
100
- content: `</${token.tag}>`
101
- });
102
- position.index += 1;
103
- } else if (token.type === 'open') {
104
- if (depth >= constants.MAX_NESTING_DEPTH) {
105
- nodes.push({
106
- type: 'text',
107
- content: `<${token.tag}${token.attrs}>`
108
- });
109
- position.index += 1;
110
- } else {
111
- position.index += 1;
112
- const result = parse(tokens, position, token.tag, depth + 1);
113
- if (result.closed) {
114
- const node = buildNode(token.tag, token.attrs, result.nodes);
115
- nodes.push(node);
116
- } else {
117
- nodes.push({
118
- type: 'text',
119
- content: `<${token.tag}${token.attrs}>`
120
- });
121
- nodes.push(...result.nodes);
122
- }
123
- }
124
- }
125
- }
126
- if (untilTag) {
127
- return {
128
- closed: false,
129
- nodes
130
- };
131
- }
132
- return {
133
- closed: true,
134
- nodes
135
- };
136
- }
137
- /**
138
- * Maps a raw tag name to a typed MarkupNode. Resolves aliases first (p→paragraph, a→link),
139
- * then builds the appropriate node shape. Link nodes carry full attributes; other element
140
- * nodes extract only accessibilityLabel.
141
- */
142
- function buildNode(rawTag, attrs, children) {
143
- const tag = constants.TAG_ALIASES[rawTag] || rawTag;
144
- if (tag === 'link') {
145
- return {
146
- type: 'link',
147
- children,
148
- ...parseAttributes(attrs)
149
- };
150
- }
151
- if (tag === 'paragraph') {
152
- return {
153
- type: 'paragraph',
154
- children
155
- };
156
- }
157
- const {
158
- accessibilityLabel
159
- } = parseAttributes(attrs);
160
- return {
161
- type: tag,
162
- children,
163
- ...(accessibilityLabel && {
164
- accessibilityLabel
165
- })
166
- };
167
- }
168
- const ATTR_REGEX = /(?<=\s)(href|action|target|accessibilityLabel)=(?:"([^"]*)"|'([^']*)')/g;
169
- /**
170
- * Extracts allowed attributes from a raw attribute string.
171
- * Supports both double- and single-quoted values. Any attribute not in the
172
- * allow-list (href, action, target, accessibilityLabel) is silently discarded.
173
- * First occurrence wins — duplicates are ignored.
174
- */
175
- function parseAttributes(attrs) {
176
- const result = {};
177
- ATTR_REGEX.lastIndex = 0;
178
- let match = ATTR_REGEX.exec(attrs);
179
- while (match !== null) {
180
- const key = match[1];
181
- const value = match[2] ?? match[3];
182
- if (!(key in result)) {
183
- const sanitized = sanitizeAttributeValue(key, value);
184
- if (sanitized !== undefined) {
185
- result[key] = sanitized;
186
- }
187
- }
188
- match = ATTR_REGEX.exec(attrs);
189
- }
190
- return result;
191
- }
192
- function sanitizeAttributeValue(key, value) {
193
- switch (key) {
194
- case 'href':
195
- return value.replace(CONTROL_CHARS, '');
196
- case 'action':
197
- if (OBJECT_PROTOTYPE_KEYS.has(value)) {
198
- return undefined;
199
- }
200
- return value;
201
- case 'target':
202
- if (!constants.ALLOWED_TARGETS.includes(value)) {
203
- return undefined;
204
- }
205
- return value;
206
- case 'accessibilityLabel':
207
- return value.replace(HTML_METACHAR, '');
208
- default:
209
- return value;
210
- }
211
- }
212
- /** Entry point: tokenises the input string, then parses the token stream into a MarkupNode tree. */
213
- function parseMarkup(input) {
214
- if (!input) {
215
- return [];
216
- }
217
- const tokens = tokenise(input);
218
- const position = {
219
- index: 0
220
- };
221
- return parse(tokens, position).nodes;
222
- }
223
-
224
- exports.MAX_NESTING_DEPTH = constants.MAX_NESTING_DEPTH;
225
- exports.parseMarkup = parseMarkup;
226
- //# sourceMappingURL=parseMarkup.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parseMarkup.js","sources":["../../../src/markup/utils/parseMarkup.ts"],"sourcesContent":["import { ALLOWED_TARGETS, MAX_NESTING_DEPTH, TAG_ALIASES, TAG_REGEX } from '../constants';\nimport { MarkupNode } from '../Markup.types';\n\nexport { MAX_NESTING_DEPTH };\n\nconst OBJECT_PROTOTYPE_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));\n\n// eslint-disable-next-line regexp/no-control-character\nconst CONTROL_CHARS = /[\\x00-\\x1f\\x7f-\\x9f]/g;\nconst HTML_METACHAR = /[<>\"']/g;\n\ntype Token =\n | { type: 'text'; content: string }\n | { type: 'newline' }\n | { type: 'open'; tag: string; attrs: string }\n | { type: 'close'; tag: string };\n\n/**\n * Splits the input string into a flat list of tokens by scanning for known tags.\n * Text between tags is emitted as text/newline tokens. Unrecognised tags are never\n * tokenised — they remain part of the surrounding text content.\n */\nfunction tokenise(input: string): Token[] {\n const tokens: Token[] = [];\n let lastIndex = 0;\n\n TAG_REGEX.lastIndex = 0;\n let match = TAG_REGEX.exec(input);\n\n while (match !== null) {\n if (match.index > lastIndex) {\n pushTextWithNewlines(tokens, input.slice(lastIndex, match.index));\n }\n\n const isClose = match[1] === '/';\n const tag = match[2];\n const attrs = match[3] || '';\n\n if (isClose) {\n tokens.push({ type: 'close', tag });\n } else {\n tokens.push({ type: 'open', tag, attrs });\n }\n\n lastIndex = TAG_REGEX.lastIndex;\n match = TAG_REGEX.exec(input);\n }\n\n if (lastIndex < input.length) {\n pushTextWithNewlines(tokens, input.slice(lastIndex));\n }\n\n return tokens;\n}\n\n/** Splits a text fragment on newline characters, interleaving newline tokens between parts. */\nfunction pushTextWithNewlines(tokens: Token[], text: string): void {\n const parts = text.split('\\n');\n for (let index = 0; index < parts.length; index += 1) {\n if (index > 0) {\n tokens.push({ type: 'newline' });\n }\n if (parts[index]) {\n tokens.push({ type: 'text', content: parts[index] });\n }\n }\n}\n\ntype ParseResult = { closed: true; nodes: MarkupNode[] } | { closed: false; nodes: MarkupNode[] };\n\n/**\n * Recursive descent parser that consumes tokens and builds a MarkupNode tree.\n *\n * When `untilTag` is provided, the function collects nodes until it finds a matching\n * close token — returning `{ closed: true }`. If it exhausts all tokens without finding\n * the close, it returns `{ closed: false }` so the caller can fall back to plain text\n * (graceful degradation for malformed input).\n *\n * The shared `position` object acts as a cursor across recursive calls, avoiding the\n * need to slice or copy the token array.\n */\nfunction parse(\n tokens: Token[],\n position: { index: number },\n untilTag?: string,\n depth = 0,\n): ParseResult {\n const nodes: MarkupNode[] = [];\n\n while (position.index < tokens.length) {\n const token = tokens[position.index];\n\n if (token.type === 'text') {\n nodes.push({ type: 'text', content: token.content });\n position.index += 1;\n } else if (token.type === 'newline') {\n nodes.push({ type: 'newline' });\n position.index += 1;\n } else if (token.type === 'close') {\n if (token.tag === untilTag) {\n position.index += 1;\n return { closed: true, nodes };\n }\n // Mismatched close tag — render as literal text\n nodes.push({ type: 'text', content: `</${token.tag}>` });\n position.index += 1;\n } else if (token.type === 'open') {\n if (depth >= MAX_NESTING_DEPTH) {\n nodes.push({ type: 'text', content: `<${token.tag}${token.attrs}>` });\n position.index += 1;\n } else {\n position.index += 1;\n const result = parse(tokens, position, token.tag, depth + 1);\n\n if (result.closed) {\n const node = buildNode(token.tag, token.attrs, result.nodes);\n nodes.push(node);\n } else {\n nodes.push({ type: 'text', content: `<${token.tag}${token.attrs}>` });\n nodes.push(...result.nodes);\n }\n }\n }\n }\n\n if (untilTag) {\n return { closed: false, nodes };\n }\n\n return { closed: true, nodes };\n}\n\n/**\n * Maps a raw tag name to a typed MarkupNode. Resolves aliases first (p→paragraph, a→link),\n * then builds the appropriate node shape. Link nodes carry full attributes; other element\n * nodes extract only accessibilityLabel.\n */\nfunction buildNode(rawTag: string, attrs: string, children: MarkupNode[]): MarkupNode {\n const tag = TAG_ALIASES[rawTag] || rawTag;\n\n if (tag === 'link') {\n return { type: 'link', children, ...parseAttributes(attrs) };\n }\n\n if (tag === 'paragraph') {\n return { type: 'paragraph', children };\n }\n\n const { accessibilityLabel } = parseAttributes(attrs);\n\n return {\n type: tag as MarkupNode['type'],\n children,\n ...(accessibilityLabel && { accessibilityLabel }),\n } as MarkupNode;\n}\n\nconst ATTR_REGEX = /(?<=\\s)(href|action|target|accessibilityLabel)=(?:\"([^\"]*)\"|'([^']*)')/g;\n\ntype ParsedAttributes = {\n href?: string;\n action?: string;\n target?: string;\n accessibilityLabel?: string;\n};\n\n/**\n * Extracts allowed attributes from a raw attribute string.\n * Supports both double- and single-quoted values. Any attribute not in the\n * allow-list (href, action, target, accessibilityLabel) is silently discarded.\n * First occurrence wins — duplicates are ignored.\n */\nfunction parseAttributes(attrs: string): ParsedAttributes {\n const result: ParsedAttributes = {};\n ATTR_REGEX.lastIndex = 0;\n let match = ATTR_REGEX.exec(attrs);\n\n while (match !== null) {\n const key = match[1] as 'href' | 'action' | 'target' | 'accessibilityLabel';\n const value = match[2] ?? match[3];\n\n if (!(key in result)) {\n const sanitized = sanitizeAttributeValue(key, value);\n if (sanitized !== undefined) {\n result[key] = sanitized;\n }\n }\n\n match = ATTR_REGEX.exec(attrs);\n }\n\n return result;\n}\n\nfunction sanitizeAttributeValue(\n key: 'href' | 'action' | 'target' | 'accessibilityLabel',\n value: string,\n): string | undefined {\n switch (key) {\n case 'href':\n return value.replace(CONTROL_CHARS, '');\n case 'action':\n if (OBJECT_PROTOTYPE_KEYS.has(value)) {\n return undefined;\n }\n return value;\n case 'target':\n if (!ALLOWED_TARGETS.includes(value)) {\n return undefined;\n }\n return value;\n case 'accessibilityLabel':\n return value.replace(HTML_METACHAR, '');\n default:\n return value;\n }\n}\n\n/** Entry point: tokenises the input string, then parses the token stream into a MarkupNode tree. */\nexport function parseMarkup(input: string): MarkupNode[] {\n if (!input) {\n return [];\n }\n\n const tokens = tokenise(input);\n const position = { index: 0 };\n return parse(tokens, position).nodes;\n}\n"],"names":["OBJECT_PROTOTYPE_KEYS","Set","Object","getOwnPropertyNames","prototype","CONTROL_CHARS","HTML_METACHAR","tokenise","input","tokens","lastIndex","TAG_REGEX","match","exec","index","pushTextWithNewlines","slice","isClose","tag","attrs","push","type","length","text","parts","split","content","parse","position","untilTag","depth","nodes","token","closed","MAX_NESTING_DEPTH","result","node","buildNode","rawTag","children","TAG_ALIASES","parseAttributes","accessibilityLabel","ATTR_REGEX","key","value","sanitized","sanitizeAttributeValue","undefined","replace","has","ALLOWED_TARGETS","includes","parseMarkup"],"mappings":"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"}