rezo 1.0.66 → 1.0.68

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 (57) hide show
  1. package/dist/adapters/entries/curl.d.ts +5 -0
  2. package/dist/adapters/entries/fetch.d.ts +5 -0
  3. package/dist/adapters/entries/http.d.ts +5 -0
  4. package/dist/adapters/entries/http2.d.ts +5 -0
  5. package/dist/adapters/entries/react-native.d.ts +5 -0
  6. package/dist/adapters/entries/xhr.d.ts +5 -0
  7. package/dist/adapters/index.cjs +6 -6
  8. package/dist/cache/index.cjs +9 -9
  9. package/dist/crawler/crawler.cjs +26 -5
  10. package/dist/crawler/crawler.js +26 -5
  11. package/dist/crawler/index.cjs +40 -40
  12. package/dist/crawler.d.ts +10 -0
  13. package/dist/entries/crawler.cjs +4 -4
  14. package/dist/index.cjs +27 -27
  15. package/dist/index.d.ts +5 -0
  16. package/dist/internal/agents/index.cjs +10 -10
  17. package/dist/platform/browser.d.ts +5 -0
  18. package/dist/platform/bun.d.ts +5 -0
  19. package/dist/platform/deno.d.ts +5 -0
  20. package/dist/platform/node.d.ts +5 -0
  21. package/dist/platform/react-native.d.ts +5 -0
  22. package/dist/platform/worker.d.ts +5 -0
  23. package/dist/proxy/index.cjs +4 -4
  24. package/dist/proxy/manager.cjs +1 -1
  25. package/dist/proxy/manager.js +1 -1
  26. package/dist/queue/index.cjs +8 -8
  27. package/dist/queue/queue.cjs +3 -1
  28. package/dist/queue/queue.js +3 -1
  29. package/dist/responses/universal/index.cjs +11 -11
  30. package/dist/wget/asset-extractor.cjs +556 -0
  31. package/dist/wget/asset-extractor.js +553 -0
  32. package/dist/wget/asset-organizer.cjs +230 -0
  33. package/dist/wget/asset-organizer.js +227 -0
  34. package/dist/wget/download-cache.cjs +221 -0
  35. package/dist/wget/download-cache.js +218 -0
  36. package/dist/wget/downloader.cjs +607 -0
  37. package/dist/wget/downloader.js +604 -0
  38. package/dist/wget/file-writer.cjs +349 -0
  39. package/dist/wget/file-writer.js +346 -0
  40. package/dist/wget/filter-lists.cjs +1330 -0
  41. package/dist/wget/filter-lists.js +1330 -0
  42. package/dist/wget/index.cjs +633 -0
  43. package/dist/wget/index.d.ts +8486 -0
  44. package/dist/wget/index.js +614 -0
  45. package/dist/wget/link-converter.cjs +297 -0
  46. package/dist/wget/link-converter.js +294 -0
  47. package/dist/wget/progress.cjs +271 -0
  48. package/dist/wget/progress.js +266 -0
  49. package/dist/wget/resume.cjs +166 -0
  50. package/dist/wget/resume.js +163 -0
  51. package/dist/wget/robots.cjs +303 -0
  52. package/dist/wget/robots.js +300 -0
  53. package/dist/wget/types.cjs +200 -0
  54. package/dist/wget/types.js +197 -0
  55. package/dist/wget/url-filter.cjs +351 -0
  56. package/dist/wget/url-filter.js +348 -0
  57. package/package.json +6 -1
