@doist/react-interpolate 0.3.7 → 0.3.8

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/README.md CHANGED
@@ -5,15 +5,15 @@
5
5
  A string interpolation component that formats and interpolates a template string in a safe way.
6
6
 
7
7
  ```jsx
8
- import Interpolate from "@doist/react-interpolate"
8
+ import Interpolate from '@doist/react-interpolate'
9
9
 
10
10
  function Greeting() {
11
11
  return (
12
12
  <Interpolate
13
13
  string="<h1>Hello {name}. Here is <a>your order info</a></h1>"
14
14
  mapping={{
15
- name: "William",
16
- a: <a href="https://orderinfo.com" />
15
+ name: 'William',
16
+ a: <a href="https://orderinfo.com" />,
17
17
  }}
18
18
  />
19
19
  )
@@ -23,9 +23,7 @@ function Greeting() {
23
23
  Would render the following HTML
24
24
 
25
25
  ```html
26
- <h1>
27
- Hello William. Here is <a href="https://orderinfo.com">your order info</a>
28
- </h1>
26
+ <h1>Hello William. Here is <a href="https://orderinfo.com">your order info</a></h1>
29
27
  ```
30
28
 
31
29
  ## Component API
@@ -51,14 +49,14 @@ An object that defines the values to be injected for placeholder and tags define
51
49
  Please contact <supportLink>support</supportLink> for help"
52
50
  mapping={{
53
51
  // you can map placholder and self-closing tag to any valid element value
54
- name: "William",
52
+ name: 'William',
55
53
  hr: <hr className="break" />,
56
54
 
57
55
  // you can map open & close tag to a rendering function
58
- orderLink: text => <a href="https://orderinfo.com">{text}</a>,
56
+ orderLink: (text) => <a href="https://orderinfo.com">{text}</a>,
59
57
 
60
58
  // or you can map open & close tag to an element
61
- supportLink: <a href="https://orderinfo.com" />
59
+ supportLink: <a href="https://orderinfo.com" />,
62
60
  }}
63
61
  />
64
62
  ```
@@ -85,7 +83,7 @@ Here is interpolation syntax you can use in your `string`.
85
83
  #### Placeholder
86
84
 
87
85
  ```jsx
88
- "hello {user_name}"
86
+ 'hello {user_name}'
89
87
  ```
90
88
 
91
89
  Placeholder name should be alphanumeric (`[A-Za-z0-9_]`). Placeholders could be mapped to any valid element value.
@@ -93,13 +91,13 @@ Placeholder name should be alphanumeric (`[A-Za-z0-9_]`). Placeholders could be
93
91
  #### Open & close tags
94
92
 
95
93
  ```jsx
96
- "Here is <a>your order info</a>"
94
+ 'Here is <a>your order info</a>'
97
95
 
98
96
  // tag name could be any alphanumeric string
99
- "Here is <link>your order info</link>"
97
+ 'Here is <link>your order info</link>'
100
98
 
101
99
  // you can nest tag and placeholder
102
- "Here is <a><b>you order info {name}</b></a>"
100
+ 'Here is <a><b>you order info {name}</b></a>'
103
101
  ```
104
102
 
105
103
  Tag name should be alphanumeric (`[A-Za-z0-9_]`).
@@ -135,12 +133,12 @@ Open & close tag could be mapped to a rendering function, which would take a sin
135
133
  <Interpolate
136
134
  string="Here is <a>your order info</a>"
137
135
  mapping={{
138
- a: text => (
136
+ a: (text) => (
139
137
  <a href="https://orderinfo.com">
140
138
  <b>{text}</b>
141
139
  <br />
142
140
  </a>
143
- )
141
+ ),
144
142
  }}
145
143
  />
146
144
  ```
@@ -149,16 +147,16 @@ Unclosed tag or incorrect nesting of tag would result in syntax error.
149
147
 
150
148
  ```js
151
149
  // bad: no close tag
152
- "Here is <a>your order info"
150
+ 'Here is <a>your order info'
153
151
 
154
152
  // bad: incorrect tag structure
155
- "Here is <a><b>your order info</a></b>"
153
+ 'Here is <a><b>your order info</a></b>'
156
154
  ```
157
155
 
158
156
  #### Self closing tag
159
157
 
160
158
  ```js
