refactor(dx): generic data transformer

This commit is contained in:
Corentin Thomasset 2023-04-10 16:34:10 +02:00 committed by Corentin THOMASSET
parent 9fa4c26929
commit 05f06f6a07
5 changed files with 78 additions and 50 deletions

1
components.d.ts vendored
View file

@ -12,6 +12,7 @@ declare module '@vue/runtime-core' {
CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default'] CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
ColoredCard: typeof import('./src/components/ColoredCard.vue')['default'] ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default'] FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default'] MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']

View file

@ -0,0 +1,57 @@
<template>
<n-form-item :label="inputLabel" v-bind="validationAttrs">
<n-input
ref="inputElement"
v-model:value="input"
:placeholder="inputPlaceholder"
type="textarea"
rows="20"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
:input-props="{ 'data-test-id': 'input' }"
/>
</n-form-item>
<n-form-item :label="outputLabel">
<textarea-copyable :value="output" :language="outputLanguage" :follow-height-of="inputElement" />
</n-form-item>
</template>
<script setup lang="ts">
import { useValidation, type UseValidationRule } from '@/composable/validation';
import _ from 'lodash';
const props = withDefaults(
defineProps<{
transformer?: (v: string) => string;
inputValidationRules?: UseValidationRule<string>[];
inputLabel?: string;
inputPlaceholder?: string;
inputDefault?: string;
outputLabel?: string;
outputLanguage?: string;
}>(),
{
transformer: _.identity,
inputValidationRules: () => [],
inputLabel: 'Input',
inputDefault: '',
inputPlaceholder: 'Input...',
outputLabel: 'Output',
outputLanguage: '',
},
);
const { transformer, inputValidationRules, inputLabel, outputLabel, outputLanguage, inputPlaceholder, inputDefault } =
toRefs(props);
const inputElement = ref();
const input = ref(inputDefault.value);
const output = computed(() => transformer.value(input.value));
const { attrs: validationAttrs } = useValidation({ source: input, rules: inputValidationRules.value });
</script>
<style scoped></style>

View file

@ -7,7 +7,7 @@
:style="height ? `min-height: ${height - 40 /* card padding */ + 10 /* negative margin compensation */}px` : ''" :style="height ? `min-height: ${height - 40 /* card padding */ + 10 /* negative margin compensation */}px` : ''"
> >
<n-config-provider :hljs="hljs"> <n-config-provider :hljs="hljs">
<n-code :code="value" :language="language" :trim="false" /> <n-code :code="value" :language="language" :trim="false" data-test-id="area-content" />
</n-config-provider> </n-config-provider>
</n-scrollbar> </n-scrollbar>
<n-tooltip v-if="value" trigger="hover"> <n-tooltip v-if="value" trigger="hover">

View file

@ -3,7 +3,7 @@ import { reactive, watch, type Ref } from 'vue';
type ValidatorReturnType = unknown; type ValidatorReturnType = unknown;
interface UseValidationRule<T> { export interface UseValidationRule<T> {
validator: (value: T) => ValidatorReturnType; validator: (value: T) => ValidatorReturnType;
message: string; message: string;
} }

View file

@ -1,57 +1,27 @@
<template> <template>
<n-form-item <format-transformer
label="Your raw json" input-label="Your raw json"
:feedback="rawJsonValidation.message" :input-default="defaultValue"
:validation-status="rawJsonValidation.status" input-placeholder="Paste your raw json here..."
> output-label="Minify version of your JSON"
<n-input output-language="json"
ref="inputElement" :input-validation-rules="rules"
v-model:value="rawJson" :transformer="transformer"
placeholder="Paste your raw json here..." />
type="textarea"
rows="20"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
</n-form-item>
<n-form-item label="Minify version of your JSON">
<textarea-copyable :value="cleanJson" language="json" :follow-height-of="inputElement" />
</n-form-item>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import TextareaCopyable from '@/components/TextareaCopyable.vue'; import type { UseValidationRule } from '@/composable/validation';
import { useValidation } from '@/composable/validation';
import { withDefaultOnError } from '@/utils/defaults'; import { withDefaultOnError } from '@/utils/defaults';
import JSON5 from 'json5'; import JSON5 from 'json5';
import { computed, ref } from 'vue';
const inputElement = ref<HTMLElement>(); const defaultValue = '{\n\t"hello": [\n\t\t"world"\n\t]\n}';
const transformer = (value: string) => withDefaultOnError(() => JSON.stringify(JSON5.parse(value), null, 0), '');
const rawJson = ref('{\n\t"hello": [\n\t\t"world"\n\t]\n}'); const rules: UseValidationRule<string>[] = [
const cleanJson = computed(() => withDefaultOnError(() => JSON.stringify(JSON5.parse(rawJson.value), null, 0), '')); {
validator: (v: string) => v === '' || JSON5.parse(v),
const rawJsonValidation = useValidation({ message: 'Provided JSON is not valid.',
source: rawJson, },
rules: [ ];
{
validator: (v) => v === '' || JSON5.parse(v),
message: 'Provided JSON is not valid.',
},
],
});
</script> </script>
<style lang="less" scoped>
.result-card {
position: relative;
.copy-button {
position: absolute;
top: 10px;
right: 10px;
}
}
</style>