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:
-
+
+
-
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: