Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-from-dom

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-from-dom - npm Package Compare versions

Comparing version 0.6.2 to 0.7.0

dist/index.d.mts

106

package.json
{
"name": "react-from-dom",
"version": "0.6.2",
"version": "0.7.0",
"description": "Convert HTML/XML source code or DOM nodes to React elements",

@@ -23,10 +23,13 @@ "author": "Gil Barbara <gilbarbara@gmail.com>",

"homepage": "https://github.com/gilbarbara/react-from-dom#readme",
"main": "lib/index.js",
"module": "esm/index.js",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"files": [
"esm",
"lib",
"dist",
"src"
],
"types": "./lib",
"types": "dist/index.d.ts",
"sideEffects": false,

@@ -37,44 +40,57 @@ "peerDependencies": {

"devDependencies": {
"@gilbarbara/eslint-config": "^0.2.1",
"@gilbarbara/prettier-config": "^0.1.0",
"@gilbarbara/tsconfig": "^0.1.0",
"@size-limit/preset-small-lib": "^7.0.8",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.0.1",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.23",
"@types/react": "^18.0.3",
"@types/react-dom": "^18.0.0",
"del-cli": "^4.0.1",
"husky": "^7.0.4",
"@arethetypeswrong/cli": "^0.15.0",
"@gilbarbara/eslint-config": "^0.7.4",
"@gilbarbara/prettier-config": "^1.0.0",
"@gilbarbara/tsconfig": "^0.2.3",
"@size-limit/preset-small-lib": "^11.0.2",
"@swc/core": "^1.4.2",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.1",
"@types/node": "^20.11.21",
"@types/react": "^18.2.60",
"@types/react-dom": "^18.2.19",
"@vitejs/plugin-react-swc": "^3.6.0",
"@vitest/coverage-v8": "^1.3.1",
"del-cli": "^5.1.0",
"husky": "^9.0.11",
"is-ci-cli": "^2.2.0",
"jest": "^27.5.1",
"jest-extended": "^2.0.0",
"jest-watch-typeahead": "^1.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"repo-tools": "^0.2.2",
"size-limit": "^7.0.8",
"ts-jest": "^27.1.4",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
"jest-extended": "^4.0.2",
"jsdom": "^24.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"repo-tools": "^0.3.1",
"size-limit": "^11.0.2",
"ts-node": "^10.9.2",
"tsup": "^8.0.2",
"typescript": "^5.3.3",
"vitest": "^1.3.1"
},
"scripts": {
"build": "npm run clean && npm run build:cjs && npm run build:esm",
"build:cjs": "tsc",
"build:esm": "tsc -m es6 --outDir esm",
"watch:cjs": "npm run build:cjs -- -w",
"watch:esm": "npm run build:esm -- -w",
"clean": "del lib/* && del esm/*",
"lint": "eslint --ext .ts,.tsx src test",
"build": "npm run clean && tsup",
"watch": "tsup --watch",
"clean": "del dist/*",
"lint": "eslint --fix src test",
"test": "is-ci \"test:coverage\" \"test:watch\"",
"test:coverage": "jest --coverage --bail",
"test:watch": "jest --watchAll --verbose",
"typecheck": "tsc --noEmit",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest watch",
"typecheck": "tsc",
"typevalidation": "attw -P",
"format": "prettier \"**/*.{js,jsx,json,yml,yaml,css,less,scss,ts,tsx,md,graphql,mdx}\" --write",
"validate": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run size",
"validate": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run size && npm run typevalidation",
"size": "size-limit",
"prepublishOnly": "npm run validate",
"prepare": "husky install"
"prepare": "husky"
},
"tsup": {
"dts": true,
"entry": [
"src/index.ts"
],
"format": [
"cjs",
"esm"
],
"sourcemap": true,
"splitting": false
},
"eslintConfig": {

@@ -88,12 +104,12 @@ "extends": [

{
"name": "lib",
"path": "./lib/index.js",
"limit": "6 kB"
"name": "commonjs",
"path": "./dist/index.js",
"limit": "5 kB"
},
{
"name": "esm",
"path": "./esm/index.js",
"limit": "6 kB"
"path": "./dist/index.mjs",
"limit": "5 kB"
}
]
}
export const styleToObject = (input: string): Record<string, any> => {
const attributes = input.split(/ ?; ?/);
/* c8 ignore next 3 */
if (typeof input !== 'string') {
return {};
}
return attributes.reduce((acc: Record<string, any>, d: string) => {
const attributes = input.replace(/\n/, '').split(/ ?; ?/);
return attributes.reduce<Record<string, string | number>>((acc, d: string) => {
const [key, value] = d.split(/ ?: ?/);
if (key && value) {
acc[key.replace(/-(\w)/g, (_$0, $1) => $1.toUpperCase())] = Number.isNaN(Number(value))
const nextKey = key.replace(/-(\w)/g, (_$0, $1) => $1.toUpperCase());
acc[key.startsWith('-') ? key : nextKey] = Number.isNaN(Number(value))
? value

@@ -17,3 +24,2 @@ : Number(value);

/* istanbul ignore next */
export function randomString(length = 6): string {

@@ -20,0 +26,0 @@ const characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

@@ -1,2 +0,1 @@

/* eslint-disable @typescript-eslint/no-use-before-define */
import * as React from 'react';

@@ -7,11 +6,48 @@

export interface Options {
/**
* An array of actions to modify the nodes before they are converted to ReactNodes.
*/
actions?: Action[];
/**
* Skip removing white spaces in the output.
*/
allowWhiteSpaces?: boolean;
/**
* Parse all nodes instead of just a single parent node.
* This will return a ReactNode array (or a NodeList if `nodeOnly` is true).
*/
includeAllNodes?: boolean;
/**
* The index to start with.
* @default 0
*/
index?: number;
/**
* The level to start with.
* @default 0
*/
level?: number;
/**
* Only return the node (or NodeList) without converting it to a ReactNode.
*/
nodeOnly?: boolean;
/**
* Add a random key to the root element.
* @default false
*/
randomKey?: boolean;
/**
* The selector to use for in the `document.querySelector` method.
* @default 'body > *'
*/
selector?: string;
type?: string;
/**
* The type of the input string.
* @default 'text/html'
*/
type?: DOMParserSupportedType;
}
export type Output = React.ReactNode | Node | NodeList;
interface Attributes {

@@ -23,2 +59,7 @@ [index: string]: any;

interface GetReactNodeOptions extends Options {
key: string;
level: number;
}
export interface Action {

@@ -37,2 +78,58 @@ // If this returns true, the two following functions are called if they are defined

function getReactNode(node: Node, options: GetReactNodeOptions): React.ReactNode {
const { key, level, ...rest } = options;
switch (node.nodeType) {
case 1: {
// regular dom-node
return React.createElement(
parseName(node.nodeName),
parseAttributes(node, key),
parseChildren(node.childNodes, level, rest),
);
}
case 3: {
// textnode
const nodeText = node.nodeValue?.toString() ?? '';
if (!rest.allowWhiteSpaces && /^\s+$/.test(nodeText) && !/[\u00A0\u202F]/.test(nodeText)) {
return null;
}
/* c8 ignore next 3 */
if (!node.parentNode) {
return nodeText;
}
const parentNodeName = node.parentNode.nodeName.toLowerCase();
if (noTextChildNodes.includes(parentNodeName)) {
if (/\S/.test(nodeText)) {
// eslint-disable-next-line no-console
console.warn(
`A textNode is not allowed inside '${parentNodeName}'. Your text "${nodeText}" will be ignored`,
);
}
return null;
}
return nodeText;
}
case 8: {
// html-comment
return null;
}
case 11: {
// fragment
return parseChildren(node.childNodes, level, options);
}
/* c8 ignore next 3 */
default: {
return null;
}
}
}
function parseAttributes(node: Node, reactKey: string): Attributes {

@@ -43,3 +140,2 @@ const attributes: Attributes = {

/* istanbul ignore else */
if (node instanceof Element) {

@@ -137,3 +233,2 @@ const nodeClassNames = node.getAttribute('class');

/* istanbul ignore else */
if (Array.isArray(actions)) {

@@ -148,3 +243,2 @@ actions.forEach((action: Action) => {

/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {

@@ -170,64 +264,34 @@ // eslint-disable-next-line no-console

switch (node.nodeType) {
case 1: {
// regular dom-node
return React.createElement(
parseName(node.nodeName),
parseAttributes(node, key),
parseChildren(node.childNodes, level, options),
);
}
case 3: {
// textnode
const nodeText = node.nodeValue?.toString() || '';
return getReactNode(node, { key, level, ...options });
}
/* istanbul ignore else */
if (/^\s+$/.test(nodeText) && !/[\u00A0\u202F]/.test(nodeText)) {
return null;
}
export function convertFromString(input: string, options: Options = {}): Output {
if (!input || typeof input !== 'string') {
return null;
}
/* istanbul ignore next */
if (!node.parentNode) {
return nodeText;
}
const {
includeAllNodes = false,
nodeOnly = false,
selector = 'body > *',
type = 'text/html',
} = options;
const parentNodeName = node.parentNode.nodeName.toLowerCase();
try {
const parser = new DOMParser();
const document = parser.parseFromString(input, type);
if (noTextChildNodes.includes(parentNodeName)) {
/* istanbul ignore else */
if (/\S/.test(nodeText)) {
// eslint-disable-next-line no-console
console.warn(
`A textNode is not allowed inside '${parentNodeName}'. Your text "${nodeText}" will be ignored`,
);
}
if (includeAllNodes) {
const { childNodes } = document.body;
return null;
if (nodeOnly) {
return childNodes;
}
return nodeText;
return [...childNodes].map(node => convertFromNode(node, options));
}
case 8: {
// html-comment
return null;
}
/* istanbul ignore next */
default: {
return null;
}
}
}
export function convertFromString(input: string, options: Options = {}): React.ReactNode | Node {
if (!input || typeof input !== 'string') {
return null;
}
const node = document.querySelector(selector) || document.body.childNodes[0];
const { nodeOnly = false, selector = 'body > *', type = 'text/html' } = options;
try {
const parser = new DOMParser();
const document = parser.parseFromString(input, type as DOMParserSupportedType);
const node = document.querySelector(selector);
/* c8 ignore next 3 */
if (!(node instanceof Node)) {

@@ -242,4 +306,4 @@ throw new TypeError('Error parsing input');

return convertFromNode(node, options);
/* c8 ignore start */
} catch (error) {
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {

@@ -252,8 +316,6 @@ // eslint-disable-next-line no-console

return null;
/* c8 ignore stop */
}
export default function convert(
input: Node | string,
options: Options = {},
): React.ReactNode | Node {
export default function convert(input: Node | string, options: Options = {}): Output {
if (typeof input === 'string') {

@@ -260,0 +322,0 @@ return convertFromString(input, options);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc