htmlnano 3.1.0 → 3.2.1

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.
Files changed (88) hide show
  1. package/README.md +37 -23
  2. package/dist/_modules/collapseAttributeWhitespace.d.mts +58 -14
  3. package/dist/_modules/collapseAttributeWhitespace.d.ts +58 -14
  4. package/dist/_modules/collapseBooleanAttributes.d.mts +58 -14
  5. package/dist/_modules/collapseBooleanAttributes.d.ts +58 -14
  6. package/dist/_modules/collapseWhitespace.d.mts +58 -14
  7. package/dist/_modules/collapseWhitespace.d.ts +58 -14
  8. package/dist/_modules/custom.d.mts +58 -14
  9. package/dist/_modules/custom.d.ts +58 -14
  10. package/dist/_modules/deduplicateAttributeValues.d.mts +58 -14
  11. package/dist/_modules/deduplicateAttributeValues.d.ts +58 -14
  12. package/dist/_modules/example.d.mts +58 -14
  13. package/dist/_modules/example.d.ts +58 -14
  14. package/dist/_modules/mergeScripts.d.mts +58 -14
  15. package/dist/_modules/mergeScripts.d.ts +58 -14
  16. package/dist/_modules/mergeScripts.js +30 -23
  17. package/dist/_modules/mergeScripts.mjs +30 -23
  18. package/dist/_modules/mergeStyles.d.mts +58 -14
  19. package/dist/_modules/mergeStyles.d.ts +58 -14
  20. package/dist/_modules/mergeStyles.js +26 -21
  21. package/dist/_modules/mergeStyles.mjs +26 -21
  22. package/dist/_modules/minifyAttributes.d.mts +58 -14
  23. package/dist/_modules/minifyAttributes.d.ts +58 -14
  24. package/dist/_modules/minifyAttributes.js +2 -2
  25. package/dist/_modules/minifyAttributes.mjs +2 -2
  26. package/dist/_modules/minifyConditionalComments.d.mts +58 -14
  27. package/dist/_modules/minifyConditionalComments.d.ts +58 -14
  28. package/dist/_modules/minifyCss.d.mts +61 -14
  29. package/dist/_modules/minifyCss.d.ts +61 -14
  30. package/dist/_modules/minifyCss.js +79 -12
  31. package/dist/_modules/minifyCss.mjs +79 -13
  32. package/dist/_modules/minifyHtmlTemplate.d.mts +58 -14
  33. package/dist/_modules/minifyHtmlTemplate.d.ts +58 -14
  34. package/dist/_modules/minifyJs.d.mts +58 -13
  35. package/dist/_modules/minifyJs.d.ts +58 -13
  36. package/dist/_modules/minifyJs.js +12 -0
  37. package/dist/_modules/minifyJs.mjs +12 -0
  38. package/dist/_modules/minifyJson.d.mts +58 -14
  39. package/dist/_modules/minifyJson.d.ts +58 -14
  40. package/dist/_modules/minifyJson.js +1 -1
  41. package/dist/_modules/minifyJson.mjs +1 -1
  42. package/dist/_modules/minifySvg.d.mts +58 -13
  43. package/dist/_modules/minifySvg.d.ts +58 -13
  44. package/dist/_modules/minifySvg.js +2 -2
  45. package/dist/_modules/minifySvg.mjs +2 -2
  46. package/dist/_modules/minifyUrls.d.mts +58 -14
  47. package/dist/_modules/minifyUrls.d.ts +58 -14
  48. package/dist/_modules/minifyUrls.js +2 -2
  49. package/dist/_modules/minifyUrls.mjs +2 -2
  50. package/dist/_modules/normalizeAttributeValues.d.mts +58 -14
  51. package/dist/_modules/normalizeAttributeValues.d.ts +58 -14
  52. package/dist/_modules/removeAttributeQuotes.d.mts +58 -14
  53. package/dist/_modules/removeAttributeQuotes.d.ts +58 -14
  54. package/dist/_modules/removeComments.d.mts +58 -14
  55. package/dist/_modules/removeComments.d.ts +58 -14
  56. package/dist/_modules/removeComments.js +1 -1
  57. package/dist/_modules/removeComments.mjs +1 -1
  58. package/dist/_modules/removeEmptyAttributes.d.mts +58 -14
  59. package/dist/_modules/removeEmptyAttributes.d.ts +58 -14
  60. package/dist/_modules/removeEmptyElements.d.mts +58 -14
  61. package/dist/_modules/removeEmptyElements.d.ts +58 -14
  62. package/dist/_modules/removeOptionalTags.d.mts +58 -14
  63. package/dist/_modules/removeOptionalTags.d.ts +58 -14
  64. package/dist/_modules/removeRedundantAttributes.d.mts +58 -14
  65. package/dist/_modules/removeRedundantAttributes.d.ts +58 -14
  66. package/dist/_modules/removeUnusedCss.d.mts +58 -14
  67. package/dist/_modules/removeUnusedCss.d.ts +58 -14
  68. package/dist/_modules/removeUnusedCss.js +3 -2
  69. package/dist/_modules/removeUnusedCss.mjs +3 -2
  70. package/dist/_modules/sortAttributes.d.mts +61 -16
  71. package/dist/_modules/sortAttributes.d.ts +61 -16
  72. package/dist/_modules/sortAttributes.js +5 -9
  73. package/dist/_modules/sortAttributes.mjs +5 -9
  74. package/dist/_modules/sortAttributesWithLists.d.mts +61 -15
  75. package/dist/_modules/sortAttributesWithLists.d.ts +61 -15
  76. package/dist/_modules/sortAttributesWithLists.js +43 -56
  77. package/dist/_modules/sortAttributesWithLists.mjs +43 -56
  78. package/dist/index.d.ts +59 -15
  79. package/dist/index.js +7 -6
  80. package/dist/index.mjs +7 -6
  81. package/dist/presets/ampSafe.d.ts +57 -12
  82. package/dist/presets/max.d.ts +57 -12
  83. package/dist/presets/max.js +9 -5
  84. package/dist/presets/max.mjs +9 -5
  85. package/dist/presets/safe.d.ts +57 -12
  86. package/dist/presets/safe.js +1 -1
  87. package/dist/presets/safe.mjs +1 -1
  88. package/package.json +20 -14
