@url-sanitize/core 2.0.4 → 2.0.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 (3) hide show
  1. package/dist/index.d.ts +669 -665
  2. package/dist/index.js +501 -432
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,469 +1,538 @@
1
- // src/catalog.ts
1
+ //#region src/catalog.ts
2
2
  function defineCatalog(catalog) {
3
- return catalog;
3
+ return catalog;
4
4
  }
5
5
  function mergeCatalogs(first, ...rest) {
6
- const catalogs = [first, ...rest];
7
- return {
8
- version: catalogs.length === 1 ? first.version : `merged(${catalogs.map((catalog) => catalog.version).join(",")})`,
9
- generatedAt: latestGeneratedAt(catalogs),
10
- sources: catalogs.flatMap((catalog) => catalog.sources.map((source) => ({ ...source }))),
11
- rules: catalogs.flatMap((catalog) => catalog.rules.map(cloneRule))
12
- };
6
+ const catalogs = [first, ...rest];
7
+ return {
8
+ version: catalogs.length === 1 ? first.version : `merged(${catalogs.map((catalog) => catalog.version).join(",")})`,
9
+ generatedAt: latestGeneratedAt(catalogs),
10
+ sources: catalogs.flatMap((catalog) => catalog.sources.map((source) => ({ ...source }))),
11
+ rules: catalogs.flatMap((catalog) => catalog.rules.map(cloneRule))
12
+ };
13
13
  }
14
14
  function latestGeneratedAt(catalogs) {
15
- return catalogs.map((catalog) => catalog.generatedAt).reduce((latest, generatedAt) => generatedAt > latest ? generatedAt : latest);
15
+ return catalogs.map((catalog) => catalog.generatedAt).reduce((latest, generatedAt) => generatedAt > latest ? generatedAt : latest);
16
16
  }
17
17
  function cloneRule(rule) {
18
- return rule.exceptions ? { ...rule, exceptions: [...rule.exceptions] } : { ...rule };
18
+ return rule.exceptions ? {
19
+ ...rule,
20
+ exceptions: [...rule.exceptions]
21
+ } : { ...rule };
19
22
  }
20
-
21
- // src/sanitize.ts
23
+ //#endregion
24
+ //#region src/sanitize.ts
22
25
  function safeRegex(pattern, flags = "") {
23
- try {
24
- return new RegExp(pattern, flags);
25
- } catch {
26
- return null;
27
- }
26
+ try {
27
+ return new RegExp(pattern, flags);
28
+ } catch {
29
+ return null;
30
+ }
28
31
  }
29
32
  function compileExceptions(patterns) {
30
- if (!patterns) return [];
31
- const out = [];
32
- for (const p of patterns) {
33
- const re = safeRegex(p, "");
34
- if (re) out.push(re);
35
- }
36
- return out;
33
+ if (!patterns) return [];
34
+ const out = [];
35
+ for (const p of patterns) {
36
+ const re = safeRegex(p, "");
37
+ if (re) out.push(re);
38
+ }
39
+ return out;
37
40
  }