@@ -0,0 +1,297 @@
1
+ const { promises: fs } = require("node:fs");
2
+ const { dirname, relative, join, extname } = require("node:path");
3
+ const { parseHTML } = require('../dom/index.cjs');
4
+
5
+ class LinkConverter {
6
+ options;
7
+ onEvent;
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ setEventHandler(handler) {
12
+ this.onEvent = handler;
13
+ }
14
+ async convertLinks(outputDir, urlMap) {
15
+ const stats = {
16
+ filesProcessed: 0,
17
+ filesModified: 0,
18
+ linksConverted: 0,
19
+ linksToRelative: 0,
20
+ linksToAbsolute: 0
21
+ };
22
+ const filesToProcess = Array.from(urlMap.values()).filter((path) => {
23
+ const ext = extname(path).toLowerCase();
24
+ return [".html", ".htm", ".xhtml", ".css"].includes(ext);
25
+ });
26
+ this.emitEvent({
27
+ phase: "start",
28
+ totalFiles: filesToProcess.length
29
+ });
30
+ for (const relativePath of filesToProcess) {
31
+ const fullPath = join(outputDir, relativePath);
32
+ try {
33
+ const ext = extname(relativePath).toLowerCase();
34
+ const content = await fs.readFile(fullPath, "utf-8");
35
+ let converted;
36
+ let linkCount;
37
+ if (ext === ".css") {
38
+ const result = this.convertCSSLinks(content, urlMap, relativePath, outputDir);
39
+ converted = result.content;
40
+ linkCount = result.linksConverted;
41
+ stats.linksToRelative += result.linksToRelative;
42
+ stats.linksToAbsolute += result.linksToAbsolute;
43
+ } else {
44
+ const result = this.convertHTMLLinks(content, urlMap, relativePath, outputDir);
45
+ converted = result.content;
46
+ linkCount = result.linksConverted;
47
+ stats.linksToRelative += result.linksToRelative;
48
+ stats.linksToAbsolute += result.linksToAbsolute;
49
+ }
50
+ stats.filesProcessed++;
51
+ stats.linksConverted += linkCount;
52
+ if (converted !== content) {
53
+ if (this.options.backupConverted) {
54
+ await fs.copyFile(fullPath, fullPath + ".orig");
55
+ }
56
+ await fs.writeFile(fullPath, converted, "utf-8");
57
+ stats.filesModified++;
58
+ }
59
+ } catch (error) {
60
+ console.warn(`Failed to convert links in ${fullPath}:`, error);
61
+ }
62
+ }
63
+ this.emitEvent({
64
+ phase: "complete",
65
+ totalFiles: filesToProcess.length,
66
+ convertedFiles: stats.filesModified,
67
+ linksConverted: stats.linksConverted
68
+ });
69
+ return stats;
70
+ }
71
+ convertHTMLLinks(html, urlMap, baseFile, outputDir) {
72
+ let linksConverted = 0;
73
+ let linksToRelative = 0;
74
+ let linksToAbsolute = 0;
75
+ const { document } = parseHTML(html);
76
+ const urlAttributes = {
77
+ a: ["href"],
78
+ area: ["href"],
79
+ link: ["href"],
80
+ script: ["src"],
81
+ img: ["src", "srcset"],
82
+ source: ["src", "srcset"],
83
+ video: ["src", "poster"],
84
+ audio: ["src"],
85
+ track: ["src"],
86
+ iframe: ["src"],
87
+ frame: ["src"],
88
+ embed: ["src"],
89
+ object: ["data"],
90
+ form: ["action"],
91
+ input: ["src"]
92
+ };
93
+ for (const [tag, attrs] of Object.entries(urlAttributes)) {
94
+ const elements = Array.from(document.querySelectorAll(tag));
95
+ for (const element of elements) {
96
+ for (const attr of attrs) {
97
+ const value = element.getAttribute(attr);
98
+ if (!value)
99
+ continue;
100
+ if (attr === "srcset") {
101
+ const converted = this.convertSrcset(value, urlMap, baseFile);
102
+ if (converted !== value) {
103
+ element.setAttribute(attr, converted);
104
+ linksConverted++;
105
+ }
106
+ continue;
107
+ }
108
+ if (this.isSpecialUrl(value))
109
+ continue;
110
+ const result = this.convertUrl(value, urlMap, baseFile);
111
+ if (result.converted !== value) {
112
+ element.setAttribute(attr, result.converted);
113
+ linksConverted++;
114
+ if (result.type === "relative") {
115
+ linksToRelative++;
116
+ } else {
117
+ linksToAbsolute++;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ const elementsWithStyle = Array.from(document.querySelectorAll("[style]"));
124
+ for (const element of elementsWithStyle) {
125
+ const style = element.getAttribute("style");
126
+ if (style && style.includes("url(")) {
127
+ const converted = this.convertCSSUrls(style, urlMap, baseFile);
128
+ if (converted !== style) {
129
+ element.setAttribute("style", converted);
130
+ linksConverted++;
131
+ }
132
+ }
133
+ }
134
+ const styleTags = Array.from(document.querySelectorAll("style"));
135
+ for (const styleTag of styleTags) {
136
+ const content = styleTag.textContent;
137
+ if (content && content.includes("url(")) {
138
+ const converted = this.convertCSSUrls(content, urlMap, baseFile);
139
+ if (converted !== content) {
140
+ styleTag.textContent = converted;
141
+ linksConverted++;
142
+ }
143
+ }
144
+ }
145
+ const serialized = document.toString();
146
+ return {
147
+ content: serialized,
148
+ linksConverted,
149
+ linksToRelative,
150
+ linksToAbsolute
151
+ };
152
+ }
153
+ convertCSSLinks(css, urlMap, baseFile, outputDir) {
154
+ let linksConverted = 0;
155
+ let linksToRelative = 0;
156
+ let linksToAbsolute = 0;
157
+ let converted = css.replace(/@import\s+(?:url\s*\(\s*)?(['"]?)([^'"\)\s;]+)\1\s*\)?/gi, (match, quote, url) => {
158
+ if (this.isSpecialUrl(url))
159
+ return match;
160
+ const result = this.convertUrl(url, urlMap, baseFile);
161
+ if (result.converted !== url) {
162
+ linksConverted++;
163
+ if (result.type === "relative") {
164
+ linksToRelative++;
165
+ } else {
166
+ linksToAbsolute++;
167
+ }
168
+ }
169
+ return `@import url(${quote}${result.converted}${quote})`;
170
+ });
171
+ converted = converted.replace(/url\s*\(\s*(['"]?)([^'"\)]+)\1\s*\)/gi, (match, quote, url) => {
172
+ if (this.isSpecialUrl(url))
173
+ return match;
174
+ const result = this.convertUrl(url, urlMap, baseFile);
175
+ if (result.converted !== url) {
176
+ linksConverted++;
177
+ if (result.type === "relative") {
178
+ linksToRelative++;
179
+ } else {
180
+ linksToAbsolute++;
181
+ }
182
+ }
183
+ return `url(${quote}${result.converted}${quote})`;
184
+ });
185
+ return {
186
+ content: converted,
187
+ linksConverted,
188
+ linksToRelative,
189
+ linksToAbsolute
190
+ };
191
+ }
192
+ convertCSSUrls(css, urlMap, baseFile) {
193
+ return css.replace(/url\s*\(\s*(['"]?)([^'"\)]+)\1\s*\)/gi, (match, quote, url) => {
194
+ if (this.isSpecialUrl(url))
195
+ return match;
196
+ const result = this.convertUrl(url, urlMap, baseFile);
197
+ return `url(${quote}${result.converted}${quote})`;
198
+ });
199
+ }
200
+ convertSrcset(srcset, urlMap, baseFile) {
201
+ const parts = srcset.split(",").map((part) => {
202
+ const trimmed = part.trim();
203
+ const spaceIndex = trimmed.search(/\s/);
204
+ if (spaceIndex === -1) {
205
+ const result = this.convertUrl(trimmed, urlMap, baseFile);
206
+ return result.converted;
207
+ }
208
+ const url = trimmed.substring(0, spaceIndex);
209
+ const descriptor = trimmed.substring(spaceIndex);
210
+ const result = this.convertUrl(url, urlMap, baseFile);
211
+ return result.converted + descriptor;
212
+ });
213
+ return parts.join(", ");
214
+ }
215
+ convertUrl(url, urlMap, baseFile) {
216
+ const normalizedUrl = this.normalizeUrl(url);
217
+ const localPath = urlMap.get(normalizedUrl) || urlMap.get(url);
218
+ if (localPath) {
219
+ const baseDir = dirname(baseFile);
220
+ const relativePath = this.getRelativePath(baseDir, localPath);
221
+ return { converted: relativePath, type: "relative" };
222
+ }
223
+ if (url.startsWith("http://") || url.startsWith("https://")) {
224
+ return { converted: url, type: "absolute" };
225
+ }
226
+ if (url.startsWith("/")) {
227
+ const baseDir = dirname(baseFile);
228
+ const parts = baseDir.split("/").filter((p) => p && p !== ".");
229
+ if (parts.length > 0) {
230
+ const firstPart = parts[0];
231
+ if (firstPart.includes(".")) {
232
+ const targetPath = firstPart + url;
233
+ const relativePath = this.getRelativePath(baseDir, targetPath);
234
+ return { converted: relativePath, type: "relative" };
235
+ }
236
+ const matchingPath = this.findSiteRootUrlInMap(url, urlMap);
237
+ if (matchingPath) {
238
+ const relativePath = this.getRelativePath(baseDir, matchingPath);
239
+ return { converted: relativePath, type: "relative" };
240
+ }
241
+ const depth = parts.length;
242
+ const prefix = depth > 0 ? "../".repeat(depth) : "./";
243
+ return { converted: prefix + url.slice(1), type: "relative" };
244
+ }
245
+ return { converted: "." + url, type: "relative" };
246
+ }
247
+ if (!url.startsWith("./") && !url.startsWith("../")) {
248
+ return { converted: "./" + url, type: "relative" };
249
+ }
250
+ return { converted: url, type: "relative" };
251
+ }
252
+ getRelativePath(from, to) {
253
+ let relativePath = relative(from, to);
254
+ relativePath = relativePath.replace(/\\/g, "/");
255
+ if (!relativePath.startsWith("../") && !relativePath.startsWith("./")) {
256
+ relativePath = "./" + relativePath;
257
+ }
258
+ return relativePath;
259
+ }
260
+ findSiteRootUrlInMap(siteRootUrl, urlMap) {
261
+ for (const [fullUrl, localPath] of urlMap) {
262
+ try {
263
+ const parsed = new URL(fullUrl);
264
+ if (parsed.pathname === siteRootUrl) {
265
+ return localPath;
266
+ }
267
+ } catch {}
268
+ }
269
+ return;
270
+ }
271
+ normalizeUrl(url) {
272
+ try {
273
+ const parsed = new URL(url);
274
+ if (parsed.pathname !== "/" && parsed.pathname.endsWith("/")) {
275
+ parsed.pathname = parsed.pathname.slice(0, -1);
276
+ }
277
+ if (parsed.protocol === "http:" && parsed.port === "80" || parsed.protocol === "https:" && parsed.port === "443") {
278
+ parsed.port = "";
279
+ }
280
+ return parsed.href;
281
+ } catch {
282
+ return url;
283
+ }
284
+ }
285
+ isSpecialUrl(url) {
286
+ return url.startsWith("data:") || url.startsWith("javascript:") || url.startsWith("mailto:") || url.startsWith("tel:") || url.startsWith("#") || url.startsWith("blob:");
287
+ }
288
+ emitEvent(event) {
289
+ if (this.onEvent) {
290
+ this.onEvent(event);
291
+ }
292
+ }
293
+ }
294
+
295
+ exports.LinkConverter = LinkConverter;
296
+ exports.default = LinkConverter;
297
+ module.exports = Object.assign(LinkConverter, exports);
@@ -0,0 +1,294 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { dirname, relative, join, extname } from "node:path";
3
+ import { parseHTML } from '../dom/index.js';
4
+
5
+ export class LinkConverter {
6
+ options;
7
+ onEvent;
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ setEventHandler(handler) {
12
+ this.onEvent = handler;
13
+ }
14
+ async convertLinks(outputDir, urlMap) {
15
+ const stats = {
16
+ filesProcessed: 0,
17
+ filesModified: 0,
18
+ linksConverted: 0,
19
+ linksToRelative: 0,
20
+ linksToAbsolute: 0
21
+ };
22
+ const filesToProcess = Array.from(urlMap.values()).filter((path) => {
23
+ const ext = extname(path).toLowerCase();
24
+ return [".html", ".htm", ".xhtml", ".css"].includes(ext);
25
+ });
26
+ this.emitEvent({
27
+ phase: "start",
28
+ totalFiles: filesToProcess.length
29
+ });
30
+ for (const relativePath of filesToProcess) {
31
+ const fullPath = join(outputDir, relativePath);
32
+ try {
33
+ const ext = extname(relativePath).toLowerCase();
34
+ const content = await fs.readFile(fullPath, "utf-8");
35
+ let converted;
36
+ let linkCount;
37
+ if (ext === ".css") {
38
+ const result = this.convertCSSLinks(content, urlMap, relativePath, outputDir);
39
+ converted = result.content;
40
+ linkCount = result.linksConverted;
41
+ stats.linksToRelative += result.linksToRelative;
42
+ stats.linksToAbsolute += result.linksToAbsolute;
43
+ } else {
44
+ const result = this.convertHTMLLinks(content, urlMap, relativePath, outputDir);
45
+ converted = result.content;
46
+ linkCount = result.linksConverted;
47
+ stats.linksToRelative += result.linksToRelative;
48
+ stats.linksToAbsolute += result.linksToAbsolute;
49
+ }
50
+ stats.filesProcessed++;
51
+ stats.linksConverted += linkCount;
52
+ if (converted !== content) {
53
+ if (this.options.backupConverted) {
54
+ await fs.copyFile(fullPath, fullPath + ".orig");
55
+ }
56
+ await fs.writeFile(fullPath, converted, "utf-8");
57
+ stats.filesModified++;
58
+ }
59
+ } catch (error) {
60
+ console.warn(`Failed to convert links in ${fullPath}:`, error);
61
+ }
62
+ }
63
+ this.emitEvent({
64
+ phase: "complete",
65
+ totalFiles: filesToProcess.length,
66
+ convertedFiles: stats.filesModified,
67
+ linksConverted: stats.linksConverted
68
+ });
69
+ return stats;
70
+ }
71
+ convertHTMLLinks(html, urlMap, baseFile, outputDir) {
72
+ let linksConverted = 0;
73
+ let linksToRelative = 0;
74
+ let linksToAbsolute = 0;
75
+ const { document } = parseHTML(html);
76
+ const urlAttributes = {
77
+ a: ["href"],
78
+ area: ["href"],
79
+ link: ["href"],
80
+ script: ["src"],
81
+ img: ["src", "srcset"],
82
+ source: ["src", "srcset"],
83
+ video: ["src", "poster"],
84
+ audio: ["src"],
85
+ track: ["src"],
86
+ iframe: ["src"],
87
+ frame: ["src"],
88
+ embed: ["src"],
89
+ object: ["data"],
90
+ form: ["action"],
91
+ input: ["src"]
92
+ };
93
+ for (const [tag, attrs] of Object.entries(urlAttributes)) {
94
+ const elements = Array.from(document.querySelectorAll(tag));
95
+ for (const element of elements) {
96
+ for (const attr of attrs) {
97
+ const value = element.getAttribute(attr);
98
+ if (!value)
99
+ continue;
100
+ if (attr === "srcset") {
101
+ const converted = this.convertSrcset(value, urlMap, baseFile);
102
+ if (converted !== value) {
103
+ element.setAttribute(attr, converted);
104
+ linksConverted++;
105
+ }
106
+ continue;
107
+ }
108
+ if (this.isSpecialUrl(value))
109
+ continue;
110
+ const result = this.convertUrl(value, urlMap, baseFile);
111
+ if (result.converted !== value) {
112
+ element.setAttribute(attr, result.converted);
113
+ linksConverted++;
114
+ if (result.type === "relative") {
115
+ linksToRelative++;
116
+ } else {
117
+ linksToAbsolute++;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ const elementsWithStyle = Array.from(document.querySelectorAll("[style]"));
124
+ for (const element of elementsWithStyle) {
125
+ const style = element.getAttribute("style");
126
+ if (style && style.includes("url(")) {
127
+ const converted = this.convertCSSUrls(style, urlMap, baseFile);
128
+ if (converted !== style) {
129
+ element.setAttribute("style", converted);
130
+ linksConverted++;
131
+ }
132
+ }
133
+ }
134
+ const styleTags = Array.from(document.querySelectorAll("style"));
135
+ for (const styleTag of styleTags) {
136
+ const content = styleTag.textContent;
137
+ if (content && content.includes("url(")) {
138
+ const converted = this.convertCSSUrls(content, urlMap, baseFile);
139
+ if (converted !== content) {
140
+ styleTag.textContent = converted;
141
+ linksConverted++;
142
+ }
143
+ }
144
+ }
145
+ const serialized = document.toString();
146
+ return {
147
+ content: serialized,
148
+ linksConverted,
149
+ linksToRelative,
150
+ linksToAbsolute
151
+ };
152
+ }
153
+ convertCSSLinks(css, urlMap, baseFile, outputDir) {
154
+ let linksConverted = 0;
155
+ let linksToRelative = 0;
156
+ let linksToAbsolute = 0;
157
+ let converted = css.replace(/@import\s+(?:url\s*\(\s*)?(['"]?)([^'"\)\s;]+)\1\s*\)?/gi, (match, quote, url) => {
158
+ if (this.isSpecialUrl(url))
159
+ return match;
160
+ const result = this.convertUrl(url, urlMap, baseFile);
161
+ if (result.converted !== url) {
162
+ linksConverted++;
163
+ if (result.type === "relative") {
164
+ linksToRelative++;
165
+ } else {
166
+ linksToAbsolute++;
167
+ }
168
+ }
169
+ return `@import url(${quote}${result.converted}${quote})`;
170
+ });
171
+ converted = converted.replace(/url\s*\(\s*(['"]?)([^'"\)]+)\1\s*\)/gi, (match, quote, url) => {
172
+ if (this.isSpecialUrl(url))
173
+ return match;
174
+ const result = this.convertUrl(url, urlMap, baseFile);
175
+ if (result.converted !== url) {
176
+ linksConverted++;
177
+ if (result.type === "relative") {
178
+ linksToRelative++;
179
+ } else {
180
+ linksToAbsolute++;
181
+ }
182
+ }
183
+ return `url(${quote}${result.converted}${quote})`;
184
+ });
185
+ return {
186
+ content: converted,
187
+ linksConverted,
188
+ linksToRelative,
189
+ linksToAbsolute
190
+ };
191
+ }
192
+ convertCSSUrls(css, urlMap, baseFile) {
193
+ return css.replace(/url\s*\(\s*(['"]?)([^'"\)]+)\1\s*\)/gi, (match, quote, url) => {
194
+ if (this.isSpecialUrl(url))
195
+ return match;
196
+ const result = this.convertUrl(url, urlMap, baseFile);
197
+ return `url(${quote}${result.converted}${quote})`;
198
+ });
199
+ }
200
+ convertSrcset(srcset, urlMap, baseFile) {
201
+ const parts = srcset.split(",").map((part) => {
202
+ const trimmed = part.trim();
203
+ const spaceIndex = trimmed.search(/\s/);
204
+ if (spaceIndex === -1) {
205
+ const result = this.convertUrl(trimmed, urlMap, baseFile);
206
+ return result.converted;
207
+ }
208
+ const url = trimmed.substring(0, spaceIndex);
209
+ const descriptor = trimmed.substring(spaceIndex);
210
+ const result = this.convertUrl(url, urlMap, baseFile);
211
+ return result.converted + descriptor;
212
+ });
213
+ return parts.join(", ");
214
+ }
215
+ convertUrl(url, urlMap, baseFile) {
216
+ const normalizedUrl = this.normalizeUrl(url);
217
+ const localPath = urlMap.get(normalizedUrl) || urlMap.get(url);
218
+ if (localPath) {
219
+ const baseDir = dirname(baseFile);
220
+ const relativePath = this.getRelativePath(baseDir, localPath);
221
+ return { converted: relativePath, type: "relative" };
222
+ }
223
+ if (url.startsWith("http://") || url.startsWith("https://")) {
224
+ return { converted: url, type: "absolute" };
225
+ }
226
+ if (url.startsWith("/")) {
227
+ const baseDir = dirname(baseFile);
228
+ const parts = baseDir.split("/").filter((p) => p && p !== ".");
229
+ if (parts.length > 0) {
230
+ const firstPart = parts[0];
231
+ if (firstPart.includes(".")) {
232
+ const targetPath = firstPart + url;
233
+ const relativePath = this.getRelativePath(baseDir, targetPath);
234
+ return { converted: relativePath, type: "relative" };
235
+ }
236
+ const matchingPath = this.findSiteRootUrlInMap(url, urlMap);
237
+ if (matchingPath) {
238
+ const relativePath = this.getRelativePath(baseDir, matchingPath);
239
+ return { converted: relativePath, type: "relative" };
240
+ }
241
+ const depth = parts.length;
242
+ const prefix = depth > 0 ? "../".repeat(depth) : "./";
243
+ return { converted: prefix + url.slice(1), type: "relative" };
244
+ }
245
+ return { converted: "." + url, type: "relative" };
246
+ }
247
+ if (!url.startsWith("./") && !url.startsWith("../")) {
248
+ return { converted: "./" + url, type: "relative" };
249
+ }
250
+ return { converted: url, type: "relative" };
251
+ }
252
+ getRelativePath(from, to) {
253
+ let relativePath = relative(from, to);
254
+ relativePath = relativePath.replace(/\\/g, "/");
255
+ if (!relativePath.startsWith("../") && !relativePath.startsWith("./")) {
256
+ relativePath = "./" + relativePath;
257
+ }
258
+ return relativePath;
259
+ }
260
+ findSiteRootUrlInMap(siteRootUrl, urlMap) {
261
+ for (const [fullUrl, localPath] of urlMap) {
262
+ try {
263
+ const parsed = new URL(fullUrl);
264
+ if (parsed.pathname === siteRootUrl) {
265
+ return localPath;
266
+ }
267
+ } catch {}
268
+ }
269
+ return;
270
+ }
271
+ normalizeUrl(url) {
272
+ try {
273
+ const parsed = new URL(url);
274
+ if (parsed.pathname !== "/" && parsed.pathname.endsWith("/")) {
275
+ parsed.pathname = parsed.pathname.slice(0, -1);
276
+ }
277
+ if (parsed.protocol === "http:" && parsed.port === "80" || parsed.protocol === "https:" && parsed.port === "443") {
278
+ parsed.port = "";
279
+ }
280
+ return parsed.href;
281
+ } catch {
282
+ return url;
283
+ }
284
+ }
285
+ isSpecialUrl(url) {
286
+ return url.startsWith("data:") || url.startsWith("javascript:") || url.startsWith("mailto:") || url.startsWith("tel:") || url.startsWith("#") || url.startsWith("blob:");
287
+ }
288
+ emitEvent(event) {
289
+ if (this.onEvent) {
290
+ this.onEvent(event);
291
+ }
292
+ }
293
+ }
294
+ export default LinkConverter;