feat(new tool): XPath tester

Fix #672
This commit is contained in:
sharevb 2024-08-23 21:52:01 +02:00 committed by ShareVB
parent 318fb6efb9
commit 23214dc9a8
6 changed files with 108 additions and 17 deletions

8
components.d.ts vendored
View file

@ -129,22 +129,15 @@ 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']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
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']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSlider: typeof import('naive-ui')['NSlider']
NSwitch: typeof import('naive-ui')['NSwitch']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
@ -187,6 +180,7 @@ declare module '@vue/runtime-core' {
WifiQrCodeGenerator: typeof import('./src/tools/wifi-qr-code-generator/wifi-qr-code-generator.vue')['default'] WifiQrCodeGenerator: typeof import('./src/tools/wifi-qr-code-generator/wifi-qr-code-generator.vue')['default']
XmlFormatter: typeof import('./src/tools/xml-formatter/xml-formatter.vue')['default'] XmlFormatter: typeof import('./src/tools/xml-formatter/xml-formatter.vue')['default']
XmlToJson: typeof import('./src/tools/xml-to-json/xml-to-json.vue')['default'] XmlToJson: typeof import('./src/tools/xml-to-json/xml-to-json.vue')['default']
XpathTester: typeof import('./src/tools/xpath-tester/xpath-tester.vue')['default']
YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default'] YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default']
YamlToToml: typeof import('./src/tools/yaml-to-toml/yaml-to-toml.vue')['default'] YamlToToml: typeof import('./src/tools/yaml-to-toml/yaml-to-toml.vue')['default']
YamlViewer: typeof import('./src/tools/yaml-viewer/yaml-viewer.vue')['default'] YamlViewer: typeof import('./src/tools/yaml-viewer/yaml-viewer.vue')['default']

View file