38
41
  function compileRule(rule) {
39
- switch (rule.kind) {
40
- case "strip-param": {
41
- const paramPattern = safeRegex(`^(?:${rule.paramPattern})$`, "i");
42
- if (!paramPattern) return null;
43
- const valuePattern = rule.valuePattern ? safeRegex(`^(?:${rule.valuePattern})$`, "i") : null;
44
- if (rule.valuePattern && !valuePattern) return null;
45
- const urlPattern = rule.urlPattern ? safeRegex(rule.urlPattern, "i") : null;
46
- if (rule.urlPattern && !urlPattern) return null;
47
- return {
48
- kind: "strip-param",
49
- source: rule.source,
50
- provider: rule.provider,
51
- urlPattern,
52
- paramPattern,
53
- valuePattern,
54
- exceptions: compileExceptions(rule.exceptions),
55
- isReferralMarketing: rule.isReferralMarketing ?? false
56
- };
57
- }
58
- case "raw-replace": {
59
- const pattern = safeRegex(rule.pattern, "gi");
60
- if (!pattern) return null;
61
- const urlPattern = rule.urlPattern ? safeRegex(rule.urlPattern, "i") : null;
62
- if (rule.urlPattern && !urlPattern) return null;
63
- return {
64
- kind: "raw-replace",
65
- source: rule.source,
66
- provider: rule.provider,
67
- urlPattern,
68
- pattern,
69
- replacement: rule.replacement,
70
- exceptions: compileExceptions(rule.exceptions)
71
- };
72
- }
73
- case "unwrap-redirect": {
74
- const pattern = safeRegex(rule.pattern, "i");
75
- if (!pattern) return null;
76
- const urlPattern = rule.urlPattern ? safeRegex(rule.urlPattern, "i") : null;
77
- if (rule.urlPattern && !urlPattern) return null;
78
- return {
79
- kind: "unwrap-redirect",
80
- source: rule.source,
81
- provider: rule.provider,
82
- urlPattern,
83
- pattern,
84
- captureGroup: rule.captureGroup,
85
- matchPart: rule.matchPart ?? "url",
86
- targetEncoding: rule.targetEncoding ?? "percent",
87
- prependScheme: rule.prependScheme,
88
- targetTemplate: rule.targetTemplate,
89
- exceptions: compileExceptions(rule.exceptions)
90
- };
91
- }
92
- case "block-domain": {
93
- const urlPattern = safeRegex(rule.urlPattern, "i");
94
- if (!urlPattern) return null;
95
- return {
96
- kind: "block-domain",
97
- source: rule.source,
98
- provider: rule.provider,
99
- urlPattern,
100
- exceptions: compileExceptions(rule.exceptions)
101
- };
102
- }
103
- }
42
+ switch (rule.kind) {
43
+ case "strip-param": {
44
+ const paramPattern = safeRegex(`^(?:${rule.paramPattern})$`, "i");
45
+ if (!paramPattern) return null;
46
+ const valuePattern = rule.valuePattern ? safeRegex(`^(?:${rule.valuePattern})$`, "i") : null;
47
+ if (rule.valuePattern && !valuePattern) return null;
48
+ const urlPattern = rule.urlPattern ? safeRegex(rule.urlPattern, "i") : null;
49
+ if (rule.urlPattern && !urlPattern) return null;
50
+ return {
51
+ kind: "strip-param",
52
+ source: rule.source,
53
+ provider: rule.provider,
54
+ urlPattern,
55
+ paramPattern,
56
+ valuePattern,
57
+ exceptions: compileExceptions(rule.exceptions),
58
+ isReferralMarketing: rule.isReferralMarketing ?? false
59
+ };
60
+ }
61
+ case "raw-replace": {
62
+ const pattern = safeRegex(rule.pattern, "gi");
63
+ if (!pattern) return null;
64
+ const urlPattern = rule.urlPattern ? safeRegex(rule.urlPattern, "i") : null;
65
+ if (rule.urlPattern && !urlPattern) return null;
66
+ return {
67
+ kind: "raw-replace",
68
+ source: rule.source,
69
+ provider: rule.provider,
70
+ urlPattern,
71
+ pattern,
72
+ replacement: rule.replacement,
73
+ exceptions: compileExceptions(rule.exceptions)
74
+ };
75
+ }
76
+ case "unwrap-redirect": {
77
+ const pattern = safeRegex(rule.pattern, "i");
78
+ if (!pattern) return null;
79
+ const urlPattern = rule.urlPattern ? safeRegex(rule.urlPattern, "i") : null;
80
+ if (rule.urlPattern && !urlPattern) return null;
81
+ return {
82
+ kind: "unwrap-redirect",
83
+ source: rule.source,
84
+ provider: rule.provider,
85
+ urlPattern,
86
+ pattern,
87
+ captureGroup: rule.captureGroup,
88
+ matchPart: rule.matchPart ?? "url",
89
+ targetEncoding: rule.targetEncoding ?? "percent",
90
+ prependScheme: rule.prependScheme,
91
+ targetTemplate: rule.targetTemplate,
92
+ exceptions: compileExceptions(rule.exceptions)
93
+ };
94
+ }
95
+ case "block-domain": {
96
+ const urlPattern = safeRegex(rule.urlPattern, "i");
97
+ if (!urlPattern) return null;
98
+ return {
99
+ kind: "block-domain",
100
+ source: rule.source,
101
+ provider: rule.provider,
102
+ urlPattern,
103
+ exceptions: compileExceptions(rule.exceptions)
104
+ };
105
+ }
106
+ }
104
107
  }
105
108
  function safeDecode(value) {
106
- try {
107
- return decodeURIComponent(value);
108
- } catch {
109
- return value;
110
- }
109
+ try {
110
+ return decodeURIComponent(value);
111
+ } catch {
112
+ return value;
113
+ }
111
114
  }
