diff --git a/components/CodeMirrorEditor.vue b/components/CodeMirrorEditor.vue index 910a66e..268ecca 100644 --- a/components/CodeMirrorEditor.vue +++ b/components/CodeMirrorEditor.vue @@ -87,6 +87,48 @@ const getJoiExtension = () => { }; +const format = async () => { + if (!view) { + return; + } + + + const code = view.state.doc.toString(); + try { + const [prettier, prettierPluginBabel, prettierPluginEstree] = await Promise.all([ + import('prettier/standalone'), + import('prettier/plugins/babel'), + import('prettier/plugins/estree'), + ]); + + + const formatted = await prettier.format(code, { + parser: language === 'json' ? 'json' : 'babel', + plugins: [ + prettierPluginBabel.default || prettierPluginBabel, + prettierPluginEstree.default || prettierPluginEstree, + ], + printWidth: 120, + semi: false, + singleQuote: true, + trailingComma: 'all', + }); + + + if (formatted !== code) { + view.dispatch({ + changes: { from: 0, insert: formatted, to: view.state.doc.length }, + }); + } + } catch (err) { + console.error('Format error:', err); + } +}; + + +defineExpose({ format }); + + onMounted(() => { const extensions = [ basicSetup, diff --git a/components/TesterContent.vue b/components/TesterContent.vue index 570e3f2..3197263 100644 --- a/components/TesterContent.vue +++ b/components/TesterContent.vue @@ -8,13 +8,19 @@
-

Schema:

- +
+

Schema:

+ +
+
-

Data To Validate:

- +
+

Data To Validate:

+ +
+
@@ -114,6 +120,10 @@ const { copy, copied: isCopied } = useClipboard(); const showResetConfirm = ref(false); +const schemaEditor = ref(null); +const validateEditor = ref(null); + + const loadJoi = async (v) => { if (!v) { return; @@ -304,6 +314,35 @@ const onShareClick = async () => { margin-bottom: 20px; } +.field-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.5rem; +} + +.field-header .tester-subTitle { + margin-bottom: 0; +} + +.format-button { + border-radius: 6px; + border: 1px solid var(--vp-c-divider); + background: var(--vp-c-bg-soft); + padding: 2px 10px; + font-size: 0.9em; + font-weight: 600; + color: var(--vp-c-text-1); + cursor: pointer; + transition: all 0.2s ease; +} + +.format-button:hover { + border-color: var(--vp-c-brand-1); + color: var(--vp-c-brand-1); + background: var(--vp-c-bg); +} + .tester-subTitle { font-size: 1.5em; margin-bottom: 5px; diff --git a/package.json b/package.json index f307142..4072dc8 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@codemirror/state": "^6.6.0", "@codemirror/view": "^6.40.0", "@lezer/highlight": "^1.2.3", + "@standard-schema/spec": "^1.1.0", "@typescript/vfs": "^1.6.4", "@uiw/codemirror-theme-darcula": "^4.25.8", "@uiw/codemirror-theme-eclipse": "^4.25.8", @@ -34,7 +35,7 @@ "es-toolkit": "^1.45.1", "joi-17": "npm:joi@17.13.3", "joi-18": "npm:joi@18.0.2", - "@standard-schema/spec": "^1.1.0", + "prettier": "^3.8.1", "semver": "^7.7.4", "vitepress-plugin-group-icons": "^1.7.1", "vue": "^3.5.30" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88ba5b5..4970763 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: joi-18: specifier: npm:joi@18.0.2 version: joi@18.0.2 + prettier: + specifier: ^3.8.1 + version: 3.8.1 semver: specifier: ^7.7.4 version: 7.7.4 @@ -1231,6 +1234,11 @@ packages: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} @@ -2412,6 +2420,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prettier@3.8.1: {} + property-information@7.1.0: {} regex-recursion@6.0.2: