Merge branch 'feat/json-editor' of https://github.com/sharevb/it-tools into feat/json-editor
This commit is contained in:
		
						commit
						b620a8d80c
					
				
							
								
								
									
										
											BIN
										
									
								
								.github/logo-dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/logo-dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 40 KiB | 
							
								
								
									
										
											BIN
										
									
								
								.github/logo-white.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/logo-white.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 39 KiB | 
							
								
								
									
										
											BIN
										
									
								
								.github/logo.png
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/logo.png
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.8 KiB | 
| @ -1,4 +1,8 @@ | |||||||
|  | <picture> | ||||||
|  |     <source srcset="./.github/logo-dark.png" media="(prefers-color-scheme: light)"> | ||||||
|  |     <source srcset="./.github/logo-white.png" media="(prefers-color-scheme: dark)"> | ||||||
|  |     <img src="./.github/logo-dark.png" alt="logo"> | ||||||
|  | </picture> | ||||||
| 
 | 
 | ||||||
| Useful tools for developer and people working in IT. [Have a look !](https://it-tools.tech). | Useful tools for developer and people working in IT. [Have a look !](https://it-tools.tech). | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -122,6 +122,7 @@ declare module '@vue/runtime-core' { | |||||||
|     LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default'] |     LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default'] | ||||||
|     MacAddressGenerator: typeof import('./src/tools/mac-address-generator/mac-address-generator.vue')['default'] |     MacAddressGenerator: typeof import('./src/tools/mac-address-generator/mac-address-generator.vue')['default'] | ||||||
|     MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default'] |     MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default'] | ||||||
|  |     MarkdownToHtml: typeof import('./src/tools/markdown-to-html/markdown-to-html.vue')['default'] | ||||||
|     MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default'] |     MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default'] | ||||||
|     MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default'] |     MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default'] | ||||||
|     MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default'] |     MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default'] | ||||||
| @ -130,9 +131,10 @@ declare module '@vue/runtime-core' { | |||||||
|     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] |     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] | ||||||
|     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] |     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] |     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||||
|     NCode: typeof import('naive-ui')['NCode'] |     NCheckbox: typeof import('naive-ui')['NCheckbox'] | ||||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] |     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] |     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||||
|  |     NDivider: typeof import('naive-ui')['NDivider'] | ||||||
|     NEllipsis: typeof import('naive-ui')['NEllipsis'] |     NEllipsis: typeof import('naive-ui')['NEllipsis'] | ||||||
|     NForm: typeof import('naive-ui')['NForm'] |     NForm: typeof import('naive-ui')['NForm'] | ||||||
|     NForm: typeof import('naive-ui')['NForm'] |     NForm: typeof import('naive-ui')['NForm'] | ||||||
| @ -140,7 +142,6 @@ declare module '@vue/runtime-core' { | |||||||
|     NH1: typeof import('naive-ui')['NH1'] |     NH1: typeof import('naive-ui')['NH1'] | ||||||
|     NH3: typeof import('naive-ui')['NH3'] |     NH3: typeof import('naive-ui')['NH3'] | ||||||
|     NIcon: typeof import('naive-ui')['NIcon'] |     NIcon: typeof import('naive-ui')['NIcon'] | ||||||
|     NInputNumber: typeof import('naive-ui')['NInputNumber'] |  | ||||||
|     NLayout: typeof import('naive-ui')['NLayout'] |     NLayout: typeof import('naive-ui')['NLayout'] | ||||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] |     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||||
|     NMenu: typeof import('naive-ui')['NMenu'] |     NMenu: typeof import('naive-ui')['NMenu'] | ||||||
| @ -157,6 +158,9 @@ declare module '@vue/runtime-core' { | |||||||
|     PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default'] |     PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default'] | ||||||
|     QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default'] |     QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default'] | ||||||
|     RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default'] |     RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default'] | ||||||
|  |     RegexMemo: typeof import('./src/tools/regex-memo/regex-memo.vue')['default'] | ||||||
|  |     'RegexMemo.content': typeof import('./src/tools/regex-memo/regex-memo.content.md')['default'] | ||||||
|  |     RegexTester: typeof import('./src/tools/regex-tester/regex-tester.vue')['default'] | ||||||
|     ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default'] |     ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default'] | ||||||
|     RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default'] |     RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default'] | ||||||
|     RouterLink: typeof import('vue-router')['RouterLink'] |     RouterLink: typeof import('vue-router')['RouterLink'] | ||||||
|  | |||||||
| @ -37,11 +37,13 @@ | |||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@it-tools/bip39": "^0.0.4", |     "@it-tools/bip39": "^0.0.4", | ||||||
|     "@it-tools/oggen": "^1.3.0", |     "@it-tools/oggen": "^1.3.0", | ||||||
|  |     "@regexper/render": "^1.0.0", | ||||||
|     "@sindresorhus/slugify": "^2.2.1", |     "@sindresorhus/slugify": "^2.2.1", | ||||||
|     "@tiptap/pm": "2.1.6", |     "@tiptap/pm": "2.1.6", | ||||||
|     "@tiptap/starter-kit": "2.1.6", |     "@tiptap/starter-kit": "2.1.6", | ||||||
|     "@tiptap/vue-3": "2.0.3", |     "@tiptap/vue-3": "2.0.3", | ||||||
|     "@types/figlet": "^1.5.8", |     "@types/figlet": "^1.5.8", | ||||||
|  |     "@types/markdown-it": "^13.0.7", | ||||||
|     "@vicons/material": "^0.12.0", |     "@vicons/material": "^0.12.0", | ||||||
|     "@vicons/tabler": "^0.12.0", |     "@vicons/tabler": "^0.12.0", | ||||||
|     "@vueuse/core": "^10.3.0", |     "@vueuse/core": "^10.3.0", | ||||||
| @ -71,6 +73,7 @@ | |||||||
|     "jwt-decode": "^3.1.2", |     "jwt-decode": "^3.1.2", | ||||||
|     "libphonenumber-js": "^1.10.28", |     "libphonenumber-js": "^1.10.28", | ||||||
|     "lodash": "^4.17.21", |     "lodash": "^4.17.21", | ||||||
|  |     "markdown-it": "^14.0.0", | ||||||
|     "marked": "^10.0.0", |     "marked": "^10.0.0", | ||||||
|     "mathjs": "^11.9.1", |     "mathjs": "^11.9.1", | ||||||
|     "mime-types": "^2.1.35", |     "mime-types": "^2.1.35", | ||||||
| @ -83,6 +86,7 @@ | |||||||
|     "pinia": "^2.0.34", |     "pinia": "^2.0.34", | ||||||
|     "plausible-tracker": "^0.3.8", |     "plausible-tracker": "^0.3.8", | ||||||
|     "qrcode": "^1.5.1", |     "qrcode": "^1.5.1", | ||||||
|  |     "randexp": "^0.5.3", | ||||||
|     "sql-formatter": "^13.0.0", |     "sql-formatter": "^13.0.0", | ||||||
|     "ua-parser-js": "^1.0.35", |     "ua-parser-js": "^1.0.35", | ||||||
|     "ulid": "^2.3.0", |     "ulid": "^2.3.0", | ||||||
| @ -93,6 +97,7 @@ | |||||||
|     "vue": "^3.3.4", |     "vue": "^3.3.4", | ||||||
|     "vue-i18n": "^9.9.1", |     "vue-i18n": "^9.9.1", | ||||||
|     "vue-router": "^4.1.6", |     "vue-router": "^4.1.6", | ||||||
|  |     "vue-shadow-dom": "^4.2.0", | ||||||
|     "vue-tsc": "^1.8.1", |     "vue-tsc": "^1.8.1", | ||||||
|     "xml-formatter": "^3.3.2", |     "xml-formatter": "^3.3.2", | ||||||
|     "xml-js": "^1.6.11", |     "xml-js": "^1.6.11", | ||||||
|  | |||||||
							
								
								
									
										97
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										97
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -11,6 +11,9 @@ dependencies: | |||||||
|   '@it-tools/oggen': |   '@it-tools/oggen': | ||||||
|     specifier: ^1.3.0 |     specifier: ^1.3.0 | ||||||
|     version: 1.3.0 |     version: 1.3.0 | ||||||
|  |   '@regexper/render': | ||||||
|  |     specifier: ^1.0.0 | ||||||
|  |     version: 1.0.0 | ||||||
|   '@sindresorhus/slugify': |   '@sindresorhus/slugify': | ||||||
|     specifier: ^2.2.1 |     specifier: ^2.2.1 | ||||||
|     version: 2.2.1 |     version: 2.2.1 | ||||||
| @ -26,6 +29,9 @@ dependencies: | |||||||
|   '@types/figlet': |   '@types/figlet': | ||||||
|     specifier: ^1.5.8 |     specifier: ^1.5.8 | ||||||
|     version: 1.5.8 |     version: 1.5.8 | ||||||
|  |   '@types/markdown-it': | ||||||
|  |     specifier: ^13.0.7 | ||||||
|  |     version: 13.0.9 | ||||||
|   '@vicons/material': |   '@vicons/material': | ||||||
|     specifier: ^0.12.0 |     specifier: ^0.12.0 | ||||||
|     version: 0.12.0 |     version: 0.12.0 | ||||||
| @ -113,6 +119,9 @@ dependencies: | |||||||
|   lodash: |   lodash: | ||||||
|     specifier: ^4.17.21 |     specifier: ^4.17.21 | ||||||
|     version: 4.17.21 |     version: 4.17.21 | ||||||
|  |   markdown-it: | ||||||
|  |     specifier: ^14.0.0 | ||||||
|  |     version: 14.1.0 | ||||||
|   marked: |   marked: | ||||||
|     specifier: ^10.0.0 |     specifier: ^10.0.0 | ||||||
|     version: 10.0.0 |     version: 10.0.0 | ||||||
| @ -149,6 +158,9 @@ dependencies: | |||||||
|   qrcode: |   qrcode: | ||||||
|     specifier: ^1.5.1 |     specifier: ^1.5.1 | ||||||
|     version: 1.5.1 |     version: 1.5.1 | ||||||
|  |   randexp: | ||||||
|  |     specifier: ^0.5.3 | ||||||
|  |     version: 0.5.3 | ||||||
|   sql-formatter: |   sql-formatter: | ||||||
|     specifier: ^13.0.0 |     specifier: ^13.0.0 | ||||||
|     version: 13.0.0 |     version: 13.0.0 | ||||||
| @ -179,6 +191,9 @@ dependencies: | |||||||
|   vue-router: |   vue-router: | ||||||
|     specifier: ^4.1.6 |     specifier: ^4.1.6 | ||||||
|     version: 4.1.6(vue@3.3.4) |     version: 4.1.6(vue@3.3.4) | ||||||
|  |   vue-shadow-dom: | ||||||
|  |     specifier: ^4.2.0 | ||||||
|  |     version: 4.2.0 | ||||||
|   vue-tsc: |   vue-tsc: | ||||||
|     specifier: ^1.8.1 |     specifier: ^1.8.1 | ||||||
|     version: 1.8.1(typescript@5.2.2) |     version: 1.8.1(typescript@5.2.2) | ||||||
| @ -2592,6 +2607,17 @@ packages: | |||||||
|     resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} |     resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|  |   /@regexper/parser@1.0.0: | ||||||
|  |     resolution: {integrity: sha512-S8AWIGpCNdl9PNHdbhI6TpXZsPk6FDU/RTZI+6UFF4rVFqDQKjCIbZSgFu7NihoEZKq57wKFPbbT1EzrjVvPHA==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|  |   /@regexper/render@1.0.0: | ||||||
|  |     resolution: {integrity: sha512-xYm9RUgnhhZotTtf8UZpK1PG2CcTRXQ3JPwfTlYUZsy2J+UcTVc7BaO/MJadpMoVuT8jrIyptH4Y0HLzqhI3hQ==} | ||||||
|  |     dependencies: | ||||||
|  |       '@regexper/parser': 1.0.0 | ||||||
|  |       '@svgdotjs/svg.js': 3.2.4 | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /@remirror/core-constants@2.0.1: |   /@remirror/core-constants@2.0.1: | ||||||
|     resolution: {integrity: sha512-ZR4aihtnnT9lMbhh5DEbsriJRlukRXmLZe7HmM+6ufJNNUDoazc75UX26xbgQlNUqgAqMcUdGFAnPc1JwgAdLQ==} |     resolution: {integrity: sha512-ZR4aihtnnT9lMbhh5DEbsriJRlukRXmLZe7HmM+6ufJNNUDoazc75UX26xbgQlNUqgAqMcUdGFAnPc1JwgAdLQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
| @ -2757,6 +2783,10 @@ packages: | |||||||
|       string.prototype.matchall: 4.0.10 |       string.prototype.matchall: 4.0.10 | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|  |   /@svgdotjs/svg.js@3.2.4: | ||||||
|  |     resolution: {integrity: sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /@tiptap/core@2.1.12(@tiptap/pm@2.1.6): |   /@tiptap/core@2.1.12(@tiptap/pm@2.1.6): | ||||||
|     resolution: {integrity: sha512-ZGc3xrBJA9KY8kln5AYTj8y+GDrKxi7u95xIl2eccrqTY5CQeRu6HRNM1yT4mAjuSaG9jmazyjGRlQuhyxCKxQ==} |     resolution: {integrity: sha512-ZGc3xrBJA9KY8kln5AYTj8y+GDrKxi7u95xIl2eccrqTY5CQeRu6HRNM1yT4mAjuSaG9jmazyjGRlQuhyxCKxQ==} | ||||||
|     peerDependencies: |     peerDependencies: | ||||||
| @ -3090,7 +3120,6 @@ packages: | |||||||
| 
 | 
 | ||||||
|   /@types/linkify-it@3.0.2: |   /@types/linkify-it@3.0.2: | ||||||
|     resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} |     resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} | ||||||
|     dev: true |  | ||||||
| 
 | 
 | ||||||
|   /@types/lodash-es@4.17.10: |   /@types/lodash-es@4.17.10: | ||||||
|     resolution: {integrity: sha512-YJP+w/2khSBwbUSFdGsSqmDvmnN3cCKoPOL7Zjle6s30ZtemkkqhjVfFqGwPN7ASil5VyjE2GtyU/yqYY6mC0A==} |     resolution: {integrity: sha512-YJP+w/2khSBwbUSFdGsSqmDvmnN3cCKoPOL7Zjle6s30ZtemkkqhjVfFqGwPN7ASil5VyjE2GtyU/yqYY6mC0A==} | ||||||
| @ -3112,6 +3141,13 @@ packages: | |||||||
|       '@types/mdurl': 1.0.2 |       '@types/mdurl': 1.0.2 | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|  |   /@types/markdown-it@13.0.9: | ||||||
|  |     resolution: {integrity: sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==} | ||||||
|  |     dependencies: | ||||||
|  |       '@types/linkify-it': 3.0.2 | ||||||
|  |       '@types/mdurl': 1.0.2 | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /@types/mdast@3.0.11: |   /@types/mdast@3.0.11: | ||||||
|     resolution: {integrity: sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==} |     resolution: {integrity: sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==} | ||||||
|     dependencies: |     dependencies: | ||||||
| @ -3120,7 +3156,6 @@ packages: | |||||||
| 
 | 
 | ||||||
|   /@types/mdurl@1.0.2: |   /@types/mdurl@1.0.2: | ||||||
|     resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} |     resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} | ||||||
|     dev: true |  | ||||||
| 
 | 
 | ||||||
