Skip to content

Commit

Permalink
Merge pull request #1123 from remarkablemark/refactor/typescript
Browse files Browse the repository at this point in the history
refactor: migrate to TypeScript
  • Loading branch information
remarkablemark authored Oct 29, 2023
2 parents 1fcb059 + 713c548 commit 4255a10
Show file tree
Hide file tree
Showing 54 changed files with 7,172 additions and 11,649 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: npm run lint

- name: Type check
run: npm run lint:dts
run: npm run lint:tsc

- name: Run unit tests
run: npm run test:ci
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ jspm_packages
.node_repl_history

# Build files
build
dist
dist/
lib/

# Vim swap files
*.swp
Expand Down
1 change: 0 additions & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"trailingComma": "none",
"singleQuote": true
}
124 changes: 74 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ To replace an element with another element, check out the [`replace`](#replace)

#### Example

```js
const parse = require('html-react-parser');
```ts
import parse from 'html-react-parser';

parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
```

Expand All @@ -43,6 +44,7 @@ parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
- [htmlparser2](#htmlparser2)
- [trim](#trim)
- [Migration](#migration)
- [v5](#v5)
- [v4](#v4)
- [v3](#v3)
- [v2](#v2)
Expand Down Expand Up @@ -100,31 +102,31 @@ yarn add html-react-parser

Import ES module:

```js
```ts
import parse from 'html-react-parser';
```

Or require CommonJS module:

```js
const parse = require('html-react-parser');
```ts
const parse = require('html-react-parser').default;
```

Parse single element:

```js
```ts
parse('<h1>single</h1>');
```

Parse multiple elements:

```js
```ts
parse('<li>Item 1</li><li>Item 2</li>');
```

Make sure to render parsed adjacent elements under a parent element:

```jsx
```tsx
<ul>
{parse(`
<li>Item 1</li>
Expand All @@ -135,15 +137,15 @@ Make sure to render parsed adjacent elements under a parent element:

Parse nested elements:

```js
```ts
parse('<body><p>Lorem ipsum</p></body>');
```

Parse element with attributes:

```js
```ts
parse(
'<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">'
'<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">',
);
```

Expand All @@ -153,19 +155,19 @@ The `replace` option allows you to replace an element with another element.

The `replace` callback's first argument is [domhandler](https://github.com/fb55/domhandler#example)'s node:

```js
```ts
parse('<br>', {
replace: (domNode) => {
replace(domNode) {
console.dir(domNode, { depth: null });
}
},
});
```

<details>
<summary>Console output</summary>
<p>

```js
```ts
Element {
type: 'tag',
parent: null,
Expand All @@ -184,29 +186,43 @@ Element {

The element is replaced if a **valid** React element is returned:

```jsx
```tsx
parse('<p id="replace">text</p>', {
replace: (domNode) => {
replace(domNode) {
if (domNode.attribs && domNode.attribs.id === 'replace') {
return <span>replaced</span>;
}
}
},
});
```

#### replace with TypeScript

For TypeScript projects, you may need to check that `domNode` is an instance of domhandler's `Element`:
For TypeScript, you'll need to check that `domNode` is an instance of domhandler's `Element`:

```tsx
import { HTMLReactParserOptions, Element } from 'html-react-parser';

const options: HTMLReactParserOptions = {
replace: (domNode) => {
replace(domNode) {
if (domNode instanceof Element && domNode.attribs) {
// ...
}
}
},
};
```

Or use a type assertion:

```tsx
import { HTMLReactParserOptions, Element } from 'html-react-parser';

const options: HTMLReactParserOptions = {
replace(domNode) {
if ((domNode as Element).attribs) {
// ...
}
},
};
```

Expand All @@ -216,7 +232,7 @@ If you're having issues take a look at our [Create React App example](./examples

Replace the element and its children (see [demo](https://replit.com/@remarkablemark/html-react-parser-replace-example)):

```jsx
```tsx
import parse, { domToReact } from 'html-react-parser';

const html = `
Expand All @@ -228,7 +244,7 @@ const html = `
`;

const options = {
replace: ({ attribs, children }) => {
replace({ attribs, children }) {
if (!attribs) {
return;
}
Expand All @@ -244,7 +260,7 @@ const options = {
</span>
);
}
}
},
};

parse(html, options);
Expand Down Expand Up @@ -273,20 +289,20 @@ parse(html, options);

Convert DOM attributes to React props with `attributesToProps`:

```jsx
```tsx
import parse, { attributesToProps } from 'html-react-parser';

const html = `
<main class="prettify" style="background: #fff; text-align: center;" />
`;

const options = {
replace: (domNode) => {
replace(domNode) {
if (domNode.attribs && domNode.name === 'main') {
const props = attributesToProps(domNode.attribs);
return <div {...props} />;
}
}
},
};

parse(html, options);
Expand All @@ -307,9 +323,9 @@ parse(html, options);

[Exclude](https://replit.com/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`:

```jsx
```tsx
parse('<p><br id="remove"></p>', {
replace: ({ attribs }) => attribs && attribs.id === 'remove' && <></>
replace: ({ attribs }) => attribs?.id === 'remove' && <></>,
});
```

Expand All @@ -330,12 +346,12 @@ The `transform` option allows you to transform each element individually after i

The `transform` callback's first argument is the React element:

```jsx
```tsx
parse('<br>', {
transform: (reactNode, domNode, index) => {
transform(reactNode, domNode, index) {
// this will wrap every element in a div
return <div>{reactNode}</div>;
}
},
});
```

Expand All @@ -345,15 +361,15 @@ The `library` option specifies the UI library. The default library is **React**.

To use Preact:

```js
```ts
parse('<br>', {
library: require('preact')
library: require('preact'),
});
```

Or a custom library:

```js
```ts
parse('<br>', {
library: {
cloneElement: () => {
Expand All @@ -364,8 +380,8 @@ parse('<br>', {
},
isValidElement: () => {
/* ... */
}
}
},
},
});
```

Expand All @@ -377,42 +393,50 @@ Default [htmlparser2 options](https://github.com/fb55/htmlparser2/wiki/Parser-op

To enable [`xmlMode`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-xmlmode):

```js
```ts
parse('<p /><p />', {
htmlparser2: {
xmlMode: true
}
xmlMode: true,
},
});
```

### trim

By default, whitespace is preserved:

```js
```ts
parse('<br>\n'); // [React.createElement('br'), '\n']
```

But certain elements like `<table>` will strip out invalid whitespace:

```js
```ts
parse('<table>\n</table>'); // React.createElement('table')
```

To remove whitespace, enable the `trim` option:

```js
```ts
parse('<br>\n', { trim: true }); // React.createElement('br')
```

However, intentional whitespace may be stripped out:

```js
```ts
parse('<p> </p>', { trim: true }); // React.createElement('p')
```

## Migration

### v5

Migrated to TypeScript. CommonJS imports require the `.default` key:

```ts
const parse = require('html-react-parser').default;
```

### v4

[htmlparser2](https://github.com/fb55/htmlparser2) has been upgraded to [v9](https://github.com/fb55/htmlparser2/releases/tag/v9.0.0).
Expand All @@ -437,11 +461,11 @@ For the `replace` option, you may need to do the following:
import { Element } from 'domhandler/lib/node';

parse('<br class="remove">', {
replace: (domNode) => {
replace(domNode) {
if (domNode instanceof Element && domNode.attribs.class === 'remove') {
return <></>;
}
}
},
});
```

Expand Down Expand Up @@ -490,8 +514,8 @@ Tags are lowercased by default. To prevent that from happening, pass the [htmlpa
```js
const options = {
htmlparser2: {
lowerCaseTags: false
}
lowerCaseTags: false,
},
};
parse('<CustomElement>', options); // React.createElement('CustomElement')
```
Expand Down Expand Up @@ -527,8 +551,8 @@ Then update your Webpack config to:
module.exports = {
// ...
resolve: {
mainFields: ['browser', 'main', 'module']
}
mainFields: ['browser', 'main', 'module'],
},
};
```

Expand Down
Loading

0 comments on commit 4255a10

Please sign in to comment.