@@ -6,6 +6,14 @@ const postcssOptions = {
6
6
  // > Set it to CSS file path or to `undefined` to prevent this warning.
7
7
  from: undefined
8
8
  };
9
+ const inlineCssExcludedPlugins = {
10
+ mergeRules: false,
11
+ minifySelectors: false,
12
+ minifyParams: false,
13
+ normalizeCharset: false,
14
+ uniqueSelectors: false,
15
+ normalizeUnicode: false
16
+ };
9
17
  /** Minify CSS with cssnano */ const mod = {
10
18
  async default (tree, _, cssnanoOptions) {
11
19
  const cssnano = await optionalImport('cssnano');
@@ -13,6 +21,9 @@ const postcssOptions = {
13
21
  if (!cssnano || !postcss) {
14
22
  return tree;
15
23
  }
24
+ const processor = createCssProcessor(postcss, cssnano, cssnanoOptions);
25
+ const inlineStyleProcessor = createCssProcessor(postcss, cssnano, getInlineCssnanoOptions(cssnanoOptions));
26
+ const minifiedCssCache = new Map();
16
27
  const promises = [];
17
28
  let p;
18
29
  tree.walk((node)=>{
@@ -21,12 +32,12 @@ const postcssOptions = {
21
32
  return node;
22
33
  }
23
34
  if (isStyleNode(node) && isCssStyleType(node)) {
24
- p = processStyleNode(node, cssnanoOptions, cssnano, postcss);
35
+ p = processStyleNode(node, processor, minifiedCssCache);
25
36
  if (p) {
26
37
  promises.push(p);
27
38
  }
28
39
  } else if (node.attrs && node.attrs.style) {
29
- p = processStyleAttr(node, cssnanoOptions, cssnano, postcss);
40
+ p = processStyleAttr(node, inlineStyleProcessor, minifiedCssCache);
30
41
  if (p) {
31
42
  promises.push(p);
32
43
  }
@@ -36,22 +47,69 @@ const postcssOptions = {
36
47
  return Promise.all(promises).then(()=>tree);
37
48
  }
38
49
  };
39
- function processStyleNode(styleNode, cssnanoOptions, cssnano, postcss) {
50
+ function createCssProcessor(postcss, cssnano, cssnanoOptions) {
51
+ return postcss([
52
+ cssnano(cssnanoOptions)
53
+ ]);
54
+ }
55
+ function getInlineCssnanoOptions(cssnanoOptions) {
56
+ if (!cssnanoOptions || typeof cssnanoOptions !== 'object') {
57
+ return {
58
+ preset: [
59
+ 'default',
60
+ inlineCssExcludedPlugins
61
+ ]
62
+ };
63
+ }
64
+ if (Array.isArray(cssnanoOptions.plugins)) {
65
+ return cssnanoOptions;
66
+ }
67
+ if (!('preset' in cssnanoOptions) || cssnanoOptions.preset === undefined) {
68
+ return {
69
+ ...cssnanoOptions,
70
+ preset: [
71
+ 'default',
72
+ inlineCssExcludedPlugins
73
+ ]
74
+ };
75
+ }
76
+ if (cssnanoOptions.preset === 'default') {
77
+ return {
78
+ ...cssnanoOptions,
79
+ preset: [
80
+ 'default',
81
+ inlineCssExcludedPlugins
82
+ ]
83
+ };
84
+ }
85
+ if (Array.isArray(cssnanoOptions.preset) && cssnanoOptions.preset[0] === 'default') {
86
+ const presetOptions = cssnanoOptions.preset[1];
87
+ return {
88
+ ...cssnanoOptions,
89
+ preset: [
90
+ 'default',
91
+ {
92
+ ...inlineCssExcludedPlugins,
93
+ ...presetOptions && typeof presetOptions === 'object' ? presetOptions : {}
94
+ }
95
+ ]
96
+ };
97
+ }
98
+ return cssnanoOptions;
99
+ }
100
+ function processStyleNode(styleNode, processor, minifiedCssCache) {
40
101
  let css = extractCssFromStyleNode(styleNode);
41
102
  if (!css || css.trim() === '') return;
42
103
  // Improve performance by avoiding calling stripCssCdata again and again
43
104
  const { strippedCss, isCdataWrapped } = stripCssCdata(css);
44
105
  css = strippedCss;
45
- return postcss([
46
- cssnano(cssnanoOptions)
47
- ]).process(css, postcssOptions).then((result)=>{
48
- const minifiedCss = isCdataWrapped ? result.toString() : result.css;
106
+ return processCss(processor, minifiedCssCache, `${isCdataWrapped ? 'style-cdata:' : 'style:'}${css}`, css, isCdataWrapped).then((minifiedCss)=>{
49
107
  styleNode.content = [
50
108
  wrapCssCdata(minifiedCss, isCdataWrapped)
51
109
  ];
52
110
  });
53
111
  }
54
- function processStyleAttr(node, cssnanoOptions, cssnano, postcss) {
112
+ function processStyleAttr(node, processor, minifiedCssCache) {
55
113
  // CSS "color: red;" is invalid. Therefore it should be wrapped inside some selector:
56
114
  // a{color: red;}
57
115
  const wrapperStart = 'a{';
@@ -63,13 +121,21 @@ function processStyleAttr(node, cssnanoOptions, cssnano, postcss) {
63
121
  return;
64
122
  }
65
123
  const wrappedStyle = wrapperStart + (node.attrs.style || '') + wrapperEnd;
66
- return postcss([
67
- cssnano(cssnanoOptions)
68
- ]).process(wrappedStyle, postcssOptions).then((result)=>{
69
- const minifiedCss = result.css;
124
+ return processCss(processor, minifiedCssCache, `attr:${wrappedStyle}`, wrappedStyle).then((minifiedCss)=>{
70
125
  // Remove wrapperStart at the start and wrapperEnd at the end of minifiedCss
71
126
  node.attrs.style = minifiedCss.substring(wrapperStart.length, minifiedCss.length - wrapperEnd.length);
72
127
  });
73
128
  }
129
+ function processCss(processor, minifiedCssCache, cacheKey, css, useToString = false) {
130
+ let minifiedCss = minifiedCssCache.get(cacheKey);
131
+ if (!minifiedCss) {
132
+ minifiedCss = processor.process(css, postcssOptions).then((result)=>useToString ? result.toString() : result.css).catch((error)=>{
133
+ minifiedCssCache.delete(cacheKey);
134
+ throw error;
135
+ });
136
+ minifiedCssCache.set(cacheKey, minifiedCss);
137
+ }
138
+ return minifiedCss;
139
+ }
74
140
 
75
- export { mod as default };
141
+ export { mod as default, getInlineCssnanoOptions };
@@ -1,25 +1,70 @@
1
1
  import PostHTML from 'posthtml';
2
- import { MinifyOptions } from 'terser';
3
- import { Options } from 'cssnano';
4
- import { Config } from 'svgo';
5
- import { UserDefinedOptions } from 'purgecss';
6
2
 
7
- type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
3
+ type PostHTMLNodeLike = PostHTML.Node | string;
4
+ type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
8
5
  options?: {
9
6
  quoteAllAttributes?: boolean | undefined;
10
7
  quoteStyle?: 0 | 1 | 2 | undefined;
11
8
  replaceQuote?: boolean | undefined;
12
9
  } | undefined;
13
10
  render(): string;
14
- render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
11
+ render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
15
12
  };
16
13
  type MaybeArray<T> = T | Array<T>;
17
- type PostHTMLNodeLike = PostHTML.Node | string;
18
14
  type HtmlnanoTemplateRule = {
19
15
  tag: string;
20
16
  attrs?: Record<string, string | boolean | void>;
21
17
  };
22
18
  type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
19
+ type HtmlnanoMinifyCssOptions = object;
20
+ type HtmlnanoMinifyJsOptions = object;
21
+ type HtmlnanoMinifySvgOptions = object;
22
+ type HtmlnanoPurgeCssPattern = string | RegExp;
23
+ type HtmlnanoPurgeCssExtractorResultDetailed = {
24
+ attributes: {
25
+ names: string[];
26
+ values: string[];
27
+ };
28
+ classes: string[];
29
+ ids: string[];
30
+ tags: string[];
31
+ undetermined: string[];
32
+ };
33
+ type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
34
+ type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
35
+ type HtmlnanoPurgeCssSourceMapOptions = {
36
+ absolute?: boolean;
37
+ annotation?: boolean | string;
38
+ from?: string;
39
+ inline?: boolean;
40
+ prev?: boolean | object | string;
41
+ sourcesContent?: boolean;
42
+ to?: string;
43
+ };
44
+ type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
45
+ standard?: HtmlnanoPurgeCssPattern[];
46
+ deep?: RegExp[];
47
+ greedy?: RegExp[];
48
+ variables?: HtmlnanoPurgeCssPattern[];
49
+ keyframes?: HtmlnanoPurgeCssPattern[];
50
+ };
51
+ interface HtmlnanoPurgeCssOptions {
52
+ tool: 'purgeCSS';
53
+ defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
54
+ fontFace?: boolean;
55
+ keyframes?: boolean;
56
+ output?: string;
57
+ rejected?: boolean;
58
+ rejectedCss?: boolean;
59
+ sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
60
+ stdin?: boolean;
61
+ stdout?: boolean;
62
+ variables?: boolean;
63
+ safelist?: HtmlnanoPurgeCssSafelist;
64
+ blocklist?: HtmlnanoPurgeCssPattern[];
65
+ skippedContentGlobs?: string[];
66
+ dynamicAttributes?: string[];
67
+ }
23
68
  interface HtmlnanoOptions {
24
69
  skipConfigLoading?: boolean;
25
70
  configPath?: string;
@@ -34,16 +79,16 @@ interface HtmlnanoOptions {
34
79
  minifyUrls?: URL | string | false;
35
80
  mergeStyles?: boolean;
36
81
  mergeScripts?: boolean;
37
- minifyCss?: Options | boolean;
82
+ minifyCss?: HtmlnanoMinifyCssOptions | boolean;
38
83
  minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
39
84
  minifyConditionalComments?: boolean;
40
- minifyJs?: MinifyOptions | boolean;
85
+ minifyJs?: HtmlnanoMinifyJsOptions | boolean;
41
86
  minifyJson?: boolean;
42
87
  minifyAttributes?: boolean | {
43
88
  metaContent?: boolean;
44
89
  redundantWhitespaces?: 'safe' | 'agressive' | false;
45
90
  };
46
- minifySvg?: Config | boolean;
91
+ minifySvg?: HtmlnanoMinifySvgOptions | boolean;
47
92
  normalizeAttributeValues?: boolean;
48
93
  removeAttributeQuotes?: boolean | {
49
94
  force?: boolean;
@@ -55,9 +100,8 @@ interface HtmlnanoOptions {
55
100
  };
56
101
  removeRedundantAttributes?: boolean;
57
102
  removeOptionalTags?: boolean;
58
- removeUnusedCss?: boolean | ({
59
- tool: 'purgeCSS';
60
- } & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
103
+ removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
104
+ tool?: 'uncss';
61
105
  banner?: boolean;
62
106
  csspath?: string;
63
107
  htmlroot?: string;
@@ -77,7 +121,7 @@ interface HtmlnanoOptions {
77
121
  type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
78
122
  type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
79
123
  type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
80
- type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
124
+ type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
81
125
  type HtmlnanoModule<Options = any> = {
82
126
  onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
83
127
  onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
@@ -1,25 +1,70 @@
1
1
  import PostHTML from 'posthtml';
2
- import { MinifyOptions } from 'terser';
3
- import { Options } from 'cssnano';
4
- import { Config } from 'svgo';
5
- import { UserDefinedOptions } from 'purgecss';
6
2
 
7
- type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
3
+ type PostHTMLNodeLike = PostHTML.Node | string;
4
+ type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
8
5
  options?: {
9
6
  quoteAllAttributes?: boolean | undefined;
10
7
  quoteStyle?: 0 | 1 | 2 | undefined;
11
8
  replaceQuote?: boolean | undefined;
12
9
  } | undefined;
13
10
  render(): string;
14
- render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
11
+ render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
15
12
  };
16
13
  type MaybeArray<T> = T | Array<T>;
17
- type PostHTMLNodeLike = PostHTML.Node | string;
18
14
  type HtmlnanoTemplateRule = {
19
15
  tag: string;
20
16
  attrs?: Record<string, string | boolean | void>;
21
17
  };
22
18
  type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
19
+ type HtmlnanoMinifyCssOptions = object;
20
+ type HtmlnanoMinifyJsOptions = object;
21
+ type HtmlnanoMinifySvgOptions = object;
22
+ type HtmlnanoPurgeCssPattern = string | RegExp;
23
+ type HtmlnanoPurgeCssExtractorResultDetailed = {
24
+ attributes: {
25
+ names: string[];
26
+ values: string[];
27
+ };
28
+ classes: string[];
29
+ ids: string[];
30
+ tags: string[];
31
+ undetermined: string[];
32
+ };
33
+ type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
34
+ type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
35
+ type HtmlnanoPurgeCssSourceMapOptions = {
36
+ absolute?: boolean;
37
+ annotation?: boolean | string;
38
+ from?: string;
39
+ inline?: boolean;
40
+ prev?: boolean | object | string;
41
+ sourcesContent?: boolean;
42
+ to?: string;
43
+ };
44
+ type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
45
+ standard?: HtmlnanoPurgeCssPattern[];
46
+ deep?: RegExp[];
47
+ greedy?: RegExp[];
48
+ variables?: HtmlnanoPurgeCssPattern[];
49
+ keyframes?: HtmlnanoPurgeCssPattern[];
50
+ };
51
+ interface HtmlnanoPurgeCssOptions {
52
+ tool: 'purgeCSS';
53
+ defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
54
+ fontFace?: boolean;
55
+ keyframes?: boolean;
56
+ output?: string;
57
+ rejected?: boolean;
58
+ rejectedCss?: boolean;
59
+ sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
60
+ stdin?: boolean;
61
+ stdout?: boolean;
62
+ variables?: boolean;
63
+ safelist?: HtmlnanoPurgeCssSafelist;
64
+ blocklist?: HtmlnanoPurgeCssPattern[];
65
+ skippedContentGlobs?: string[];
66
+ dynamicAttributes?: string[];
67
+ }
23
68
  interface HtmlnanoOptions {
24
69
  skipConfigLoading?: boolean;
25
70
  configPath?: string;
@@ -34,16 +79,16 @@ interface HtmlnanoOptions {
34
79
  minifyUrls?: URL | string | false;
35
80
  mergeStyles?: boolean;
36
81
  mergeScripts?: boolean;
37
- minifyCss?: Options | boolean;
82
+ minifyCss?: HtmlnanoMinifyCssOptions | boolean;
38
83
  minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
39
84
  minifyConditionalComments?: boolean;
40
- minifyJs?: MinifyOptions | boolean;
85
+ minifyJs?: HtmlnanoMinifyJsOptions | boolean;
41
86
  minifyJson?: boolean;
42
87
  minifyAttributes?: boolean | {
43
88
  metaContent?: boolean;
44
89
  redundantWhitespaces?: 'safe' | 'agressive' | false;
45
90
  };
46
- minifySvg?: Config | boolean;
91
+ minifySvg?: HtmlnanoMinifySvgOptions | boolean;
47
92
  normalizeAttributeValues?: boolean;
48
93
  removeAttributeQuotes?: boolean | {
49
94
  force?: boolean;
@@ -55,9 +100,8 @@ interface HtmlnanoOptions {
55
100
  };
56
101
  removeRedundantAttributes?: boolean;
57
102
  removeOptionalTags?: boolean;
58
- removeUnusedCss?: boolean | ({
59
- tool: 'purgeCSS';
60
- } & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
103
+ removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
104
+ tool?: 'uncss';
61
105
  banner?: boolean;
62
106
  csspath?: string;
63
107
  htmlroot?: string;
@@ -77,7 +121,7 @@ interface HtmlnanoOptions {
77
121
  type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
78
122
  type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
79
123
  type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
80
- type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
124
+ type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
81
125
  type HtmlnanoModule<Options = any> = {
82
126
  onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
83
127
  onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
@@ -1,25 +1,71 @@
1
1
  import PostHTML from 'posthtml';
2
2
  import { MinifyOptions } from 'terser';
3
- import { Options } from 'cssnano';
4
- import { Config } from 'svgo';
5
- import { UserDefinedOptions } from 'purgecss';
6
3
 
7
- type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
4
+ type PostHTMLNodeLike = PostHTML.Node | string;
5
+ type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
8
6
  options?: {
9
7
  quoteAllAttributes?: boolean | undefined;
10
8
  quoteStyle?: 0 | 1 | 2 | undefined;
11
9
  replaceQuote?: boolean | undefined;
12
10
  } | undefined;
13
11
  render(): string;
14
- render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
12
+ render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
15
13
  };
16
14
  type MaybeArray<T> = T | Array<T>;
17
- type PostHTMLNodeLike = PostHTML.Node | string;
18
15
  type HtmlnanoTemplateRule = {
19
16
  tag: string;
20
17
  attrs?: Record<string, string | boolean | void>;
21
18
  };
22
19
  type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
20
+ type HtmlnanoMinifyCssOptions = object;
21
+ type HtmlnanoMinifyJsOptions = object;
22
+ type HtmlnanoMinifySvgOptions = object;
23
+ type HtmlnanoPurgeCssPattern = string | RegExp;
24
+ type HtmlnanoPurgeCssExtractorResultDetailed = {
25
+ attributes: {
26
+ names: string[];
27
+ values: string[];
28
+ };
29
+ classes: string[];
30
+ ids: string[];
31
+ tags: string[];
32
+ undetermined: string[];
33
+ };
34
+ type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
35
+ type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
36
+ type HtmlnanoPurgeCssSourceMapOptions = {
37
+ absolute?: boolean;
38
+ annotation?: boolean | string;
39
+ from?: string;
40
+ inline?: boolean;
41
+ prev?: boolean | object | string;
42
+ sourcesContent?: boolean;
43
+ to?: string;
44
+ };
45
+ type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
46
+ standard?: HtmlnanoPurgeCssPattern[];
47
+ deep?: RegExp[];
48
+ greedy?: RegExp[];
49
+ variables?: HtmlnanoPurgeCssPattern[];
50
+ keyframes?: HtmlnanoPurgeCssPattern[];
51
+ };
52
+ interface HtmlnanoPurgeCssOptions {
53
+ tool: 'purgeCSS';
54
+ defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
55
+ fontFace?: boolean;
56
+ keyframes?: boolean;
57
+ output?: string;
58
+ rejected?: boolean;
59
+ rejectedCss?: boolean;
60
+ sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
61
+ stdin?: boolean;
62
+ stdout?: boolean;
63
+ variables?: boolean;
64
+ safelist?: HtmlnanoPurgeCssSafelist;
65
+ blocklist?: HtmlnanoPurgeCssPattern[];
66
+ skippedContentGlobs?: string[];
67
+ dynamicAttributes?: string[];
68
+ }
23
69
  interface HtmlnanoOptions {
24
70
  skipConfigLoading?: boolean;
25
71
  configPath?: string;
@@ -34,16 +80,16 @@ interface HtmlnanoOptions {
34
80
  minifyUrls?: URL | string | false;
35
81
  mergeStyles?: boolean;
36
82
  mergeScripts?: boolean;
37
- minifyCss?: Options | boolean;
83
+ minifyCss?: HtmlnanoMinifyCssOptions | boolean;
38
84
  minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
39
85
  minifyConditionalComments?: boolean;
40
- minifyJs?: MinifyOptions | boolean;
86
+ minifyJs?: HtmlnanoMinifyJsOptions | boolean;
41
87
  minifyJson?: boolean;
42
88
  minifyAttributes?: boolean | {
43
89
  metaContent?: boolean;
44
90
  redundantWhitespaces?: 'safe' | 'agressive' | false;
45
91
  };
46
- minifySvg?: Config | boolean;
92
+ minifySvg?: HtmlnanoMinifySvgOptions | boolean;
47
93
  normalizeAttributeValues?: boolean;
48
94
  removeAttributeQuotes?: boolean | {
49
95
  force?: boolean;
@@ -55,9 +101,8 @@ interface HtmlnanoOptions {
55
101
  };
56
102
  removeRedundantAttributes?: boolean;
57
103
  removeOptionalTags?: boolean;
58
- removeUnusedCss?: boolean | ({
59
- tool: 'purgeCSS';
60
- } & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
104
+ removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
105
+ tool?: 'uncss';
61
106
  banner?: boolean;
62
107
  csspath?: string;
63
108
  htmlroot?: string;
@@ -77,7 +122,7 @@ interface HtmlnanoOptions {
77
122
  type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
78
123
  type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
79
124
  type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
80
- type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
125
+ type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
81
126
  type HtmlnanoModule<Options = any> = {
82
127
  onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
83
128
  onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
@@ -1,25 +1,71 @@
1
1
  import PostHTML from 'posthtml';
2
2
  import { MinifyOptions } from 'terser';
3
- import { Options } from 'cssnano';
4
- import { Config } from 'svgo';
5
- import { UserDefinedOptions } from 'purgecss';
6
3
 
7
- type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
4
+ type PostHTMLNodeLike = PostHTML.Node | string;
5
+ type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
8
6
  options?: {
9
7
  quoteAllAttributes?: boolean | undefined;
10
8
  quoteStyle?: 0 | 1 | 2 | undefined;
11
9
  replaceQuote?: boolean | undefined;
12
10
  } | undefined;
13
11
  render(): string;
14
- render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
12
+ render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
15
13
  };
16
14
  type MaybeArray<T> = T | Array<T>;
17
- type PostHTMLNodeLike = PostHTML.Node | string;
18
15
  type HtmlnanoTemplateRule = {
19
16
  tag: string;
20
17
  attrs?: Record<string, string | boolean | void>;
21
18
  };
22
19
  type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
20
+ type HtmlnanoMinifyCssOptions = object;
21
+ type HtmlnanoMinifyJsOptions = object;
22
+ type HtmlnanoMinifySvgOptions = object;
23
+ type HtmlnanoPurgeCssPattern = string | RegExp;
24
+ type HtmlnanoPurgeCssExtractorResultDetailed = {
25
+ attributes: {
26
+ names: string[];
27
+ values: string[];
28
+ };
29
+ classes: string[];
30
+ ids: string[];
31
+ tags: string[];
32
+ undetermined: string[];
33
+ };
34
+ type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
35
+ type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
36
+ type HtmlnanoPurgeCssSourceMapOptions = {
37
+ absolute?: boolean;
38
+ annotation?: boolean | string;
39
+ from?: string;
40
+ inline?: boolean;
41
+ prev?: boolean | object | string;
42
+ sourcesContent?: boolean;
43
+ to?: string;
44
+ };
45
+ type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
46
+ standard?: HtmlnanoPurgeCssPattern[];
47
+ deep?: RegExp[];
48
+ greedy?: RegExp[];
49
+ variables?: HtmlnanoPurgeCssPattern[];
50
+ keyframes?: HtmlnanoPurgeCssPattern[];
51
+ };
52
+ interface HtmlnanoPurgeCssOptions {
53
+ tool: 'purgeCSS';
54
+ defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
55
+ fontFace?: boolean;
56
+ keyframes?: boolean;
57
+ output?: string;
58
+ rejected?: boolean;
59
+ rejectedCss?: boolean;
60
+ sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
61
+ stdin?: boolean;
62
+ stdout?: boolean;
63
+ variables?: boolean;
64
+ safelist?: HtmlnanoPurgeCssSafelist;
65
+ blocklist?: HtmlnanoPurgeCssPattern[];
66
+ skippedContentGlobs?: string[];
67
+ dynamicAttributes?: string[];
68
+ }
23
69
  interface HtmlnanoOptions {
24
70
  skipConfigLoading?: boolean;
25
71
  configPath?: string;
@@ -34,16 +80,16 @@ interface HtmlnanoOptions {
34
80
  minifyUrls?: URL | string | false;
35
81
  mergeStyles?: boolean;
36
82
  mergeScripts?: boolean;
37
- minifyCss?: Options | boolean;
83
+ minifyCss?: HtmlnanoMinifyCssOptions | boolean;
38
84
  minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
39
85
  minifyConditionalComments?: boolean;
40
- minifyJs?: MinifyOptions | boolean;
86
+ minifyJs?: HtmlnanoMinifyJsOptions | boolean;
41
87
  minifyJson?: boolean;
42
88
  minifyAttributes?: boolean | {
43
89
  metaContent?: boolean;
44
90
  redundantWhitespaces?: 'safe' | 'agressive' | false;
45
91
  };
46
- minifySvg?: Config | boolean;
92
+ minifySvg?: HtmlnanoMinifySvgOptions | boolean;
47
93
  normalizeAttributeValues?: boolean;
48
94
  removeAttributeQuotes?: boolean | {
49
95
  force?: boolean;
@@ -55,9 +101,8 @@ interface HtmlnanoOptions {
55
101
  };
56
102
  removeRedundantAttributes?: boolean;
57
103
  removeOptionalTags?: boolean;
58
- removeUnusedCss?: boolean | ({
59
- tool: 'purgeCSS';
60
- } & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
104
+ removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
105
+ tool?: 'uncss';
61
106
  banner?: boolean;
62
107
  csspath?: string;
63
108
  htmlroot?: string;
@@ -77,7 +122,7 @@ interface HtmlnanoOptions {
77
122
  type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
78
123
  type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
79
124
  type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
80
- type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
125
+ type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
81
126
  type HtmlnanoModule<Options = any> = {
82
127
  onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
83
128
  onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
@@ -192,10 +192,22 @@ function processNodeWithOnAttrs(node, terserOptions, terser) {
192
192
  const minifiedJs = code.substring(jsWrapperStart.length, code.length - jsWrapperEnd.length);
193
193
  node.attrs[attrName] = minifiedJs;
194
194
  }
195
+ }).catch((error)=>{
196
+ // Skip invalid inline handler code and preserve the original value.
197
+ if (isTerserParseError(error)) {
198
+ return;
199
+ }
200
+ throw error;
195
201
  });
196
202
  promises.push(promise);
197
203
  }
198
204
  return promises;
199
205
  }
206
+ function isTerserParseError(error) {
207
+ if (!(error instanceof Error)) {
208
+ return false;
209
+ }
210
+ return error.name === 'SyntaxError' || error.message.includes('JS_Parse_Error');
211
+ }
200
212
 
201
213
  exports.default = mod;
@@ -190,10 +190,22 @@ function processNodeWithOnAttrs(node, terserOptions, terser) {
190
190
  const minifiedJs = code.substring(jsWrapperStart.length, code.length - jsWrapperEnd.length);
191
191
  node.attrs[attrName] = minifiedJs;
192
192
  }
193
+ }).catch((error)=>{
194
+ // Skip invalid inline handler code and preserve the original value.
195
+ if (isTerserParseError(error)) {
196
+ return;
197
+ }
198
+ throw error;
193
199
  });
194
200
  promises.push(promise);
195
201
  }
196
202
  return promises;
197
203
  }
204
+ function isTerserParseError(error) {
205
+ if (!(error instanceof Error)) {
206
+ return false;
207
+ }
208
+ return error.name === 'SyntaxError' || error.message.includes('JS_Parse_Error');
209
+ }
198
210
 
199
211
  export { mod as default };