Merge branch 'main' into fix/token-generator
This commit is contained in:
		
						commit
						123c26d6b8
					
				
							
								
								
									
										
											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). | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -130,17 +130,14 @@ 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'] | ||||||
|     NButton: typeof import('naive-ui')['NButton'] |     NCheckbox: typeof import('naive-ui')['NCheckbox'] | ||||||
|     NCode: typeof import('naive-ui')['NCode'] |  | ||||||
|     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'] |  | ||||||
|     NFormItem: typeof import('naive-ui')['NFormItem'] |  | ||||||
|     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 +154,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,12 +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/markdown-it": "^13.0.7", |  | ||||||
|     "@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", | ||||||
| @ -84,6 +85,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 +95,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", | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								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 | ||||||
| @ -152,6 +155,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 +185,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) | ||||||
| @ -2480,6 +2489,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: | ||||||
| @ -2629,6 +2649,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: | ||||||
| @ -4962,6 +4986,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 | ||||||
| @ -7758,6 +7787,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: | ||||||
| @ -7928,6 +7965,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'} | ||||||
| @ -9268,6 +9310,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: | ||||||
|  | |||||||
| @ -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'); | ||||||
|  | |||||||
| @ -9,6 +9,8 @@ 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 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'; | ||||||
| @ -156,6 +158,8 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|       xmlFormatter, |       xmlFormatter, | ||||||
|       yamlViewer, |       yamlViewer, | ||||||
|       emailNormalizer, |       emailNormalizer, | ||||||
|  |       regexTester, | ||||||
|  |       regexMemo, | ||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|  | |||||||
							
								
								
									
										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