|   /@types/mime-types@2.1.1: |   /@types/mime-types@2.1.1: | ||||||
|     resolution: {integrity: sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==} |     resolution: {integrity: sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==} | ||||||
| @ -4125,7 +4160,7 @@ packages: | |||||||
|   /@vueuse/shared@10.0.0(vue@3.3.4): |   /@vueuse/shared@10.0.0(vue@3.3.4): | ||||||
|     resolution: {integrity: sha512-Zh3LgJqvUBWVY3SiMvXanTcfAneGbt63QPczBRDNgQ6jd/ehodO9a1lCFzaA6SWJJoI+ugVTjHFYJdoR656DVQ==} |     resolution: {integrity: sha512-Zh3LgJqvUBWVY3SiMvXanTcfAneGbt63QPczBRDNgQ6jd/ehodO9a1lCFzaA6SWJJoI+ugVTjHFYJdoR656DVQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
|       vue-demi: 0.14.10(vue@3.3.4) |       vue-demi: 0.14.5(vue@3.3.4) | ||||||
|     transitivePeerDependencies: |     transitivePeerDependencies: | ||||||
|       - '@vue/composition-api' |       - '@vue/composition-api' | ||||||
|       - vue |       - vue | ||||||
| @ -4134,7 +4169,7 @@ packages: | |||||||
|   /@vueuse/shared@10.3.0(vue@3.3.4): |   /@vueuse/shared@10.3.0(vue@3.3.4): | ||||||
|     resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} |     resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} | ||||||
|     dependencies: |     dependencies: | ||||||
|       vue-demi: 0.14.10(vue@3.3.4) |       vue-demi: 0.14.5(vue@3.3.4) | ||||||
|     transitivePeerDependencies: |     transitivePeerDependencies: | ||||||
|       - '@vue/composition-api' |       - '@vue/composition-api' | ||||||
|       - vue |       - vue | ||||||
| @ -5141,6 +5176,11 @@ packages: | |||||||
|       tslib: 2.5.0 |       tslib: 2.5.0 | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|  |   /drange@1.1.1: | ||||||
|  |     resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} | ||||||
|  |     engines: {node: '>=4'} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /duplexer@0.1.2: |   /duplexer@0.1.2: | ||||||
|     resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} |     resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} | ||||||
|     dev: true |     dev: true | ||||||
| @ -5206,7 +5246,6 @@ packages: | |||||||
|   /entities@4.5.0: |   /entities@4.5.0: | ||||||
|     resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} |     resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} | ||||||
|     engines: {node: '>=0.12'} |     engines: {node: '>=0.12'} | ||||||
|     dev: true |  | ||||||
| 
 | 
 | ||||||
