@automattic/interpolate-components 1.2.1 → 1.2.2
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 +5 -0
- package/dist/cjs/index.js +10 -40
- package/dist/cjs/tokenize.js +4 -10
- package/dist/esm/index.js +10 -37
- package/dist/esm/tokenize.js +4 -9
- package/package.json +12 -4
- package/types/index.d.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.2]
|
|
11
|
+
|
|
12
|
+
- Declare React 19 compatibility for package consumers (#111721).
|
|
13
|
+
|
|
10
14
|
## [1.2.1]
|
|
11
15
|
|
|
12
16
|
### Changed
|
|
17
|
+
|
|
13
18
|
- @types/react peer dependency increased from >=16.2.0 to >=16.14.23
|
|
14
19
|
|
|
15
20
|
## [1.2.0]
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,137 +1,107 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
-
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
7
|
exports.default = interpolate;
|
|
9
|
-
|
|
10
8
|
var _react = require("react");
|
|
11
|
-
|
|
12
9
|
var _tokenize = _interopRequireDefault(require("./tokenize"));
|
|
13
|
-
|
|
14
10
|
function getCloseIndex(openIndex, tokens) {
|
|
15
11
|
const openToken = tokens[openIndex];
|
|
16
12
|
let nestLevel = 0;
|
|
17
|
-
|
|
18
13
|
for (let i = openIndex + 1; i < tokens.length; i++) {
|
|
19
14
|
const token = tokens[i];
|
|
20
|
-
|
|
21
15
|
if (token.value === openToken.value) {
|
|
22
16
|
if (token.type === 'componentOpen') {
|
|
23
17
|
nestLevel++;
|
|
24
18
|
continue;
|
|
25
19
|
}
|
|
26
|
-
|
|
27
20
|
if (token.type === 'componentClose') {
|
|
28
21
|
if (nestLevel === 0) {
|
|
29
22
|
return i;
|
|
30
23
|
}
|
|
31
|
-
|
|
32
24
|
nestLevel--;
|
|
33
25
|
}
|
|
34
26
|
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
}
|
|
28
|
+
// if we get this far, there was no matching close token
|
|
38
29
|
throw new Error('Missing closing component token `' + openToken.value + '`');
|
|
39
30
|
}
|
|
40
|
-
|
|
41
31
|
function buildChildren(tokens, components) {
|
|
42
32
|
let children = [];
|
|
43
33
|
let openComponent;
|
|
44
34
|
let openIndex;
|
|
45
|
-
|
|
46
35
|
for (let i = 0; i < tokens.length; i++) {
|
|
47
36
|
const token = tokens[i];
|
|
48
|
-
|
|
49
37
|
if (token.type === 'string') {
|
|
50
38
|
children.push(token.value);
|
|
51
39
|
continue;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
}
|
|
41
|
+
// component node should at least be set
|
|
55
42
|
if (components[token.value] === undefined) {
|
|
56
43
|
throw new Error(`Invalid interpolation, missing component node: \`${token.value}\``);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
}
|
|
45
|
+
// should be either ReactElement or null (both type "object"), all other types deprecated
|
|
60
46
|
if (typeof components[token.value] !== 'object') {
|
|
61
47
|
throw new Error(`Invalid interpolation, component node must be a ReactElement or null: \`${token.value}\``);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
48
|
+
}
|
|
49
|
+
// we should never see a componentClose token in this loop
|
|
65
50
|
if (token.type === 'componentClose') {
|
|
66
51
|
throw new Error(`Missing opening component token: \`${token.value}\``);
|
|
67
52
|
}
|
|
68
|
-
|
|
69
53
|
if (token.type === 'componentOpen') {
|
|
70
54
|
openComponent = components[token.value];
|
|
71
55
|
openIndex = i;
|
|
72
56
|
break;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
57
|
+
}
|
|
58
|
+
// componentSelfClosing token
|
|
76
59
|
children.push(components[token.value]);
|
|
77
60
|
continue;
|
|
78
61
|
}
|
|
79
|
-
|
|
80
62
|
if (openComponent) {
|
|
81
63
|
const closeIndex = getCloseIndex(openIndex, tokens);
|
|
82
64
|
const grandChildTokens = tokens.slice(openIndex + 1, closeIndex);
|
|
83
65
|
const grandChildren = buildChildren(grandChildTokens, components);
|
|
84
66
|
const clonedOpenComponent = /*#__PURE__*/(0, _react.cloneElement)(openComponent, {}, grandChildren);
|
|
85
67
|
children.push(clonedOpenComponent);
|
|
86
|
-
|
|
87
68
|
if (closeIndex < tokens.length - 1) {
|
|
88
69
|
const siblingTokens = tokens.slice(closeIndex + 1);
|
|
89
70
|
const siblings = buildChildren(siblingTokens, components);
|
|
90
71
|
children = children.concat(siblings);
|
|
91
72
|
}
|
|
92
73
|
}
|
|
93
|
-
|
|
94
74
|
children = children.filter(Boolean);
|
|
95
|
-
|
|
96
75
|
if (children.length === 0) {
|
|
97
76
|
return null;
|
|
98
77
|
}
|
|
99
|
-
|
|
100
78
|
if (children.length === 1) {
|
|
101
79
|
return children[0];
|
|
102
80
|
}
|
|
103
|
-
|
|
104
81
|
return /*#__PURE__*/(0, _react.createElement)(_react.Fragment, null, ...children);
|
|
105
82
|
}
|
|
106
|
-
|
|
107
83
|
function interpolate(options) {
|
|
108
84
|
const {
|
|
109
85
|
mixedString,
|
|
110
86
|
components,
|
|
111
87
|
throwErrors
|
|
112
88
|
} = options;
|
|
113
|
-
|
|
114
89
|
if (!components) {
|
|
115
90
|
return mixedString;
|
|
116
91
|
}
|
|
117
|
-
|
|
118
92
|
if (typeof components !== 'object') {
|
|
119
93
|
if (throwErrors) {
|
|
120
94
|
throw new Error(`Interpolation Error: unable to process \`${mixedString}\` because components is not an object`);
|
|
121
95
|
}
|
|
122
|
-
|
|
123
96
|
return mixedString;
|
|
124
97
|
}
|
|
125
|
-
|
|
126
98
|
const tokens = (0, _tokenize.default)(mixedString);
|
|
127
|
-
|
|
128
99
|
try {
|
|
129
100
|
return buildChildren(tokens, components);
|
|
130
101
|
} catch (error) {
|
|
131
102
|
if (throwErrors) {
|
|
132
103
|
throw new Error(`Interpolation Error: unable to process \`${mixedString}\` because of error \`${error.message}\``);
|
|
133
104
|
}
|
|
134
|
-
|
|
135
105
|
return mixedString;
|
|
136
106
|
}
|
|
137
107
|
}
|
package/dist/cjs/tokenize.js
CHANGED
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = tokenize;
|
|
7
|
-
|
|
8
7
|
function identifyToken(item) {
|
|
9
8
|
// {{/example}}
|
|
10
9
|
if (item.startsWith('{{/')) {
|
|
@@ -12,32 +11,27 @@ function identifyToken(item) {
|
|
|
12
11
|
type: 'componentClose',
|
|
13
12
|
value: item.replace(/\W/g, '')
|
|
14
13
|
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
}
|
|
15
|
+
// {{example /}}
|
|
18
16
|
if (item.endsWith('/}}')) {
|
|
19
17
|
return {
|
|
20
18
|
type: 'componentSelfClosing',
|
|
21
19
|
value: item.replace(/\W/g, '')
|
|
22
20
|
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
}
|
|
22
|
+
// {{example}}
|
|
26
23
|
if (item.startsWith('{{')) {
|
|
27
24
|
return {
|
|
28
25
|
type: 'componentOpen',
|
|
29
26
|
value: item.replace(/\W/g, '')
|
|
30
27
|
};
|
|
31
28
|
}
|
|
32
|
-
|
|
33
29
|
return {
|
|
34
30
|
type: 'string',
|
|
35
31
|
value: item
|
|
36
32
|
};
|
|
37
33
|
}
|
|
38
|
-
|
|
39
34
|
function tokenize(mixedString) {
|
|
40
35
|
const tokenStrings = mixedString.split(/(\{\{\/?\s*\w+\s*\/?\}\})/g); // split to components and strings
|
|
41
|
-
|
|
42
36
|
return tokenStrings.map(identifyToken);
|
|
43
37
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,127 +1,100 @@
|
|
|
1
1
|
import { cloneElement, createElement, Fragment } from 'react';
|
|
2
2
|
import tokenize from './tokenize';
|
|
3
|
-
|
|
4
3
|
function getCloseIndex(openIndex, tokens) {
|
|
5
4
|
const openToken = tokens[openIndex];
|
|
6
5
|
let nestLevel = 0;
|
|
7
|
-
|
|
8
6
|
for (let i = openIndex + 1; i < tokens.length; i++) {
|
|
9
7
|
const token = tokens[i];
|
|
10
|
-
|
|
11
8
|
if (token.value === openToken.value) {
|
|
12
9
|
if (token.type === 'componentOpen') {
|
|
13
10
|
nestLevel++;
|
|
14
11
|
continue;
|
|
15
12
|
}
|
|
16
|
-
|
|
17
13
|
if (token.type === 'componentClose') {
|
|
18
14
|
if (nestLevel === 0) {
|
|
19
15
|
return i;
|
|
20
16
|
}
|
|
21
|
-
|
|
22
17
|
nestLevel--;
|
|
23
18
|
}
|
|
24
19
|
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
}
|
|
21
|
+
// if we get this far, there was no matching close token
|
|
28
22
|
throw new Error('Missing closing component token `' + openToken.value + '`');
|
|
29
23
|
}
|
|
30
|
-
|
|
31
24
|
function buildChildren(tokens, components) {
|
|
32
25
|
let children = [];
|
|
33
26
|
let openComponent;
|
|
34
27
|
let openIndex;
|
|
35
|
-
|
|
36
28
|
for (let i = 0; i < tokens.length; i++) {
|
|
37
29
|
const token = tokens[i];
|
|
38
|
-
|
|
39
30
|
if (token.type === 'string') {
|
|
40
31
|
children.push(token.value);
|
|
41
32
|
continue;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
}
|
|
34
|
+
// component node should at least be set
|
|
45
35
|
if (components[token.value] === undefined) {
|
|
46
36
|
throw new Error(`Invalid interpolation, missing component node: \`${token.value}\``);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
}
|
|
38
|
+
// should be either ReactElement or null (both type "object"), all other types deprecated
|
|
50
39
|
if (typeof components[token.value] !== 'object') {
|
|
51
40
|
throw new Error(`Invalid interpolation, component node must be a ReactElement or null: \`${token.value}\``);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
}
|
|
42
|
+
// we should never see a componentClose token in this loop
|
|
55
43
|
if (token.type === 'componentClose') {
|
|
56
44
|
throw new Error(`Missing opening component token: \`${token.value}\``);
|
|
57
45
|
}
|
|
58
|
-
|
|
59
46
|
if (token.type === 'componentOpen') {
|
|
60
47
|
openComponent = components[token.value];
|
|
61
48
|
openIndex = i;
|
|
62
49
|
break;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
}
|
|
51
|
+
// componentSelfClosing token
|
|
66
52
|
children.push(components[token.value]);
|
|
67
53
|
continue;
|
|
68
54
|
}
|
|
69
|
-
|
|
70
55
|
if (openComponent) {
|
|
71
56
|
const closeIndex = getCloseIndex(openIndex, tokens);
|
|
72
57
|
const grandChildTokens = tokens.slice(openIndex + 1, closeIndex);
|
|
73
58
|
const grandChildren = buildChildren(grandChildTokens, components);
|
|
74
59
|
const clonedOpenComponent = /*#__PURE__*/cloneElement(openComponent, {}, grandChildren);
|
|
75
60
|
children.push(clonedOpenComponent);
|
|
76
|
-
|
|
77
61
|
if (closeIndex < tokens.length - 1) {
|
|
78
62
|
const siblingTokens = tokens.slice(closeIndex + 1);
|
|
79
63
|
const siblings = buildChildren(siblingTokens, components);
|
|
80
64
|
children = children.concat(siblings);
|
|
81
65
|
}
|
|
82
66
|
}
|
|
83
|
-
|
|
84
67
|
children = children.filter(Boolean);
|
|
85
|
-
|
|
86
68
|
if (children.length === 0) {
|
|
87
69
|
return null;
|
|
88
70
|
}
|
|
89
|
-
|
|
90
71
|
if (children.length === 1) {
|
|
91
72
|
return children[0];
|
|
92
73
|
}
|
|
93
|
-
|
|
94
74
|
return /*#__PURE__*/createElement(Fragment, null, ...children);
|
|
95
75
|
}
|
|
96
|
-
|
|
97
76
|
export default function interpolate(options) {
|
|
98
77
|
const {
|
|
99
78
|
mixedString,
|
|
100
79
|
components,
|
|
101
80
|
throwErrors
|
|
102
81
|
} = options;
|
|
103
|
-
|
|
104
82
|
if (!components) {
|
|
105
83
|
return mixedString;
|
|
106
84
|
}
|
|
107
|
-
|
|
108
85
|
if (typeof components !== 'object') {
|
|
109
86
|
if (throwErrors) {
|
|
110
87
|
throw new Error(`Interpolation Error: unable to process \`${mixedString}\` because components is not an object`);
|
|
111
88
|
}
|
|
112
|
-
|
|
113
89
|
return mixedString;
|
|
114
90
|
}
|
|
115
|
-
|
|
116
91
|
const tokens = tokenize(mixedString);
|
|
117
|
-
|
|
118
92
|
try {
|
|
119
93
|
return buildChildren(tokens, components);
|
|
120
94
|
} catch (error) {
|
|
121
95
|
if (throwErrors) {
|
|
122
96
|
throw new Error(`Interpolation Error: unable to process \`${mixedString}\` because of error \`${error.message}\``);
|
|
123
97
|
}
|
|
124
|
-
|
|
125
98
|
return mixedString;
|
|
126
99
|
}
|
|
127
100
|
}
|
package/dist/esm/tokenize.js
CHANGED
|
@@ -5,32 +5,27 @@ function identifyToken(item) {
|
|
|
5
5
|
type: 'componentClose',
|
|
6
6
|
value: item.replace(/\W/g, '')
|
|
7
7
|
};
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
}
|
|
9
|
+
// {{example /}}
|
|
11
10
|
if (item.endsWith('/}}')) {
|
|
12
11
|
return {
|
|
13
12
|
type: 'componentSelfClosing',
|
|
14
13
|
value: item.replace(/\W/g, '')
|
|
15
14
|
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
}
|
|
16
|
+
// {{example}}
|
|
19
17
|
if (item.startsWith('{{')) {
|
|
20
18
|
return {
|
|
21
19
|
type: 'componentOpen',
|
|
22
20
|
value: item.replace(/\W/g, '')
|
|
23
21
|
};
|
|
24
22
|
}
|
|
25
|
-
|
|
26
23
|
return {
|
|
27
24
|
type: 'string',
|
|
28
25
|
value: item
|
|
29
26
|
};
|
|
30
27
|
}
|
|
31
|
-
|
|
32
28
|
export default function tokenize(mixedString) {
|
|
33
29
|
const tokenStrings = mixedString.split(/(\{\{\/?\s*\w+\s*\/?\}\})/g); // split to components and strings
|
|
34
|
-
|
|
35
30
|
return tokenStrings.map(identifyToken);
|
|
36
31
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/interpolate-components",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Convert strings into structured React components.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
7
7
|
"calypso:src": "src/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"calypso:src": "./src/index.js",
|
|
11
|
+
"types": "./types/index.d.ts",
|
|
12
|
+
"import": "./dist/esm/index.js",
|
|
13
|
+
"require": "./dist/cjs/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
8
16
|
"sideEffects": false,
|
|
9
17
|
"repository": {
|
|
10
18
|
"type": "git",
|
|
@@ -20,10 +28,10 @@
|
|
|
20
28
|
"homepage": "https://github.com/Automattic/wp-calypso/tree/HEAD/packages/interpolate-components#readme",
|
|
21
29
|
"devDependencies": {
|
|
22
30
|
"@automattic/calypso-typescript-config": "^1.0.0",
|
|
23
|
-
"react-dom": "^
|
|
31
|
+
"react-dom": "^18.3.1"
|
|
24
32
|
},
|
|
25
33
|
"peerDependencies": {
|
|
26
|
-
"@types/react": ">=16.14.
|
|
34
|
+
"@types/react": ">=16.14.65",
|
|
27
35
|
"react": ">=16.2.0"
|
|
28
36
|
},
|
|
29
37
|
"peerDependenciesMeta": {
|
|
@@ -33,7 +41,7 @@
|
|
|
33
41
|
},
|
|
34
42
|
"scripts": {
|
|
35
43
|
"clean": "rm -rf dist",
|
|
36
|
-
"build": "
|
|
44
|
+
"build": "transpile",
|
|
37
45
|
"prepack": "yarn run clean && yarn run build"
|
|
38
46
|
},
|
|
39
47
|
"types": "types"
|
package/types/index.d.ts
CHANGED