@meng-xi/vite-plugin 0.1.4 → 0.1.6

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 (151) hide show
  1. package/README-en.md +34 -20
  2. package/README.md +33 -19
  3. package/dist/common/format/index.cjs +1 -1
  4. package/dist/common/format/index.d.cts +19 -114
  5. package/dist/common/format/index.d.mts +19 -114
  6. package/dist/common/format/index.d.ts +19 -114
  7. package/dist/common/format/index.mjs +1 -1
  8. package/dist/common/fs/index.cjs +1 -1
  9. package/dist/common/fs/index.d.cts +36 -89
  10. package/dist/common/fs/index.d.mts +36 -89
  11. package/dist/common/fs/index.d.ts +36 -89
  12. package/dist/common/fs/index.mjs +1 -1
  13. package/dist/common/html/index.cjs +2 -2
  14. package/dist/common/html/index.d.cts +12 -307
  15. package/dist/common/html/index.d.mts +12 -307
  16. package/dist/common/html/index.d.ts +12 -307
  17. package/dist/common/html/index.mjs +2 -2
  18. package/dist/common/index.cjs +1 -1
  19. package/dist/common/index.d.cts +7 -11
  20. package/dist/common/index.d.mts +7 -11
  21. package/dist/common/index.d.ts +7 -11
  22. package/dist/common/index.mjs +1 -1
  23. package/dist/common/script/index.cjs +1 -1
  24. package/dist/common/script/index.d.cts +1 -44
  25. package/dist/common/script/index.d.mts +1 -44
  26. package/dist/common/script/index.d.ts +1 -44
  27. package/dist/common/script/index.mjs +1 -1
  28. package/dist/common/ui/index.cjs +1 -1
  29. package/dist/common/ui/index.d.cts +1 -111
  30. package/dist/common/ui/index.d.mts +1 -111
  31. package/dist/common/ui/index.d.ts +1 -111
  32. package/dist/common/ui/index.mjs +1 -1
  33. package/dist/common/validation/index.cjs +1 -1
  34. package/dist/common/validation/index.d.cts +2 -80
  35. package/dist/common/validation/index.d.mts +2 -80
  36. package/dist/common/validation/index.d.ts +2 -80
  37. package/dist/common/validation/index.mjs +1 -1
  38. package/dist/factory/index.cjs +1 -1
  39. package/dist/factory/index.d.cts +1 -1
  40. package/dist/factory/index.d.mts +1 -1
  41. package/dist/factory/index.d.ts +1 -1
  42. package/dist/factory/index.mjs +1 -1
  43. package/dist/index.cjs +1 -1
  44. package/dist/index.d.cts +10 -12
  45. package/dist/index.d.mts +10 -12
  46. package/dist/index.d.ts +10 -12
  47. package/dist/index.mjs +1 -1
  48. package/dist/logger/index.d.cts +92 -1
  49. package/dist/logger/index.d.mts +92 -1
  50. package/dist/logger/index.d.ts +92 -1
  51. package/dist/plugins/autoImport/index.cjs +19 -0
  52. package/dist/plugins/autoImport/index.d.cts +291 -0
  53. package/dist/plugins/autoImport/index.d.mts +291 -0
  54. package/dist/plugins/autoImport/index.d.ts +291 -0
  55. package/dist/plugins/autoImport/index.mjs +19 -0
  56. package/dist/plugins/buildProgress/index.cjs +1 -1
  57. package/dist/plugins/buildProgress/index.d.cts +1 -1
  58. package/dist/plugins/buildProgress/index.d.mts +1 -1
  59. package/dist/plugins/buildProgress/index.d.ts +1 -1
  60. package/dist/plugins/buildProgress/index.mjs +2 -2
  61. package/dist/plugins/bundleAnalyzer/index.cjs +21 -21
  62. package/dist/plugins/bundleAnalyzer/index.d.cts +1 -1
  63. package/dist/plugins/bundleAnalyzer/index.d.mts +1 -1
  64. package/dist/plugins/bundleAnalyzer/index.d.ts +1 -1
  65. package/dist/plugins/bundleAnalyzer/index.mjs +18 -18
  66. package/dist/plugins/compressAssets/index.cjs +1 -1
  67. package/dist/plugins/compressAssets/index.d.cts +1 -1
  68. package/dist/plugins/compressAssets/index.d.mts +1 -1
  69. package/dist/plugins/compressAssets/index.d.ts +1 -1
  70. package/dist/plugins/compressAssets/index.mjs +1 -1
  71. package/dist/plugins/copyFile/index.cjs +1 -1
  72. package/dist/plugins/copyFile/index.d.cts +1 -1
  73. package/dist/plugins/copyFile/index.d.mts +1 -1
  74. package/dist/plugins/copyFile/index.d.ts +1 -1
  75. package/dist/plugins/copyFile/index.mjs +1 -1
  76. package/dist/plugins/envGuard/index.cjs +11 -11
  77. package/dist/plugins/envGuard/index.d.cts +101 -2
  78. package/dist/plugins/envGuard/index.d.mts +101 -2
  79. package/dist/plugins/envGuard/index.d.ts +101 -2
  80. package/dist/plugins/envGuard/index.mjs +9 -9
  81. package/dist/plugins/faviconManager/index.cjs +1 -1
  82. package/dist/plugins/faviconManager/index.d.cts +1 -1
  83. package/dist/plugins/faviconManager/index.d.mts +1 -1
  84. package/dist/plugins/faviconManager/index.d.ts +1 -1
  85. package/dist/plugins/faviconManager/index.mjs +1 -1
  86. package/dist/plugins/generateRouter/index.cjs +5 -4
  87. package/dist/plugins/generateRouter/index.d.cts +34 -1
  88. package/dist/plugins/generateRouter/index.d.mts +34 -1
  89. package/dist/plugins/generateRouter/index.d.ts +34 -1
  90. package/dist/plugins/generateRouter/index.mjs +5 -4
  91. package/dist/plugins/generateVersion/index.cjs +1 -1
  92. package/dist/plugins/generateVersion/index.d.cts +1 -1
  93. package/dist/plugins/generateVersion/index.d.mts +1 -1
  94. package/dist/plugins/generateVersion/index.d.ts +1 -1
  95. package/dist/plugins/generateVersion/index.mjs +1 -1
  96. package/dist/plugins/htmlInject/index.cjs +7 -1
  97. package/dist/plugins/htmlInject/index.d.cts +2 -2
  98. package/dist/plugins/htmlInject/index.d.mts +2 -2
  99. package/dist/plugins/htmlInject/index.d.ts +2 -2
  100. package/dist/plugins/htmlInject/index.mjs +7 -1
  101. package/dist/plugins/index.cjs +1 -1
  102. package/dist/plugins/index.d.cts +3 -3
  103. package/dist/plugins/index.d.mts +3 -3
  104. package/dist/plugins/index.d.ts +3 -3
  105. package/dist/plugins/index.mjs +1 -1
  106. package/dist/plugins/loadingManager/index.cjs +26 -26
  107. package/dist/plugins/loadingManager/index.d.cts +1 -1
  108. package/dist/plugins/loadingManager/index.d.mts +1 -1
  109. package/dist/plugins/loadingManager/index.d.ts +1 -1
  110. package/dist/plugins/loadingManager/index.mjs +10 -10
  111. package/dist/plugins/versionUpdateChecker/index.cjs +5 -5
  112. package/dist/plugins/versionUpdateChecker/index.d.cts +1 -1
  113. package/dist/plugins/versionUpdateChecker/index.d.mts +1 -1
  114. package/dist/plugins/versionUpdateChecker/index.d.ts +1 -1
  115. package/dist/plugins/versionUpdateChecker/index.mjs +6 -6
  116. package/dist/shared/vite-plugin.B8FuZce1.d.cts +45 -0
  117. package/dist/shared/vite-plugin.B8FuZce1.d.mts +45 -0
  118. package/dist/shared/vite-plugin.B8FuZce1.d.ts +45 -0
  119. package/dist/shared/{vite-plugin.FfJ-Wwfu.d.cts → vite-plugin.BI9taN75.d.cts} +1 -22
  120. package/dist/shared/{vite-plugin.FfJ-Wwfu.d.mts → vite-plugin.BI9taN75.d.mts} +1 -22
  121. package/dist/shared/{vite-plugin.FfJ-Wwfu.d.ts → vite-plugin.BI9taN75.d.ts} +1 -22
  122. package/dist/shared/vite-plugin.CcvHfrL8.cjs +1 -0
  123. package/dist/shared/vite-plugin.CuXEJAWX.mjs +1 -0
  124. package/package.json +7 -17
  125. package/dist/common/compress/index.cjs +0 -1
  126. package/dist/common/compress/index.d.cts +0 -23
  127. package/dist/common/compress/index.d.mts +0 -23
  128. package/dist/common/compress/index.d.ts +0 -23
  129. package/dist/common/compress/index.mjs +0 -1
  130. package/dist/common/object/index.cjs +0 -1
  131. package/dist/common/object/index.d.cts +0 -30
  132. package/dist/common/object/index.d.mts +0 -30
  133. package/dist/common/object/index.d.ts +0 -30
  134. package/dist/common/object/index.mjs +0 -1
  135. package/dist/common/path/index.cjs +0 -1
  136. package/dist/common/path/index.d.cts +0 -22
  137. package/dist/common/path/index.d.mts +0 -22
  138. package/dist/common/path/index.d.ts +0 -22
  139. package/dist/common/path/index.mjs +0 -1
  140. package/dist/shared/vite-plugin.BCuhU1au.mjs +0 -7
  141. package/dist/shared/vite-plugin.BrI73DHA.cjs +0 -7
  142. package/dist/shared/vite-plugin.CLr0ttuO.d.cts +0 -135
  143. package/dist/shared/vite-plugin.CLr0ttuO.d.mts +0 -135
  144. package/dist/shared/vite-plugin.CLr0ttuO.d.ts +0 -135
  145. package/dist/shared/vite-plugin.CmtcnItg.d.cts +0 -261
  146. package/dist/shared/vite-plugin.CmtcnItg.d.mts +0 -261
  147. package/dist/shared/vite-plugin.CmtcnItg.d.ts +0 -261
  148. package/dist/shared/vite-plugin.DnFDPjNf.mjs +0 -1
  149. package/dist/shared/vite-plugin.Dumot0up.mjs +0 -1
  150. package/dist/shared/vite-plugin.soT9a-KD.cjs +0 -1
  151. package/dist/shared/vite-plugin.vwox4bU0.cjs +0 -1