|   /errno@0.1.8: |   /errno@0.1.8: | ||||||
|     resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} |     resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} | ||||||
| @ -6932,6 +6971,12 @@ packages: | |||||||
|     dependencies: |     dependencies: | ||||||
|       uc.micro: 1.0.6 |       uc.micro: 1.0.6 | ||||||
| 
 | 
 | ||||||
|  |   /linkify-it@5.0.0: | ||||||
|  |     resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} | ||||||
|  |     dependencies: | ||||||
|  |       uc.micro: 2.1.0 | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /local-pkg@0.4.3: |   /local-pkg@0.4.3: | ||||||
|     resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} |     resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} | ||||||
|     engines: {node: '>=14'} |     engines: {node: '>=14'} | ||||||
| @ -7072,6 +7117,18 @@ packages: | |||||||
|       mdurl: 1.0.1 |       mdurl: 1.0.1 | ||||||
|       uc.micro: 1.0.6 |       uc.micro: 1.0.6 | ||||||
| 
 | 
 | ||||||
|  |   /markdown-it@14.1.0: | ||||||
|  |     resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} | ||||||
|  |     hasBin: true | ||||||
|  |     dependencies: | ||||||
|  |       argparse: 2.0.1 | ||||||
|  |       entities: 4.5.0 | ||||||
|  |       linkify-it: 5.0.0 | ||||||
|  |       mdurl: 2.0.0 | ||||||
|  |       punycode.js: 2.3.1 | ||||||
|  |       uc.micro: 2.1.0 | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /marked@10.0.0: |   /marked@10.0.0: | ||||||
|     resolution: {integrity: sha512-YiGcYcWj50YrwBgNzFoYhQ1hT6GmQbFG8SksnYJX1z4BXTHSOrz1GB5/Jm2yQvMg4nN1FHP4M6r03R10KrVUiA==} |     resolution: {integrity: sha512-YiGcYcWj50YrwBgNzFoYhQ1hT6GmQbFG8SksnYJX1z4BXTHSOrz1GB5/Jm2yQvMg4nN1FHP4M6r03R10KrVUiA==} | ||||||
|     engines: {node: '>= 18'} |     engines: {node: '>= 18'} | ||||||
| @ -7119,6 +7176,10 @@ packages: | |||||||
|   /mdurl@1.0.1: |   /mdurl@1.0.1: | ||||||
|     resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} |     resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} | ||||||
| 
 | 
 | ||||||