112
115
  function safeBase64Decode(value) {
113
- try {
114
- const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
115
- const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
116
- const binary = globalThis.atob(padded);
117
- const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
118
- return new TextDecoder().decode(bytes);
119
- } catch {
120
- return null;
121
- }
116
+ try {
117
+ const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
118
+ const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
119
+ const binary = globalThis.atob(padded);
120
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
121
+ return new TextDecoder().decode(bytes);
122
+ } catch {
123
+ return null;
124
+ }
122
125
  }
123
126
  function templateTarget(template, match) {
124
- return template.replace(/\$([1-9])/g, (_, index) => match[Number(index)] ?? "");
127
+ return template.replace(/\$([1-9])/g, (_, index) => match[Number(index)] ?? "");
125
128
  }
126
129
  function targetWithPrependedScheme(target, scheme) {
127
- if (!scheme) return target;
128
- try {
129
- new URL(target);
130
- return target;
131
- } catch {
132
- return `${scheme}://${target.replace(/^\/+/, "")}`;
133
- }
130
+ if (!scheme) return target;
131
+ try {
132
+ new URL(target);
133
+ return target;
134
+ } catch {
135
+ return `${scheme}://${target.replace(/^\/+/, "")}`;
136
+ }
134
137
  }
135
138
  function matchesAny(url, patterns) {
136
- return patterns.some((re) => re.test(url));
139
+ return patterns.some((re) => re.test(url));
137
140
  }
138
141
  function appliesTo(rule, url) {
139
- if (rule.kind !== "block-domain" && rule.urlPattern && !rule.urlPattern.test(url)) {
140
- return false;
141
- }
142
- if (rule.kind === "block-domain" && !rule.urlPattern.test(url)) return false;
143
- if (matchesAny(url, rule.exceptions)) return false;
144
- return true;
142
+ if (rule.kind !== "block-domain" && rule.urlPattern && !rule.urlPattern.test(url)) return false;
143
+ if (rule.kind === "block-domain" && !rule.urlPattern.test(url)) return false;
144
+ if (matchesAny(url, rule.exceptions)) return false;
145
+ return true;
145
146
  }
