@fanboynz/network-scanner 1.0.68 → 1.0.69
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.
- package/nwss.js +62 -31
- package/package.json +1 -1
- package/regex-tool/index.html +713 -0
package/nwss.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// === Network scanner script (nwss.js) v1.0.
|
|
1
|
+
// === Network scanner script (nwss.js) v1.0.69 ===
|
|
2
2
|
|
|
3
3
|
// puppeteer for browser automation, fs for file system operations, psl for domain parsing.
|
|
4
4
|
// const pLimit = require('p-limit'); // Will be dynamically imported
|
|
@@ -44,6 +44,37 @@ function fastTimeout(ms) {
|
|
|
44
44
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// --- Configuration Constants ---
|
|
48
|
+
const TIMEOUTS = {
|
|
49
|
+
DEFAULT_PAGE: 30000,
|
|
50
|
+
DEFAULT_NAVIGATION: 25000,
|
|
51
|
+
DEFAULT_NAVIGATION_REDUCED: 20000, // Reduced timeout for faster failures
|
|
52
|
+
DEFAULT_PAGE_REDUCED: 15000, // Reduced page timeout
|
|
53
|
+
FRAME_LOAD_WAIT: 2000,
|
|
54
|
+
NETWORK_IDLE: 2000,
|
|
55
|
+
NETWORK_IDLE_MAX: 10000,
|
|
56
|
+
FAST_SITE_THRESHOLD: 15000,
|
|
57
|
+
EMERGENCY_RESTART_DELAY: 2000,
|
|
58
|
+
BROWSER_STABILIZE_DELAY: 1000,
|
|
59
|
+
CURL_HANDLER_DELAY: 3000,
|
|
60
|
+
PROTOCOL_TIMEOUT: 60000,
|
|
61
|
+
REDIRECT_JS_TIMEOUT: 5000
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const CACHE_LIMITS = {
|
|
65
|
+
DISK_CACHE_SIZE: 52428800, // 50MB
|
|
66
|
+
MEDIA_CACHE_SIZE: 52428800, // 50MB
|
|
67
|
+
DEFAULT_CACHE_PATH: '.cache',
|
|
68
|
+
DEFAULT_MAX_SIZE: 5000
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const CONCURRENCY_LIMITS = {
|
|
72
|
+
MIN: 1,
|
|
73
|
+
MAX: 50,
|
|
74
|
+
DEFAULT: 6,
|
|
75
|
+
HIGH_CONCURRENCY_THRESHOLD: 12 // Auto-enable aggressive caching above this
|
|
76
|
+
};
|
|
77
|
+
|
|
47
78
|
/**
|
|
48
79
|
* Detects the installed Puppeteer version dynamically
|
|
49
80
|
* @returns {Object} Version info and compatibility settings
|
|
@@ -87,7 +118,7 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
|
|
|
87
118
|
const { monitorBrowserHealth, isBrowserHealthy } = require('./lib/browserhealth');
|
|
88
119
|
|
|
89
120
|
// --- Script Configuration & Constants ---
|
|
90
|
-
const VERSION = '1.0.
|
|
121
|
+
const VERSION = '1.0.69'; // Script version
|
|
91
122
|
|
|
92
123
|
// get startTime
|
|
93
124
|
const startTime = Date.now();
|
|
@@ -278,7 +309,7 @@ if (clearCache && !dryRunMode) {
|
|
|
278
309
|
clearPersistentCache({
|
|
279
310
|
silent: silentMode,
|
|
280
311
|
forceDebug,
|
|
281
|
-
cachePath:
|
|
312
|
+
cachePath: CACHE_LIMITS.DEFAULT_CACHE_PATH // Default path, will be updated after config loads if needed
|
|
282
313
|
});
|
|
283
314
|
}
|
|
284
315
|
|
|
@@ -568,24 +599,24 @@ const {
|
|
|
568
599
|
const MAX_CONCURRENT_SITES = (() => {
|
|
569
600
|
// Check command line argument first
|
|
570
601
|
if (maxConcurrentSites !== null) {
|
|
571
|
-
if (maxConcurrentSites
|
|
602
|
+
if (maxConcurrentSites >= CONCURRENCY_LIMITS.MIN && maxConcurrentSites <= CONCURRENCY_LIMITS.MAX) {
|
|
572
603
|
if (forceDebug) console.log(formatLogMessage('debug', `Using command line max_concurrent_sites: ${maxConcurrentSites}`));
|
|
573
604
|
return maxConcurrentSites;
|
|
574
605
|
} else {
|
|
575
|
-
console.warn(`⚠ Invalid --max-concurrent value: ${maxConcurrentSites}. Must be
|
|
606
|
+
console.warn(`⚠ Invalid --max-concurrent value: ${maxConcurrentSites}. Must be ${CONCURRENCY_LIMITS.MIN}-${CONCURRENCY_LIMITS.MAX}. Using config/default value.`);
|
|
576
607
|
}
|
|
577
608
|
}
|
|
578
609
|
|
|
579
610
|
// Check config.json value
|
|
580
|
-
if (typeof max_concurrent_sites === 'number' && max_concurrent_sites
|
|
611
|
+
if (typeof max_concurrent_sites === 'number' && max_concurrent_sites >= CONCURRENCY_LIMITS.MIN && max_concurrent_sites <= CONCURRENCY_LIMITS.MAX) {
|
|
581
612
|
if (forceDebug) console.log(formatLogMessage('debug', `Using config max_concurrent_sites: ${max_concurrent_sites}`));
|
|
582
613
|
return max_concurrent_sites;
|
|
583
|
-
} else if (max_concurrent_sites !==
|
|
584
|
-
console.warn(`⚠ Invalid config max_concurrent_sites value: ${max_concurrent_sites}. Using default:
|
|
614
|
+
} else if (max_concurrent_sites !== CONCURRENCY_LIMITS.DEFAULT) {
|
|
615
|
+
console.warn(`⚠ Invalid config max_concurrent_sites value: ${max_concurrent_sites}. Using default: ${CONCURRENCY_LIMITS.DEFAULT}`);
|
|
585
616
|
}
|
|
586
617
|
|
|
587
618
|
// Use default
|
|
588
|
-
return
|
|
619
|
+
return CONCURRENCY_LIMITS.DEFAULT;
|
|
589
620
|
})();
|
|
590
621
|
|
|
591
622
|
const RESOURCE_CLEANUP_INTERVAL = (() => {
|
|
@@ -621,7 +652,7 @@ if (clearCache && dryRunMode) {
|
|
|
621
652
|
}
|
|
622
653
|
|
|
623
654
|
// Also clear for custom cache paths in normal mode if not already cleared
|
|
624
|
-
if (clearCache && !dryRunMode && config.cache_path && config.cache_path !==
|
|
655
|
+
if (clearCache && !dryRunMode && config.cache_path && config.cache_path !== CACHE_LIMITS.DEFAULT_CACHE_PATH) {
|
|
625
656
|
clearPersistentCache({
|
|
626
657
|
silent: silentMode,
|
|
627
658
|
forceDebug,
|
|
@@ -638,11 +669,11 @@ smartCache = createSmartCache({
|
|
|
638
669
|
...config,
|
|
639
670
|
forceDebug,
|
|
640
671
|
max_concurrent_sites: MAX_CONCURRENT_SITES, // Pass concurrency info
|
|
641
|
-
cache_aggressive_mode: MAX_CONCURRENT_SITES >
|
|
672
|
+
cache_aggressive_mode: MAX_CONCURRENT_SITES > CONCURRENCY_LIMITS.HIGH_CONCURRENCY_THRESHOLD, // Auto-enable for high concurrency
|
|
642
673
|
cache_persistence: false, // Disable persistence completely
|
|
643
674
|
cache_autosave: false, // Disable auto-save completely
|
|
644
675
|
cache_autosave_minutes: config.cache_autosave_minutes || 1,
|
|
645
|
-
cache_max_size: config.cache_max_size ||
|
|
676
|
+
cache_max_size: config.cache_max_size || CACHE_LIMITS.DEFAULT_MAX_SIZE
|
|
646
677
|
});
|
|
647
678
|
}
|
|
648
679
|
|
|
@@ -1142,8 +1173,8 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1142
1173
|
args: [
|
|
1143
1174
|
// Disk space controls - 50MB cache limits
|
|
1144
1175
|
'--disable-features=VizDisplayCompositor',
|
|
1145
|
-
|
|
1146
|
-
|
|
1176
|
+
`--disk-cache-size=${CACHE_LIMITS.DISK_CACHE_SIZE}`, // 50MB disk cache
|
|
1177
|
+
`--media-cache-size=${CACHE_LIMITS.MEDIA_CACHE_SIZE}`, // 50MB media cache
|
|
1147
1178
|
'--disable-application-cache',
|
|
1148
1179
|
'--disable-offline-load-stale-cache',
|
|
1149
1180
|
'--disable-background-downloads',
|
|
@@ -1188,7 +1219,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1188
1219
|
'--no-zygote', // Better process isolation
|
|
1189
1220
|
],
|
|
1190
1221
|
// Optimized timeouts for Puppeteer 23.x performance
|
|
1191
|
-
protocolTimeout:
|
|
1222
|
+
protocolTimeout: TIMEOUTS.PROTOCOL_TIMEOUT,
|
|
1192
1223
|
slowMo: 0, // No artificial delays
|
|
1193
1224
|
defaultViewport: null, // Use system default viewport
|
|
1194
1225
|
ignoreDefaultArgs: ['--enable-automation'] // Avoid automation detection
|
|
@@ -1336,7 +1367,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1336
1367
|
matchedDomains.set('dryRunNetTools', []);
|
|
1337
1368
|
matchedDomains.set('dryRunSearchString', new Map()); // Map URL to search results
|
|
1338
1369
|
}
|
|
1339
|
-
const timeout = siteConfig.timeout ||
|
|
1370
|
+
const timeout = siteConfig.timeout || TIMEOUTS.DEFAULT_PAGE;
|
|
1340
1371
|
|
|
1341
1372
|
if (!silentMode) console.log(`\n${messageColors.scanning('Scanning:')} ${currentUrl}`);
|
|
1342
1373
|
|
|
@@ -1393,8 +1424,8 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1393
1424
|
|
|
1394
1425
|
// Set aggressive timeouts for problematic operations
|
|
1395
1426
|
// Optimized timeouts for Puppeteer 23.x responsiveness
|
|
1396
|
-
page.setDefaultTimeout(Math.min(timeout,
|
|
1397
|
-
page.setDefaultNavigationTimeout(Math.min(timeout,
|
|
1427
|
+
page.setDefaultTimeout(Math.min(timeout, TIMEOUTS.DEFAULT_PAGE_REDUCED));
|
|
1428
|
+
page.setDefaultNavigationTimeout(Math.min(timeout, TIMEOUTS.DEFAULT_NAVIGATION));
|
|
1398
1429
|
// Aggressive timeouts prevent hanging in Puppeteer 23.x while maintaining speed
|
|
1399
1430
|
|
|
1400
1431
|
page.on('console', (msg) => {
|
|
@@ -1461,8 +1492,8 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
1461
1492
|
// Apply flowProxy timeouts if detection is enabled
|
|
1462
1493
|
if (flowproxyDetection) {
|
|
1463
1494
|
const flowproxyTimeouts = getFlowProxyTimeouts(siteConfig);
|
|
1464
|
-
page.setDefaultTimeout(Math.min(flowproxyTimeouts.pageTimeout,
|
|
1465
|
-
page.setDefaultNavigationTimeout(Math.min(flowproxyTimeouts.navigationTimeout,
|
|
1495
|
+
page.setDefaultTimeout(Math.min(flowproxyTimeouts.pageTimeout, TIMEOUTS.DEFAULT_NAVIGATION));
|
|
1496
|
+
page.setDefaultNavigationTimeout(Math.min(flowproxyTimeouts.navigationTimeout, TIMEOUTS.DEFAULT_PAGE));
|
|
1466
1497
|
if (forceDebug) {
|
|
1467
1498
|
console.log(formatLogMessage('debug', `Applied flowProxy timeouts - page: ${flowproxyTimeouts.pageTimeout}ms, nav: ${flowproxyTimeouts.navigationTimeout}ms`));
|
|
1468
1499
|
}
|
|
@@ -2293,13 +2324,13 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2293
2324
|
// Use explicit Promise-based timeouts instead of page.waitForTimeout()
|
|
2294
2325
|
|
|
2295
2326
|
// Use faster defaults for sites with long timeouts to improve responsiveness
|
|
2296
|
-
const isFastSite = timeout <=
|
|
2327
|
+
const isFastSite = timeout <= TIMEOUTS.FAST_SITE_THRESHOLD;
|
|
2297
2328
|
const defaultWaitUntil = 'domcontentloaded'; // Always use faster option in Puppeteer 23.x
|
|
2298
2329
|
|
|
2299
2330
|
// Enhanced navigation options for Puppeteer 23.x
|
|
2300
2331
|
const defaultGotoOptions = {
|
|
2301
2332
|
waitUntil: defaultWaitUntil,
|
|
2302
|
-
timeout: Math.min(timeout,
|
|
2333
|
+
timeout: Math.min(timeout, TIMEOUTS.DEFAULT_PAGE), // Cap at default page timeout
|
|
2303
2334
|
// Puppeteer 23.x: Fixed referrer header handling
|
|
2304
2335
|
...(siteConfig.referrer_headers && (() => {
|
|
2305
2336
|
const referrerUrl = Array.isArray(siteConfig.referrer_headers)
|
|
@@ -2418,7 +2449,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2418
2449
|
if (forceDebug) {
|
|
2419
2450
|
try {
|
|
2420
2451
|
// Use fast timeout helper for compatibility
|
|
2421
|
-
await fastTimeout(
|
|
2452
|
+
await fastTimeout(TIMEOUTS.FRAME_LOAD_WAIT); // Give iframes time to load
|
|
2422
2453
|
const frames = page.frames();
|
|
2423
2454
|
console.log(formatLogMessage('debug', `Total frames found: ${frames.length}`));
|
|
2424
2455
|
frames.forEach((frame, index) => {
|
|
@@ -2462,10 +2493,10 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2462
2493
|
const delayMs = siteConfig.delay || 4000;
|
|
2463
2494
|
|
|
2464
2495
|
// Optimized delays for Puppeteer 23.x performance
|
|
2465
|
-
const isFastSite = timeout <=
|
|
2466
|
-
const networkIdleTime =
|
|
2467
|
-
const networkIdleTimeout = Math.min(timeout / 2,
|
|
2468
|
-
const actualDelay = Math.min(delayMs,
|
|
2496
|
+
const isFastSite = timeout <= TIMEOUTS.FAST_SITE_THRESHOLD;
|
|
2497
|
+
const networkIdleTime = TIMEOUTS.NETWORK_IDLE; // Balanced: 2s for reliable network detection
|
|
2498
|
+
const networkIdleTimeout = Math.min(timeout / 2, TIMEOUTS.NETWORK_IDLE_MAX); // Balanced: 10s timeout
|
|
2499
|
+
const actualDelay = Math.min(delayMs, TIMEOUTS.NETWORK_IDLE); // Balanced: 2s delay for stability
|
|
2469
2500
|
|
|
2470
2501
|
await page.waitForNetworkIdle({
|
|
2471
2502
|
idleTime: networkIdleTime,
|
|
@@ -2550,7 +2581,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2550
2581
|
|
|
2551
2582
|
// Wait a moment for async nettools/searchstring operations to complete
|
|
2552
2583
|
// Use fast timeout helper for Puppeteer 22.x compatibility
|
|
2553
|
-
await fastTimeout(
|
|
2584
|
+
await fastTimeout(TIMEOUTS.CURL_HANDLER_DELAY); // Wait for async operations
|
|
2554
2585
|
|
|
2555
2586
|
outputDryRunResults(currentUrl, enhancedMatches, dryRunNetTools, pageTitle);
|
|
2556
2587
|
|
|
@@ -2767,7 +2798,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2767
2798
|
|
|
2768
2799
|
// Reset cleanup counter and add delay
|
|
2769
2800
|
urlsSinceLastCleanup = 0;
|
|
2770
|
-
await fastTimeout(
|
|
2801
|
+
await fastTimeout(TIMEOUTS.BROWSER_STABILIZE_DELAY);
|
|
2771
2802
|
}
|
|
2772
2803
|
|
|
2773
2804
|
if (forceDebug) {
|
|
@@ -2835,7 +2866,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
2835
2866
|
}
|
|
2836
2867
|
browser = await createBrowser();
|
|
2837
2868
|
urlsSinceLastCleanup = 0; // Reset counter
|
|
2838
|
-
await fastTimeout(
|
|
2869
|
+
await fastTimeout(TIMEOUTS.EMERGENCY_RESTART_DELAY); // Give browser time to stabilize
|
|
2839
2870
|
} catch (emergencyRestartErr) {
|
|
2840
2871
|
if (forceDebug) console.log(formatLogMessage('debug', `Emergency restart failed: ${emergencyRestartErr.message}`));
|
|
2841
2872
|
}
|
|
@@ -3013,7 +3044,7 @@ function setupFrameHandling(page, forceDebug) {
|
|
|
3013
3044
|
forceDebug,
|
|
3014
3045
|
comprehensive: true
|
|
3015
3046
|
});
|
|
3016
|
-
await fastTimeout(
|
|
3047
|
+
await fastTimeout(TIMEOUTS.BROWSER_STABILIZE_DELAY); // Give filesystem time to sync
|
|
3017
3048
|
|
|
3018
3049
|
// Calculate timing, success rates, and provide summary information
|
|
3019
3050
|
if (forceDebug) console.log(formatLogMessage('debug', `Calculating timing statistics...`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.69",
|
|
4
4
|
"description": "A Puppeteer-based network scanner for analyzing web traffic, generating adblock filter rules, and identifying third-party requests. Features include fingerprint spoofing, Cloudflare bypass, content analysis with curl/grep, and multiple output formats.",
|
|
5
5
|
"main": "nwss.js",
|
|
6
6
|
"scripts": {
|
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Regex Tools - Converter & Validator</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
padding: 20px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.container {
|
|
22
|
+
max-width: 1000px;
|
|
23
|
+
margin: 0 auto;
|
|
24
|
+
background: rgba(255, 255, 255, 0.95);
|
|
25
|
+
border-radius: 20px;
|
|
26
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.header {
|
|
31
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
32
|
+
color: white;
|
|
33
|
+
padding: 30px;
|
|
34
|
+
text-align: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.header h1 {
|
|
38
|
+
font-size: 2.5em;
|
|
39
|
+
margin-bottom: 10px;
|
|
40
|
+
animation: fadeInDown 0.5s ease;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.header p {
|
|
44
|
+
opacity: 0.9;
|
|
45
|
+
font-size: 1.1em;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.tabs {
|
|
49
|
+
display: flex;
|
|
50
|
+
background: #f7f9fc;
|
|
51
|
+
border-bottom: 2px solid #e2e8f0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.tab {
|
|
55
|
+
flex: 1;
|
|
56
|
+
padding: 20px;
|
|
57
|
+
text-align: center;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
background: transparent;
|
|
60
|
+
border: none;
|
|
61
|
+
font-size: 1.1em;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
color: #64748b;
|
|
64
|
+
transition: all 0.3s ease;
|
|
65
|
+
position: relative;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tab:hover {
|
|
69
|
+
background: rgba(102, 126, 234, 0.1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.tab.active {
|
|
73
|
+
color: #667eea;
|
|
74
|
+
background: white;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.tab.active::after {
|
|
78
|
+
content: '';
|
|
79
|
+
position: absolute;
|
|
80
|
+
bottom: -2px;
|
|
81
|
+
left: 0;
|
|
82
|
+
right: 0;
|
|
83
|
+
height: 3px;
|
|
84
|
+
background: linear-gradient(90deg, #667eea, #764ba2);
|
|
85
|
+
animation: slideIn 0.3s ease;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.content {
|
|
89
|
+
padding: 40px;
|
|
90
|
+
min-height: 500px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.tab-content {
|
|
94
|
+
display: none;
|
|
95
|
+
animation: fadeIn 0.3s ease;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.tab-content.active {
|
|
99
|
+
display: block;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.input-group {
|
|
103
|
+
margin-bottom: 30px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.input-group label {
|
|
107
|
+
display: block;
|
|
108
|
+
margin-bottom: 10px;
|
|
109
|
+
font-weight: 600;
|
|
110
|
+
color: #334155;
|
|
111
|
+
font-size: 1.1em;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.input-group input[type="text"],
|
|
115
|
+
.input-group textarea {
|
|
116
|
+
width: 100%;
|
|
117
|
+
padding: 15px;
|
|
118
|
+
border: 2px solid #e2e8f0;
|
|
119
|
+
border-radius: 10px;
|
|
120
|
+
font-size: 1em;
|
|
121
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
122
|
+
transition: all 0.3s ease;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.input-group input[type="text"]:focus,
|
|
126
|
+
.input-group textarea:focus {
|
|
127
|
+
outline: none;
|
|
128
|
+
border-color: #667eea;
|
|
129
|
+
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.input-group textarea {
|
|
133
|
+
resize: vertical;
|
|
134
|
+
min-height: 100px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.checkbox-group {
|
|
138
|
+
display: flex;
|
|
139
|
+
align-items: center;
|
|
140
|
+
margin-bottom: 20px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.checkbox-group input[type="checkbox"] {
|
|
144
|
+
width: 20px;
|
|
145
|
+
height: 20px;
|
|
146
|
+
margin-right: 10px;
|
|
147
|
+
cursor: pointer;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.checkbox-group label {
|
|
151
|
+
cursor: pointer;
|
|
152
|
+
font-weight: 500;
|
|
153
|
+
color: #475569;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.button {
|
|
157
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
158
|
+
color: white;
|
|
159
|
+
border: none;
|
|
160
|
+
padding: 15px 40px;
|
|
161
|
+
border-radius: 10px;
|
|
162
|
+
font-size: 1.1em;
|
|
163
|
+
font-weight: 600;
|
|
164
|
+
cursor: pointer;
|
|
165
|
+
transition: all 0.3s ease;
|
|
166
|
+
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.button:hover {
|
|
170
|
+
transform: translateY(-2px);
|
|
171
|
+
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.button:active {
|
|
175
|
+
transform: translateY(0);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.output-section {
|
|
179
|
+
margin-top: 40px;
|
|
180
|
+
padding: 25px;
|
|
181
|
+
background: #f8fafc;
|
|
182
|
+
border-radius: 10px;
|
|
183
|
+
border: 2px solid #e2e8f0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.output-section h3 {
|
|
187
|
+
margin-bottom: 15px;
|
|
188
|
+
color: #334155;
|
|
189
|
+
font-size: 1.3em;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.output-box {
|
|
193
|
+
background: white;
|
|
194
|
+
padding: 20px;
|
|
195
|
+
border-radius: 8px;
|
|
196
|
+
border: 1px solid #e2e8f0;
|
|
197
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
198
|
+
margin-bottom: 20px;
|
|
199
|
+
word-break: break-all;
|
|
200
|
+
transition: all 0.3s ease;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.output-box:hover {
|
|
204
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.examples-list {
|
|
208
|
+
list-style: none;
|
|
209
|
+
padding: 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.examples-list li {
|
|
213
|
+
background: white;
|
|
214
|
+
padding: 15px;
|
|
215
|
+
margin-bottom: 10px;
|
|
216
|
+
border-radius: 8px;
|
|
217
|
+
border-left: 4px solid #667eea;
|
|
218
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
219
|
+
transition: all 0.3s ease;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.examples-list li:hover {
|
|
223
|
+
transform: translateX(5px);
|
|
224
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.error {
|
|
228
|
+
background: #fee;
|
|
229
|
+
color: #c00;
|
|
230
|
+
padding: 15px;
|
|
231
|
+
border-radius: 8px;
|
|
232
|
+
border: 1px solid #fcc;
|
|
233
|
+
margin-top: 10px;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.success {
|
|
237
|
+
background: #e6fffa;
|
|
238
|
+
color: #047857;
|
|
239
|
+
padding: 15px;
|
|
240
|
+
border-radius: 8px;
|
|
241
|
+
border: 1px solid #6ee7b7;
|
|
242
|
+
margin-top: 10px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@keyframes fadeIn {
|
|
246
|
+
from {
|
|
247
|
+
opacity: 0;
|
|
248
|
+
transform: translateY(10px);
|
|
249
|
+
}
|
|
250
|
+
to {
|
|
251
|
+
opacity: 1;
|
|
252
|
+
transform: translateY(0);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@keyframes fadeInDown {
|
|
257
|
+
from {
|
|
258
|
+
opacity: 0;
|
|
259
|
+
transform: translateY(-20px);
|
|
260
|
+
}
|
|
261
|
+
to {
|
|
262
|
+
opacity: 1;
|
|
263
|
+
transform: translateY(0);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
@keyframes slideIn {
|
|
268
|
+
from {
|
|
269
|
+
transform: scaleX(0);
|
|
270
|
+
}
|
|
271
|
+
to {
|
|
272
|
+
transform: scaleX(1);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@media (max-width: 768px) {
|
|
277
|
+
.header h1 {
|
|
278
|
+
font-size: 1.8em;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.content {
|
|
282
|
+
padding: 20px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.button {
|
|
286
|
+
width: 100%;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
</style>
|
|
290
|
+
</head>
|
|
291
|
+
<body>
|
|
292
|
+
<div class="container">
|
|
293
|
+
<div class="header">
|
|
294
|
+
<h1>🔍 Regex Tools</h1>
|
|
295
|
+
<p>Convert and Validate Regular Expressions with Ease</p>
|
|
296
|
+
</div>
|
|
297
|
+
|
|
298
|
+
<div class="tabs">
|
|
299
|
+
<button class="tab active" onclick="switchTab('convert')">
|
|
300
|
+
📝 Convert to JSON
|
|
301
|
+
</button>
|
|
302
|
+
<button class="tab" onclick="switchTab('validate')">
|
|
303
|
+
✅ Validate Regex
|
|
304
|
+
</button>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div class="content">
|
|
308
|
+
<!-- Convert Tab -->
|
|
309
|
+
<div id="convert" class="tab-content active">
|
|
310
|
+
<div class="input-group">
|
|
311
|
+
<label for="standardRegex">Enter Standard Regex Pattern:</label>
|
|
312
|
+
<input type="text" id="standardRegex" placeholder="e.g., ^https?://.*\.example\.com/.*$">
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<button class="button" onclick="convertToJSON()">Convert to JSON</button>
|
|
316
|
+
|
|
317
|
+
<div id="convertOutput"></div>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<!-- Validate Tab -->
|
|
321
|
+
<div id="validate" class="tab-content">
|
|
322
|
+
<div class="checkbox-group" style="background: #f0f9ff; padding: 15px; border-radius: 8px; margin-bottom: 20px; border: 2px solid #0ea5e9;">
|
|
323
|
+
<input type="checkbox" id="useStandardRegex" onchange="toggleRegexInput()">
|
|
324
|
+
<label for="useStandardRegex"><strong>✓ Check this box to validate Standard Regex</strong> (uncheck for JSON format)</label>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<div class="input-group">
|
|
328
|
+
<label for="regexToValidate">Enter Regex Pattern:</label>
|
|
329
|
+
<textarea id="regexToValidate" placeholder='⚠️ IMPORTANT: Check the box above if entering standard regex! For JSON (box unchecked): {"filterRegex": ["^https?:\\\\/\\\\/.*"]} For Standard (box checked): ^https?:\\/\\/.*'></textarea>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
<button class="button" onclick="validateRegex()">Validate Regex</button>
|
|
333
|
+
|
|
334
|
+
<div id="validateOutput"></div>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<script>
|
|
340
|
+
function switchTab(tabName) {
|
|
341
|
+
// Update tabs
|
|
342
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
|
343
|
+
tab.classList.remove('active');
|
|
344
|
+
});
|
|
345
|
+
event.target.classList.add('active');
|
|
346
|
+
|
|
347
|
+
// Update content
|
|
348
|
+
document.querySelectorAll('.tab-content').forEach(content => {
|
|
349
|
+
content.classList.remove('active');
|
|
350
|
+
});
|
|
351
|
+
document.getElementById(tabName).classList.add('active');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function toggleRegexInput() {
|
|
355
|
+
const checkbox = document.getElementById('useStandardRegex');
|
|
356
|
+
const textarea = document.getElementById('regexToValidate');
|
|
357
|
+
|
|
358
|
+
if (checkbox.checked) {
|
|
359
|
+
textarea.placeholder = 'Enter standard regex pattern, e.g., ^https?://.*';
|
|
360
|
+
} else {
|
|
361
|
+
textarea.placeholder = 'Enter JSON regex, e.g., {"pattern": "^https?://.*", "flags": "gi"}';
|
|
362
|
+
}
|
|
363
|
+
textarea.value = '';
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function generateExamples(regex) {
|
|
367
|
+
const examples = [];
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
// Get the pattern string
|
|
371
|
+
const pattern = regex.source || regex.pattern || regex.toString();
|
|
372
|
+
|
|
373
|
+
// Helper function to generate random string of specific length
|
|
374
|
+
function generateRandomString(minLen, maxLen) {
|
|
375
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-+=';
|
|
376
|
+
const length = maxLen ? Math.floor(Math.random() * (maxLen - minLen + 1)) + minLen : minLen;
|
|
377
|
+
let result = '';
|
|
378
|
+
for (let i = 0; i < length; i++) {
|
|
379
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (pattern.includes('http')) {
|
|
385
|
+
// Check for specific domain requirements
|
|
386
|
+
if (pattern.includes('com|org')) {
|
|
387
|
+
// Pattern requires .com or .org domains
|
|
388
|
+
const protocols = pattern.includes('https?') ? ['https://', 'http://'] : ['https://'];
|
|
389
|
+
const domains = ['example', 'test-site', 'web-app', 'api-server', 'my-service'];
|
|
390
|
+
const extensions = ['com', 'org'];
|
|
391
|
+
|
|
392
|
+
for (let i = 0; i < 5; i++) {
|
|
393
|
+
const protocol = protocols[i % protocols.length];
|
|
394
|
+
const domain = domains[i % domains.length];
|
|
395
|
+
const ext = extensions[i % extensions.length];
|
|
396
|
+
|
|
397
|
+
// Build the path part
|
|
398
|
+
let path = '';
|
|
399
|
+
|
|
400
|
+
// Check for specific length requirements in path
|
|
401
|
+
const pathMatch = pattern.match(/\[A-Za-z0-9[^\]]*\]\{(\d+),?(\d*)\}/);
|
|
402
|
+
if (pathMatch) {
|
|
403
|
+
const minLen = parseInt(pathMatch[1]);
|
|
404
|
+
const maxLen = pathMatch[2] ? parseInt(pathMatch[2]) : minLen + 20;
|
|
405
|
+
path = generateRandomString(minLen, maxLen);
|
|
406
|
+
} else {
|
|
407
|
+
path = 'api/v1/users/profile/data';
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
let url = `${protocol}${domain}.${ext}/${path}`;
|
|
411
|
+
|
|
412
|
+
// Add query params if pattern requires them
|
|
413
|
+
if (pattern.includes('\\?')) {
|
|
414
|
+
// Check for minimum length requirements in query
|
|
415
|
+
const queryMatch = pattern.match(/\\\?\.\{(\d+),?(\d*)\}/);
|
|
416
|
+
if (queryMatch) {
|
|
417
|
+
const minLen = parseInt(queryMatch[1]);
|
|
418
|
+
const maxLen = queryMatch[2] ? parseInt(queryMatch[2]) : minLen + 10;
|
|
419
|
+
url += '?' + generateRandomString(minLen, maxLen);
|
|
420
|
+
} else if (pattern.match(/\?\.\{(\d+),/)) {
|
|
421
|
+
// Handle any {n,} pattern after ?
|
|
422
|
+
const match = pattern.match(/\?\.\{(\d+),/);
|
|
423
|
+
const minLen = parseInt(match[1]);
|
|
424
|
+
url += '?param=' + generateRandomString(Math.max(minLen - 6, 1), minLen + 15);
|
|
425
|
+
} else {
|
|
426
|
+
url += '?param=value&key=data';
|
|
427
|
+
}
|
|
428
|
+
} else if (pattern.includes('&.{')) {
|
|
429
|
+
// Handle &.{n,} case
|
|
430
|
+
const ampMatch = pattern.match(/&\.\{(\d+),/);
|
|
431
|
+
if (ampMatch) {
|
|
432
|
+
const minLen = parseInt(ampMatch[1]);
|
|
433
|
+
url += '&' + generateRandomString(minLen, minLen + 15);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
examples.push(url);
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
// General URL patterns
|
|
441
|
+
const protocols = pattern.includes('https?') ? ['http://', 'https://'] : ['https://'];
|
|
442
|
+
const urls = [
|
|
443
|
+
'www.example.com/path/to/resource',
|
|
444
|
+
'subdomain.test.com/api/endpoint',
|
|
445
|
+
'example.org/page/section/item',
|
|
446
|
+
'demo.net/products/category',
|
|
447
|
+
'sample.io/user/profile/settings'
|
|
448
|
+
];
|
|
449
|
+
|
|
450
|
+
urls.forEach((url, i) => {
|
|
451
|
+
if (i < 5) {
|
|
452
|
+
let fullUrl = protocols[i % protocols.length] + url;
|
|
453
|
+
|
|
454
|
+
// Check for length requirements
|
|
455
|
+
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
|
|
456
|
+
if (lengthMatch && !pattern.includes('\\?')) {
|
|
457
|
+
const minLen = parseInt(lengthMatch[1]);
|
|
458
|
+
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 10;
|
|
459
|
+
fullUrl += '/' + generateRandomString(minLen, maxLen);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
examples.push(fullUrl);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Test all generated examples against the regex
|
|
468
|
+
const validExamples = [];
|
|
469
|
+
for (const example of examples) {
|
|
470
|
+
try {
|
|
471
|
+
// Reset regex lastIndex in case of global flag
|
|
472
|
+
regex.lastIndex = 0;
|
|
473
|
+
if (regex.test(example)) {
|
|
474
|
+
validExamples.push(example);
|
|
475
|
+
}
|
|
476
|
+
} catch (e) {
|
|
477
|
+
console.error('Error testing example:', e);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// If we don't have enough valid examples, try more specific ones with proper lengths
|
|
482
|
+
if (validExamples.length < 5) {
|
|
483
|
+
const moreSpecific = [];
|
|
484
|
+
for (let i = 0; i < 10; i++) {
|
|
485
|
+
const protocol = i % 2 === 0 ? 'https://' : 'http://';
|
|
486
|
+
const domain = ['test-api', 'web-server', 'my-app', 'demo-site', 'api-gateway'][i % 5];
|
|
487
|
+
const ext = i % 2 === 0 ? 'com' : 'org';
|
|
488
|
+
|
|
489
|
+
// Generate path with proper length if specified
|
|
490
|
+
let path = 'Path_';
|
|
491
|
+
const pathMatch = pattern.match(/\[A-Za-z0-9[^\]]*\]\{(\d+),?(\d*)\}/);
|
|
492
|
+
if (pathMatch) {
|
|
493
|
+
const minLen = parseInt(pathMatch[1]);
|
|
494
|
+
const maxLen = pathMatch[2] ? parseInt(pathMatch[2]) : minLen + 20;
|
|
495
|
+
path = generateRandomString(minLen, maxLen);
|
|
496
|
+
} else {
|
|
497
|
+
path += generateRandomString(10, 30);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
let url = `${protocol}${domain}.${ext}/${path}`;
|
|
501
|
+
|
|
502
|
+
// Add query with proper length if needed
|
|
503
|
+
if (pattern.includes('\\?')) {
|
|
504
|
+
const queryMatch = pattern.match(/\\\?\.\{(\d+),?(\d*)\}/);
|
|
505
|
+
if (queryMatch) {
|
|
506
|
+
const minLen = parseInt(queryMatch[1]);
|
|
507
|
+
url += '?q=' + generateRandomString(Math.max(minLen - 2, 1), minLen + 10);
|
|
508
|
+
} else if (pattern.match(/\?\.\{(\d+),/)) {
|
|
509
|
+
const match = pattern.match(/\?\.\{(\d+),/);
|
|
510
|
+
const minLen = parseInt(match[1]);
|
|
511
|
+
url += '?' + generateRandomString(minLen, minLen + 15);
|
|
512
|
+
} else {
|
|
513
|
+
url += '?param=' + generateRandomString(10, 20);
|
|
514
|
+
}
|
|
515
|
+
} else if (pattern.includes('&.{')) {
|
|
516
|
+
const ampMatch = pattern.match(/&\.\{(\d+),/);
|
|
517
|
+
if (ampMatch) {
|
|
518
|
+
const minLen = parseInt(ampMatch[1]);
|
|
519
|
+
url += '&' + generateRandomString(minLen, minLen + 15);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
moreSpecific.push(url);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
for (const url of moreSpecific) {
|
|
527
|
+
regex.lastIndex = 0;
|
|
528
|
+
if (regex.test(url) && validExamples.length < 5) {
|
|
529
|
+
validExamples.push(url);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return validExamples.length > 0 ? validExamples.slice(0, 5) : [
|
|
535
|
+
'Pattern is very specific - generating custom examples...',
|
|
536
|
+
'Try: https://example.com/Page_Name/path?query=value12345',
|
|
537
|
+
'Try: http://test.org/API_endpoint/data?param=longvalue123',
|
|
538
|
+
'Manual testing recommended for this pattern',
|
|
539
|
+
'Validation successful'
|
|
540
|
+
];
|
|
541
|
+
} else if (pattern.includes('@')) {
|
|
542
|
+
examples.push(
|
|
543
|
+
'user@example.com',
|
|
544
|
+
'john.doe@company.org',
|
|
545
|
+
'admin+tag@subdomain.example.com',
|
|
546
|
+
'contact@business.co.uk',
|
|
547
|
+
'support123@service.io'
|
|
548
|
+
);
|
|
549
|
+
} else if (pattern.includes('\\d')) {
|
|
550
|
+
// Check for length requirements
|
|
551
|
+
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
|
|
552
|
+
if (lengthMatch) {
|
|
553
|
+
const minLen = parseInt(lengthMatch[1]);
|
|
554
|
+
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 10;
|
|
555
|
+
for (let i = 0; i < 5; i++) {
|
|
556
|
+
examples.push(generateRandomString(minLen, maxLen));
|
|
557
|
+
}
|
|
558
|
+
} else {
|
|
559
|
+
examples.push(
|
|
560
|
+
'12345',
|
|
561
|
+
'2024-01-15',
|
|
562
|
+
'ID-9876-XY',
|
|
563
|
+
'Version 3.14.159',
|
|
564
|
+
'Order #00425'
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
} else if (pattern.includes('\\w')) {
|
|
568
|
+
// Check for length requirements
|
|
569
|
+
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
|
|
570
|
+
if (lengthMatch) {
|
|
571
|
+
const minLen = parseInt(lengthMatch[1]);
|
|
572
|
+
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 10;
|
|
573
|
+
for (let i = 0; i < 5; i++) {
|
|
574
|
+
examples.push(generateRandomString(minLen, maxLen));
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
examples.push(
|
|
578
|
+
'HelloWorld',
|
|
579
|
+
'user_name_123',
|
|
580
|
+
'CamelCaseExample',
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
// Check for any length requirements in the pattern
|
|
585
|
+
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
|
|
586
|
+
if (lengthMatch) {
|
|
587
|
+
const minLen = parseInt(lengthMatch[1]);
|
|
588
|
+
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 15;
|
|
589
|
+
for (let i = 0; i < 5; i++) {
|
|
590
|
+
examples.push(generateRandomString(minLen, maxLen));
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
// Generic examples
|
|
594
|
+
examples.push(
|
|
595
|
+
'example text',
|
|
596
|
+
'Sample String 123',
|
|
597
|
+
'test-data-here',
|
|
598
|
+
'Another_Example',
|
|
599
|
+
'final.test.value'
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Filter examples that actually match the regex
|
|
605
|
+
const validExamples = examples.filter(ex => {
|
|
606
|
+
try {
|
|
607
|
+
regex.lastIndex = 0;
|
|
608
|
+
return regex.test(ex);
|
|
609
|
+
} catch {
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
return validExamples.length > 0 ? validExamples.slice(0, 5) : [
|
|
615
|
+
'No automatic examples could be generated.',
|
|
616
|
+
'The pattern may be too specific.',
|
|
617
|
+
'Try testing with your own strings.',
|
|
618
|
+
'Enter test strings manually.',
|
|
619
|
+
'Pattern validation successful.'
|
|
620
|
+
];
|
|
621
|
+
} catch (error) {
|
|
622
|
+
console.error('Error in generateExamples:', error);
|
|
623
|
+
return ['Error generating examples'];
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function convertToJSON() {
|
|
628
|
+
const standardRegex = document.getElementById('standardRegex').value;
|
|
629
|
+
const outputDiv = document.getElementById('convertOutput');
|
|
630
|
+
|
|
631
|
+
if (!standardRegex) {
|
|
632
|
+
outputDiv.innerHTML = '<div class="error">Please enter a regex pattern</div>';
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
try {
|
|
637
|
+
// Remove surrounding quotes if present
|
|
638
|
+
let cleanPattern = standardRegex.trim();
|
|
639
|
+
if ((cleanPattern.startsWith('"') && cleanPattern.endsWith('"')) ||
|
|
640
|
+
(cleanPattern.startsWith("'") && cleanPattern.endsWith("'"))) {
|
|
641
|
+
cleanPattern = cleanPattern.slice(1, -1);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Test if the regex is valid first (using the cleaned pattern)
|
|
645
|
+
const testRegex = new RegExp(cleanPattern);
|
|
646
|
+
|
|
647
|
+
// For JSON string format: the input pattern stays as is
|
|
648
|
+
// JSON.stringify will handle the escaping
|
|
649
|
+
const jsonOutput = {
|
|
650
|
+
filterRegex: [cleanPattern]
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// Generate examples
|
|
654
|
+
const examples = generateExamples(testRegex);
|
|
655
|
+
|
|
656
|
+
outputDiv.innerHTML = `
|
|
657
|
+
<div class="output-section">
|
|
658
|
+
<h3>📋 JSON Output:</h3>
|
|
659
|
+
<div class="output-box">${JSON.stringify(jsonOutput, null, 2)}</div>
|
|
660
|
+
|
|
661
|
+
<h3>✨ Example Matches:</h3>
|
|
662
|
+
<ul class="examples-list">
|
|
663
|
+
${examples.map(ex => `<li>${escapeHtml(ex)}</li>`).join('')}
|
|
664
|
+
</ul>
|
|
665
|
+
|
|
666
|
+
<div class="success">✅ Regex successfully converted to JSON format!</div>
|
|
667
|
+
</div>
|
|
668
|
+
`;
|
|
669
|
+
} catch (error) {
|
|
670
|
+
outputDiv.innerHTML = `<div class="error">❌ Invalid regex pattern: ${escapeHtml(error.message)}</div>`;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function validatandard ? 'Standard Regex' : 'JSON Regex'}
|
|
675
|
+
</div>
|
|
676
|
+
|
|
677
|
+
<h3>✨ Example Matches:</h3>
|
|
678
|
+
<ul class="examples-list">
|
|
679
|
+
${examples.map(ex => `<li>${escapeHtml(ex)}</li>`).join('')}
|
|
680
|
+
</ul>
|
|
681
|
+
|
|
682
|
+
<div class="success">✅ Regex is valid!</div>
|
|
683
|
+
</div>
|
|
684
|
+
`;
|
|
685
|
+
} catch (error) {
|
|
686
|
+
if (error instanceof SyntaxError && !useStandard) {
|
|
687
|
+
outputDiv.innerHTML = `<div class="error">❌ Invalid JSON syntax: ${escapeHtml(error.message)}<br><br>Expected format: {"filterRegex": ["your-regex-pattern"]} or "your-regex-pattern"</div>`;
|
|
688
|
+
} else {
|
|
689
|
+
outputDiv.innerHTML = `<div class="error">❌ Invalid regex: ${escapeHtml(error.message)}</div>`;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function escapeHtml(text) {
|
|
695
|
+
const div = document.createElement('div');
|
|
696
|
+
div.textContent = text;
|
|
697
|
+
return div.innerHTML;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Add enter key support
|
|
701
|
+
document.getElementById('standardRegex').addEventListener('keypress', function(e) {
|
|
702
|
+
if (e.key === 'Enter') convertToJSON();
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
document.getElementById('regexToValidate').addEventListener('keypress', function(e) {
|
|
706
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
707
|
+
e.preventDefault();
|
|
708
|
+
validateRegex();
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
</script>
|
|
712
|
+
</body>
|
|
713
|
+
</html>
|