|  |   /mdurl@2.0.0: | ||||||
|  |     resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /memoize-one@6.0.0: |   /memoize-one@6.0.0: | ||||||
|     resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} |     resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} | ||||||
|     dev: false |     dev: false | ||||||
| @ -7944,6 +8005,11 @@ packages: | |||||||
|     resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} |     resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|  |   /punycode.js@2.3.1: | ||||||
|  |     resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} | ||||||
|  |     engines: {node: '>=6'} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /punycode@2.3.0: |   /punycode@2.3.0: | ||||||
|     resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} |     resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} | ||||||
|     engines: {node: '>=6'} |     engines: {node: '>=6'} | ||||||
| @ -7983,6 +8049,14 @@ packages: | |||||||
|       ret: 0.1.15 |       ret: 0.1.15 | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|  |   /randexp@0.5.3: | ||||||
|  |     resolution: {integrity: sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==} | ||||||
|  |     engines: {node: '>=4'} | ||||||
|  |     dependencies: | ||||||
|  |       drange: 1.1.1 | ||||||
|  |       ret: 0.2.2 | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /randombytes@2.1.0: |   /randombytes@2.1.0: | ||||||
|     resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} |     resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
| @ -8157,6 +8231,11 @@ packages: | |||||||
|     engines: {node: '>=0.12'} |     engines: {node: '>=0.12'} | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|  |   /ret@0.2.2: | ||||||
|  |     resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} | ||||||
|  |     engines: {node: '>=4'} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /reusify@1.0.4: |   /reusify@1.0.4: | ||||||
|     resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} |     resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} | ||||||
|     engines: {iojs: '>=1.0.0', node: '>=0.10.0'} |     engines: {iojs: '>=1.0.0', node: '>=0.10.0'} | ||||||
| @ -8926,6 +9005,10 @@ packages: | |||||||
|   /uc.micro@1.0.6: |   /uc.micro@1.0.6: | ||||||
|     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} |     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} | ||||||
| 
 | 
 | ||||||
|  |   /uc.micro@2.1.0: | ||||||
|  |     resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /ufo@1.1.2: |   /ufo@1.1.2: | ||||||
|     resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} |     resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} | ||||||
| 
 | 
 | ||||||
| @ -9565,6 +9648,10 @@ packages: | |||||||
|       vue: 3.3.4 |       vue: 3.3.4 | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|  |   /vue-shadow-dom@4.2.0: | ||||||
|  |     resolution: {integrity: sha512-lguI064rT2HT/dxqSmXtz860KOvCq+W3nU1jMqroTmX3K1H46q22BMR4emh/Ld3ozy35XJKOaNGcr6mkJ/t/yg==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /vue-template-compiler@2.7.14: |   /vue-template-compiler@2.7.14: | ||||||
|     resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} |     resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import sqlHljs from 'highlight.js/lib/languages/sql'; | |||||||
| import xmlHljs from 'highlight.js/lib/languages/xml'; | import xmlHljs from 'highlight.js/lib/languages/xml'; | ||||||
| import yamlHljs from 'highlight.js/lib/languages/yaml'; | import yamlHljs from 'highlight.js/lib/languages/yaml'; | ||||||
| import iniHljs from 'highlight.js/lib/languages/ini'; | import iniHljs from 'highlight.js/lib/languages/ini'; | ||||||
|  | import markdownHljs from 'highlight.js/lib/languages/markdown'; | ||||||
| import { useCopy } from '@/composable/copy'; | import { useCopy } from '@/composable/copy'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults( | const props = withDefaults( | ||||||
| @ -30,6 +31,7 @@ hljs.registerLanguage('html', xmlHljs); | |||||||
| hljs.registerLanguage('xml', xmlHljs); | hljs.registerLanguage('xml', xmlHljs); | ||||||
| hljs.registerLanguage('yaml', yamlHljs); | hljs.registerLanguage('yaml', yamlHljs); | ||||||
| hljs.registerLanguage('toml', iniHljs); | hljs.registerLanguage('toml', iniHljs); | ||||||
|  | hljs.registerLanguage('markdown', markdownHljs); | ||||||
| 
 | 
 | ||||||
| const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(props); | const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(props); | ||||||
| const { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) }; | const { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) }; | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| import { useRouteQuery } from '@vueuse/router'; | import { useRouteQuery } from '@vueuse/router'; | ||||||
| import { computed } from 'vue'; | import { computed } from 'vue'; | ||||||
|  | import { useStorage } from '@vueuse/core'; | ||||||
| 
 | 
 | ||||||
| export { useQueryParam }; | export { useQueryParam, useQueryParamOrStorage }; | ||||||
| 
 | 
 | ||||||