146
147
  function compileSanitizer(catalog, options = {}) {
147
- const {
148
- stripReferralMarketing = false,
149
- unwrapRedirects = true,
150
- domainBlocking = false
151
- } = options;
152
- const compiled = [];
153
- for (const rule of catalog.rules) {
154
- const c = compileRule(rule);
155
- if (c) compiled.push(c);
156
- }
157
- return function sanitize(input) {
158
- let parsed;
159
- try {
160
- parsed = new URL(input);
161
- } catch {
162
- return { kind: "unchanged", url: input };
163
- }
164
- let current = parsed.toString();
165
- const original = input;
166
- const strippedParams = [];
167
- const matchedRules = [];
168
- for (const rule of compiled) {
169
- if (!appliesTo(rule, current)) continue;
170
- switch (rule.kind) {
171
- case "block-domain": {
172
- if (!domainBlocking) continue;
173
- return {
174
- kind: "blocked",
175
- original,
176
- via: { source: rule.source, provider: rule.provider, kind: rule.kind }
177
- };
178
- }
179
- case "unwrap-redirect": {
180
- if (!unwrapRedirects) continue;
181
- let matchInput = current;
182
- if (rule.matchPart === "pathname") {
183
- try {
184
- matchInput = new URL(current).pathname;
185
- } catch {
186
- continue;
187
- }
188
- }
189
- const m = rule.pattern.exec(matchInput);
190
- if (!m) continue;
191
- const captured = rule.targetTemplate ? templateTarget(rule.targetTemplate, m) : m[rule.captureGroup];
192
- if (typeof captured === "string" && captured.length > 0) {
193
- const decodedTarget = rule.targetEncoding === "base64" ? safeBase64Decode(safeDecode(captured)) : safeDecode(captured);
194
- if (!decodedTarget) continue;
195
- const target = targetWithPrependedScheme(decodedTarget, rule.prependScheme);
196
- if (!target) continue;
197
- try {
198
- const targetUrl = new URL(target);
199
- return {
200
- kind: "redirected",
201
- original,
202
- url: targetUrl.toString(),
203
- via: { source: rule.source, provider: rule.provider, kind: rule.kind }
204
- };
205
- } catch {
206
- }
207
- }
208
- continue;
209
- }
210
- case "raw-replace": {
211
- const next = current.replace(rule.pattern, rule.replacement);
212
- if (next !== current) {
213
- current = next;
214
- matchedRules.push({
215
- source: rule.source,
216
- provider: rule.provider,
217
- kind: rule.kind
218
- });
219
- }
220
- continue;
221
- }
222
- case "strip-param": {
223
- if (rule.isReferralMarketing && !stripReferralMarketing) continue;
224
- let urlObj;
225
- try {
226
- urlObj = new URL(current);
227
- } catch {
228
- continue;
229
- }
230
- const search = stripFromQueryString(urlObj.search, rule.paramPattern, rule.valuePattern);
231
- const hash = stripFromQueryString(urlObj.hash, rule.paramPattern, rule.valuePattern);
232
- const removed = [...search.removed, ...hash.removed];
233
- if (removed.length === 0) continue;
234
- urlObj.search = search.result;
235
- urlObj.hash = hash.result;
236
- current = urlObj.toString();
237
- strippedParams.push(...removed);
238
- matchedRules.push({
239
- source: rule.source,
240
- provider: rule.provider,
241
- kind: rule.kind,
242
- detail: removed.join(",")
243
- });
244
- continue;
245
- }
246
- }
247
- }
248
- if (current === original) return { kind: "unchanged", url: original };
249
- return {
250
- kind: "cleaned",
251
- original,
252
- url: current,
253
- strippedParams,
254
- matchedRules
255
- };
256
- };
148
+ const { stripReferralMarketing = false, unwrapRedirects = true, domainBlocking = false } = options;
149
+ const compiled = [];
150
+ for (const rule of catalog.rules) {
151
+ const c = compileRule(rule);
152
+ if (c) compiled.push(c);
153
+ }
154
+ return function sanitize(input) {
155
+ let parsed;
156
+ try {
157
+ parsed = new URL(input);
158
+ } catch {
159
+ return {
160
+ kind: "unchanged",
161
+ url: input
162
+ };
163
+ }
164
+ let current = parsed.toString();
165
+ const original = input;
166
+ const strippedParams = [];
167
+ const matchedRules = [];
168
+ for (const rule of compiled) {
169
+ if (!appliesTo(rule, current)) continue;
170
+ switch (rule.kind) {
171
+ case "block-domain":
172
+ if (!domainBlocking) continue;
173
+ return {
174
+ kind: "blocked",
175
+ original,
176
+ via: {
177
+ source: rule.source,
178
+ provider: rule.provider,
179
+ kind: rule.kind
180
+ }
181
+ };
182
+ case "unwrap-redirect": {
183
+ if (!unwrapRedirects) continue;
184
+ let matchInput = current;
185
+ if (rule.matchPart === "pathname") try {
186
+ matchInput = new URL(current).pathname;
187
+ } catch {
188
+ continue;
189
+ }
190
+ const m = rule.pattern.exec(matchInput);
191
+ if (!m) continue;
192
+ const captured = rule.targetTemplate ? templateTarget(rule.targetTemplate, m) : m[rule.captureGroup];
193
+ if (typeof captured === "string" && captured.length > 0) {
194
+ const decodedTarget = rule.targetEncoding === "base64" ? safeBase64Decode(safeDecode(captured)) : safeDecode(captured);
195
+ if (!decodedTarget) continue;
196
+ const target = targetWithPrependedScheme(decodedTarget, rule.prependScheme);
197
+ if (!target) continue;
198
+ try {
199
+ return {
200
+ kind: "redirected",
201
+ original,
202
+ url: new URL(target).toString(),
203
+ via: {
204
+ source: rule.source,
205
+ provider: rule.provider,
206
+ kind: rule.kind
207
+ }
208
+ };
209
+ } catch {}
210
+ }
211
+ continue;
212
+ }
213
+ case "raw-replace": {
214
+ const next = current.replace(rule.pattern, rule.replacement);
215
+ if (next !== current) {
216
+ current = next;
217
+ matchedRules.push({
218
+ source: rule.source,
219
+ provider: rule.provider,
220
+ kind: rule.kind
221
+ });
222
+ }
223
+ continue;
224
+ }
225
+ case "strip-param": {
226
+ if (rule.isReferralMarketing && !stripReferralMarketing) continue;
227
+ let urlObj;
228
+ try {
229
+ urlObj = new URL(current);
230
+ } catch {
231
+ continue;
232
+ }
233
+ const search = stripFromQueryString(urlObj.search, rule.paramPattern, rule.valuePattern);
234
+ const hash = stripFromQueryString(urlObj.hash, rule.paramPattern, rule.valuePattern);
235
+ const removed = [...search.removed, ...hash.removed];
236
+ if (removed.length === 0) continue;
237
+ urlObj.search = search.result;
238
+ urlObj.hash = hash.result;
239
+ current = urlObj.toString();
240
+ strippedParams.push(...removed);
241
+ matchedRules.push({
242
+ source: rule.source,
243
+ provider: rule.provider,
244
+ kind: rule.kind,
245
+ detail: removed.join(",")
246
+ });
247
+ continue;
248
+ }
249
+ }
250
+ }
251
+ if (current === original) return {
252
+ kind: "unchanged",
253
+ url: original
254
+ };
255
+ return {
256
+ kind: "cleaned",
257
+ original,
258
+ url: current,
259
+ strippedParams,
260
+ matchedRules
261
+ };
262
+ };
257
263
  }