@@ -45,75 +45,12 @@ interface CopyResult {
45
45
  executionTime: number;
46
46
  }
47
47
 
48
- /**
49
- * 文件/目录条目信息
50
- */
51
- interface FileEntry {
52
- /** 完整路径 */
53
- path: string;
54
- /** 是否为文件 */
55
- isFile: boolean;
56
- /** 是否为目录 */
57
- isDirectory: boolean;
58
- }
59
48
  /**
60
49
  * 检查源文件是否存在
61
50
  * @param sourcePath 源文件路径
62
51
  * @throws 当源文件不存在或无法访问时抛出异常
63
52
  */
64
53
  declare function checkSourceExists(sourcePath: string): Promise<void>;
65
- /**
66
- * 创建目标目录
67
- * @param targetPath 目标目录路径
68
- * @throws 当无法创建目标目录时抛出异常
69
- */
70
- declare function ensureTargetDir(targetPath: string): Promise<void>;
71
- /**
72
- * 读取目录内容(优化版:一次性获取文件类型信息)
73
- * @param dirPath 目录路径
74
- * @param recursive 是否递归读取
75
- * @returns 文件和目录条目列表
76
- */
77
- declare function readDirRecursive(dirPath: string, recursive: boolean): Promise<FileEntry[]>;
78
- /**
79
- * 检查文件是否需要更新
80
- * @param sourceFile 源文件路径
81
- * @param targetFile 目标文件路径
82
- * @returns 是否需要更新
83
- */
84
- declare function shouldUpdateFile(sourceFile: string, targetFile: string): Promise<boolean>;
85
- /**
86
- * 检查文件是否存在
87
- * @param filePath 文件路径
88
- * @returns 是否存在
89
- *
90
- * @example
91
- * ```typescript
92
- * if (await fileExists('/path/to/file')) {
93
- * console.log('文件存在')
94
- * }
95
- * ```
96
- */
97
- declare function fileExists(filePath: string): Promise<boolean>;
98
- /**
99
- * 带并发限制的批量执行
100
- *
101
- * @param items 待处理项
102
- * @param handler 处理函数
103
- * @param concurrency 并发数
104
- * @returns 处理结果数组,顺序与输入项对应
105
- *
106
- * @example
107
- * ```typescript
108
- * const urls = ['url1', 'url2', 'url3', 'url4', 'url5']
109
- * const results = await runWithConcurrency(
110
- * urls,
111
- * async (url) => fetch(url),
112
- * 3 // 最多同时处理3个请求
113
- * )
114
- * ```
115
- */
116
- declare function runWithConcurrency<T, R>(items: T[], handler: (item: T) => Promise<R>, concurrency: number): Promise<R[]>;
117
54
  /**
118
55
  * 执行文件复制操作(优化版:并行IO)
119
56
  * @param sourcePath 源文件或目录路径
@@ -130,21 +67,6 @@ declare function copySourceToTarget(sourcePath: string, targetPath: string, opti
130
67
  * @throws 当写入过程中出现错误时抛出异常
131
68
  */
