@react-email/render 2.0.3 → 2.0.4
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/dist/browser/index.js +2 -1
- package/dist/browser/index.mjs +3 -2
- package/dist/browser/index.mjs.map +1 -1
- package/dist/edge/index.js +2 -1
- package/dist/edge/index.mjs +3 -2
- package/dist/edge/index.mjs.map +1 -1
- package/dist/node/index.js +4 -3
- package/dist/node/index.mjs +3 -2
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.js
CHANGED
|
@@ -112,8 +112,9 @@ function toPlainText(html, options) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
//#endregion
|
|
115
|
-
//#region src/shared/error-boundary.
|
|
115
|
+
//#region src/shared/error-boundary.tsx
|
|
116
116
|
function createErrorBoundary(reject) {
|
|
117
|
+
if (!react.default.Component) return (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: props.children });
|
|
117
118
|
return class ErrorBoundary extends react.default.Component {
|
|
118
119
|
componentDidCatch(error) {
|
|
119
120
|
reject(error);
|
package/dist/browser/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import * as html from "prettier/plugins/html";
|
|
|
2
2
|
import { format } from "prettier/standalone";
|
|
3
3
|
import { convert } from "html-to-text";
|
|
4
4
|
import React, { Suspense } from "react";
|
|
5
|
-
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
6
6
|
|
|
7
7
|
//#region src/shared/utils/pretty.ts
|
|
8
8
|
function recursivelyMapDoc(doc, callback) {
|
|
@@ -84,8 +84,9 @@ function toPlainText(html$1, options) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
//#endregion
|
|
87
|
-
//#region src/shared/error-boundary.
|
|
87
|
+
//#region src/shared/error-boundary.tsx
|
|
88
88
|
function createErrorBoundary(reject) {
|
|
89
|
+
if (!React.Component) return (props) => /* @__PURE__ */ jsx(Fragment, { children: props.children });
|
|
89
90
|
return class ErrorBoundary extends React.Component {
|
|
90
91
|
componentDidCatch(error) {
|
|
91
92
|
reject(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","chunks: Uint8Array[]","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/error-boundary.
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","chunks: Uint8Array[]","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/error-boundary.tsx","../../src/shared/read-stream.browser.ts","../../src/browser/render.tsx"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type: 'element' | 'text' | 'ieConditionalComment';\n name?: string;\n sourceSpan: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nif (modifiedHtml.printers) {\n const previousPrint = modifiedHtml.printers.html.print;\n modifiedHtml.printers.html.print = (path, options, print, args) => {\n const node = path.getNode() as HtmlNode;\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (node.type === 'ieConditionalComment') {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n wordwrap: false,\n ...options,\n selectors: [...plainTextSelectors, ...(options?.selectors ?? [])],\n });\n}\n","import React from 'react';\n\nexport function createErrorBoundary(reject: (error: unknown) => void) {\n // React Server Components don't support React.Component, so it's just not defined here\n if (!React.Component) {\n return (props: { children?: React.ReactNode }) => <>{props.children}</>;\n }\n\n return class ErrorBoundary extends React.Component<{\n children: React.ReactNode;\n }> {\n componentDidCatch(error: unknown) {\n reject(error);\n }\n render() {\n return this.props.children;\n }\n };\n}\n","import type { ReactDOMServerReadableStream } from 'react-dom/server.browser';\n\nconst decoder = new TextDecoder('utf-8');\n\nexport const readStream = async (stream: ReactDOMServerReadableStream) => {\n const chunks: Uint8Array[] = [];\n\n const writableStream = new WritableStream({\n write(chunk: Uint8Array) {\n chunks.push(chunk);\n },\n abort(reason) {\n throw new Error('Stream aborted', {\n cause: {\n reason,\n },\n });\n },\n });\n await stream.pipeTo(writableStream);\n\n let length = 0;\n chunks.forEach((item) => {\n length += item.length;\n });\n const mergedChunks = new Uint8Array(length);\n let offset = 0;\n chunks.forEach((item) => {\n mergedChunks.set(item, offset);\n offset += item.length;\n });\n\n return decoder.decode(mergedChunks);\n};\n","import { Suspense } from 'react';\nimport { pretty, toPlainText } from '../node';\nimport { createErrorBoundary } from '../shared/error-boundary';\nimport type { Options } from '../shared/options';\nimport { readStream } from '../shared/read-stream.browser';\n\nexport const render = async (node: React.ReactNode, options?: Options) => {\n const reactDOMServer = await import('react-dom/server').then((m) => {\n if ('default' in m) {\n return m.default;\n }\n return m;\n });\n\n const html = await new Promise<string>((resolve, reject) => {\n const ErrorBoundary = createErrorBoundary(reject);\n reactDOMServer\n .renderToReadableStream(\n <Suspense>\n <ErrorBoundary>{node}</ErrorBoundary>\n </Suspense>,\n {\n onError(error: unknown) {\n reject(error);\n },\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n },\n )\n .then(readStream)\n .then(resolve)\n .catch(reject);\n });\n\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const doctype =\n '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">';\n\n const document = `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n};\n"],"mappings":"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"}
|
package/dist/edge/index.js
CHANGED
|
@@ -112,8 +112,9 @@ function toPlainText(html, options) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
//#endregion
|
|
115
|
-
//#region src/shared/error-boundary.
|
|
115
|
+
//#region src/shared/error-boundary.tsx
|
|
116
116
|
function createErrorBoundary(reject) {
|
|
117
|
+
if (!react.default.Component) return (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: props.children });
|
|
117
118
|
return class ErrorBoundary extends react.default.Component {
|
|
118
119
|
componentDidCatch(error) {
|
|
119
120
|
reject(error);
|
package/dist/edge/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import * as html from "prettier/plugins/html";
|
|
|
2
2
|
import { format } from "prettier/standalone";
|
|
3
3
|
import { convert } from "html-to-text";
|
|
4
4
|
import React, { Suspense } from "react";
|
|
5
|
-
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
6
6
|
|
|
7
7
|
//#region src/shared/utils/pretty.ts
|
|
8
8
|
function recursivelyMapDoc(doc, callback) {
|
|
@@ -84,8 +84,9 @@ function toPlainText(html$1, options) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
//#endregion
|
|
87
|
-
//#region src/shared/error-boundary.
|
|
87
|
+
//#region src/shared/error-boundary.tsx
|
|
88
88
|
function createErrorBoundary(reject) {
|
|
89
|
+
if (!React.Component) return (props) => /* @__PURE__ */ jsx(Fragment, { children: props.children });
|
|
89
90
|
return class ErrorBoundary extends React.Component {
|
|
90
91
|
componentDidCatch(error) {
|
|
91
92
|
reject(error);
|
package/dist/edge/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","chunks: Uint8Array[]","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/error-boundary.
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","chunks: Uint8Array[]","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/error-boundary.tsx","../../src/shared/read-stream.browser.ts","../../src/edge/import-react-dom.tsx","../../src/edge/render.tsx"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type: 'element' | 'text' | 'ieConditionalComment';\n name?: string;\n sourceSpan: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nif (modifiedHtml.printers) {\n const previousPrint = modifiedHtml.printers.html.print;\n modifiedHtml.printers.html.print = (path, options, print, args) => {\n const node = path.getNode() as HtmlNode;\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (node.type === 'ieConditionalComment') {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n wordwrap: false,\n ...options,\n selectors: [...plainTextSelectors, ...(options?.selectors ?? [])],\n });\n}\n","import React from 'react';\n\nexport function createErrorBoundary(reject: (error: unknown) => void) {\n // React Server Components don't support React.Component, so it's just not defined here\n if (!React.Component) {\n return (props: { children?: React.ReactNode }) => <>{props.children}</>;\n }\n\n return class ErrorBoundary extends React.Component<{\n children: React.ReactNode;\n }> {\n componentDidCatch(error: unknown) {\n reject(error);\n }\n render() {\n return this.props.children;\n }\n };\n}\n","import type { ReactDOMServerReadableStream } from 'react-dom/server.browser';\n\nconst decoder = new TextDecoder('utf-8');\n\nexport const readStream = async (stream: ReactDOMServerReadableStream) => {\n const chunks: Uint8Array[] = [];\n\n const writableStream = new WritableStream({\n write(chunk: Uint8Array) {\n chunks.push(chunk);\n },\n abort(reason) {\n throw new Error('Stream aborted', {\n cause: {\n reason,\n },\n });\n },\n });\n await stream.pipeTo(writableStream);\n\n let length = 0;\n chunks.forEach((item) => {\n length += item.length;\n });\n const mergedChunks = new Uint8Array(length);\n let offset = 0;\n chunks.forEach((item) => {\n mergedChunks.set(item, offset);\n offset += item.length;\n });\n\n return decoder.decode(mergedChunks);\n};\n","export const importReactDom = () => {\n // We don't use async here because tsup converts it to a generator syntax\n // that esbuild doesn't understand as dealing with the import failing during\n // bundling: https://github.com/evanw/esbuild/issues/3216#issuecomment-1628913722\n return import('react-dom/server.edge').catch(\n () =>\n // This ensures that we still have compatibility with React 18,\n // which doesn't have the `.edge` export.\n import('react-dom/server'),\n );\n};\n","import { Suspense } from 'react';\nimport { pretty } from '../node';\nimport { createErrorBoundary } from '../shared/error-boundary';\nimport type { Options } from '../shared/options';\nimport { readStream } from '../shared/read-stream.browser';\nimport { toPlainText } from '../shared/utils/to-plain-text';\nimport { importReactDom } from './import-react-dom';\n\nexport const render = async (\n element: React.ReactElement,\n options?: Options,\n) => {\n const reactDOMServer = await importReactDom().then((m) => {\n if ('default' in m) {\n return m.default;\n }\n\n return m;\n });\n\n const html = await new Promise<string>((resolve, reject) => {\n const ErrorBoundary = createErrorBoundary(reject);\n reactDOMServer\n .renderToReadableStream(\n <ErrorBoundary>\n <Suspense>{element}</Suspense>\n </ErrorBoundary>,\n {\n onError(error: unknown) {\n reject(error);\n },\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n },\n )\n .then(readStream)\n .then(resolve)\n .catch(reject);\n });\n\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const doctype =\n '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">';\n\n const document = `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n};\n"],"mappings":";;;;;;;AAgBA,SAAS,kBACP,KACA,UACc;AACd,KAAI,MAAM,QAAQ,IAAI,CACpB,QAAO,IAAI,KAAK,aAAa,kBAAkB,UAAU,SAAS,CAAC;AAGrE,KAAI,OAAO,QAAQ,UAAU;AAC3B,MAAI,IAAI,SAAS,QACf,QAAO;GACL,GAAG;GACH,UAAU,kBAAkB,IAAI,UAAU,SAAS;GACnD,gBAAgB,kBACd,IAAI,gBACJ,SACD;GACF;AAGH,MAAI,cAAc,IAChB,QAAO;GACL,GAAG;GACH,UAAU,kBAAkB,IAAI,UAAU,SAAS;GACpD;AAGH,MAAI,WAAW,IACb,QAAO;GACL,GAAG;GACH,OAAO,kBAAkB,IAAI,OAAO,SAAS;GAC9C;AAGH,MAAI,IAAI,SAAS,WACf,QAAO;GACL,GAAG;GACH,eAAe,kBAAkB,IAAI,eAAe,SAAS;GAC7D,cAAc,kBAAkB,IAAI,cAAc,SAAS;GAC5D;;AAIL,QAAO,SAAS,IAAI;;AAGtB,MAAM,eAAe,EAAE,GAAG,MAAM;AAChC,IAAI,aAAa,UAAU;CACzB,MAAM,gBAAgB,aAAa,SAAS,KAAK;AACjD,cAAa,SAAS,KAAK,SAAS,MAAM,SAAS,OAAO,SAAS;EACjE,MAAM,OAAO,KAAK,SAAS;EAE3B,MAAM,oBAAoB,cAAc,MAAM,SAAS,OAAO,KAAK;AAEnE,MAAI,KAAK,SAAS,uBAShB,QARuB,kBAAkB,oBAAoB,QAAQ;AACnE,OAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,OAC1C,QAAO,IAAI,OAAO,KAAK;AAGzB,UAAO;IACP;AAKJ,SAAO;;;AAIX,MAAMA,WAAoB;CACxB,WAAW;CACX,UAAU;CACV,SAAS,CAAC,aAAa;CACvB,iBAAiB;CACjB,QAAQ;CACT;AAED,MAAa,UAAU,KAAa,UAAmB,EAAE,KAAK;AAC5D,QAAO,OAAO,IAAI,WAAW,MAAM,GAAG,EAAE;EACtC,GAAG;EACH,GAAG;EACJ,CAAC;;;;;AC5FJ,MAAaC,qBAA2C;CACtD;EAAE,UAAU;EAAO,QAAQ;EAAQ;CACnC;EAAE,UAAU;EAA4B,QAAQ;EAAQ;CACxD;EACE,UAAU;EACV,SAAS;GAAE,cAAc;GAAO,0BAA0B;GAAM;EACjE;CACF;AAED,SAAgB,YAAY,QAAc,SAA6B;AACrE,QAAO,QAAQC,QAAM;EACnB,UAAU;EACV,GAAG;EACH,WAAW,CAAC,GAAG,oBAAoB,GAAI,SAAS,aAAa,EAAE,CAAE;EAClE,CAAC;;;;;AClBJ,SAAgB,oBAAoB,QAAkC;AAEpE,KAAI,CAAC,MAAM,UACT,SAAQ,UAA0C,0CAAG,MAAM,WAAY;AAGzE,QAAO,MAAM,sBAAsB,MAAM,UAEtC;EACD,kBAAkB,OAAgB;AAChC,UAAO,MAAM;;EAEf,SAAS;AACP,UAAO,KAAK,MAAM;;;;;;;ACbxB,MAAM,UAAU,IAAI,YAAY,QAAQ;AAExC,MAAa,aAAa,OAAO,WAAyC;CACxE,MAAMC,SAAuB,EAAE;CAE/B,MAAM,iBAAiB,IAAI,eAAe;EACxC,MAAM,OAAmB;AACvB,UAAO,KAAK,MAAM;;EAEpB,MAAM,QAAQ;AACZ,SAAM,IAAI,MAAM,kBAAkB,EAChC,OAAO,EACL,QACD,EACF,CAAC;;EAEL,CAAC;AACF,OAAM,OAAO,OAAO,eAAe;CAEnC,IAAI,SAAS;AACb,QAAO,SAAS,SAAS;AACvB,YAAU,KAAK;GACf;CACF,MAAM,eAAe,IAAI,WAAW,OAAO;CAC3C,IAAI,SAAS;AACb,QAAO,SAAS,SAAS;AACvB,eAAa,IAAI,MAAM,OAAO;AAC9B,YAAU,KAAK;GACf;AAEF,QAAO,QAAQ,OAAO,aAAa;;;;;AChCrC,MAAa,uBAAuB;AAIlC,QAAO,OAAO,yBAAyB,YAInC,OAAO,oBACV;;;;;ACDH,MAAa,SAAS,OACpB,SACA,YACG;CACH,MAAM,iBAAiB,MAAM,gBAAgB,CAAC,MAAM,MAAM;AACxD,MAAI,aAAa,EACf,QAAO,EAAE;AAGX,SAAO;GACP;CAEF,MAAMC,SAAO,MAAM,IAAI,SAAiB,SAAS,WAAW;EAC1D,MAAM,gBAAgB,oBAAoB,OAAO;AACjD,iBACG,uBACC,oBAAC,2BACC,oBAAC,sBAAU,UAAmB,GAChB,EAChB;GACE,QAAQ,OAAgB;AACtB,WAAO,MAAM;;GAEf,sBAAsB,OAAO;GAC9B,CACF,CACA,KAAK,WAAW,CAChB,KAAK,QAAQ,CACb,MAAM,OAAO;GAChB;AAEF,KAAI,SAAS,UACX,QAAO,YAAYA,QAAM,QAAQ,kBAAkB;CAMrD,MAAM,WAAW,4HAAaA,OAAK,QAAQ,iBAAiB,GAAG;AAE/D,KAAI,SAAS,OACX,QAAO,OAAO,SAAS;AAGzB,QAAO"}
|
package/dist/node/index.js
CHANGED
|
@@ -29,10 +29,10 @@ let html_to_text = require("html-to-text");
|
|
|
29
29
|
html_to_text = __toESM(html_to_text);
|
|
30
30
|
let react = require("react");
|
|
31
31
|
react = __toESM(react);
|
|
32
|
-
let node_stream = require("node:stream");
|
|
33
|
-
node_stream = __toESM(node_stream);
|
|
34
32
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
35
33
|
react_jsx_runtime = __toESM(react_jsx_runtime);
|
|
34
|
+
let node_stream = require("node:stream");
|
|
35
|
+
node_stream = __toESM(node_stream);
|
|
36
36
|
|
|
37
37
|
//#region src/shared/utils/pretty.ts
|
|
38
38
|
function recursivelyMapDoc(doc, callback) {
|
|
@@ -114,8 +114,9 @@ function toPlainText(html, options) {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
//#endregion
|
|
117
|
-
//#region src/shared/error-boundary.
|
|
117
|
+
//#region src/shared/error-boundary.tsx
|
|
118
118
|
function createErrorBoundary(reject) {
|
|
119
|
+
if (!react.default.Component) return (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: props.children });
|
|
119
120
|
return class ErrorBoundary extends react.default.Component {
|
|
120
121
|
componentDidCatch(error) {
|
|
121
122
|
reject(error);
|
package/dist/node/index.mjs
CHANGED
|
@@ -2,8 +2,8 @@ import * as html from "prettier/plugins/html";
|
|
|
2
2
|
import { format } from "prettier/standalone";
|
|
3
3
|
import { convert } from "html-to-text";
|
|
4
4
|
import React, { Suspense } from "react";
|
|
5
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
5
6
|
import { Writable } from "node:stream";
|
|
6
|
-
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
|
|
8
8
|
//#region src/shared/utils/pretty.ts
|
|
9
9
|
function recursivelyMapDoc(doc, callback) {
|
|
@@ -85,8 +85,9 @@ function toPlainText(html$1, options) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
//#endregion
|
|
88
|
-
//#region src/shared/error-boundary.
|
|
88
|
+
//#region src/shared/error-boundary.tsx
|
|
89
89
|
function createErrorBoundary(reject) {
|
|
90
|
+
if (!React.Component) return (props) => /* @__PURE__ */ jsx(Fragment, { children: props.children });
|
|
90
91
|
return class ErrorBoundary extends React.Component {
|
|
91
92
|
componentDidCatch(error) {
|
|
92
93
|
reject(error);
|
package/dist/node/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","html!: string","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/error-boundary.ts","../../src/node/read-stream.ts","../../src/node/render.tsx"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type: 'element' | 'text' | 'ieConditionalComment';\n name?: string;\n sourceSpan: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nif (modifiedHtml.printers) {\n const previousPrint = modifiedHtml.printers.html.print;\n modifiedHtml.printers.html.print = (path, options, print, args) => {\n const node = path.getNode() as HtmlNode;\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (node.type === 'ieConditionalComment') {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n wordwrap: false,\n ...options,\n selectors: [...plainTextSelectors, ...(options?.selectors ?? [])],\n });\n}\n","import React from 'react';\n\nexport function createErrorBoundary(reject: (error: unknown) => void) {\n return class ErrorBoundary extends React.Component<{\n children: React.ReactNode;\n }> {\n componentDidCatch(error: unknown) {\n reject(error);\n }\n render() {\n return this.props.children;\n }\n };\n}\n","import { Writable } from 'node:stream';\nimport type {\n PipeableStream,\n ReactDOMServerReadableStream,\n} from 'react-dom/server.browser';\n\nexport const readStream = async (\n stream: PipeableStream | ReactDOMServerReadableStream,\n) => {\n let result = '';\n // Create a single TextDecoder instance to handle streaming properly\n // This fixes issues with multi-byte characters (e.g., CJK) being split across chunks\n const decoder = new TextDecoder('utf-8');\n\n if ('pipeTo' in stream) {\n // means it's a readable stream\n const writableStream = new WritableStream({\n write(chunk: BufferSource) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n },\n close() {\n // Flush any remaining bytes\n result += decoder.decode();\n },\n });\n await stream.pipeTo(writableStream);\n } else {\n const writable = new Writable({\n write(chunk: BufferSource, _encoding, callback) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n\n callback();\n },\n final(callback) {\n // Flush any remaining bytes\n result += decoder.decode();\n callback();\n },\n });\n await new Promise<void>((resolve, reject) => {\n writable.on('pipe', (source) => {\n source.on('error', (err: Error) => {\n writable.destroy(err);\n });\n });\n writable.on('error', reject);\n writable.on('close', () => {\n resolve();\n });\n\n stream.pipe(writable);\n });\n }\n\n return result;\n};\n","import { Suspense } from 'react';\nimport { createErrorBoundary } from '../shared/error-boundary';\nimport type { Options } from '../shared/options';\nimport { pretty } from '../shared/utils/pretty';\nimport { toPlainText } from '../shared/utils/to-plain-text';\nimport { readStream } from './read-stream';\n\nexport const render = async (node: React.ReactNode, options?: Options) => {\n const reactDOMServer = await import('react-dom/server').then((m) => {\n if ('default' in m) {\n return m.default;\n }\n return m;\n });\n\n let html!: string;\n await new Promise<void>((resolve, reject) => {\n if (\n Object.hasOwn(reactDOMServer, 'renderToReadableStream') &&\n typeof WritableStream !== 'undefined'\n ) {\n const ErrorBoundary = createErrorBoundary(reject);\n reactDOMServer\n .renderToReadableStream(\n <ErrorBoundary>\n <Suspense>{node}</Suspense>\n </ErrorBoundary>,\n {\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n onError(error) {\n // Throw immediately when an error occurs to prevent CSR fallback\n throw error;\n },\n },\n )\n .then((stream) => readStream(stream))\n .then((result) => {\n html = result;\n resolve();\n })\n .catch(reject);\n } else {\n const ErrorBoundary = createErrorBoundary(reject);\n const stream = reactDOMServer.renderToPipeableStream(\n <ErrorBoundary>\n <Suspense>{node}</Suspense>\n </ErrorBoundary>,\n {\n async onAllReady() {\n html = await readStream(stream);\n resolve();\n },\n onError(error) {\n reject(error);\n },\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n },\n );\n }\n });\n\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const doctype =\n '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">';\n\n const document = `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","html!: string","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/error-boundary.tsx","../../src/node/read-stream.ts","../../src/node/render.tsx"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type: 'element' | 'text' | 'ieConditionalComment';\n name?: string;\n sourceSpan: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nif (modifiedHtml.printers) {\n const previousPrint = modifiedHtml.printers.html.print;\n modifiedHtml.printers.html.print = (path, options, print, args) => {\n const node = path.getNode() as HtmlNode;\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (node.type === 'ieConditionalComment') {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n wordwrap: false,\n ...options,\n selectors: [...plainTextSelectors, ...(options?.selectors ?? [])],\n });\n}\n","import React from 'react';\n\nexport function createErrorBoundary(reject: (error: unknown) => void) {\n // React Server Components don't support React.Component, so it's just not defined here\n if (!React.Component) {\n return (props: { children?: React.ReactNode }) => <>{props.children}</>;\n }\n\n return class ErrorBoundary extends React.Component<{\n children: React.ReactNode;\n }> {\n componentDidCatch(error: unknown) {\n reject(error);\n }\n render() {\n return this.props.children;\n }\n };\n}\n","import { Writable } from 'node:stream';\nimport type {\n PipeableStream,\n ReactDOMServerReadableStream,\n} from 'react-dom/server.browser';\n\nexport const readStream = async (\n stream: PipeableStream | ReactDOMServerReadableStream,\n) => {\n let result = '';\n // Create a single TextDecoder instance to handle streaming properly\n // This fixes issues with multi-byte characters (e.g., CJK) being split across chunks\n const decoder = new TextDecoder('utf-8');\n\n if ('pipeTo' in stream) {\n // means it's a readable stream\n const writableStream = new WritableStream({\n write(chunk: BufferSource) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n },\n close() {\n // Flush any remaining bytes\n result += decoder.decode();\n },\n });\n await stream.pipeTo(writableStream);\n } else {\n const writable = new Writable({\n write(chunk: BufferSource, _encoding, callback) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n\n callback();\n },\n final(callback) {\n // Flush any remaining bytes\n result += decoder.decode();\n callback();\n },\n });\n await new Promise<void>((resolve, reject) => {\n writable.on('pipe', (source) => {\n source.on('error', (err: Error) => {\n writable.destroy(err);\n });\n });\n writable.on('error', reject);\n writable.on('close', () => {\n resolve();\n });\n\n stream.pipe(writable);\n });\n }\n\n return result;\n};\n","import { Suspense } from 'react';\nimport { createErrorBoundary } from '../shared/error-boundary';\nimport type { Options } from '../shared/options';\nimport { pretty } from '../shared/utils/pretty';\nimport { toPlainText } from '../shared/utils/to-plain-text';\nimport { readStream } from './read-stream';\n\nexport const render = async (node: React.ReactNode, options?: Options) => {\n const reactDOMServer = await import('react-dom/server').then((m) => {\n if ('default' in m) {\n return m.default;\n }\n return m;\n });\n\n let html!: string;\n await new Promise<void>((resolve, reject) => {\n if (\n Object.hasOwn(reactDOMServer, 'renderToReadableStream') &&\n typeof WritableStream !== 'undefined'\n ) {\n const ErrorBoundary = createErrorBoundary(reject);\n reactDOMServer\n .renderToReadableStream(\n <ErrorBoundary>\n <Suspense>{node}</Suspense>\n </ErrorBoundary>,\n {\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n onError(error) {\n // Throw immediately when an error occurs to prevent CSR fallback\n throw error;\n },\n },\n )\n .then((stream) => readStream(stream))\n .then((result) => {\n html = result;\n resolve();\n })\n .catch(reject);\n } else {\n const ErrorBoundary = createErrorBoundary(reject);\n const stream = reactDOMServer.renderToPipeableStream(\n <ErrorBoundary>\n <Suspense>{node}</Suspense>\n </ErrorBoundary>,\n {\n async onAllReady() {\n html = await readStream(stream);\n resolve();\n },\n onError(error) {\n reject(error);\n },\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n },\n );\n }\n });\n\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const doctype =\n '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">';\n\n const document = `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n};\n"],"mappings":"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"}
|