258
264
  function stripFromQueryString(searchOrHash, paramPattern, valuePattern) {
259
- if (!searchOrHash) return { result: searchOrHash, removed: [] };
260
- const prefix = searchOrHash.charAt(0);
261
- const body = prefix === "?" || prefix === "#" ? searchOrHash.slice(1) : searchOrHash;
262
- if (!body) return { result: searchOrHash, removed: [] };
263
- const pairs = body.split("&").filter(Boolean);
264
- const kept = [];
265
- const removed = [];
266
- for (const pair of pairs) {
267
- const eqIdx = pair.indexOf("=");
268
- const name = eqIdx === -1 ? pair : pair.slice(0, eqIdx);
269
- const value = eqIdx === -1 ? "" : pair.slice(eqIdx + 1);
270
- if (paramPattern.test(name) && (!valuePattern || valuePattern.test(value))) {
271
- removed.push(name);
272
- } else {
273
- kept.push(pair);
274
- }
275
- }
276
- if (removed.length === 0) return { result: searchOrHash, removed: [] };
277
- if (kept.length === 0) return { result: "", removed };
278
- return { result: prefix + kept.join("&"), removed };
265
+ if (!searchOrHash) return {
266
+ result: searchOrHash,
267
+ removed: []
268
+ };
269
+ const prefix = searchOrHash.charAt(0);
270
+ const body = prefix === "?" || prefix === "#" ? searchOrHash.slice(1) : searchOrHash;
271
+ if (!body) return {
272
+ result: searchOrHash,
273
+ removed: []
274
+ };
275
+ const pairs = body.split("&").filter(Boolean);
276
+ const kept = [];
277
+ const removed = [];
278
+ for (const pair of pairs) {
279
+ const eqIdx = pair.indexOf("=");
280
+ const name = eqIdx === -1 ? pair : pair.slice(0, eqIdx);
281
+ const value = eqIdx === -1 ? "" : pair.slice(eqIdx + 1);
282
+ if (paramPattern.test(name) && (!valuePattern || valuePattern.test(value))) removed.push(name);
283
+ else kept.push(pair);
284
+ }
285
+ if (removed.length === 0) return {
286
+ result: searchOrHash,
287
+ removed: []
288
+ };
289
+ if (kept.length === 0) return {
290
+ result: "",
291
+ removed
292
+ };
293
+ return {
294
+ result: prefix + kept.join("&"),
295
+ removed
296
+ };
279
297
  }