132
69
  declare function writeFileContent(filePath: string, content: string): Promise<void>;
133
- /**
134
- * 读取文件内容
135
- * @param filePath 文件路径
136
- * @returns 文件内容字符串
137
- * @throws 当读取过程中出现错误时抛出异常
138
- */
139
- declare function readFileContent(filePath: string): Promise<string>;
140
- /**
141
- * 同步读取文件内容
142
- * @param filePath 文件路径
143
- * @returns 文件内容字符串
144
- * @throws 当读取过程中出现错误时抛出异常
145
- * @deprecated 请使用异步版本 readFileContent
146
- */
147
- declare function readFileSync(filePath: string): string;
148
70
  /**
149
71
  * 扫描目录中的文件信息
150
72
  */
@@ -177,20 +99,11 @@ interface ScanDirectoryOptions {
177
99
  *
178
100
  * @description 递归遍历指定目录下的所有文件,收集每个文件的大小和扩展名信息,
179
101
  * 支持按扩展名、路径模式和自定义过滤函数进行过滤。
180
- * 这是通用的目录扫描函数,可被不同插件复用。
181
102
  *
182
103
  * @example
183
104
  * ```typescript
184
- * // 扫描所有 .js 文件
185
105
  * const jsFiles = await scanDirectory('dist', { includeExtensions: ['.js'] })
186
- *
187
- * // 排除 node_modules
188
106
  * const files = await scanDirectory('dist', { excludePatterns: ['node_modules'] })
189
- *
190
- * // 使用自定义过滤
191
- * const largeFiles = await scanDirectory('dist', {
192
- * filter: (filePath, ext, size) => size > 1024
193
- * })
194
107
  * ```
195
108
  */
196
109
  declare function scanDirectory(dirPath: string, options?: ScanDirectoryOptions): Promise<ScannedFile[]>;
@@ -209,10 +122,44 @@ declare function scanDirectory(dirPath: string, options?: ScanDirectoryOptions):
209
122
  * @example
210
123
  * ```typescript
211
124
  * await writeJsonReport('dist/report.json', { timestamp: Date.now(), stats: [] })
212
- * await writeJsonReport('dist/report.json', data, 4)
213
125
  * ```
214
126
  */
215
127
  declare function writeJsonReport(filePath: string, data: object, indent?: number): Promise<void>;
128
+ /**
129
+ * 同步写入文件内容,自动创建不存在的目录
130
+ *
131
+ * @param filePath 文件路径
132
+ * @param content 文件内容
133
+ *
134
+ * @description 同步写入文件,如果目标目录不存在会自动递归创建。
135
+ * 适用于构建钩子中需要同步写入的场景(如 `transform` 钩子)。
136
+ *
137
+ * @throws 当文件写入失败时(如权限不足),抛出 `NodeJS.ErrnoException`
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * writeFileSyncSafely('/project/src/auto-imports.d.ts', 'declare global { ... }')
142
+ * ```
143
+ */
144
+ declare function writeFileSyncSafely(filePath: string, content: string): void;
145
+ /**
146
+ * 检查文件内容是否需要更新(同步版本)
147
+ *
148
+ * @param filePath 文件路径
149
+ * @param newContent 新生成的文件内容
150
+ * @returns 如果需要更新返回 `true`,否则返回 `false`
151
+ *
152
+ * @description 对比现有文件内容与新生成的内容,
153
+ * 仅在内容发生变化时才需要写入,减少不必要的文件 IO 操作。
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * if (shouldUpdateFileContent('/project/src/auto-imports.d.ts', newContent)) {
158
+ * writeFileSyncSafely('/project/src/auto-imports.d.ts', newContent)
159
+ * }
160
+ * ```
161
+ */
162
+ declare function shouldUpdateFileContent(filePath: string, newContent: string): boolean;
216
163
 
217
- export { checkSourceExists, copySourceToTarget, ensureTargetDir, fileExists, readDirRecursive, readFileContent, readFileSync, runWithConcurrency, scanDirectory, shouldUpdateFile, writeFileContent, writeJsonReport };
164
+ export { checkSourceExists, copySourceToTarget, scanDirectory, shouldUpdateFileContent, writeFileContent, writeFileSyncSafely, writeJsonReport };
218
165
  export type { CopyOptions, CopyResult, ScanDirectoryOptions, ScannedFile };
@@ -1 +1 @@
1
- import r from"fs";import w from"path";const T=10;async function k(u){try{await r.promises.access(u,r.constants.F_OK)}catch(t){const e=t;throw e.code==="ENOENT"?new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728 - ${u}`):e.code==="EACCES"?new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u8BBF\u95EE\u6E90\u6587\u4EF6 - ${u}`):new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u68C0\u67E5\u6E90\u6587\u4EF6\u65F6\u51FA\u9519 - ${u}\uFF0C\u9519\u8BEF\uFF1A${e.message}`)}}async function D(u){try{await r.promises.mkdir(u,{recursive:!0})}catch(t){const e=t;throw e.code==="EACCES"?new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u521B\u5EFA\u76EE\u6807\u76EE\u5F55 - ${u}`):new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u521B\u5EFA\u76EE\u6807\u76EE\u5F55\u65F6\u51FA\u9519 - ${u}\uFF0C\u9519\u8BEF\uFF1A${e.message}`)}}async function h(u,t){const e=await r.promises.readdir(u,{withFileTypes:!0}),i=[];for(const n of e){const a=w.join(u,n.name),F=n.isFile(),c=n.isDirectory();if(i.push({path:a,isFile:F,isDirectory:c}),c&&t){const E=await h(a,t);i.push(...E)}}return i}async function B(u,t){try{const[e,i]=await Promise.all([r.promises.stat(u),r.promises.stat(t)]);return e.mtimeMs>i.mtimeMs||e.size!==i.size}catch{return!0}}async function C(u){try{return await r.promises.access(u,r.constants.F_OK),!0}catch{return!1}}async function g(u,t,e){const i=[];let n=0;async function a(){for(;n<u.length;){const c=n++,E=await t(u[c]);i[c]=E}}const F=Array(Math.min(e,u.length)).fill(null).map(()=>a());return await Promise.all(F),i}async function v(u,t,e){const i=Date.now(),{recursive:n,overwrite:a,incremental:F=!1,parallelLimit:c=T}=e;let E=0,p=0,l=0;if((await r.promises.stat(u)).isDirectory()){await D(t);const o=await h(u,n),f=o.filter(s=>s.isFile);l=o.filter(s=>s.isDirectory).length;const $=new Set;for(const s of f){const A=w.relative(u,s.path),y=w.dirname(w.join(t,A));$.add(y)}await Promise.all([...$].map(s=>D(s)));const x=await g(f,async s=>{const A=w.relative(u,s.path),y=w.join(t,A);let d=a;return d||(d=!await C(y)),F&&d&&(d=await B(s.path,y)),d?(await r.promises.copyFile(s.path,y),{copied:!0,skipped:!1}):{copied:!1,skipped:!0}},c);for(const s of x)s.copied&&E++,s.skipped&&p++}else{await D(w.dirname(t));let o=a;o||(o=!await C(t)),F&&o&&(o=await B(u,t)),o?(await r.promises.copyFile(u,t),E++):p++}const m=Date.now()-i;return{copiedFiles:E,skippedFiles:p,copiedDirs:l,executionTime:m}}async function S(u,t){try{await r.promises.writeFile(u,t,"utf-8")}catch(e){const i=e;throw i.code==="EACCES"?new Error(`\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u5199\u5165\u6587\u4EF6 - ${u}`):new Error(`\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A\u5199\u5165\u6587\u4EF6\u65F6\u51FA\u9519 - ${u}\uFF0C\u9519\u8BEF\uFF1A${i.message}`)}}async function z(u){try{return await r.promises.readFile(u,"utf-8")}catch(t){const e=t;throw e.code==="EACCES"?new Error(`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u8BFB\u53D6\u6587\u4EF6 - ${u}`):new Error(`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A\u8BFB\u53D6\u6587\u4EF6\u65F6\u51FA\u9519 - ${u}\uFF0C\u9519\u8BEF\uFF1A${e.message}`)}}function P(u){try{return r.readFileSync(u,"utf-8")}catch(t){const e=t;throw e.code==="EACCES"?new Error(`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u8BFB\u53D6\u6587\u4EF6 - ${u}`):new Error(`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A\u8BFB\u53D6\u6587\u4EF6\u65F6\u51FA\u9519 - ${u}\uFF0C\u9519\u8BEF\uFF1A${e.message}`)}}async function j(u,t={}){const{includeExtensions:e=[],excludePatterns:i=[],filter:n}=t,a=[];async function F(c){const E=await r.promises.readdir(c,{withFileTypes:!0});for(const p of E){const l=w.join(c,p.name);if(p.isDirectory()){await F(l);continue}if(!p.isFile()||i.some(f=>f.startsWith("*")?l.endsWith(f.slice(1)):l.includes(f)))continue;const m=w.extname(p.name).toLowerCase();if(e.length>0&&!e.includes(m))continue;const o=await r.promises.stat(l);n&&!n(l,m,o.size)||a.push({filePath:l,size:o.size,extension:m})}}return await F(u),a}async function O(u,t,e=2){await S(u,JSON.stringify(t,null,e))}export{k as checkSourceExists,v as copySourceToTarget,D as ensureTargetDir,C as fileExists,h as readDirRecursive,z as readFileContent,P as readFileSync,g as runWithConcurrency,j as scanDirectory,B as shouldUpdateFile,S as writeFileContent,O as writeJsonReport};
1
+ import e from"fs";import F from"path";const B=10;async function k(t){try{await e.promises.access(t,e.constants.F_OK)}catch(u){const i=u;throw i.code==="ENOENT"?new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728 - ${t}`):i.code==="EACCES"?new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u8BBF\u95EE\u6E90\u6587\u4EF6 - ${t}`):new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u68C0\u67E5\u6E90\u6587\u4EF6\u65F6\u51FA\u9519 - ${t}\uFF0C\u9519\u8BEF\uFF1A${i.message}`)}}async function D(t){try{await e.promises.mkdir(t,{recursive:!0})}catch(u){const i=u;throw i.code==="EACCES"?new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u521B\u5EFA\u76EE\u6807\u76EE\u5F55 - ${t}`):new Error(`\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A\u521B\u5EFA\u76EE\u6807\u76EE\u5F55\u65F6\u51FA\u9519 - ${t}\uFF0C\u9519\u8BEF\uFF1A${i.message}`)}}async function C(t,u){const i=await e.promises.readdir(t,{withFileTypes:!0}),r=[];for(const n of i){const a=F.join(t,n.name),l=n.isFile(),c=n.isDirectory();if(r.push({path:a,isFile:l,isDirectory:c}),c&&u){const p=await C(a,u);r.push(...p)}}return r}async function S(t,u){try{const[i,r]=await Promise.all([e.promises.stat(t),e.promises.stat(u)]);return i.mtimeMs>r.mtimeMs||i.size!==r.size}catch{return!0}}async function x(t){try{return await e.promises.access(t,e.constants.F_OK),!0}catch{return!1}}async function v(t,u,i){const r=[];let n=0;async function a(){for(;n<t.length;){const c=n++,p=await u(t[c]);r[c]=p}}const l=Array(Math.min(i,t.length)).fill(null).map(()=>a());return await Promise.all(l),r}async function T(t,u,i){const r=Date.now(),{recursive:n,overwrite:a,incremental:l=!1,parallelLimit:c=B}=i;let p=0,E=0,w=0;if((await e.promises.stat(t)).isDirectory()){await D(u);const o=await C(t,n),f=o.filter(s=>s.isFile);w=o.filter(s=>s.isDirectory).length;const A=new Set;for(const s of f){const h=F.relative(t,s.path),y=F.dirname(F.join(u,h));A.add(y)}await Promise.all([...A].map(s=>D(s)));const $=await v(f,async s=>{const h=F.relative(t,s.path),y=F.join(u,h);let d=a;return d||(d=!await x(y)),l&&d&&(d=await S(s.path,y)),d?(await e.promises.copyFile(s.path,y),{copied:!0,skipped:!1}):{copied:!1,skipped:!0}},c);for(const s of $)s.copied&&p++,s.skipped&&E++}else{await D(F.dirname(u));let o=a;o||(o=!await x(u)),l&&o&&(o=await S(t,u)),o?(await e.promises.copyFile(t,u),p++):E++}const m=Date.now()-r;return{copiedFiles:p,skippedFiles:E,copiedDirs:w,executionTime:m}}async function g(t,u){try{await e.promises.writeFile(t,u,"utf-8")}catch(i){const r=i;throw r.code==="EACCES"?new Error(`\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A\u6CA1\u6709\u6743\u9650\u5199\u5165\u6587\u4EF6 - ${t}`):new Error(`\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A\u5199\u5165\u6587\u4EF6\u65F6\u51FA\u9519 - ${t}\uFF0C\u9519\u8BEF\uFF1A${r.message}`)}}async function z(t,u={}){const{includeExtensions:i=[],excludePatterns:r=[],filter:n}=u,a=[];async function l(c){const p=await e.promises.readdir(c,{withFileTypes:!0});for(const E of p){const w=F.join(c,E.name);if(E.isDirectory()){await l(w);continue}if(!E.isFile()||r.some(f=>f.startsWith("*")?w.endsWith(f.slice(1)):w.includes(f)))continue;const m=F.extname(E.name).toLowerCase();if(i.length>0&&!i.includes(m))continue;const o=await e.promises.stat(w);n&&!n(w,m,o.size)||a.push({filePath:w,size:o.size,extension:m})}}return await l(t),a}async function P(t,u,i=2){await g(t,JSON.stringify(u,null,i))}function j(t,u){const i=F.dirname(t);e.existsSync(i)||e.mkdirSync(i,{recursive:!0}),e.writeFileSync(t,u,"utf-8")}function O(t,u){if(!e.existsSync(t))return!0;try{return e.readFileSync(t,"utf-8")!==u}catch{return!0}}export{k as checkSourceExists,T as copySourceToTarget,z as scanDirectory,O as shouldUpdateFileContent,g as writeFileContent,j as writeFileSyncSafely,P as writeJsonReport};
@@ -1,2 +1,2 @@
1
- "use strict";const security=require("../../shared/vite-plugin.BrI73DHA.cjs");require("../script/index.cjs");function injectBeforeTag(e,t,r){const i=new RegExp(t,"i");return i.test(e)?{html:e.replace(i,`${r}
2
- ${t}`),injected:!0}:{html:e,injected:!1}}function injectHtmlByPriority(e,t,r=["</head>","</body>","</html>"]){for(const i of r){const n=injectBeforeTag(e,i,t);if(n.injected)return n}return{html:e+t,injected:!0}}function injectBeforeTagWithFallback(e,t,r){const i=injectBeforeTag(e,"</body>",t);if(i.injected)return{...i,usedFallback:!1};const n=injectBeforeTag(e,"</html>",t);return n.injected?{...n,usedFallback:!1}:{html:e+t,injected:!0,usedFallback:!0}}function injectHeadAndBody(e,t,r){let i=e,n=!1;if(t){const c=injectBeforeTag(i,"</head>",t);c.injected&&(i=c.html,n=!0)}const o=injectBeforeTagWithFallback(i,r);return{html:o.html,headInjected:n,bodyInjected:o.injected,usedFallback:o.usedFallback}}exports.DEFAULT_BLOCKED_ATTRIBUTES=security.DEFAULT_BLOCKED_ATTRIBUTES,exports.DEFAULT_BLOCKED_TAGS=security.DEFAULT_BLOCKED_TAGS,exports.applyTemplateVars=security.applyTemplateVars,exports.evaluateCondition=security.evaluateCondition,exports.findSelectorMatch=security.findSelectorMatch,exports.injectAtPosition=security.injectAtPosition,exports.sanitizeContent=security.sanitizeContent,exports.sortRulesByPriority=security.sortRulesByPriority,exports.validateSecurityConfig=security.validateSecurityConfig,exports.injectBeforeTag=injectBeforeTag,exports.injectBeforeTagWithFallback=injectBeforeTagWithFallback,exports.injectHeadAndBody=injectHeadAndBody,exports.injectHtmlByPriority=injectHtmlByPriority;
1
+ "use strict";const security=require("../../shared/vite-plugin.CcvHfrL8.cjs");function injectBeforeTag(e,t,l){const n=new RegExp(t,"i");return n.test(e)?{html:e.replace(n,`${l}
2
+ ${t}`),injected:!0}:{html:e,injected:!1}}function c(e,t,l){const n=injectBeforeTag(e,"</body>",t);if(n.injected)return{...n,usedFallback:!1};const s=injectBeforeTag(e,"</html>",t);return s.injected?{...s,usedFallback:!1}:{html:e+t,injected:!0,usedFallback:!0}}function injectHeadAndBody(e,t,l){let n=e,s=!1;if(t){const r=injectBeforeTag(n,"</head>",t);r.injected&&(n=r.html,s=!0)}const i=c(n,l);return{html:i.html,headInjected:s,bodyInjected:i.injected,usedFallback:i.usedFallback}}exports.escapeHtmlAttr=security.escapeHtmlAttr,exports.sanitizeContent=security.sanitizeContent,exports.injectBeforeTag=injectBeforeTag,exports.injectHeadAndBody=injectHeadAndBody;
@@ -1,235 +1,27 @@
1
- import { I as InjectCondition, b as SelectorMatch, a as InjectPosition, P as PositionInjectResult, S as SecurityConfig, H as HtmlInjectResult, D as DualInjectResult } from '../../shared/vite-plugin.FfJ-Wwfu.cjs';
2
- export { C as ConditionType } from '../../shared/vite-plugin.FfJ-Wwfu.cjs';
1
+ import { S as SecurityConfig, H as HtmlInjectResult, D as DualInjectResult } from '../../shared/vite-plugin.BI9taN75.cjs';
2
+ export { C as ConditionType, I as InjectCondition, a as InjectPosition, b as SelectorMatch } from '../../shared/vite-plugin.BI9taN75.cjs';
3
3
 
4
4
  /**
5
- * HTML 注入工具模块
5
+ * 转义 HTML 属性值中的特殊字符
6
6
  *
7
- * @module common/html/inject
8
- * @description 提供高级 HTML 内容注入功能,包括选择器匹配、模板变量替换、
9
- * 条件判断、规则排序和多位置注入等能力,为插件提供灵活的 HTML 操作支持。
10
- */
11
-
12
- /**
13
- * 在 HTML 中查找选择器匹配位置
14
- *
15
- * @param html - 要搜索的 HTML 字符串
16
- * @param selector - 选择器字符串(普通字符串或正则表达式字符串)
17
- * @param selectorMatch - 匹配模式,`'string'` 为精确字符串匹配,`'regex'` 为正则匹配
18
- * @returns 匹配结果对象(包含 `index` 和 `length`),未匹配时返回 `null`
19
- *
20
- * @description 根据匹配模式在 HTML 中查找选择器的位置:
21
- * - 字符串模式:使用 `indexOf` 进行精确匹配
22
- * - 正则模式:使用 `RegExp` 进行正则匹配,正则语法错误时返回 `null`
23
- *
24
- * @example
25
- * ```typescript
26
- * // 字符串匹配
27
- * findSelectorMatch('<div id="app">content</div>', '<div id="app">')
28
- * // { index: 0, length: 14 }
29
- *
30
- * // 正则匹配
31
- * findSelectorMatch('<div class="foo">bar</div>', 'class="\\w+"', 'regex')
32
- * // { index: 5, length: 12 }
33
- *
34
- * // 未匹配
35
- * findSelectorMatch('<div>hello</div>', '<span>')
36
- * // null
37
- * ```
38
- */
39
- declare function findSelectorMatch(html: string, selector: string, selectorMatch?: SelectorMatch): {
40
- index: number;
41
- length: number;
42
- } | null;
43
- /**
44
- * 替换模板字符串中的变量占位符
45
- *
46
- * @param content - 包含 `{{变量名}}` 占位符的模板字符串
47
- * @param ruleVars - 规则级变量映射(优先级高于全局变量)
48
- * @param globalVars - 全局变量映射
49
- * @returns 替换所有匹配占位符后的字符串
7
+ * @param str - 需要转义的字符串
8
+ * @returns 转义后的安全字符串
50
9
  *
51
- * @description 将模板字符串中形如 `{{key}}` 的占位符替换为对应的值。
52
- * 规则变量(`ruleVars`)优先级高于全局变量(`globalVars`),
53
- * 当两者存在相同键时,规则变量的值会覆盖全局变量的值。
54
- * 变量名中的正则特殊字符会被自动转义,替换值中的 `$` 也会被安全处理。
10
+ * @description 将字符串中的 `&`、`"`、`'`、`<`、`>` 转义为对应的 HTML 实体,
11
+ * 防止在 HTML 属性值中注入恶意代码。
55
12
  *
56
13
  * @example
57
14
  * ```typescript
58
- * // 基本替换
59
- * applyTemplateVars('<div>{{name}}</div>', { name: 'test' })
60
- * // '<div>test</div>'
61
- *
62
- * // 规则变量覆盖全局变量
63
- * applyTemplateVars('{{a}}-{{b}}', { a: '1' }, { a: '0', b: '2' })
64
- * // '1-2'
65
- *
66
- * // 无匹配占位符
67
- * applyTemplateVars('no vars', { x: 'y' })
68
- * // 'no vars'
69
- * ```
70
- */
71
- declare function applyTemplateVars(content: string, ruleVars?: Record<string, string>, globalVars?: Record<string, string>): string;
72
- /**
73
- * 评估注入条件是否满足
74
- *
75
- * @param condition - 注入条件配置
76
- * @param html - 当前 HTML 内容(用于 `file-contains` 类型判断)
77
- * @returns 条件是否满足(布尔值)
78
- *
79
- * @description 根据条件类型评估注入条件:
80
- * - `env`:检查环境变量是否存在且不为 `'false'` 或 `'0'`
81
- * - `file-contains`:检查 HTML 内容是否包含指定字符串
82
- * - `custom`:执行自定义函数,捕获异常时返回 `false`
83
- * - 支持通过 `negate` 字段对结果取反
84
- *
85
- * @example
86
- * ```typescript
87
- * // 环境变量判断
88
- * evaluateCondition({ type: 'env', value: 'ENABLE_ANALYTICS' }, '')
89
- *
90
- * // 内容包含判断
91
- * evaluateCondition({ type: 'file-contains', value: '<div id="app">' }, html)
92
- *
93
- * // 自定义函数(带取反)
94
- * evaluateCondition(
95
- * { type: 'custom', value: () => isDev(), negate: true },
96
- * html
97
- * )
15
+ * escapeHtmlAttr('hello "world" & <friends>')
16
+ * // 'hello &quot;world&quot; &amp; &lt;friends&gt;'
98
17
  * ```
99
18
  */
100
- declare function evaluateCondition(condition: InjectCondition, html: string): boolean;
101
- /**
102
- * 按优先级排序规则列表
103
- *
104
- * @typeParam T - 规则类型,必须包含可选的 `priority` 字段
105
- * @param rules - 待排序的规则数组
106
- * @returns 按 `priority` 升序排列的新数组(不修改原数组)
107
- *
108
- * @description 将规则按 `priority` 字段升序排列,`priority` 越小优先级越高。
109
- * 未指定 `priority` 的规则默认优先级为 100。
110
- * 返回新数组,不修改原数组。
111
- *
112
- * @example
113
- * ```typescript
114
- * const rules = [
115
- * { priority: 30, name: 'C' },
116
- * { priority: 10, name: 'A' },
117
- * { name: 'D' }, // 默认 priority=100
118
- * { priority: 20, name: 'B' }
119
- * ]
120
- * sortRulesByPriority(rules)
121
- * // [{ priority: 10, name: 'A' }, { priority: 20, name: 'B' },
122
- * // { priority: 30, name: 'C' }, { name: 'D' }]
123
- * ```
124
- */
125
- declare function sortRulesByPriority<T extends {
126
- priority?: number;
127
- }>(rules: T[]): T[];
128
- /**
129
- * 在 HTML 的指定位置注入内容
130
- *
131
- * @param html - 原始 HTML 字符串
132
- * @param content - 要注入的内容
133
- * @param position - 注入位置
134
- * @param selector - 选择器字符串(仅 `before-selector`、`after-selector`、`replace-selector` 位置需要)
135
- * @param selectorMatch - 选择器匹配模式(默认为字符串匹配)
136
- * @returns 注入结果对象,包含注入后的 HTML、是否成功标志和失败原因
137
- *
138
- * @description 根据 `position` 参数将内容注入到 HTML 的指定位置:
139
- * - `head-start`:在 `<head>` 标签开始后注入
140
- * - `head-end`:在 `</head>` 标签前注入
141
- * - `body-start`:在 `<body>` 标签开始后注入
142
- * - `body-end`:在 `</body>` 标签前注入
143
- * - `before-selector`:在选择器匹配位置前注入
144
- * - `after-selector`:在选择器匹配位置后注入
145
- * - `replace-selector`:替换选择器匹配的内容
146
- *
147
- * 当目标标签或选择器未找到时,返回 `injected: false` 并附带 `reason` 说明。
148
- *
149
- * @example
150
- * ```typescript
151
- * const html = '<html><head><title>Test</title></head><body><div id="app"></div></body></html>'
152
- *
153
- * // 在 head 开始后注入 meta 标签
154
- * injectAtPosition(html, '<meta charset="utf-8">', 'head-start')
155
- *
156
- * // 在 body 结束前注入脚本
157
- * injectAtPosition(html, '<script>app()</script>', 'body-end')
158
- *
159
- * // 在指定元素前注入
160
- * injectAtPosition(html, '<nav>menu</nav>', 'before-selector', '<div id="app">')
161
- *
162
- * // 替换指定元素
163
- * injectAtPosition(html, '<div id="root"></div>', 'replace-selector', '<div id="app">')
164
- * ```
165
- */
166
- declare function injectAtPosition(html: string, content: string, position: InjectPosition, selector?: string, selectorMatch?: SelectorMatch): PositionInjectResult;
167
-
168
- /**
169
- * HTML 安全过滤模块
170
- *
171
- * @module common/html/security
172
- * @description 提供 HTML 内容安全过滤和验证功能,防止 XSS 攻击和危险内容注入,
173
- * 包括危险标签检测、危险属性过滤和安全配置验证等能力。
174
- */
175
-
176
- /**
177
- * 默认阻止的 HTML 标签列表
178
- *
179
- * @description 包含可能导致安全风险的 HTML 标签:
180
- * - `script`:可执行 JavaScript 代码
181
- * - `iframe`:可嵌入外部页面
182
- * - `object`/`embed`/`applet`:可嵌入插件
183
- * - `form`/`input`/`textarea`/`select`/`button`:可创建表单
184
- */
185
- declare const DEFAULT_BLOCKED_TAGS: string[];
186
- /**
187
- * 默认阻止的 HTML 事件属性列表
188
- *
189
- * @description 包含所有可能导致 JavaScript 执行的事件处理属性,
190
- * 涵盖鼠标事件、键盘事件、表单事件、拖拽事件和动画事件等。
191
- */
192
- declare const DEFAULT_BLOCKED_ATTRIBUTES: string[];
193
- /**
194
- * 验证安全配置的合法性
195
- *
196
- * @param security - 安全配置对象
197
- * @throws 当 `blockedTags` 不是字符串数组时抛出错误
198
- * @throws 当 `allowedTags` 不是字符串数组时抛出错误
199
- * @throws 当 `blockedAttributes` 不是字符串数组时抛出错误
200
- *
201
- * @description 检查安全配置中的数组字段是否为合法的字符串数组类型,
202
- * 传入 `undefined` 时直接跳过验证。
203
- *
204
- * @example
205
- * ```typescript
206
- * // 合法配置
207
- * validateSecurityConfig({ blockedTags: ['iframe'], allowedTags: ['div'] })
208
- *
209
- * // 非法配置(抛出错误)
210
- * validateSecurityConfig({ blockedTags: 'iframe' })
211
- * // Error: security.blockedTags 必须是字符串数组
212
- * ```
213
- */
214
- declare function validateSecurityConfig(security?: SecurityConfig): void;
19
+ declare function escapeHtmlAttr(str: string): string;
215
20
  /**
216
21
  * 内容消毒规则选项
217
- *
218
- * @description 定义对单条注入规则内容进行安全过滤时的选项,
219
- * 控制是否允许脚本注入等特殊行为。
220
22
  */
221
23
  interface SanitizeRuleOptions {
222
- /** 规则标识符,用于错误消息和警告日志中标识来源规则 */
223
24
  id?: string;
224
- /**
225
- * 是否允许注入 `<script>` 标签和被阻止的标签/属性
226
- *
227
- * @description 设置为 `true` 时,将跳过对危险标签和属性的安全检查,
228
- * 但仍会输出警告日志提醒开发者注意安全风险。
229
- * 仅在注入内容来源可信时使用此选项。
230
- *
231
- * @default false
232
- */
233
25
  allowScriptInjection?: boolean;
234
26
  }
235
27
  /**
@@ -238,33 +30,8 @@ interface SanitizeRuleOptions {
238
30
  * @param content - 待过滤的 HTML 内容字符串
239
31
  * @param rule - 当前注入规则的消毒选项
240
32
  * @param security - 全局安全配置
241
- * @param logger - 日志记录器(需提供 `warn` 方法),用于输出安全警告
33
+ * @param logger - 日志记录器
242
34
  * @returns 过滤后的安全 HTML 内容字符串
243
- * @throws 当内容包含被阻止的标签且未启用 `allowScriptInjection` 时抛出错误
244
- * @throws 当内容包含危险属性且未启用 `allowScriptInjection` 时抛出错误
245
- *
246
- * @description 对 HTML 内容进行安全过滤,防止 XSS 攻击:
247
- * 1. **标签过滤**:检测并阻止默认阻止列表中的标签(如 script、iframe),
248
- * 可通过 `security.allowedTags` 放行特定标签
249
- * 2. **属性过滤**:检测并阻止事件处理属性(如 onclick、onerror)
250
- * 3. **脚本检测**:特别检测 `<script>` 标签,需要显式启用 `allowScriptInjection`
251
- *
252
- * 当 `rule.allowScriptInjection` 为 `true` 时,跳过安全检查但输出警告日志。
253
- *
254
- * @example
255
- * ```typescript
256
- * // 安全内容直接通过
257
- * sanitizeContent('<div>safe</div>', { id: 'rule1' })
258
- *
259
- * // 包含 script 标签(抛出错误)
260
- * sanitizeContent('<script>alert(1)</script>', { id: 'rule2' })
261
- *
262
- * // 允许脚本注入(通过但输出警告)
263
- * sanitizeContent('<script>alert(1)</script>', { id: 'rule3', allowScriptInjection: true }, undefined, console)
264
- *
265
- * // 自定义安全配置
266
- * sanitizeContent('<iframe>test</iframe>', { id: 'rule4' }, { allowedTags: ['iframe'] })
267
- * ```
268
35
  */
269
36
  declare function sanitizeContent(content: string, rule: SanitizeRuleOptions, security?: SecurityConfig, logger?: {
270
37
  warn: (msg: string) => void;
@@ -277,59 +44,8 @@ declare function sanitizeContent(content: string, rule: SanitizeRuleOptions, sec
277
44
  * @param tag - 目标闭合标签(如 `</head>`、`</body>`、`</html>`)
278
45
  * @param code - 要注入的代码
279
46
  * @returns 注入结果对象
280
- *
281
- * @example
282
- * ```typescript
283
- * // 在 </head> 前注入 CSS
284
- * const result = injectBeforeTag(html, '</head>', '<style>...</style>')
285
- *
286
- * // 在 </body> 前注入 JS
287
- * const result = injectBeforeTag(html, '</body>', '<script>...</script>')
288
- * ```
289
47
  */
290
48
  declare function injectBeforeTag(html: string, tag: string, code: string): HtmlInjectResult;
291
- /**
292
- * 按优先级向 HTML 中注入代码
293
- *
294
- * @description 依次尝试在 `</head>`、`</body>`、`</html>` 前注入代码,
295
- * 优先注入到靠前的标签位置。适用于需要注入到页面中但无特定位置要求的场景
296
- *
297
- * @param html - 原始 HTML 内容
298
- * @param code - 要注入的代码
299
- * @param targets - 目标标签优先级列表,默认为 `['</head>', '</body>', '</html>']`
300
- * @returns 注入结果对象
301
- *
302
- * @example
303
- * ```typescript
304
- * // 优先注入到 </body> 前
305
- * const result = injectHtmlByPriority(html, scriptCode, ['</body>', '</html>'])
306
- * ```
307
- */
308
- declare function injectHtmlByPriority(html: string, code: string, targets?: string[]): HtmlInjectResult;
309
- /**
310
- * 带回退策略的 HTML 注入
311
- *
312
- * @description 依次尝试在 `</body>`、`</html>` 前注入代码,
313
- * 如果均未找到目标标签,则将代码追加到 HTML 末尾。
314
- * 适用于需要注入到页面底部但不确定 HTML 结构是否完整的场景。
315
- *
316
- * @param html - 原始 HTML 内容
317
- * @param code - 要注入的代码
318
- * @param fallbackMessage - 回退到末尾时的警告信息,为空则不输出警告
319
- * @returns 注入结果对象,包含注入后的 HTML、是否成功标志和是否使用了回退策略
320
- *
321
- * @example
322
- * ```typescript
323
- * // 注入 JS 脚本到页面底部
324
- * const result = injectBeforeTagWithFallback(html, '<script>...</script>')
325
- *
326
- * // 带自定义警告信息
327
- * const result = injectBeforeTagWithFallback(html, scriptCode, '未找到 </body> 标签,代码追加到文件末尾')
328
- * ```
329
- */
330
- declare function injectBeforeTagWithFallback(html: string, code: string, _fallbackMessage?: string): HtmlInjectResult & {
331
- usedFallback: boolean;
332
- };
333
49
  /**
334
50
  * 双区域 HTML 注入(head + body)
335
51
  *
@@ -340,19 +56,8 @@ declare function injectBeforeTagWithFallback(html: string, code: string, _fallba
340
56
  * @param headCode - 注入到 `</head>` 前的代码(如 CSS、meta 标签),不提供则跳过 head 注入
341
57
  * @param bodyCode - 注入到 `</body>` 前的代码(如 JS 脚本),回退到 `</html>` 前或末尾
342
58
  * @returns 双区域注入结果对象
343
- *
344
- * @example
345
- * ```typescript
346
- * // CSS 注入到 head,JS 注入到 body
347
- * const result = injectHeadAndBody(html, '<style>...</style>', '<script>...</script>')
348
- * if (!result.headInjected) logger.warn('未找到 </head> 标签')
349
- * if (result.usedFallback) logger.warn('代码追加到文件末尾')
350
- *
351
- * // 仅注入到 body
352
- * const result = injectHeadAndBody(html, undefined, '<script>...</script>')
353
- * ```
354
59
  */
355
60
  declare function injectHeadAndBody(html: string, headCode: string | undefined, bodyCode: string): DualInjectResult;
356
61
 
357
- export { DEFAULT_BLOCKED_ATTRIBUTES, DEFAULT_BLOCKED_TAGS, DualInjectResult, HtmlInjectResult, InjectCondition, InjectPosition, PositionInjectResult, SecurityConfig, SelectorMatch, applyTemplateVars, evaluateCondition, findSelectorMatch, injectAtPosition, injectBeforeTag, injectBeforeTagWithFallback, injectHeadAndBody, injectHtmlByPriority, sanitizeContent, sortRulesByPriority, validateSecurityConfig };
62
+ export { DualInjectResult, HtmlInjectResult, SecurityConfig, escapeHtmlAttr, injectBeforeTag, injectHeadAndBody, sanitizeContent };
358
63
  export type { SanitizeRuleOptions };