| const transformers = { | const transformers = { | ||||||
|   number: { |   number: { | ||||||
| @ -16,6 +17,12 @@ const transformers = { | |||||||
|     fromQuery: (value: string) => value.toLowerCase() === 'true', |     fromQuery: (value: string) => value.toLowerCase() === 'true', | ||||||
|     toQuery: (value: boolean) => (value ? 'true' : 'false'), |     toQuery: (value: boolean) => (value ? 'true' : 'false'), | ||||||
|   }, |   }, | ||||||
|  |   object: { | ||||||
|  |     fromQuery: (value: string) => { | ||||||
|  |       return JSON.parse(value); | ||||||
|  |     }, | ||||||
|  |     toQuery: (value: object) => JSON.stringify(value), | ||||||
|  |   }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function useQueryParam<T>({ name, defaultValue }: { name: string; defaultValue: T }) { | function useQueryParam<T>({ name, defaultValue }: { name: string; defaultValue: T }) { | ||||||
| @ -33,3 +40,27 @@ function useQueryParam<T>({ name, defaultValue }: { name: string; defaultValue: | |||||||
|     }, |     }, | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | function useQueryParamOrStorage<T>({ name, storageName, defaultValue }: { name: string; storageName: string; defaultValue: T }) { | ||||||
|  |   const type = typeof defaultValue; | ||||||
|  |   const transformer = transformers[type as keyof typeof transformers] ?? transformers.string; | ||||||
|  | 
 | ||||||
|  |   const storageRef = useStorage(storageName, defaultValue); | ||||||
|  |   const proxyDefaultValue = transformer.toQuery(defaultValue as never); | ||||||
|  |   const proxy = useRouteQuery(name, proxyDefaultValue); | ||||||
|  | 
 | ||||||
|  |   const r = ref(defaultValue); | ||||||
|  | 
 | ||||||
|  |   watch(r, | ||||||
|  |     (value) => { | ||||||
|  |       proxy.value = transformer.toQuery(value as never); | ||||||
|  |       storageRef.value = value as never; | ||||||
|  |     }, | ||||||
|  |     { deep: true }); | ||||||
|  | 
 | ||||||
|  |   r.value = (proxy.value && proxy.value !== proxyDefaultValue | ||||||
|  |     ? transformer.fromQuery(proxy.value) as unknown as T | ||||||
|  |     : storageRef.value as T) as never; | ||||||
|  | 
 | ||||||
|  |   return r; | ||||||
|  | } | ||||||
|  | |||||||
| @ -3,9 +3,11 @@ import _ from 'lodash'; | |||||||
| import { type Ref, reactive, watch } from 'vue'; | import { type Ref, reactive, watch } from 'vue'; | ||||||
| 
 | 
 | ||||||
| type ValidatorReturnType = unknown; | type ValidatorReturnType = unknown; | ||||||
|  | type GetErrorMessageReturnType = string; | ||||||
| 
 | 
 | ||||||
| export interface UseValidationRule<T> { | export interface UseValidationRule<T> { | ||||||
|   validator: (value: T) => ValidatorReturnType |   validator: (value: T) => ValidatorReturnType | ||||||
|  |   getErrorMessage?: (value: T) => GetErrorMessageReturnType | ||||||
|   message: string |   message: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -24,6 +26,15 @@ export function isFalsyOrHasThrown(cb: () => ValidatorReturnType): boolean { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export function getErrorMessageOrThrown(cb: () => GetErrorMessageReturnType): string { | ||||||
|  |   try { | ||||||
|  |     return cb() || ''; | ||||||
|  |   } | ||||||
|  |   catch (e: any) { | ||||||
|  |     return e.toString(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export interface ValidationAttrs { | export interface ValidationAttrs { | ||||||
|   feedback: string |   feedback: string | ||||||
|   validationStatus: string | undefined |   validationStatus: string | undefined | ||||||
| @ -61,7 +72,13 @@ export function useValidation<T>({ | |||||||
| 
 | 
 | ||||||
|       for (const rule of get(rules)) { |       for (const rule of get(rules)) { | ||||||
|         if (isFalsyOrHasThrown(() => rule.validator(source.value))) { |         if (isFalsyOrHasThrown(() => rule.validator(source.value))) { | ||||||
|  |           if (rule.getErrorMessage) { | ||||||
|  |             const getErrorMessage = rule.getErrorMessage; | ||||||
|  |             state.message = rule.message.replace('{0}', getErrorMessageOrThrown(() => getErrorMessage(source.value))); | ||||||
|  |           } | ||||||
|  |           else { | ||||||
|             state.message = rule.message; |             state.message = rule.message; | ||||||
|  |           } | ||||||
|           state.status = 'error'; |           state.status = 'error'; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import { createPinia } from 'pinia'; | |||||||
| import { createHead } from '@vueuse/head'; | import { createHead } from '@vueuse/head'; | ||||||
| 
 | 
 | ||||||
| import { registerSW } from 'virtual:pwa-register'; | import { registerSW } from 'virtual:pwa-register'; | ||||||
|  | import shadow from 'vue-shadow-dom'; | ||||||
| import { plausible } from './plugins/plausible.plugin'; | import { plausible } from './plugins/plausible.plugin'; | ||||||
| 
 | 
 | ||||||
| import 'virtual:uno.css'; | import 'virtual:uno.css'; | ||||||
| @ -23,5 +24,6 @@ app.use(i18nPlugin); | |||||||
| app.use(router); | app.use(router); | ||||||
| app.use(naive); | app.use(naive); | ||||||
| app.use(plausible); | app.use(plausible); | ||||||
|  | app.use(shadow); | ||||||
| 
 | 
 | ||||||
| app.mount('#app'); | app.mount('#app'); | ||||||
|  | |||||||
| @ -10,6 +10,9 @@ import { tool as textToUnicode } from './text-to-unicode'; | |||||||
| import { tool as safelinkDecoder } from './safelink-decoder'; | import { tool as safelinkDecoder } from './safelink-decoder'; | ||||||
| import { tool as xmlToJson } from './xml-to-json'; | import { tool as xmlToJson } from './xml-to-json'; | ||||||
| import { tool as jsonToXml } from './json-to-xml'; | import { tool as jsonToXml } from './json-to-xml'; | ||||||
|  | import { tool as regexTester } from './regex-tester'; | ||||||
|  | import { tool as regexMemo } from './regex-memo'; | ||||||
|  | import { tool as markdownToHtml } from './markdown-to-html'; | ||||||
| import { tool as pdfSignatureChecker } from './pdf-signature-checker'; | import { tool as pdfSignatureChecker } from './pdf-signature-checker'; | ||||||
| import { tool as numeronymGenerator } from './numeronym-generator'; | import { tool as numeronymGenerator } from './numeronym-generator'; | ||||||
| import { tool as macAddressGenerator } from './mac-address-generator'; | import { tool as macAddressGenerator } from './mac-address-generator'; | ||||||
| @ -113,6 +116,7 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|       tomlToYaml, |       tomlToYaml, | ||||||
|       xmlToJson, |       xmlToJson, | ||||||
|       jsonToXml, |       jsonToXml, | ||||||
|  |       markdownToHtml, | ||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
| @ -156,6 +160,8 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|       yamlViewer, |       yamlViewer, | ||||||
|       jsonEditor, |       jsonEditor, | ||||||
|       emailNormalizer, |       emailNormalizer, | ||||||
|  |       regexTester, | ||||||
|  |       regexMemo, | ||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								src/tools/markdown-to-html/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/markdown-to-html/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { Markdown } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'Markdown to HTML', | ||||||
|  |   path: '/markdown-to-html', | ||||||
|  |   description: 'Convert Markdown to Html and allow to print (as PDF)', | ||||||
|  |   keywords: ['markdown', 'html', 'converter', 'pdf'], | ||||||
|  |   component: () => import('./markdown-to-html.vue'), | ||||||
|  |   icon: Markdown, | ||||||
|  |   createdAt: new Date('2024-08-25'), | ||||||
|  | }); | ||||||
							
								
								
									
										44
									
								
								src/tools/markdown-to-html/markdown-to-html.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/tools/markdown-to-html/markdown-to-html.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import markdownit from 'markdown-it'; | ||||||
|  | import TextareaCopyable from '@/components/TextareaCopyable.vue'; | ||||||
|  | 
 | ||||||
|  | const inputMarkdown = ref(''); | ||||||
|  | const outputHtml = computed(() => { | ||||||
|  |   const md = markdownit(); | ||||||
|  |   return md.render(inputMarkdown.value); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | function printHtml() { | ||||||
|  |   const w = window.open(); | ||||||
|  |   if (w === null) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   w.document.body.innerHTML = outputHtml.value; | ||||||
|  |   w.print(); | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <c-input-text | ||||||
|  |       v-model:value="inputMarkdown" | ||||||
|  |       multiline raw-text | ||||||
|  |       placeholder="Your Markdown content..." | ||||||
|  |       rows="8" | ||||||
|  |       autofocus | ||||||
|  |       label="Your Markdown to convert:" | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <n-divider /> | ||||||
|  | 
 | ||||||
|  |     <n-form-item label="Output HTML:"> | ||||||
|  |       <TextareaCopyable :value="outputHtml" :word-wrap="true" language="html" /> | ||||||
|  |     </n-form-item> | ||||||
|  | 
 | ||||||
|  |     <div flex justify-center> | ||||||
|  |       <n-button @click="printHtml"> | ||||||
|  |         Print as PDF | ||||||
|  |       </n-button> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										12
									
								
								src/tools/regex-memo/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/regex-memo/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { BrandJavascript } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'Regex cheatsheet', | ||||||
|  |   path: '/regex-memo', | ||||||
|  |   description: 'Javascript Regex/Regular Expression cheatsheet', | ||||||
|  |   keywords: ['regex', 'regular', 'expression', 'javascript', 'memo', 'cheatsheet'], | ||||||
|  |   component: () => import('./regex-memo.vue'), | ||||||
|  |   icon: BrandJavascript, | ||||||
|  |   createdAt: new Date('2024-09-20'), | ||||||
|  | }); | ||||||
							
								
								
									
										121
									
								
								src/tools/regex-memo/regex-memo.content.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/tools/regex-memo/regex-memo.content.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | ### Normal characters | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `.` or `[^\n\r]` | any character *excluding* a newline or carriage return | ||||||
|  | `[A-Za-z]` | alphabet | ||||||
|  | `[a-z]` | lowercase alphabet | ||||||
|  | `[A-Z]` | uppercase alphabet | ||||||
|  | `\d` or `[0-9]` | digit | ||||||
|  | `\D` or `[^0-9]` | non-digit | ||||||
|  | `_` | underscore | ||||||
|  | `\w` or `[A-Za-z0-9_]` | alphabet, digit or underscore | ||||||
|  | `\W` or `[^A-Za-z0-9_]` | inverse of `\w` | ||||||
|  | `\S` | inverse of `\s` | ||||||
|  | 
 | ||||||
|  | ### Whitespace characters | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | ` ` | space | ||||||
|  | `\t` | tab | ||||||
|  | `\n` | newline | ||||||
|  | `\r` | carriage return | ||||||
|  | `\s` | space, tab, newline or carriage return | ||||||
|  | 
 | ||||||
|  | ### Character set | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `[xyz]` | either `x`, `y` or `z` | ||||||
|  | `[^xyz]` | neither `x`, `y` nor `z` | ||||||
|  | `[1-3]` | either `1`, `2` or `3` | ||||||
|  | `[^1-3]` | neither `1`, `2` nor `3` | ||||||
|  | 
 | ||||||
|  | - Think of a character set as an `OR` operation on the single characters that are enclosed between the square brackets. | ||||||
|  | - Use `^` after the opening `[` to “negate” the character set. | ||||||
|  | - Within a character set, `.` means a literal period. | ||||||
|  | 
 | ||||||
|  | ### Characters that require escaping | ||||||
|  | 
 | ||||||
|  | #### Outside a character set | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `\.` | period | ||||||
|  | `\^` | caret | ||||||
|  | `\$` | dollar sign | ||||||
|  | `\|` | pipe | ||||||
|  | `\\` | back slash | ||||||
|  | `\/` | forward slash | ||||||
|  | `\(` | opening bracket | ||||||
|  | `\)` | closing bracket | ||||||
|  | `\[` | opening square bracket | ||||||
|  | `\]` | closing square bracket | ||||||
|  | `\{` | opening curly bracket | ||||||
|  | `\}` | closing curly bracket | ||||||
|  | 
 | ||||||
|  | #### Inside a character set | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `\\` | back slash | ||||||
|  | `\]` | closing square bracket | ||||||
|  | 
 | ||||||
|  | - A `^` must be escaped only if it occurs immediately after the opening `[` of the character set. | ||||||
|  | - A `-` must be escaped only if it occurs between two alphabets or two digits. | ||||||
|  | 
 | ||||||
|  | ### Quantifiers | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `{2}` | exactly 2 | ||||||
|  | `{2,}` | at least 2 | ||||||
|  | `{2,7}` | at least 2 but no more than 7 | ||||||
|  | `*` | 0 or more | ||||||
|  | `+` | 1 or more | ||||||
|  | `?` | exactly 0 or 1 | ||||||
|  | 
 | ||||||
|  | - The quantifier goes *after* the expression to be quantified. | ||||||
|  | 
 | ||||||
|  | ### Boundaries | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `^` | start of string | ||||||
|  | `$` | end of string | ||||||
|  | `\b` | word boundary | ||||||
|  | 
 | ||||||
|  | - How word boundary matching works: | ||||||
|  |     - At the beginning of the string if the first character is `\w`. | ||||||
|  |     - Between two adjacent characters within the string, if the first character is `\w` and the second character is `\W`. | ||||||
|  |     - At the end of the string if the last character is `\w`. | ||||||
|  | 
 | ||||||
|  | ### Matching | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `foo\|bar` | match either `foo` or `bar` | ||||||
|  | `foo(?=bar)` | match `foo` if it’s before `bar` | ||||||
|  | `foo(?!bar)` | match `foo` if it’s *not* before `bar` | ||||||
|  | `(?<=bar)foo` | match `foo` if it’s after `bar` | ||||||
|  | `(?<!bar)foo` | match `foo` if it’s *not* after `bar` | ||||||
|  | 
 | ||||||
|  | ### Grouping and capturing | ||||||
|  | 
 | ||||||
|  | Expression | Description | ||||||
|  | :--|:-- | ||||||
|  | `(foo)` | capturing group; match and capture `foo` | ||||||
|  | `(?:foo)` | non-capturing group; match `foo` but *without* capturing `foo` | ||||||
|  | `(foo)bar\1` | `\1` is a backreference to the 1st capturing group; match `foobarfoo` | ||||||
|  | 
 | ||||||
|  | - Capturing groups are only relevant in the following methods: | ||||||
|  |     - `string.match(regexp)` | ||||||
|  |     - `string.matchAll(regexp)` | ||||||
|  |     - `string.replace(regexp, callback)` | ||||||
|  | - `\N` is a backreference to the `Nth` capturing group. Capturing groups are numbered starting from 1. | ||||||
|  | 
 | ||||||
|  | ## References and tools | ||||||
|  | 
 | ||||||
|  | - [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) | ||||||
|  | - [RegExplained](https://leaverou.github.io/regexplained/) | ||||||
							
								
								
									
										32
									
								
								src/tools/regex-memo/regex-memo.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/tools/regex-memo/regex-memo.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { useThemeVars } from 'naive-ui'; | ||||||
|  | import Memo from './regex-memo.content.md'; | ||||||
|  | 
 | ||||||
|  | const themeVars = useThemeVars(); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <Memo /> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style lang="less" scoped> | ||||||
|  | ::v-deep(pre) { | ||||||
|  |   margin: 0; | ||||||
|  |   padding: 15px 22px; | ||||||
|  |   background-color: v-bind('themeVars.cardColor'); | ||||||
|  |   border-radius: 4px; | ||||||
|  |   overflow: auto; | ||||||
|  | } | ||||||
|  | ::v-deep(table) { | ||||||
|  |   border-collapse: collapse; | ||||||
|  | } | ||||||
|  | ::v-deep(table), ::v-deep(td), ::v-deep(th) { | ||||||
|  |   border: 1px solid v-bind('themeVars.textColor1'); | ||||||
|  |   padding: 5px; | ||||||
|  | } | ||||||
|  | ::v-deep(a) { | ||||||
|  |   color: v-bind('themeVars.textColor1'); | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										12
									
								
								src/tools/regex-tester/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/regex-tester/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { Language } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'Regex Tester', | ||||||
|  |   path: '/regex-tester', | ||||||
|  |   description: 'Regex Tester', | ||||||
|  |   keywords: ['regex', 'tester', 'sample', 'expression'], | ||||||
|  |   component: () => import('./regex-tester.vue'), | ||||||
|  |   icon: Language, | ||||||
|  |   createdAt: new Date('2024-09-20'), | ||||||
|  | }); | ||||||
							
								
								
									
										106
									
								
								src/tools/regex-tester/regex-tester.service.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/tools/regex-tester/regex-tester.service.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,106 @@ | |||||||
|  | import { describe, expect, it } from 'vitest'; | ||||||
|  | import { matchRegex } from './regex-tester.service'; | ||||||
|  | 
 | ||||||
|  | const regexesData = [ | ||||||
|  |   { | ||||||
|  |     regex: '', | ||||||
|  |     text: '', | ||||||
|  |     flags: '', | ||||||
|  |     result: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     regex: '.*', | ||||||
|  |     text: '', | ||||||
|  |     flags: '', | ||||||
|  |     result: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     regex: '', | ||||||
|  |     text: 'aaa', | ||||||
|  |     flags: '', | ||||||
|  |     result: [], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     regex: 'a', | ||||||
|  |     text: 'baaa', | ||||||
|  |     flags: '', | ||||||
|  |     result: [ | ||||||
|  |       { | ||||||
|  |         captures: [], | ||||||
|  |         groups: [], | ||||||
|  |         index: 1, | ||||||
|  |         value: 'a', | ||||||
|  |       }, | ||||||
|  |     ], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     regex: '(.)(?<g>r)', | ||||||
|  |     text: 'azertyr', | ||||||
|  |     flags: 'g', | ||||||
|  |     result: [ | ||||||
|  |       { | ||||||
|  |         captures: [ | ||||||
|  |           { | ||||||
|  |             end: 3, | ||||||
|  |             name: '1', | ||||||
|  |             start: 2, | ||||||
|  |             value: 'e', | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             end: 4, | ||||||
|  |             name: '2', | ||||||
|  |             start: 3, | ||||||
|  |             value: 'r', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |         groups: [ | ||||||
|  |           { | ||||||
|  |             end: 4, | ||||||
|  |             name: 'g', | ||||||
|  |             start: 3, | ||||||
|  |             value: 'r', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |         index: 2, | ||||||
|  |         value: 'er', | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         captures: [ | ||||||
|  |           { | ||||||
|  |             end: 6, | ||||||
|  |             name: '1', | ||||||
|  |             start: 5, | ||||||
|  |             value: 'y', | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             end: 7, | ||||||
|  |             name: '2', | ||||||
|  |             start: 6, | ||||||
|  |             value: 'r', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |         groups: [ | ||||||
|  |           { | ||||||
|  |             end: 7, | ||||||
|  |             name: 'g', | ||||||
|  |             start: 6, | ||||||
|  |             value: 'r', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |         index: 5, | ||||||
|  |         value: 'yr', | ||||||
|  |       }, | ||||||
|  |     ], | ||||||
|  |   }, | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | describe('regex-tester', () => { | ||||||
|  |   for (const reg of regexesData) { | ||||||
|  |     const { regex, text, flags, result: expected_result } = reg; | ||||||
|  |     it(`Should matchRegex("${regex}","${text}","${flags}") return correct result`, async () => { | ||||||
|  |       const result = matchRegex(regex, text, `${flags}d`); | ||||||
|  | 
 | ||||||
|  |       expect(result).to.deep.equal(expected_result); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }); | ||||||
							
								
								
									
										61
									
								
								src/tools/regex-tester/regex-tester.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/tools/regex-tester/regex-tester.service.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | |||||||
|  | interface RegExpGroupIndices { | ||||||
|  |   [name: string]: [number, number] | ||||||
|  | } | ||||||
|  | interface RegExpIndices extends Array<[number, number]> { | ||||||
|  |   groups: RegExpGroupIndices | ||||||
|  | } | ||||||
|  | interface RegExpExecArrayWithIndices extends RegExpExecArray { | ||||||
|  |   indices: RegExpIndices | ||||||
|  | } | ||||||
|  | interface GroupCapture { | ||||||
|  |   name: string | ||||||
|  |   value: string | ||||||
|  |   start: number | ||||||
|  |   end: number | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export function matchRegex(regex: string, text: string, flags: string) { | ||||||
|  |   // if (regex === '' || text === '') {
 | ||||||
|  |   //   return [];
 | ||||||
|  |   // }
 | ||||||
|  | 
 | ||||||
|  |   let lastIndex = -1; | ||||||
|  |   const re = new RegExp(regex, flags); | ||||||
|  |   const results = []; | ||||||
|  |   let match = re.exec(text) as RegExpExecArrayWithIndices; | ||||||
|  |   while (match !== null) { | ||||||
|  |     if (re.lastIndex === lastIndex || match[0] === '') { | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     const indices = match.indices; | ||||||
|  |     const captures: Array<GroupCapture> = []; | ||||||
|  |     Object.entries(match).forEach(([captureName, captureValue]) => { | ||||||
|  |       if (captureName !== '0' && captureName.match(/\d+/)) { | ||||||
|  |         captures.push({ | ||||||
|  |           name: captureName, | ||||||
|  |           value: captureValue, | ||||||
|  |           start: indices[Number(captureName)][0], | ||||||
|  |           end: indices[Number(captureName)][1], | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     const groups: Array<GroupCapture> = []; | ||||||
|  |     Object.entries(match.groups || {}).forEach(([groupName, groupValue]) => { | ||||||
|  |       groups.push({ | ||||||
|  |         name: groupName, | ||||||
|  |         value: groupValue, | ||||||
|  |         start: indices.groups[groupName][0], | ||||||
|  |         end: indices.groups[groupName][1], | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |     results.push({ | ||||||
|  |       index: match.index, | ||||||
|  |       value: match[0], | ||||||
|  |       captures, | ||||||
|  |       groups, | ||||||
|  |     }); | ||||||
|  |     lastIndex = re.lastIndex; | ||||||
|  |     match = re.exec(text) as RegExpExecArrayWithIndices; | ||||||
|  |   } | ||||||
|  |   return results; | ||||||
|  | } | ||||||
							
								
								
									
										193
									
								
								src/tools/regex-tester/regex-tester.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								src/tools/regex-tester/regex-tester.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,193 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import RandExp from 'randexp'; | ||||||
|  | import { render } from '@regexper/render'; | ||||||
|  | import type { ShadowRootExpose } from 'vue-shadow-dom'; | ||||||
|  | import { matchRegex } from './regex-tester.service'; | ||||||
|  | import { useValidation } from '@/composable/validation'; | ||||||
|  | import { useQueryParamOrStorage } from '@/composable/queryParams'; | ||||||
|  | 
 | ||||||
|  | const regex = useQueryParamOrStorage({ name: 'regex', storageName: 'regex-tester:regex', defaultValue: '' }); | ||||||
|  | const text = ref(''); | ||||||
|  | const global = ref(true); | ||||||
|  | const ignoreCase = ref(false); | ||||||
|  | const multiline = ref(false); | ||||||
|  | const dotAll = ref(true); | ||||||
|  | const unicode = ref(true); | ||||||
|  | const unicodeSets = ref(false); | ||||||
|  | const visualizerSVG = ref<ShadowRootExpose>(); | ||||||
|  | 
 | ||||||
|  | const regexValidation = useValidation({ | ||||||
|  |   source: regex, | ||||||
|  |   rules: [ | ||||||
|  |     { | ||||||
|  |       message: 'Invalid regex: {0}', | ||||||
|  |       validator: value => new RegExp(value), | ||||||
|  |       getErrorMessage: (value) => { | ||||||
|  |         const _ = new RegExp(value); | ||||||
|  |         return ''; | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  | }); | ||||||
|  | const results = computed(() => { | ||||||
|  |   let flags = 'd'; | ||||||
|  |   if (global.value) { | ||||||
|  |     flags += 'g'; | ||||||
|  |   } | ||||||
|  |   if (ignoreCase.value) { | ||||||
|  |     flags += 'i'; | ||||||
|  |   } | ||||||
|  |   if (multiline.value) { | ||||||
|  |     flags += 'm'; | ||||||
|  |   } | ||||||
|  |   if (dotAll.value) { | ||||||
|  |     flags += 's'; | ||||||
|  |   } | ||||||
|  |   if (unicode.value) { | ||||||
|  |     flags += 'u'; | ||||||
|  |   } | ||||||
|  |   else if (unicodeSets.value) { | ||||||
|  |     flags += 'v'; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   try { | ||||||
|  |     return matchRegex(regex.value, text.value, flags); | ||||||
|  |   } | ||||||
|  |   catch (_) { | ||||||
|  |     return []; | ||||||
|  |   } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const sample = computed(() => { | ||||||
|  |   try { | ||||||
|  |     const randexp = new RandExp(new RegExp(regex.value.replace(/\(\?\<[^\>]*\>/g, '(?:'))); | ||||||
|  |     return randexp.gen(); | ||||||
|  |   } | ||||||
|  |   catch (_) { | ||||||
|  |     return ''; | ||||||
|  |   } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | watchEffect( | ||||||
|  |   async () => { | ||||||
|  |     const regexValue = regex.value; | ||||||
|  |     // shadow root is required: | ||||||
|  |     // @regexper/render append a <defs><style> that broke svg transparency of icons in the whole site | ||||||
|  |     const visualizer = visualizerSVG.value?.shadow_root; | ||||||
|  |     if (visualizer) { | ||||||
|  |       while (visualizer.lastChild) { | ||||||
|  |         visualizer.removeChild(visualizer.lastChild); | ||||||
|  |       } | ||||||
|  |       const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | ||||||
|  |       try { | ||||||
|  |         await render(regexValue, svg); | ||||||
|  |       } | ||||||
|  |       catch (_) { | ||||||
|  |       } | ||||||
|  |       visualizer.appendChild(svg); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div max-w-600px> | ||||||
|  |     <c-card title="Regex" mb-1> | ||||||
|  |       <c-input-text | ||||||
|  |         v-model:value="regex" | ||||||
|  |         label="Regex to test:" | ||||||
|  |         placeholder="Put the regex to test" | ||||||
|  |         multiline | ||||||
|  |         rows="3" | ||||||
|  |         :validation="regexValidation" | ||||||
|  |       /> | ||||||
|  |       <router-link target="_blank" to="/regex-memo" mb-1 mt-1> | ||||||
|  |         See Regular Expression Cheatsheet | ||||||
|  |       </router-link> | ||||||
|  |       <n-space> | ||||||
|  |         <n-checkbox v-model:checked="global"> | ||||||
|  |           <span title="Global search">Global search. (<code>g</code>)</span> | ||||||
|  |         </n-checkbox> | ||||||
|  |         <n-checkbox v-model:checked="ignoreCase"> | ||||||
|  |           <span title="Case-insensitive search">Case-insensitive search. (<code>i</code>)</span> | ||||||
|  |         </n-checkbox> | ||||||
|  |         <n-checkbox v-model:checked="multiline"> | ||||||
|  |           <span title="Allows ^ and $ to match next to newline characters.">Multiline(<code>m</code>)</span> | ||||||
|  |         </n-checkbox> | ||||||
|  |         <n-checkbox v-model:checked="dotAll"> | ||||||
|  |           <span title="Allows . to match newline characters.">Singleline(<code>s</code>)</span> | ||||||
|  |         </n-checkbox> | ||||||
|  |         <n-checkbox v-model:checked="unicode"> | ||||||
|  |           <span title="Unicode; treat a pattern as a sequence of Unicode code points.">Unicode(<code>u</code>)</span> | ||||||
|  |         </n-checkbox> | ||||||
|  |         <n-checkbox v-model:checked="unicodeSets"> | ||||||
|  |           <span title="An upgrade to the u mode with more Unicode features.">Unicode Sets (<code>v</code>)</span> | ||||||
|  |         </n-checkbox> | ||||||
|  |       </n-space> | ||||||
|  | 
 | ||||||
|  |       <n-divider /> | ||||||
|  | 
 | ||||||
|  |       <c-input-text | ||||||
|  |         v-model:value="text" | ||||||
|  |         label="Text to match:" | ||||||
|  |         placeholder="Put the text to match" | ||||||
|  |         multiline | ||||||
|  |         rows="5" | ||||||
|  |       /> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card title="Matches" mb-1 mt-3> | ||||||
|  |       <n-table v-if="results?.length > 0"> | ||||||
|  |         <thead> | ||||||
|  |           <tr> | ||||||
|  |             <th scope="col"> | ||||||
|  |               Index in text | ||||||
|  |             </th> | ||||||
|  |             <th scope="col"> | ||||||
|  |               Value | ||||||
|  |             </th> | ||||||
|  |             <th scope="col"> | ||||||
|  |               Captures | ||||||
|  |             </th> | ||||||
|  |             <th scope="col"> | ||||||
|  |               Groups | ||||||
|  |             </th> | ||||||
|  |           </tr> | ||||||
|  |         </thead> | ||||||
|  |         <tbody> | ||||||
|  |           <tr v-for="match of results" :key="match.index"> | ||||||
|  |             <td>{{ match.index }}</td> | ||||||
|  |             <td>{{ match.value }}</td> | ||||||
|  |             <td> | ||||||
|  |               <ul> | ||||||
|  |                 <li v-for="capture in match.captures" :key="capture.name"> | ||||||
|  |                   "{{ capture.name }}" = {{ capture.value }} [{{ capture.start }} - {{ capture.end }}] | ||||||
|  |                 </li> | ||||||
|  |               </ul> | ||||||
|  |             </td> | ||||||
|  |             <td> | ||||||
|  |               <ul> | ||||||
|  |                 <li v-for="group in match.groups" :key="group.name"> | ||||||
|  |                   "{{ group.name }}" = {{ group.value }} [{{ group.start }} - {{ group.end }}] | ||||||
|  |                 </li> | ||||||
|  |               </ul> | ||||||
|  |             </td> | ||||||
|  |           </tr> | ||||||
|  |         </tbody> | ||||||
|  |       </n-table> | ||||||
|  |       <c-alert v-else> | ||||||
|  |         No match | ||||||
|  |       </c-alert> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card title="Sample matching text" mt-3> | ||||||
|  |       <pre style="white-space: pre-wrap; word-break: break-all;">{{ sample }}</pre> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card title="Regex Diagram" style="overflow-x: scroll;" mt-3> | ||||||
|  |       <shadow-root ref="visualizerSVG"> | ||||||
|  |   | ||||||
|  |       </shadow-root> | ||||||
|  |     </c-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user