Skip to content

Commit 82f10c2

Browse files
committed
refactor: code style
1 parent 5b1ad7b commit 82f10c2

File tree

12 files changed

+172
-154
lines changed

12 files changed

+172
-154
lines changed

src/applyStyleWithOptions.ts renamed to src/applyStyleFromOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Options } from './options'
22

3-
export function applyStyleWithOptions<T extends HTMLElement>(
3+
export function applyStyleFromOptions<T extends HTMLElement>(
44
node: T,
55
options: Options,
66
): T {

src/cloneNode.ts

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,23 @@ import { getBlobFromURL } from './getBlobFromURL'
33
import { clonePseudoElements } from './clonePseudoElements'
44
import { createImage, getMimeType, makeDataUrl, toArray } from './util'
55

6-
async function cloneCanvasElement(node: HTMLCanvasElement) {
7-
const dataURL = node.toDataURL()
6+
async function cloneCanvasElement(canvas: HTMLCanvasElement) {
7+
const dataURL = canvas.toDataURL()
88
if (dataURL === 'data:,') {
9-
return Promise.resolve(node.cloneNode(false) as HTMLCanvasElement)
9+
return canvas.cloneNode(false) as HTMLCanvasElement
1010
}
1111

1212
return createImage(dataURL)
1313
}
1414

15-
async function cloneVideoElement(node: HTMLVideoElement, options: Options) {
16-
return Promise.resolve(node.poster)
17-
.then((url) => getBlobFromURL(url, options))
18-
.then((data) =>
19-
makeDataUrl(data.blob, getMimeType(node.poster) || data.contentType),
20-
)
21-
.then((dataURL) => createImage(dataURL))
15+
async function cloneVideoElement(video: HTMLVideoElement, options: Options) {
16+
const poster = video.poster
17+
const metadata = await getBlobFromURL(poster, options)
18+
const dataURL = makeDataUrl(
19+
metadata.blob,
20+
getMimeType(poster) || metadata.contentType,
21+
)
22+
return createImage(dataURL)
2223
}
2324

2425
async function cloneSingleNode<T extends HTMLElement>(
@@ -33,7 +34,7 @@ async function cloneSingleNode<T extends HTMLElement>(
3334
return cloneVideoElement(node, options)
3435
}
3536

36-
return Promise.resolve(node.cloneNode(false) as T)
37+
return node.cloneNode(false) as T
3738
}
3839

3940
const isSlotElement = (node: HTMLElement): node is HTMLSlotElement =>
@@ -50,17 +51,15 @@ async function cloneChildren<T extends HTMLElement>(
5051
: toArray<T>((nativeNode.shadowRoot ?? nativeNode).childNodes)
5152

5253
if (children.length === 0 || nativeNode instanceof HTMLVideoElement) {
53-
return Promise.resolve(clonedNode)
54+
return clonedNode
5455
}
5556

5657
return children
5758
.reduce(
5859
(deferred, child) =>
5960
deferred
60-
// eslint-disable-next-line no-use-before-define
6161
.then(() => cloneNode(child, options))
6262
.then((clonedChild: HTMLElement | null) => {
63-
// eslint-disable-next-line promise/always-return
6463
if (clonedChild) {
6564
clonedNode.appendChild(clonedChild)
6665
}
@@ -71,26 +70,29 @@ async function cloneChildren<T extends HTMLElement>(
7170
}
7271

7372
function cloneCSSStyle<T extends HTMLElement>(nativeNode: T, clonedNode: T) {
74-
const source = window.getComputedStyle(nativeNode)
75-
const target = clonedNode.style
73+
const sourceStyle = window.getComputedStyle(nativeNode)
74+
const targetStyle = clonedNode.style
7675

77-
if (!target) {
76+
if (!targetStyle) {
7877
return
7978
}
8079

81-
if (source.cssText) {
82-
target.cssText = source.cssText
83-
target.transformOrigin = source.transformOrigin
80+
if (sourceStyle.cssText) {
81+
targetStyle.cssText = sourceStyle.cssText
82+
targetStyle.transformOrigin = sourceStyle.transformOrigin
8483
} else {
85-
toArray<string>(source).forEach((name) => {
86-
let value = source.getPropertyValue(name)
87-
84+
toArray<string>(sourceStyle).forEach((name) => {
85+
let value = sourceStyle.getPropertyValue(name)
8886
if (name === 'font-size' && value.endsWith('px')) {
8987
const reducedFont =
9088
Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1
9189
value = `${reducedFont}px`
9290
}
93-
target.setProperty(name, value, source.getPropertyPriority(name))
91+
targetStyle.setProperty(
92+
name,
93+
value,
94+
sourceStyle.getPropertyPriority(name),
95+
)
9496
})
9597
}
9698
}
@@ -118,20 +120,17 @@ function cloneSelectValue<T extends HTMLElement>(nativeNode: T, clonedNode: T) {
118120
}
119121
}
120122

121-
async function decorate<T extends HTMLElement>(
122-
nativeNode: T,
123-
clonedNode: T,
124-
): Promise<T> {
123+
function decorate<T extends HTMLElement>(nativeNode: T, clonedNode: T): T {
125124
if (!(clonedNode instanceof Element)) {
126-
return Promise.resolve(clonedNode)
125+
return clonedNode
127126
}
128127

129-
return Promise.resolve()
130-
.then(() => cloneCSSStyle(nativeNode, clonedNode))
131-
.then(() => clonePseudoElements(nativeNode, clonedNode))
132-
.then(() => cloneInputValue(nativeNode, clonedNode))
133-
.then(() => cloneSelectValue(nativeNode, clonedNode))
134-
.then(() => clonedNode)
128+
cloneCSSStyle(nativeNode, clonedNode)
129+
clonePseudoElements(nativeNode, clonedNode)
130+
cloneInputValue(nativeNode, clonedNode)
131+
cloneSelectValue(nativeNode, clonedNode)
132+
133+
return clonedNode
135134
}
136135

137136
export async function cloneNode<T extends HTMLElement>(
@@ -140,7 +139,7 @@ export async function cloneNode<T extends HTMLElement>(
140139
isRoot?: boolean,
141140
): Promise<T | null> {
142141
if (!isRoot && options.filter && !options.filter(node)) {
143-
return Promise.resolve(null)
142+
return null
144143
}
145144

146145
return Promise.resolve(node)

src/embedImages.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ async function embedBackground<T extends HTMLElement>(
99
): Promise<T> {
1010
const background = clonedNode.style?.getPropertyValue('background')
1111
if (!background) {
12-
return Promise.resolve(clonedNode)
12+
return clonedNode
1313
}
1414

1515
return Promise.resolve(background)

src/embedResources.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,15 @@ export async function embedResources(
8585
options: Options,
8686
): Promise<string> {
8787
if (!shouldEmbed(cssText)) {
88-
return Promise.resolve(cssText)
88+
return cssText
8989
}
9090

9191
const filteredCSSText = filterPreferredFontFormat(cssText, options)
92-
return Promise.resolve(filteredCSSText)
93-
.then(parseURLs)
94-
.then((urls) =>
95-
urls.reduce(
96-
(deferred, url) =>
97-
// eslint-disable-next-line promise/no-nesting
98-
deferred.then((css) => embed(css, url, baseUrl, options)),
99-
Promise.resolve(filteredCSSText),
100-
),
101-
)
92+
const urls = parseURLs(filteredCSSText)
93+
return urls.reduce(
94+
(deferred, url) =>
95+
// eslint-disable-next-line promise/no-nesting
96+
deferred.then((css) => embed(css, url, baseUrl, options)),
97+
Promise.resolve(filteredCSSText),
98+
)
10299
}

src/getBlobFromURL.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ export interface Metadata {
66
contentType: string
77
}
88

9-
const cache: {
10-
[url: string]: Promise<Metadata>
11-
} = {}
9+
const cache: { [url: string]: Promise<Metadata> } = {}
1210

1311
function getCacheKey(url: string, includeQueryParams: boolean | undefined) {
1412
let key = url.replace(/\?.*/, '')
@@ -25,7 +23,7 @@ function getCacheKey(url: string, includeQueryParams: boolean | undefined) {
2523
return key
2624
}
2725

28-
export function getBlobFromURL(
26+
export async function getBlobFromURL(
2927
url: string,
3028
options: Options,
3129
): Promise<Metadata> {

src/index.ts

Lines changed: 40 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,96 @@
11
import { Options } from './options'
22
import { cloneNode } from './cloneNode'
33
import { embedImages } from './embedImages'
4-
import { applyStyleWithOptions } from './applyStyleWithOptions'
4+
import { applyStyleFromOptions } from './applyStyleFromOptions'
55
import { embedWebFonts, getWebFontCSS } from './embedWebFonts'
66
import {
7-
getNodeWidth,
8-
getNodeHeight,
7+
getImageSize,
98
getPixelRatio,
109
createImage,
1110
canvasToBlob,
1211
nodeToDataURL,
12+
checkCanvasDimensions,
1313
} from './util'
1414

15-
function getImageSize(node: HTMLElement, options: Options = {}) {
16-
const width = options.width || getNodeWidth(node)
17-
const height = options.height || getNodeHeight(node)
18-
19-
return { width, height }
20-
}
21-
2215
export async function toSvg<T extends HTMLElement>(
2316
node: T,
2417
options: Options = {},
2518
): Promise<string> {
2619
const { width, height } = getImageSize(node, options)
27-
28-
return Promise.resolve(node)
29-
.then((nativeNode) => cloneNode(nativeNode, options, true))
30-
.then((clonedNode) => embedWebFonts(clonedNode!, options))
31-
.then((clonedNode) => embedImages(clonedNode, options))
32-
.then((clonedNode) => applyStyleWithOptions(clonedNode, options))
33-
.then((clonedNode) => nodeToDataURL(clonedNode, width, height))
20+
const clonedNode = (await cloneNode(node, options, true)) as HTMLElement
21+
await embedWebFonts(clonedNode, options)
22+
await embedImages(clonedNode, options)
23+
applyStyleFromOptions(clonedNode, options)
24+
const datauri = await nodeToDataURL(clonedNode, width, height)
25+
return datauri
3426
}
3527

36-
const dimensionCanvasLimit = 16384 // as per https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size
37-
38-
function checkCanvasDimensions(canvas: HTMLCanvasElement) {
39-
if (
40-
canvas.width > dimensionCanvasLimit ||
41-
canvas.height > dimensionCanvasLimit
42-
) {
43-
if (
44-
canvas.width > dimensionCanvasLimit &&
45-
canvas.height > dimensionCanvasLimit
46-
) {
47-
if (canvas.width > canvas.height) {
48-
canvas.height *= dimensionCanvasLimit / canvas.width
49-
canvas.width = dimensionCanvasLimit
50-
} else {
51-
canvas.width *= dimensionCanvasLimit / canvas.height
52-
canvas.height = dimensionCanvasLimit
53-
}
54-
} else if (canvas.width > dimensionCanvasLimit) {
55-
canvas.height *= dimensionCanvasLimit / canvas.width
56-
canvas.width = dimensionCanvasLimit
57-
} else {
58-
canvas.width *= dimensionCanvasLimit / canvas.height
59-
canvas.height = dimensionCanvasLimit
60-
}
61-
}
62-
}
6328
export async function toCanvas<T extends HTMLElement>(
6429
node: T,
6530
options: Options = {},
6631
): Promise<HTMLCanvasElement> {
67-
return toSvg(node, options)
68-
.then(createImage)
69-
.then((img) => {
70-
const canvas = document.createElement('canvas')
71-
const context = canvas.getContext('2d')!
72-
const ratio = options.pixelRatio || getPixelRatio()
73-
const { width, height } = getImageSize(node, options)
32+
const svg = await toSvg(node, options)
33+
const img = await createImage(svg)
7434

75-
const canvasWidth = options.canvasWidth || width
76-
const canvasHeight = options.canvasHeight || height
35+
const canvas = document.createElement('canvas')
36+
const context = canvas.getContext('2d')!
37+
const ratio = options.pixelRatio || getPixelRatio()
38+
const { width, height } = getImageSize(node, options)
39+
const canvasWidth = options.canvasWidth || width
40+
const canvasHeight = options.canvasHeight || height
7741

78-
canvas.width = canvasWidth * ratio
79-
canvas.height = canvasHeight * ratio
42+
canvas.width = canvasWidth * ratio
43+
canvas.height = canvasHeight * ratio
8044

81-
if (!options.skipAutoScale) {
82-
checkCanvasDimensions(canvas)
83-
}
84-
canvas.style.width = `${canvasWidth}`
85-
canvas.style.height = `${canvasHeight}`
45+
if (!options.skipAutoScale) {
46+
checkCanvasDimensions(canvas)
47+
}
48+
canvas.style.width = `${canvasWidth}`
49+
canvas.style.height = `${canvasHeight}`
8650

87-
if (options.backgroundColor) {
88-
context.fillStyle = options.backgroundColor
89-
context.fillRect(0, 0, canvas.width, canvas.height)
90-
}
51+
if (options.backgroundColor) {
52+
context.fillStyle = options.backgroundColor
53+
context.fillRect(0, 0, canvas.width, canvas.height)
54+
}
9155

92-
context.drawImage(img, 0, 0, canvas.width, canvas.height)
56+
context.drawImage(img, 0, 0, canvas.width, canvas.height)
9357

94-
return canvas
95-
})
58+
return canvas
9659
}
9760

9861
export async function toPixelData<T extends HTMLElement>(
9962
node: T,
10063
options: Options = {},
10164
): Promise<Uint8ClampedArray> {
10265
const { width, height } = getImageSize(node, options)
103-
return toCanvas(node, options).then((canvas) => {
104-
const ctx = canvas.getContext('2d')!
105-
return ctx.getImageData(0, 0, width, height).data
106-
})
66+
const canvas = await toCanvas(node, options)
67+
const ctx = canvas.getContext('2d')!
68+
return ctx.getImageData(0, 0, width, height).data
10769
}
10870

10971
export async function toPng<T extends HTMLElement>(
11072
node: T,
11173
options: Options = {},
11274
): Promise<string> {
113-
return toCanvas(node, options).then((canvas) => canvas.toDataURL())
75+
const canvas = await toCanvas(node, options)
76+
return canvas.toDataURL()
11477
}
11578

11679
export async function toJpeg<T extends HTMLElement>(
11780
node: T,
11881
options: Options = {},
11982
): Promise<string> {
120-
return toCanvas(node, options).then((canvas) =>
121-
canvas.toDataURL('image/jpeg', options.quality || 1),
122-
)
83+
const canvas = await toCanvas(node, options)
84+
return canvas.toDataURL('image/jpeg', options.quality || 1)
12385
}
12486

12587
export async function toBlob<T extends HTMLElement>(
12688
node: T,
12789
options: Options = {},
12890
): Promise<Blob | null> {
129-
return toCanvas(node, options).then(canvasToBlob)
91+
const canvas = await toCanvas(node, options)
92+
const blob = await canvasToBlob(canvas)
93+
return blob
13094
}
13195

13296
export async function getFontEmbedCSS<T extends HTMLElement>(

0 commit comments

Comments
 (0)