161
- "Hello.<br/>Here is your order"
159
+ 'Hello.<br/>Here is your order'
162
160
  ```
163
161
 
164
162
  Tag name should be alphanumeric (`[A-Za-z0-9_]`). Self closing tags could be mapped to any valid element value.
@@ -16,16 +16,16 @@ var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallChec
16
16
  var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass);
17
17
  var _objectWithoutProperties__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutProperties);
18
18
 
19
- var TOKEN_PLACEHOLDER = "TOKEN_PLACEHOLDER";
20
- var TOKEN_OPEN_TAG = "TOKEN_OPEN_TAG";
21
- var TOKEN_CLOSE_TAG = "TOKEN_CLOSE_TAG";
22
- var TOKEN_SELF_TAG = "TOKEN_SELF_TAG";
23
- var TOKEN_TEXT = "TOKEN_TEXT";
24
- var NODE_FRAGMENT = "NODE_FRAGMENT";
25
- var NODE_TAG_ELEMENT = "NODE_TAG_ELEMENT";
26
- var NODE_VOID_ELEMENT = "NODE_VOID_ELEMENT";
27
- var NODE_PLACEHOLDER = "NODE_PLACEHOLDER";
28
- var NODE_TEXT = "NODE_TEXT";
19
+ var TOKEN_PLACEHOLDER = 'TOKEN_PLACEHOLDER';
20
+ var TOKEN_OPEN_TAG = 'TOKEN_OPEN_TAG';
21
+ var TOKEN_CLOSE_TAG = 'TOKEN_CLOSE_TAG';
22
+ var TOKEN_SELF_TAG = 'TOKEN_SELF_TAG';
23
+ var TOKEN_TEXT = 'TOKEN_TEXT';
24
+ var NODE_FRAGMENT = 'NODE_FRAGMENT';
25
+ var NODE_TAG_ELEMENT = 'NODE_TAG_ELEMENT';
26
+ var NODE_VOID_ELEMENT = 'NODE_VOID_ELEMENT';
27
+ var NODE_PLACEHOLDER = 'NODE_PLACEHOLDER';
28
+ var NODE_TEXT = 'NODE_TEXT';
29
29
 
30
30
  var _excluded = ["type", "children"];
31
31
 
@@ -193,7 +193,7 @@ function lexer(string, syntax) {
193
193
  });
194
194
  var text = string.substring(start);
195
195
 
196
- if (text !== "") {
196
+ if (text !== '') {
197
197
  textTokens.push({
198
198
  type: TOKEN_TEXT,
199
199
  string: text,
@@ -217,10 +217,10 @@ function parser(string, syntax) {
217
217
  var p = new Parser(tokens);
218
218
  return p.parse();
219
219
  }
220
- var SYNTAX_ERROR = "Syntax error. Please check if each open tag is closed correctly"; // A special token representing end of the tream
220
+ var SYNTAX_ERROR = 'Syntax error. Please check if each open tag is closed correctly'; // A special token representing end of the tream
221
221
 
222
222
  var EPSILON = {
223
- type: "EPSILON"
223
+ type: 'EPSILON'
224
224
  };
225
225
  /*
226
226
  * A recursive descent parser that construct a syntax tree represeting
@@ -413,7 +413,7 @@ var createElement = function createElement(node, mapping, keyPrefix) {
413
413
  {
414
414
  var val = mapping[node.name];
415
415
 
416
- if (typeof val === "function") {
416
+ if (typeof val === 'function') {
417
417
  return val();
418
418
  }
419
419
 
@@ -428,13 +428,13 @@ var createElement = function createElement(node, mapping, keyPrefix) {
428
428
  return /*#__PURE__*/React__default["default"].createElement(node.name, null, children);
429
429
  }
430
430
 
431
- if (typeof _val === "function") {
431
+ if (typeof _val === 'function') {
432
432
  return _val(children);
433
433
  }
434
434
 
435
435
  if ( /*#__PURE__*/React__default["default"].isValidElement(_val)) {
436
436
  if (React__default["default"].Children.count(_val.props.children) !== 0) {
437
- throw new Error("when passing an element as value, the element should not contains children");
437
+ throw new Error('when passing an element as value, the element should not contains children');
438
438
  }
439
439
 
440
440
  return /*#__PURE__*/React__default["default"].cloneElement(_val, {
@@ -454,7 +454,7 @@ var createElement = function createElement(node, mapping, keyPrefix) {
454
454
  return node.string;
455
455
  }
456
456
 
457
- if (typeof _val2 === "function") {
457
+ if (typeof _val2 === 'function') {
458
458
  return _val2();
459
459
  }
460
460
 
@@ -4,16 +4,16 @@ import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
4
4
  import _createClass from '@babel/runtime/helpers/createClass';
5
5
  import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
6
6
 
7
- var TOKEN_PLACEHOLDER = "TOKEN_PLACEHOLDER";
8
- var TOKEN_OPEN_TAG = "TOKEN_OPEN_TAG";
9
- var TOKEN_CLOSE_TAG = "TOKEN_CLOSE_TAG";
10
- var TOKEN_SELF_TAG = "TOKEN_SELF_TAG";
11
- var TOKEN_TEXT = "TOKEN_TEXT";
12
- var NODE_FRAGMENT = "NODE_FRAGMENT";
13
- var NODE_TAG_ELEMENT = "NODE_TAG_ELEMENT";
14
- var NODE_VOID_ELEMENT = "NODE_VOID_ELEMENT";
15
- var NODE_PLACEHOLDER = "NODE_PLACEHOLDER";
16
- var NODE_TEXT = "NODE_TEXT";
7
+ var TOKEN_PLACEHOLDER = 'TOKEN_PLACEHOLDER';
8
+ var TOKEN_OPEN_TAG = 'TOKEN_OPEN_TAG';
9
+ var TOKEN_CLOSE_TAG = 'TOKEN_CLOSE_TAG';
10
+ var TOKEN_SELF_TAG = 'TOKEN_SELF_TAG';
11
+ var TOKEN_TEXT = 'TOKEN_TEXT';
12
+ var NODE_FRAGMENT = 'NODE_FRAGMENT';
13
+ var NODE_TAG_ELEMENT = 'NODE_TAG_ELEMENT';
14
+ var NODE_VOID_ELEMENT = 'NODE_VOID_ELEMENT';
15
+ var NODE_PLACEHOLDER = 'NODE_PLACEHOLDER';
16
+ var NODE_TEXT = 'NODE_TEXT';
17
17
 
18
18
  var _excluded = ["type", "children"];
19
19
 
@@ -181,7 +181,7 @@ function lexer(string, syntax) {
181
181
  });
182
182
  var text = string.substring(start);
183
183
 
184
- if (text !== "") {
184
+ if (text !== '') {
185
185
  textTokens.push({
186
186
  type: TOKEN_TEXT,
187
187
  string: text,
@@ -205,10 +205,10 @@ function parser(string, syntax) {
205
205
  var p = new Parser(tokens);
206
206
  return p.parse();
207
207
  }
208
- var SYNTAX_ERROR = "Syntax error. Please check if each open tag is closed correctly"; // A special token representing end of the tream
208
+ var SYNTAX_ERROR = 'Syntax error. Please check if each open tag is closed correctly'; // A special token representing end of the tream
209
209
 
210
210
  var EPSILON = {
211
- type: "EPSILON"
211
+ type: 'EPSILON'
212
212
  };
213
213
  /*
214
214
  * A recursive descent parser that construct a syntax tree represeting
@@ -401,7 +401,7 @@ var createElement = function createElement(node, mapping, keyPrefix) {
401
401
  {
402
402
  var val = mapping[node.name];
403
403
 
404
- if (typeof val === "function") {
404
+ if (typeof val === 'function') {
405
405
  return val();
406
406
  }
407
407
 
@@ -416,13 +416,13 @@ var createElement = function createElement(node, mapping, keyPrefix) {
416
416
  return /*#__PURE__*/React.createElement(node.name, null, children);
417
417
  }
418
418
 
419
- if (typeof _val === "function") {
419
+ if (typeof _val === 'function') {
420
420
  return _val(children);
421
421
  }
422
422
 
423
423
  if ( /*#__PURE__*/React.isValidElement(_val)) {
424
424
  if (React.Children.count(_val.props.children) !== 0) {
425
- throw new Error("when passing an element as value, the element should not contains children");
425
+ throw new Error('when passing an element as value, the element should not contains children');
426
426
  }
427
427
 
428
428
  return /*#__PURE__*/React.cloneElement(_val, {
@@ -442,7 +442,7 @@ var createElement = function createElement(node, mapping, keyPrefix) {
442
442
  return node.string;
443
443
  }
444
444
 
445
- if (typeof _val2 === "function") {
445
+ if (typeof _val2 === 'function') {
446
446
  return _val2();
447
447
  }
448
448
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/react-interpolate",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "A string interpolation component that formats and interpolates a template string in a safe way",
5
5
  "main": "dist/react-interpolate.cjs",
6
6
  "module": "dist/react-interpolate.mjs",
@@ -8,13 +8,19 @@
8
8
  "node": "16.13",
9
9
  "npm": "8.1.0"
10
10
  },
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
11
15
  "scripts": {
12
16
  "test": "jest",
13
17
  "lint": "eslint ./src ./__test__",
14
18
  "build": "del dist && rollup -c && npm run mini-cjs && npm run mini-mjs",
15
19
  "mini-cjs": "uglifyjs dist/react-interpolate.cjs --compress --mangle --enclose --output dist/react-interpolate.min.cjs",
16
- "mini-mjs": "uglifyjs dist/react-interpolate.mjs --compress --mangle --enclose --output dist/react-interpolate.min.mjs"
20
+ "mini-mjs": "uglifyjs dist/react-interpolate.mjs --compress --mangle --enclose --output dist/react-interpolate.min.mjs",
21
+ "prettify": "prettier --write ."
17
22
  },
23
+ "prettier": "@doist/prettier-config",
18
24
  "repository": {
19
25
  "type": "git",
20
26
  "url": "https://github.com/Doist/react-interpolate.git"
@@ -40,23 +46,26 @@
40
46
  "@babel/plugin-transform-runtime": "^7.16.4",
41
47
  "@babel/preset-env": "^7.16.4",
42
48
  "@babel/preset-react": "^7.16.0",
49
+ "@doist/eslint-config": "^7.0.0",
50
+ "@doist/prettier-config": "^3.0.5",
43
51
  "@testing-library/react": "^12.1.2",
44
- "babel-jest": "^27.3.1",
45
- "core-js": "^3.19.1",
52
+ "babel-jest": "^27.4.1",
53
+ "core-js": "^3.19.2",
46
54
  "del-cli": "^4.0.1",
47
- "eslint": "^8.2.0",
55
+ "eslint": "^8.3.0",
48
56
  "eslint-config-prettier": "^8.3.0",
49
57
  "eslint-plugin-compat": "^4.0.0",
50
- "eslint-plugin-jest": "^25.2.4",
58
+ "eslint-plugin-import": "^2.25.3",
59
+ "eslint-plugin-jest": "^25.3.0",
51
60
  "eslint-plugin-prettier": "^4.0.0",
52
- "eslint-plugin-react": "^7.27.0",
61
+ "eslint-plugin-react": "^7.27.1",
53
62
  "eslint-plugin-react-hooks": "^4.3.0",
54
63
  "gzip-cli": "^1.2.0",
55
- "jest": "^27.3.1",
56
- "prettier": "^2.4.1",
64
+ "jest": "^27.4.1",
65
+ "prettier": "^2.5.0",
57
66
  "react": "^17.0.2",
58
67
  "react-dom": "^17.0.2",
59
- "rollup": "^2.60.0",
68
+ "rollup": "^2.60.2",
60
69
  "rollup-plugin-babel": "^4.4.0",
61
70
  "uglify-es": "^3.3.9"
62
71
  },
package/src/constants.js CHANGED
@@ -1,11 +1,11 @@
1
- export const TOKEN_PLACEHOLDER = "TOKEN_PLACEHOLDER"
2
- export const TOKEN_OPEN_TAG = "TOKEN_OPEN_TAG"
3
- export const TOKEN_CLOSE_TAG = "TOKEN_CLOSE_TAG"
4
- export const TOKEN_SELF_TAG = "TOKEN_SELF_TAG"
5
- export const TOKEN_TEXT = "TOKEN_TEXT"
1
+ export const TOKEN_PLACEHOLDER = 'TOKEN_PLACEHOLDER'
2
+ export const TOKEN_OPEN_TAG = 'TOKEN_OPEN_TAG'
3
+ export const TOKEN_CLOSE_TAG = 'TOKEN_CLOSE_TAG'
4
+ export const TOKEN_SELF_TAG = 'TOKEN_SELF_TAG'
5
+ export const TOKEN_TEXT = 'TOKEN_TEXT'
6
6
 
7
- export const NODE_FRAGMENT = "NODE_FRAGMENT"
8
- export const NODE_TAG_ELEMENT = "NODE_TAG_ELEMENT"
9
- export const NODE_VOID_ELEMENT = "NODE_VOID_ELEMENT"
10
- export const NODE_PLACEHOLDER = "NODE_PLACEHOLDER"
11
- export const NODE_TEXT = "NODE_TEXT"
7
+ export const NODE_FRAGMENT = 'NODE_FRAGMENT'
8
+ export const NODE_TAG_ELEMENT = 'NODE_TAG_ELEMENT'
9
+ export const NODE_VOID_ELEMENT = 'NODE_VOID_ELEMENT'
10
+ export const NODE_PLACEHOLDER = 'NODE_PLACEHOLDER'
11
+ export const NODE_TEXT = 'NODE_TEXT'
package/src/index.js CHANGED
@@ -1,10 +1,5 @@
1
- import Interpolate from "./interpolate"
1
+ import Interpolate from './interpolate'
2
2
  export default Interpolate
3
3
 
4
- export { SYNTAX_I18NEXT, SYNTAX_BUILT_IN } from "./syntax"
5
- export {
6
- TOKEN_PLACEHOLDER,
7
- TOKEN_OPEN_TAG,
8
- TOKEN_CLOSE_TAG,
9
- TOKEN_SELF_TAG
10
- } from "./constants"
4
+ export { SYNTAX_I18NEXT, SYNTAX_BUILT_IN } from './syntax'
5
+ export { TOKEN_PLACEHOLDER, TOKEN_OPEN_TAG, TOKEN_CLOSE_TAG, TOKEN_SELF_TAG } from './constants'
@@ -1,19 +1,17 @@
1
- import React from "react"
2
- import PropTypes from "prop-types"
3
- import parser from "./parser"
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import parser from './parser'
4
4
  import {
5
5
  NODE_FRAGMENT,
6
6
  NODE_TAG_ELEMENT,
7
7
  NODE_VOID_ELEMENT,
8
8
  NODE_PLACEHOLDER,
9
- NODE_TEXT
10
- } from "./constants"
9
+ NODE_TEXT,
10
+ } from './constants'
11
11
 
12
12
  const createElement = (node, mapping, keyPrefix) => {
13
13
  const children = node.children.map((c, i) => (
14
- <React.Fragment key={keyPrefix + i}>
15
- {createElement(c, mapping, keyPrefix)}
16
- </React.Fragment>
14
+ <React.Fragment key={keyPrefix + i}>{createElement(c, mapping, keyPrefix)}</React.Fragment>
17
15
  ))
18
16
 
19
17
  switch (node.type) {
@@ -25,7 +23,7 @@ const createElement = (node, mapping, keyPrefix) => {
25
23
  }
26
24
  case NODE_VOID_ELEMENT: {
27
25
  const val = mapping[node.name]
28
- if (typeof val === "function") {
26
+ if (typeof val === 'function') {
29
27
  return val()
30
28
  }
31
29
 
@@ -38,14 +36,14 @@ const createElement = (node, mapping, keyPrefix) => {
38
36
  return React.createElement(node.name, null, children)
39
37
  }
40
38
 
41
- if (typeof val === "function") {
39
+ if (typeof val === 'function') {
42
40
  return val(children)
43
41
  }
44
42
 
45
43
  if (React.isValidElement(val)) {
46
44
  if (React.Children.count(val.props.children) !== 0) {
47
45
  throw new Error(
48
- "when passing an element as value, the element should not contains children"
46
+ 'when passing an element as value, the element should not contains children',
49
47
  )
50
48
  }
51
49
 
@@ -53,7 +51,7 @@ const createElement = (node, mapping, keyPrefix) => {
53
51
  }
54
52
 
55
53
  throw new Error(
56
- `Invalid mapping value for "${node.name}". Only element or render function are accepted`
54
+ `Invalid mapping value for "${node.name}". Only element or render function are accepted`,
57
55
  )
58
56
  }
59
57
  case NODE_PLACEHOLDER: {
@@ -63,7 +61,7 @@ const createElement = (node, mapping, keyPrefix) => {
63
61
  return node.string
64
62
  }
65
63
 
66
- if (typeof val === "function") {
64
+ if (typeof val === 'function') {
67
65
  return val()
68
66
  }
69
67
 
@@ -74,12 +72,7 @@ const createElement = (node, mapping, keyPrefix) => {
74
72
  }
75
73
  }
76
74
 
77
- export default function Interpolate({
78
- string,
79
- syntax,
80
- mapping = {},
81
- graceful = true
82
- }) {
75
+ export default function Interpolate({ string, syntax, mapping = {}, graceful = true }) {
83
76
  try {
84
77
  const tree = parser(string, syntax)
85
78
  return createElement(tree, mapping, string)
@@ -96,5 +89,5 @@ export default function Interpolate({
96
89
  Interpolate.propTypes = {
97
90
  string: PropTypes.string.isRequired,
98
91
  mapping: PropTypes.object,
99
- graceful: PropTypes.bool
92
+ graceful: PropTypes.bool,
100
93
  }
package/src/lexer.js CHANGED
@@ -1,5 +1,5 @@
1
- import { TOKEN_TEXT } from "./constants"
2
- export { SYNTAX_I18NEXT, SYNTAX_BUILT_IN } from "./syntax"
1
+ import { TOKEN_TEXT } from './constants'
2
+ export { SYNTAX_I18NEXT, SYNTAX_BUILT_IN } from './syntax'
3
3
 
4
4
  /*
5
5
  * return a array of token object
@@ -17,7 +17,7 @@ export default function lexer(string, syntax) {
17
17
  string: res[0],
18
18
  name: res[1],
19
19
  start: res.index,
20
- end: res.index + res[0].length
20
+ end: res.index + res[0].length,
21
21
  })
22
22
  }
23
23
  }
@@ -26,7 +26,7 @@ export default function lexer(string, syntax) {
26
26
  const textTokens = []
27
27
 
28
28
  let start = 0
29
- matches.forEach(match => {
29
+ matches.forEach((match) => {
30
30
  if (match.start === start) {
31
31
  start = match.end
32
32
  return
@@ -40,25 +40,23 @@ export default function lexer(string, syntax) {
40
40
  string: text,
41
41
  text,
42
42
  start,
43
- end
43
+ end,
44
44
  })
45
45
 
46
46
  start = match.end
47
47
  })
48
48
 
49
49
  const text = string.substring(start)
50
- if (text !== "") {
50
+ if (text !== '') {
51
51
  textTokens.push({
52
52
  type: TOKEN_TEXT,
53
53
  string: text,
54
54
  start,
55
- end: string.length
55
+ end: string.length,
56
56
  })
57
57
  }
58
58
 
59
- const tokens = []
60
- .concat(textTokens, matches)
61
- .sort((a, b) => a.start - b.start)
59
+ const tokens = [].concat(textTokens, matches).sort((a, b) => a.start - b.start)
62
60
 
63
61
  return tokens
64
62
  }
package/src/node.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  NODE_TAG_ELEMENT,
4
4
  NODE_VOID_ELEMENT,
5
5
  NODE_PLACEHOLDER,
6
- NODE_TEXT
7
- } from "./constants"
6
+ NODE_TEXT,
7
+ } from './constants'
8
8
 
9
9
  export default class Node {
10
10
  constructor({ type, children, ...fields }) {
@@ -34,32 +34,32 @@ Node.createTagNode = (token, children) =>
34
34
  type: NODE_TAG_ELEMENT,
35
35
  children,
36
36
  name: token.name,
37
- token
37
+ token,
38
38
  })
39
39
 
40
- Node.createFragmentNode = children =>
40
+ Node.createFragmentNode = (children) =>
41
41
  new Node({
42
42
  type: NODE_FRAGMENT,
43
- children
43
+ children,
44
44
  })
45
45
 
46
- Node.createVoidNode = token =>
46
+ Node.createVoidNode = (token) =>
47
47
  new Node({
48
48
  type: NODE_VOID_ELEMENT,
49
49
  name: token.name,
50
- token
50
+ token,
51
51
  })
52
52
 
53
- Node.createTextNode = token =>
53
+ Node.createTextNode = (token) =>
54
54
  new Node({
55
55
  type: NODE_TEXT,
56
56
  text: token.string,
57
- token
57
+ token,
58
58
  })
59
59
 
60
- Node.createPlaceholderNode = token =>
60
+ Node.createPlaceholderNode = (token) =>
61
61
  new Node({
62
62
  type: NODE_PLACEHOLDER,
63
63
  name: token.name,
64
- token
64
+ token,
65
65
  })
package/src/parser.js CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  TOKEN_OPEN_TAG,
4
4
  TOKEN_CLOSE_TAG,
5
5
  TOKEN_SELF_TAG,
6
- TOKEN_TEXT
7
- } from "./constants"
8
- import Node from "./node.js"
9
- import lexer from "./lexer"
10
- import { SYNTAX_BUILT_IN } from "./syntax"
6
+ TOKEN_TEXT,
7
+ } from './constants'
8
+ import Node from './node.js'
9
+ import lexer from './lexer'
10
+ import { SYNTAX_BUILT_IN } from './syntax'
11
11
 
12
12
  export default function parser(string, syntax) {
13
13
  if (!syntax) {
@@ -19,12 +19,11 @@ export default function parser(string, syntax) {
19
19
  return p.parse()
20
20
  }
21
21
 
22
- const SYNTAX_ERROR =
23
- "Syntax error. Please check if each open tag is closed correctly"
22
+ const SYNTAX_ERROR = 'Syntax error. Please check if each open tag is closed correctly'
24
23
 
25
24
  // A special token representing end of the tream
26
25
  const EPSILON = {
27
- type: "EPSILON"
26
+ type: 'EPSILON',
28
27
  }
29
28
 
30
29
  /*
package/src/syntax.js CHANGED
@@ -1,38 +1,33 @@
1
- import {
2
- TOKEN_PLACEHOLDER,
3
- TOKEN_OPEN_TAG,
4
- TOKEN_CLOSE_TAG,
5
- TOKEN_SELF_TAG
6
- } from "./constants"
1
+ import { TOKEN_PLACEHOLDER, TOKEN_OPEN_TAG, TOKEN_CLOSE_TAG, TOKEN_SELF_TAG } from './constants'
7
2
 
8
3
  export const SYNTAX_BUILT_IN = [
9
4
  {
10
5
  type: TOKEN_PLACEHOLDER,
11
- regex: /{\s*(\w+)\s*}/g
6
+ regex: /{\s*(\w+)\s*}/g,
12
7
  },
13
8
  {
14
9
  type: TOKEN_OPEN_TAG,
15
- regex: /<(\w+)>/g
10
+ regex: /<(\w+)>/g,
16
11
  },
17
12
  {
18
13
  type: TOKEN_CLOSE_TAG,
19
- regex: /<\/(\w+)>/g
14
+ regex: /<\/(\w+)>/g,
20
15
  },
21
- { type: TOKEN_SELF_TAG, regex: /<(\w+)\s*\/>/g }
16
+ { type: TOKEN_SELF_TAG, regex: /<(\w+)\s*\/>/g },
22
17
  ]
23
18
 
24
19
  export const SYNTAX_I18NEXT = [
25
20
  {
26
21
  type: TOKEN_PLACEHOLDER,
27
- regex: /{{\s*(\w+)\s*}}/g
22
+ regex: /{{\s*(\w+)\s*}}/g,
28
23
  },
29
24
  {
30
25
  type: TOKEN_OPEN_TAG,
31
- regex: /<(\w+)>/g
26
+ regex: /<(\w+)>/g,
32
27
  },
33
28
  {
34
29
  type: TOKEN_CLOSE_TAG,
35
- regex: /<\/(\w+)>/g
30
+ regex: /<\/(\w+)>/g,
36
31
  },
37
- { type: TOKEN_SELF_TAG, regex: /<(\w+)\s*\/>/g }
32
+ { type: TOKEN_SELF_TAG, regex: /<(\w+)\s*\/>/g },
38
33
  ]
package/.eslintrc.js DELETED
@@ -1,35 +0,0 @@
1
- const config = {
2
- extends: [
3
- "eslint:recommended",
4
- "plugin:react/recommended",
5
- "prettier",
6
- "plugin:compat/recommended"
7
- ],
8
- env: {
9
- browser: true,
10
- "jest/globals": true
11
- },
12
- parserOptions: {
13
- ecmaFeatures: {
14
- jsx: true,
15
- impliedStrict: true
16
- },
17
- sourceType: "module"
18
- },
19
- plugins: ["react", "prettier", "react-hooks", "jest"],
20
- parser: "@babel/eslint-parser",
21
- rules: {
22
- semi: ["error", "never"],
23
- "arrow-parens": ["error", "as-needed"],
24
- "prettier/prettier": "error",
25
- "react-hooks/rules-of-hooks": "error",
26
- "react-hooks/exhaustive-deps": "error"
27
- },
28
- settings: {
29
- react: {
30
- version: "16.0"
31
- }
32
- }
33
- }
34
-
35
- module.exports = config
@@ -1,24 +0,0 @@
1
- name: CI
2
-
3
- on: [push, pull_request]
4
-
5
- jobs:
6
- build:
7
- runs-on: ubuntu-latest
8
-
9
- strategy:
10
- matrix:
11
- node-version: [16.x]
12
-
13
- steps:
14
- - uses: actions/checkout@v2
15
- - name: Use Node.js ${{ matrix.node-version }}
16
- uses: actions/setup-node@v1
17
- with:
18
- node-version: ${{ matrix.node-version }}
19
- - run: npm ci
20
- - run: npm run build
21
- - run: npm test
22
- env:
23
- CI: true
24
- - run: npm run lint
@@ -1,53 +0,0 @@
1
- name: Release @doist/react-interpolate package
2
-
3
- on:
4
- release:
5
- types: [created]
6
- workflow_dispatch:
7
-
8
- jobs:
9
- publish:
10
- runs-on: ubuntu-latest
11
- steps:
12
- - uses: actions/checkout@v2
13
-
14
- - name: Read Node.js version from '.nvmrc'
15
- id: nvmrc
16
- run: |
17
- echo "::set-output name=NODE_VERSION::$(cat .nvmrc)"
18
-
19
- - name: Setup Node
20
- uses: actions/setup-node@v1
21
- with:
22
- node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
23
-
24
- - name: Install dependencies
25
- run: npm ci
26
-
27
- - name: Lint
28
- run: npm run lint
29
- env:
30
- CI: true
31
-
32
- - name: Build
33
- run: npm run build
34
-
35
- - name: Publish to GitHub Package Registry
36
- uses: actions/setup-node@v1
37
- with:
38
- node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
39
- registry-url: https://npm.pkg.github.com/
40
- scope: "@doist"
41
- - run: npm publish
42
- env:
43
- NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
44
-
45
- - name: Publish to npm registry
46
- uses: actions/setup-node@v1
47
- with:
48
- node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
49
- registry-url: https://registry.npmjs.org/
50
- scope: "@doist"
51
- - run: npm publish
52
- env:
53
- NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
package/.nvmrc DELETED
@@ -1 +0,0 @@
1
- 16.13.0
package/.prettierrc.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "printWidth": 80,
3
- "tabWidth": 4,
4
- "semi": false,
5
- "trailingComma": "none",
6
- "bracketSpacing": true,
7
- "arrowParens": "avoid",
8
- "proseWrap": "never"
9
- }
package/CONTRIBUTING.md DELETED
@@ -1,7 +0,0 @@
1
- ## Dependencies and target environment
2
-
3
- One core goal this library is to deliver a lightweight solution. Therefore, it comes to critically when it comes to user of dependencies and also polyfill usage.
4
-
5
- - `react` should be its only dependencies.
6
- - No polyfill.
7
-
@@ -1,203 +0,0 @@
1
- /* eslint-disable react/display-name */
2
- import React from "react"
3
- import { render } from "@testing-library/react"
4
- import Interpolate, { SYNTAX_I18NEXT } from "../src"
5
-
6
- Interpolate.defaultProps = {
7
- graceful: false
8
- }
9
-
10
- const surpressConsole = () => {
11
- const w = jest.spyOn(console, "warn").mockImplementation()
12
- const e = jest.spyOn(console, "error").mockImplementation()
13
-
14
- return () => {
15
- w.mockRestore()
16
- e.mockRestore()
17
- }
18
- }
19
-
20
- describe("Interpolate", () => {
21
- function renderTest({ expected, ...props }) {
22
- const { container } = render(<Interpolate {...props} />)
23
- expect(container.innerHTML).toEqual(expected)
24
- }
25
-
26
- test("when no mapping is provide", () => {
27
- const restore = surpressConsole() // Interpolate will output warning when no mapping is provided
28
-
29
- renderTest({
30
- string: "<h1>hello <b>{name}</b></h1><br/>. welcome to todoist",
31
- expected: "<h1>hello <b>{name}</b></h1><br>. welcome to todoist"
32
- })
33
-
34
- restore()
35
- })
36
-
37
- test("tag mapping", () =>
38
- renderTest({
39
- string: "<h1>hello <b>steven</b></h1>. welcome to todoist",
40
- mapping: {
41
- b: child => <i>{child}</i>,
42
- h1: child => <h2>{child}</h2>
43
- },
44
- expected: "<h2>hello <i>steven</i></h2>. welcome to todoist"
45
- }))
46
-
47
- test("tag mapping: should accept element directly", () =>
48
- renderTest({
49
- string: "<h1>hello <b>steven</b></h1>. welcome to todoist",
50
- mapping: {
51
- b: <i />,
52
- h1: <h2 />
53
- },
54
- expected: "<h2>hello <i>steven</i></h2>. welcome to todoist"
55
- }))
56
-
57
- test("placholder mapping", () =>
58
- renderTest({
59
- string: "{greeting} <b>{name}</b>. welcome to todoist",
60
- mapping: {
61
- greeting: "hi",
62
- name: () => <i>steven</i>
63
- },
64
- expected: "hi <b><i>steven</i></b>. welcome to todoist"
65
- }))
66
-
67
- test("void tag mapping", () =>
68
- renderTest({
69
- string: "hello <br/>",
70
- mapping: {
71
- br: <hr />
72
- },
73
- expected: "hello <hr>"
74
- }))
75
-
76
- test("combination of mapping", () =>
77
- renderTest({
78
- string: "<h1>hello <b>{name}</b></h1>.<br/> welcome to todoist",
79
- mapping: {
80
- h1: child => <h2>{child}</h2>,
81
- b: child => <i>{child}</i>,
82
- name: "steven",
83
- br: <hr />
84
- },
85
- expected: "<h2>hello <i>steven</i></h2>.<hr> welcome to todoist"
86
- }))
87
-
88
- test("combination of mapping with function component", () => {
89
- // eslint-disable-next-line
90
- const Subheader = ({ children }) => {
91
- return <h2 className="subheader">{children}</h2>
92
- }
93
-
94
- renderTest({
95
- string: "<h1>hello <b>{name}</b></h1>.<br/> welcome to todoist",
96
- mapping: {
97
- h1: child => <Subheader>{child}</Subheader>,
98
- b: child => <i>{child}</i>,
99
- name: "steven",
100
- br: <hr />
101
- },
102
- expected:
103
- '<h2 class="subheader">hello <i>steven</i></h2>.<hr> welcome to todoist'
104
- })
105
- })
106
-
107
- test("spacing in the void tag and placeholder should be allowed", () =>
108
- renderTest({
109
- string: "hello { name }<br /> welcome to todoist",
110
- mapping: {
111
- name: "steven",
112
- br: <hr />
113
- },
114
- expected: "hello steven<hr> welcome to todoist"
115
- }))
116
-
117
- test("the mapping value should be interpolate corrected with proper html escape", () => {
118
- renderTest({
119
- string: "hello { name }<br /> welcome to todoist",
120
- mapping: {
121
- name: "<script>window.xss = 1</script>",
122
- br: "<script>window.xss = 1</script>"
123
- },
124
- expected:
125
- "hello &lt;script&gt;window.xss = 1&lt;/script&gt;&lt;script&gt;window.xss = 1&lt;/script&gt; welcome to todoist"
126
- })
127
-
128
- expect(window.css).toBeUndefined()
129
- })
130
-
131
- test("when graceful flag is on and string contains syntax error, interpolate should return the original string and should not throw error", () => {
132
- const restore = surpressConsole()
133
-
134
- renderTest({
135
- string: "</h1>",
136
- expected: "&lt;/h1&gt;",
137
- graceful: true
138
- })
139
-
140
- restore()
141
- })
142
-
143
- test("using SYNTAX_I18NEXT", () => {
144
- renderTest({
145
- syntax: SYNTAX_I18NEXT,
146
- string: "<0>hello <b>{{name}}</b></0>.<br/> welcome to todoist",
147
- mapping: {
148
- 0: child => <h2 className="subheader">{child}</h2>,
149
- b: child => <i>{child}</i>,
150
- name: "steven",
151
- br: <hr />
152
- },
153
- expected:
154
- '<h2 class="subheader">hello <i>steven</i></h2>.<hr> welcome to todoist'
155
- })
156
- })
157
- })
158
-
159
- describe("Interpolate: error cases", () => {
160
- let restore
161
- beforeAll(() => {
162
- restore = surpressConsole()
163
- })
164
- afterAll(() => {
165
- restore()
166
- })
167
-
168
- function renderTest({ expectedError, ...props }) {
169
- return () => {
170
- expect(() => render(<Interpolate {...props} />)).toThrow(
171
- expectedError
172
- )
173
- }
174
- }
175
-
176
- test(
177
- "non-closing tag",
178
- renderTest({
179
- string: "<b>",
180
- expectedError:
181
- "Syntax error. Please check if each open tag is closed correctly"
182
- })
183
- )
184
-
185
- test(
186
- "mapping value for tag should always be a function",
187
- renderTest({
188
- string: "<h1>hello</h1>. welcome to todoist",
189
- mapping: { h1: "hi" },
190
- expectedError: "Invalid mapping value for"
191
- })
192
- )
193
-
194
- test(
195
- "when passing element as value but the element contains children, error should be thrown",
196
- renderTest({
197
- string: "<h1>hello</h1>. welcome to todoist",
198
- mapping: { h1: <h1>hi</h1> },
199
- expectedError:
200
- "when passing an element as value, the element should not contains children"
201
- })
202
- )
203
- })
@@ -1,45 +0,0 @@
1
- import parser from "../src/parser"
2
-
3
- describe("parser", () => {
4
- const tests = [
5
- "hello",
6
- "{steven}",
7
- "<br />",
8
- "<div></div>",
9
- "hello {steven} from taiwan",
10
- "hello {steven} from taiwan <br/>",
11
- "<div>hello</div>",
12
- "<div>hello {steven}</div>",
13
- "<div>hello <b>{steven}</b></div>",
14
- "<div>hello <b>mr {steven} from taiwan</b></div>",
15
- "<div>hello <b>mr {steven} from taiwan</b><br /></div>",
16
- "<div>hello</div><b>steven</b>"
17
- ]
18
-
19
- tests.forEach(string => {
20
- test(string, () => {
21
- parser(string)
22
- })
23
- })
24
- })
25
-
26
- describe("parser: error handling", () => {
27
- const invalids = [
28
- "<div>hello",
29
- "hello<div>",
30
- "<br>",
31
- "hello {steven}</div>",
32
- "<div>hello <b>{steven}</div></b>",
33
- "<div>hello <b>{steven}</b></b></div>"
34
- ]
35
-
36
- invalids.forEach(string => {
37
- test(`invalid syntax: ${string}`, () => {
38
- expect(() => {
39
- parser(string)
40
- }).toThrow(
41
- "Syntax error. Please check if each open tag is closed correctly"
42
- )
43
- })
44
- })
45
- })
package/babel.config.js DELETED
@@ -1,18 +0,0 @@
1
- module.exports = function(api) {
2
- api.cache(true)
3
-
4
- return {
5
- presets: [
6
- [
7
- "@babel/preset-env",
8
- {
9
- targets: {
10
- browsers: ["IE 11"]
11
- }
12
- }
13
- ],
14
- "@babel/react"
15
- ],
16
- plugins: ["@babel/plugin-transform-runtime"]
17
- }
18
- }
package/jest.config.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- testEnvironment: "jsdom"
3
- }
package/rollup.config.js DELETED
@@ -1,17 +0,0 @@
1
- import babel from "rollup-plugin-babel"
2
- import pkg from "./package.json"
3
-
4
- export default {
5
- input: "src/index.js",
6
- output: [
7
- {
8
- file: pkg.main,
9
- format: "cjs"
10
- },
11
- {
12
- file: pkg.module,
13
- format: "es"
14
- }
15
- ],
16
- plugins: [babel({ runtimeHelpers: true })]
17
- }