@ -47,6 +47,7 @@
"@vueuse/core": "^10.3.0", "@vueuse/core": "^10.3.0",
"@vueuse/head": "^1.0.0", "@vueuse/head": "^1.0.0",
"@vueuse/router": "^10.0.0", "@vueuse/router": "^10.0.0",
"@xmldom/xmldom": "^0.8.10",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"change-case": "^4.1.2", "change-case": "^4.1.2",
"colord": "^2.9.3", "colord": "^2.9.3",
@ -94,6 +95,7 @@
"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",
"xpath": "^0.0.34",
"yaml": "^2.2.1" "yaml": "^2.2.1"
}, },
"devDependencies": { "devDependencies": {

36
pnpm-lock.yaml generated
View file

@ -41,6 +41,9 @@ dependencies:
'@vueuse/router': '@vueuse/router':
specifier: ^10.0.0 specifier: ^10.0.0
version: 10.0.0(vue-router@4.1.6)(vue@3.3.4) version: 10.0.0(vue-router@4.1.6)(vue@3.3.4)
'@xmldom/xmldom':
specifier: ^0.8.10
version: 0.8.10
bcryptjs: bcryptjs:
specifier: ^2.4.3 specifier: ^2.4.3
version: 2.4.3 version: 2.4.3
@ -182,6 +185,9 @@ dependencies:
xml-js: xml-js:
specifier: ^1.6.11 specifier: ^1.6.11
version: 1.6.11 version: 1.6.11
xpath:
specifier: ^0.0.34
version: 0.0.34
yaml: yaml:
specifier: ^2.2.1 specifier: ^2.2.1
version: 2.2.1 version: 2.2.1
@ -3360,7 +3366,7 @@ packages:
dependencies: dependencies:
'@unhead/dom': 0.5.1 '@unhead/dom': 0.5.1
'@unhead/schema': 0.5.1 '@unhead/schema': 0.5.1
'@vueuse/shared': 10.11.1(vue@3.3.4) '@vueuse/shared': 11.0.3(vue@3.3.4)
unhead: 0.5.1 unhead: 0.5.1
vue: 3.3.4 vue: 3.3.4
transitivePeerDependencies: transitivePeerDependencies:
@ -3993,15 +3999,6 @@ packages:
- vue - vue
dev: false dev: false
/@vueuse/shared@10.11.1(vue@3.3.4):
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
dependencies:
vue-demi: 0.14.10(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: false
/@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:
@ -4011,6 +4008,20 @@ packages:
- vue - vue
dev: false dev: false
/@vueuse/shared@11.0.3(vue@3.3.4):
resolution: {integrity: sha512-0rY2m6HS5t27n/Vp5cTDsKTlNnimCqsbh/fmT2LgE+aaU42EMfXo8+bNX91W9I7DDmxfuACXMmrd7d79JxkqWA==}
dependencies:
vue-demi: 0.14.10(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: false
/@xmldom/xmldom@0.8.10:
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
engines: {node: '>=10.0.0'}
dev: false
/@zhead/schema@1.0.0-beta.13: /@zhead/schema@1.0.0-beta.13:
resolution: {integrity: sha512-P1A1vRGFBhITco8Iw4/hvnDYoE/SoVrd71dW1pBFdXJb3vP+pBtoOuhbEKy0ROJGOyzQuqvFibcwzyLlWMqNiQ==} resolution: {integrity: sha512-P1A1vRGFBhITco8Iw4/hvnDYoE/SoVrd71dW1pBFdXJb3vP+pBtoOuhbEKy0ROJGOyzQuqvFibcwzyLlWMqNiQ==}
dev: false dev: false
@ -9587,6 +9598,11 @@ packages:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
dev: true dev: true
/xpath@0.0.34:
resolution: {integrity: sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==}
engines: {node: '>=0.6.0'}
dev: false
/y18n@4.0.3: /y18n@4.0.3:
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
dev: false dev: false

View file

@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter'; import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as emailNormalizer } from './email-normalizer'; import { tool as emailNormalizer } from './email-normalizer';
import { tool as xpathTester } from './xpath-tester';
import { tool as asciiTextDrawer } from './ascii-text-drawer'; import { tool as asciiTextDrawer } from './ascii-text-drawer';
@ -154,6 +155,7 @@ export const toolsByCategory: ToolCategory[] = [
xmlFormatter, xmlFormatter,
yamlViewer, yamlViewer,
emailNormalizer, emailNormalizer,
xpathTester,
], ],
}, },
{ {

View file

@ -0,0 +1,12 @@
import { Brackets } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'XPath Tester',
path: '/xpath-tester',
description: 'Test XPath expression against XML content',
keywords: ['xpath', 'xml', 'tester'],
component: () => import('./xpath-tester.vue'),
icon: Brackets,
createdAt: new Date('2024-08-15'),
});

View file

@ -0,0 +1,65 @@
<script setup lang="ts">
import XPathEngine from 'xpath';
import { DOMParser } from '@xmldom/xmldom';
import { useValidation } from '@/composable/validation';
const xpath = ref('//title');
const xml = ref('<book><title>Harry Potter</title></book>');
const selectedNodes = computed(() => {
try {
const doc = new DOMParser().parseFromString(xml.value, 'text/xml');
return XPathEngine.select(xpath.value, doc);
}
catch (e: any) {
return e.toString();
}
});
const xmlValidation = useValidation({
source: xml,
rules: [
{
validator: (v) => {
new DOMParser().parseFromString(v, 'text/xml');
return true;
},
message: 'Provided XML is not valid.',
},
],
});
</script>
<template>
<div style="max-width: 600px;">
<c-card title="Input" mb-2>
<c-input-text
v-model:value="xpath"
label="XPath Expression"
placeholder="Put your XPath expression here..."
mb-2
/>
<c-input-text
v-model:value="xml"
label="XML"
multiline
placeholder="Put your XML here..."
rows="5"
:validation="xmlValidation"
mb-2
/>
</c-card>
<c-card title="Result(s)">
<ul v-if="selectedNodes?.length > 0">
<li v-for="(node, index) in selectedNodes" :key="index">
{{ node }}
</li>
</ul>
<c-alert v-if="!selectedNodes?.length">
XPath expression selected nothing
</c-alert>
</c-card>
</div>
</template>