280
-
281
- // src/schemas.ts
282
- var ruleSourceValues = ["clearurls", "adguard", "brave", "firefox", "custom"];
283
- var ruleKindValues = ["strip-param", "raw-replace", "unwrap-redirect", "block-domain"];
284
- var redirectMatchPartValues = ["url", "pathname"];
285
- var redirectTargetEncodingValues = ["percent", "base64"];
286
- var redirectPrependSchemeValues = ["http", "https"];
287
- var catalogSourceSchema = {
288
- type: "object",
289
- required: ["name"],
290
- additionalProperties: false,
291
- properties: {
292
- name: { enum: ruleSourceValues },
293
- version: { type: "string" },
294
- hash: { type: "string" },
295
- license: { type: "string" },
296
- upstream: { type: "string" }
297
- }
298
+ //#endregion
299
+ //#region src/schemas.ts
300
+ const ruleSourceValues = [
301
+ "clearurls",
302
+ "adguard",
303
+ "brave",
304
+ "firefox",
305
+ "custom"
306
+ ];
307
+ const ruleKindValues = [
308
+ "strip-param",
309
+ "raw-replace",
310
+ "unwrap-redirect",
311
+ "block-domain"
312
+ ];
313
+ const redirectMatchPartValues = ["url", "pathname"];
314
+ const redirectTargetEncodingValues = ["percent", "base64"];
315
+ const redirectPrependSchemeValues = ["http", "https"];
316
+ const catalogSourceSchema = {
317
+ type: "object",
318
+ required: ["name"],
319
+ additionalProperties: false,
320
+ properties: {
321
+ name: { enum: ruleSourceValues },
322
+ version: { type: "string" },
323
+ hash: { type: "string" },
324
+ license: { type: "string" },
325
+ upstream: { type: "string" }
326
+ }
298
327
  };
299
- var ruleBaseProperties = {
300
- source: { enum: ruleSourceValues },
301
- provider: { type: "string" },
302
- urlPattern: { type: "string" },
303
- exceptions: {
304
- type: "array",
305
- items: { type: "string" }
306
- }
328
+ const ruleBaseProperties = {
329
+ source: { enum: ruleSourceValues },
330
+ provider: { type: "string" },
331
+ urlPattern: { type: "string" },
332
+ exceptions: {
333
+ type: "array",
334
+ items: { type: "string" }
335
+ }
307
336
  };
308
- var matchedRuleSchema = {
309
- type: "object",
310
- required: ["source", "provider", "kind"],
311
- additionalProperties: false,
312
- properties: {
313
- source: { enum: ruleSourceValues },
314
- provider: { type: "string" },
315
- kind: { enum: ruleKindValues },
316
- detail: { type: "string" }
317
- }
337
+ const matchedRuleSchema = {
338
+ type: "object",
339
+ required: [
340
+ "source",
341
+ "provider",
342
+ "kind"
343
+ ],
344
+ additionalProperties: false,
345
+ properties: {
346
+ source: { enum: ruleSourceValues },
347
+ provider: { type: "string" },
348
+ kind: { enum: ruleKindValues },
349
+ detail: { type: "string" }
350
+ }
318
351
  };
319
- var sanitizerOptionsJsonSchema = {
320
- $schema: "https://json-schema.org/draft/2020-12/schema",
321
- $id: "https://url-sanitize.dev/schema/v1/options.json",
322
- title: "url-sanitize options",
323
- type: "object",
324
- additionalProperties: false,
325
- properties: {
326
- stripReferralMarketing: { type: "boolean" },
327
- unwrapRedirects: { type: "boolean" },
328
- domainBlocking: { type: "boolean" }
329
- }
352
+ const sanitizerOptionsJsonSchema = {
353
+ $schema: "https://json-schema.org/draft/2020-12/schema",
354
+ $id: "https://url-sanitize.dev/schema/v1/options.json",
355
+ title: "url-sanitize options",
356
+ type: "object",
357
+ additionalProperties: false,
358
+ properties: {
359
+ stripReferralMarketing: { type: "boolean" },
360
+ unwrapRedirects: { type: "boolean" },
361
+ domainBlocking: { type: "boolean" }
362
+ }
330
363
  };
331
- var sanitizerCatalogJsonSchema = {
332
- $schema: "https://json-schema.org/draft/2020-12/schema",
333
- $id: "https://url-sanitize.dev/schema/v1/catalog.json",
334
- title: "url-sanitize catalog",
335
- type: "object",
336
- required: ["version", "generatedAt", "sources", "rules"],
337
- additionalProperties: false,
338
- properties: {
339
- version: { type: "string" },
340
- generatedAt: { type: "string" },
341
- sources: {
342
- type: "array",
343
- items: catalogSourceSchema
344
- },
345
- rules: {
346
- type: "array",
347
- items: {
348
- oneOf: [
349
- {
350
- type: "object",
351
- required: ["kind", "source", "provider", "paramPattern"],
352
- additionalProperties: false,
353
- properties: {
354
- ...ruleBaseProperties,
355
- kind: { const: "strip-param" },
356
- paramPattern: { type: "string" },
357
- valuePattern: { type: "string" },
358
- isReferralMarketing: { type: "boolean" }
359
- }
360
- },
361
- {
362
- type: "object",
363
- required: ["kind", "source", "provider", "pattern", "replacement"],
364
- additionalProperties: false,
365
- properties: {
366
- ...ruleBaseProperties,
367
- kind: { const: "raw-replace" },
368
- pattern: { type: "string" },
369
- replacement: { type: "string" }
370
- }
371
- },
372
- {
373
- type: "object",
374
- required: ["kind", "source", "provider", "pattern", "captureGroup"],
375
- additionalProperties: false,
376
- properties: {
377
- ...ruleBaseProperties,
378
- kind: { const: "unwrap-redirect" },
379
- pattern: { type: "string" },
380
- captureGroup: { type: "integer", minimum: 0 },
381
- matchPart: { enum: redirectMatchPartValues },
382
- targetEncoding: { enum: redirectTargetEncodingValues },
383
- prependScheme: { enum: redirectPrependSchemeValues },
384
- targetTemplate: { type: "string" }
385
- }
386
- },
387
- {
388
- type: "object",
389
- required: ["kind", "source", "provider", "urlPattern"],
390
- additionalProperties: false,
391
- properties: {
392
- ...ruleBaseProperties,
393
- kind: { const: "block-domain" }
394
- }
395
- }
396
- ]
397
- }
398
- }
399
- }
364
+ const sanitizerCatalogJsonSchema = {
365
+ $schema: "https://json-schema.org/draft/2020-12/schema",
366
+ $id: "https://url-sanitize.dev/schema/v1/catalog.json",
367
+ title: "url-sanitize catalog",
368
+ type: "object",
369
+ required: [
370
+ "version",
371
+ "generatedAt",
372
+ "sources",
373
+ "rules"
374
+ ],
375
+ additionalProperties: false,
376
+ properties: {
377
+ version: { type: "string" },
378
+ generatedAt: { type: "string" },
379
+ sources: {
380
+ type: "array",
381
+ items: catalogSourceSchema
382
+ },
383
+ rules: {
384
+ type: "array",
385
+ items: { oneOf: [
386
+ {
387
+ type: "object",
388
+ required: [
389
+ "kind",
390
+ "source",
391
+ "provider",
392
+ "paramPattern"
393
+ ],
394
+ additionalProperties: false,
395
+ properties: {
396
+ ...ruleBaseProperties,
397
+ kind: { const: "strip-param" },
398
+ paramPattern: { type: "string" },
399
+ valuePattern: { type: "string" },
400
+ isReferralMarketing: { type: "boolean" }
401
+ }
402
+ },
403
+ {
404
+ type: "object",
405
+ required: [
406
+ "kind",
407
+ "source",
408
+ "provider",
409
+ "pattern",
410
+ "replacement"
411
+ ],
412
+ additionalProperties: false,
413
+ properties: {
414
+ ...ruleBaseProperties,
415
+ kind: { const: "raw-replace" },
416
+ pattern: { type: "string" },
417
+ replacement: { type: "string" }
418
+ }
419
+ },
420
+ {
421
+ type: "object",
422
+ required: [
423
+ "kind",
424
+ "source",
425
+ "provider",
426
+ "pattern",
427
+ "captureGroup"
428
+ ],
429
+ additionalProperties: false,
430
+ properties: {
431
+ ...ruleBaseProperties,
432
+ kind: { const: "unwrap-redirect" },
433
+ pattern: { type: "string" },
434
+ captureGroup: {
435
+ type: "integer",
436
+ minimum: 0
437
+ },
438
+ matchPart: { enum: redirectMatchPartValues },
439
+ targetEncoding: { enum: redirectTargetEncodingValues },
440
+ prependScheme: { enum: redirectPrependSchemeValues },
441
+ targetTemplate: { type: "string" }
442
+ }
443
+ },
444
+ {
445
+ type: "object",
446
+ required: [
447
+ "kind",
448
+ "source",
449
+ "provider",
450
+ "urlPattern"
451
+ ],
452
+ additionalProperties: false,
453
+ properties: {
454
+ ...ruleBaseProperties,
455
+ kind: { const: "block-domain" }
456
+ }
457
+ }
458
+ ] }
459
+ }
460
+ }
400
461
  };
401
- var sanitizeResultJsonSchema = {
402
- $schema: "https://json-schema.org/draft/2020-12/schema",
403
- $id: "https://url-sanitize.dev/schema/v1/result.json",
404
- title: "url-sanitize result",
405
- oneOf: [
406
- {
407
- type: "object",
408
- required: ["kind", "url"],
409
- additionalProperties: false,
410
- properties: {
411
- kind: { const: "unchanged" },
412
- url: { type: "string" }
413
- }
414
- },
415
- {
416
- type: "object",
417
- required: ["kind", "original", "url", "strippedParams", "matchedRules"],
418
- additionalProperties: false,
419
- properties: {
420
- kind: { const: "cleaned" },
421
- original: { type: "string" },
422
- url: { type: "string" },
423
- strippedParams: {
424
- type: "array",
425
- items: { type: "string" }
426
- },
427
- matchedRules: {
428
- type: "array",
429
- items: matchedRuleSchema
430
- }
431
- }
432
- },
433
- {
434
- type: "object",
435
- required: ["kind", "original", "url", "via"],
436
- additionalProperties: false,
437
- properties: {
438
- kind: { const: "redirected" },
439
- original: { type: "string" },
440
- url: { type: "string" },
441
- via: matchedRuleSchema
442
- }
443
- },
444
- {
445
- type: "object",
446
- required: ["kind", "original", "via"],
447
- additionalProperties: false,
448
- properties: {
449
- kind: { const: "blocked" },
450
- original: { type: "string" },
451
- via: matchedRuleSchema
452
- }
453
- }
454
- ]
462
+ const sanitizeResultJsonSchema = {
463
+ $schema: "https://json-schema.org/draft/2020-12/schema",
464
+ $id: "https://url-sanitize.dev/schema/v1/result.json",
465
+ title: "url-sanitize result",
466
+ oneOf: [
467
+ {
468
+ type: "object",
469
+ required: ["kind", "url"],
470
+ additionalProperties: false,
471
+ properties: {
472
+ kind: { const: "unchanged" },
473
+ url: { type: "string" }
474
+ }
475
+ },
476
+ {
477
+ type: "object",
478
+ required: [
479
+ "kind",
480
+ "original",
481
+ "url",
482
+ "strippedParams",
483
+ "matchedRules"
484
+ ],
485
+ additionalProperties: false,
486
+ properties: {
487
+ kind: { const: "cleaned" },
488
+ original: { type: "string" },
489
+ url: { type: "string" },
490
+ strippedParams: {
491
+ type: "array",
492
+ items: { type: "string" }
493
+ },
494
+ matchedRules: {
495
+ type: "array",
496
+ items: matchedRuleSchema
497
+ }
498
+ }
499
+ },
500
+ {
501
+ type: "object",
502
+ required: [
503
+ "kind",
504
+ "original",
505
+ "url",
506
+ "via"
507
+ ],
508
+ additionalProperties: false,
509
+ properties: {
510
+ kind: { const: "redirected" },
511
+ original: { type: "string" },
512
+ url: { type: "string" },
513
+ via: matchedRuleSchema
514
+ }
515
+ },
516
+ {
517
+ type: "object",
518
+ required: [
519
+ "kind",
520
+ "original",
521
+ "via"
522
+ ],
523
+ additionalProperties: false,
524
+ properties: {
525
+ kind: { const: "blocked" },
526
+ original: { type: "string" },
527
+ via: matchedRuleSchema
528
+ }
529
+ }
530
+ ]
455
531
  };
456
- var urlSanitizeJsonSchemas = {
457
- catalog: sanitizerCatalogJsonSchema,
458
- options: sanitizerOptionsJsonSchema,
459
- result: sanitizeResultJsonSchema
460
- };
461
- export {
462
- compileSanitizer,
463
- defineCatalog,
464
- mergeCatalogs,
465
- sanitizeResultJsonSchema,
466
- sanitizerCatalogJsonSchema,
467
- sanitizerOptionsJsonSchema,
468
- urlSanitizeJsonSchemas
532
+ const urlSanitizeJsonSchemas = {
533
+ catalog: sanitizerCatalogJsonSchema,
534
+ options: sanitizerOptionsJsonSchema,
535
+ result: sanitizeResultJsonSchema
469
536
  };
537
+ //#endregion
538
+ export { compileSanitizer, defineCatalog, mergeCatalogs, sanitizeResultJsonSchema, sanitizerCatalogJsonSchema, sanitizerOptionsJsonSchema, urlSanitizeJsonSchemas };