refactor: ts and composition api for single instance components

This commit is contained in:
Fabio Di Stasio 2022-05-14 11:15:42 +02:00
parent 45b2eb2934
commit 8a55b36527
12 changed files with 364 additions and 343 deletions

View File

@ -59,7 +59,7 @@ async function restartElectron () {
console.error(chalk.red(data.toString())); console.error(chalk.red(data.toString()));
}); });
electronProcess.on('exit', (code, signal) => { electronProcess.on('exit', () => {
if (!manualRestart) process.exit(0); if (!manualRestart) process.exit(0);
}); });
} }

View File

@ -2,5 +2,5 @@ export function bufferToBase64 (buf: Buffer) {
const binstr = Array.prototype.map.call(buf, ch => { const binstr = Array.prototype.map.call(buf, ch => {
return String.fromCharCode(ch); return String.fromCharCode(ch);
}).join(''); }).join('');
return Buffer.from(binstr, 'base64'); return Buffer.from(binstr, 'binary').toString('base64');
} }

View File

@ -99,7 +99,7 @@ onMounted(() => {
enableLiveAutocompletion: false enableLiveAutocompletion: false
}); });
editor.session.on('changeFold', () => { (editor.session as unknown as ace.Ace.Editor).on('change', () => {
const content = editor.getValue(); const content = editor.getValue();
emit('update:modelValue', content); emit('update:modelValue', content);
}); });

View File

@ -104,151 +104,148 @@
</fieldset> </fieldset>
</template> </template>
<script> <script setup lang="ts">
import { computed, PropType, Ref, ref, watch } from 'vue';
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes'; import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
import BaseUploadInput from '@/components/BaseUploadInput'; import BaseUploadInput from '@/components/BaseUploadInput.vue';
import ForeignKeySelect from '@/components/ForeignKeySelect'; import ForeignKeySelect from '@/components/ForeignKeySelect.vue';
import FakerMethods from 'common/FakerMethods'; import FakerMethods from 'common/FakerMethods';
export default { const props = defineProps({
name: 'FakerSelect', type: String,
components: { field: Object,
ForeignKeySelect, isChecked: Boolean,
BaseUploadInput foreignKeys: Array,
}, keyUsage: Array as PropType<{field: string}[]>,
props: { fieldLength: Number,
type: String, fieldObj: Object
field: Object, });
isChecked: Boolean, const emit = defineEmits(['update:modelValue']);
foreignKeys: Array,
keyUsage: Array,
fieldLength: Number,
fieldObj: Object
},
emits: ['update:modelValue'],
data () {
return {
localType: null,
selectedGroup: 'manual',
selectedMethod: '',
selectedValue: '',
debounceTimeout: null,
methodParams: {},
enumArray: null
};
},
computed: {
fakerGroups () {
if ([...TEXT, ...LONG_TEXT].includes(this.type))
this.localType = 'string';
else if (NUMBER.includes(this.type))
this.localType = 'number';
else if (FLOAT.includes(this.type))
this.localType = 'float';
else if ([...DATE, ...DATETIME].includes(this.type))
this.localType = 'datetime';
else if (TIME.includes(this.type))
this.localType = 'time';
else
this.localType = 'none';
return FakerMethods.getGroupsByType(this.localType); const localType: Ref<string> = ref(null);
}, const selectedGroup: Ref<string> = ref('manual');
fakerMethods () { const selectedMethod: Ref<string> = ref('');
return FakerMethods.getMethods({ type: this.localType, group: this.selectedGroup }); const selectedValue: Ref<string> = ref('');
}, const debounceTimeout: Ref<NodeJS.Timeout> = ref(null);
methodData () { const methodParams: Ref<{[key: string]: string}> = ref({});
return this.fakerMethods.find(method => method.name === this.selectedMethod); const enumArray: Ref<string[]> = ref(null);
}
},
watch: {
fieldObj () {
if (this.fieldObj) {
if (Array.isArray(this.fieldObj.value)) {
this.enumArray = this.fieldObj.value;
this.selectedValue = this.fieldObj.value[0];
}
else
this.selectedValue = this.fieldObj.value;
}
},
selectedGroup () {
if (this.fakerMethods.length)
this.selectedMethod = this.fakerMethods[0].name;
else
this.selectedMethod = '';
},
selectedMethod () {
this.onChange();
},
selectedValue () {
clearTimeout(this.debounceTimeout);
this.debounceTimeout = null;
this.debounceTimeout = setTimeout(() => {
this.onChange();
}, 200);
}
},
methods: {
inputProps () {
if ([...TEXT, ...LONG_TEXT].includes(this.type))
return { type: 'text', mask: false };
if ([...NUMBER, ...FLOAT].includes(this.type)) const fakerGroups = computed(() => {
return { type: 'number', mask: false }; if ([...TEXT, ...LONG_TEXT].includes(props.type))
localType.value = 'string';
else if (NUMBER.includes(props.type))
localType.value = 'number';
else if (FLOAT.includes(props.type))
localType.value = 'float';
else if ([...DATE, ...DATETIME].includes(props.type))
localType.value = 'datetime';
else if (TIME.includes(props.type))
localType.value = 'time';
else
localType.value = 'none';
if (TIME.includes(this.type)) { return FakerMethods.getGroupsByType(localType.value);
let timeMask = '##:##:##'; });
const precision = this.fieldLength;
for (let i = 0; i < precision; i++) const fakerMethods = computed(() => {
timeMask += i === 0 ? '.#' : '#'; return FakerMethods.getMethods({ type: localType.value, group: selectedGroup.value });
});
return { type: 'text', mask: timeMask }; const methodData = computed(() => {
} return fakerMethods.value.find(method => method.name === selectedMethod.value);
});
if (DATE.includes(this.type)) const inputProps = () => {
return { type: 'text', mask: '####-##-##' }; if ([...TEXT, ...LONG_TEXT].includes(props.type))
return { type: 'text', mask: false };
if (DATETIME.includes(this.type)) { if ([...NUMBER, ...FLOAT].includes(props.type))
let datetimeMask = '####-##-## ##:##:##'; return { type: 'number', mask: false };
const precision = this.fieldLength;
for (let i = 0; i < precision; i++) if (TIME.includes(props.type)) {
datetimeMask += i === 0 ? '.#' : '#'; let timeMask = '##:##:##';
const precision = props.fieldLength;
return { type: 'text', mask: datetimeMask }; for (let i = 0; i < precision; i++)
} timeMask += i === 0 ? '.#' : '#';
if (BLOB.includes(this.type)) return { type: 'text', mask: timeMask };
return { type: 'file', mask: false };
if (BIT.includes(this.type))
return { type: 'text', mask: false };
return { type: 'text', mask: false };
},
getKeyUsage (keyName) {
return this.keyUsage.find(key => key.field === keyName);
},
filesChange (event) {
const { files } = event.target;
if (!files.length) return;
this.selectedValue = files[0].path;
},
clearValue () {
this.selectedValue = '';
},
onChange () {
this.$emit('update:modelValue', {
group: this.selectedGroup,
method: this.selectedMethod,
params: this.methodParams,
value: this.selectedValue,
length: this.fieldLength
});
}
} }
if (DATE.includes(props.type))
return { type: 'text', mask: '####-##-##' };
if (DATETIME.includes(props.type)) {
let datetimeMask = '####-##-## ##:##:##';
const precision = props.fieldLength;
for (let i = 0; i < precision; i++)
datetimeMask += i === 0 ? '.#' : '#';
return { type: 'text', mask: datetimeMask };
}
if (BLOB.includes(props.type))
return { type: 'file', mask: false };
if (BIT.includes(props.type))
return { type: 'text', mask: false };
return { type: 'text', mask: false };
}; };
const getKeyUsage = (keyName: string) => {
return props.keyUsage.find(key => key.field === keyName);
};
const filesChange = ({ target } : {target: HTMLInputElement }) => {
const { files } = target;
if (!files.length) return;
selectedValue.value = files[0].path;
};
const clearValue = () => {
selectedValue.value = '';
};
const onChange = () => {
emit('update:modelValue', {
group: selectedGroup.value,
method: selectedMethod.value,
params: methodParams.value,
value: selectedValue.value,
length: props.fieldLength
});
};
watch(() => props.fieldObj, () => {
if (props.fieldObj) {
if (Array.isArray(props.fieldObj.value)) {
enumArray.value = props.fieldObj.value;
selectedValue.value = props.fieldObj.value[0];
}
else
selectedValue.value = props.fieldObj.value;
}
});
watch(selectedGroup, () => {
if (fakerMethods.value.length)
selectedMethod.value = fakerMethods.value[0].name;
else
selectedMethod.value = '';
});
watch(selectedMethod, () => {
onChange();
});
watch(selectedValue, () => {
clearTimeout(debounceTimeout.value);
debounceTimeout.value = null;
debounceTimeout.value = setTimeout(() => {
onChange();
}, 200);
});
</script> </script>

View File

@ -271,7 +271,7 @@ export default {
else if ([...TIME, ...DATE].includes(field.type)) else if ([...TIME, ...DATE].includes(field.type))
fieldDefault = field.default; fieldDefault = field.default;
else if (BIT.includes(field.type)) else if (BIT.includes(field.type))
fieldDefault = field.default.replaceAll('\'', '').replaceAll('b', ''); fieldDefault = field.default?.replaceAll('\'', '').replaceAll('b', '');
else if (DATETIME.includes(field.type)) { else if (DATETIME.includes(field.type)) {
if (field.default && ['current_timestamp', 'now()'].some(term => field.default.toLowerCase().includes(term))) { if (field.default && ['current_timestamp', 'now()'].some(term => field.default.toLowerCase().includes(term))) {
let datePrecision = ''; let datePrecision = '';

View File

@ -26,46 +26,39 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { shell } from 'electron';
import { storeToRefs } from 'pinia';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import { storeToRefs } from 'pinia'; import { computed, ComputedRef } from 'vue';
const { shell } = require('electron');
export default { interface DatabaseInfos {// TODO: temp
name: 'TheFooter', name: string;
setup () { number: string;
const applicationStore = useApplicationStore(); arch: string;
const workspacesStore = useWorkspacesStore(); os: string;
}
const { getSelected: workspace } = storeToRefs(workspacesStore); const applicationStore = useApplicationStore();
const workspacesStore = useWorkspacesStore();
const { appVersion, showSettingModal } = applicationStore; const { getSelected: workspace } = storeToRefs(workspacesStore);
const { getWorkspace } = workspacesStore;
return { const { showSettingModal } = applicationStore;
appVersion, const { getWorkspace } = workspacesStore;
showSettingModal,
workspace, const version: ComputedRef<DatabaseInfos> = computed(() => {
getWorkspace return getWorkspace(workspace.value) ? getWorkspace(workspace.value).version : null;
}; });
},
computed: { const versionString = computed(() => {
version () { if (version.value)
return this.getWorkspace(this.workspace) ? this.getWorkspace(this.workspace).version : null; return `${version.value.name} ${version.value.number} (${version.value.arch} ${version.value.os})`;
}, return '';
versionString () { });
if (this.version)
return `${this.version.name} ${this.version.number} (${this.version.arch} ${this.version.os})`; const openOutside = (link: string) => shell.openExternal(link);
return '';
}
},
methods: {
openOutside (link) {
shell.openExternal(link);
}
}
};
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -16,71 +16,51 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { computed, Ref, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useNotificationsStore } from '@/stores/notifications'; import { useNotificationsStore } from '@/stores/notifications';
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
import BaseNotification from '@/components/BaseNotification'; import BaseNotification from '@/components/BaseNotification.vue';
import { storeToRefs } from 'pinia';
export default { const notificationsStore = useNotificationsStore();
name: 'TheNotificationsBoard', const settingsStore = useSettingsStore();
components: {
BaseNotification
},
setup () {
const notificationsStore = useNotificationsStore();
const settingsStore = useSettingsStore();
const { removeNotification } = notificationsStore; const { removeNotification } = notificationsStore;
const { notifications } = storeToRefs(notificationsStore); const { notifications } = storeToRefs(notificationsStore);
const { notificationsTimeout } = storeToRefs(settingsStore); const { notificationsTimeout } = storeToRefs(settingsStore) as {notificationsTimeout: Ref<number>};// TODO: temp
return { const timeouts: Ref<{[key: string]: NodeJS.Timeout}> = ref({});
removeNotification,
notifications, const latestNotifications = computed(() => notifications.value.slice(0, 10));
notificationsTimeout
}; watch(() => notifications.value.length, (val) => {
}, if (val > 0) {
data () { const nUid: string = notifications.value[0].uid;
return { timeouts.value[nUid] = setTimeout(() => {
timeouts: {} removeNotification(nUid);
}; delete timeouts.value[nUid];
}, }, notificationsTimeout.value * 1000);
computed: { }
latestNotifications () { });
return this.notifications.slice(0, 10);
} const clearTimeouts = () => {
}, for (const uid in timeouts.value) {
watch: { clearTimeout(timeouts.value[uid]);
'notifications.length': function (val) { delete timeouts.value[uid];
if (val > 0) { }
const nUid = this.notifications[0].uid; };
this.timeouts[nUid] = setTimeout(() => {
this.removeNotification(nUid); const rearmTimeouts = () => {
delete this.timeouts[nUid]; const delay = 50;
}, this.notificationsTimeout * 1000); let i = notifications.value.length * delay;
} for (const notification of notifications.value) {
} timeouts.value[notification.uid] = setTimeout(() => {
}, removeNotification(notification.uid);
methods: { delete timeouts.value[notification.uid];
clearTimeouts () { }, (notificationsTimeout.value * 1000) + i);
for (const uid in this.timeouts) { i = i > delay ? i - delay : 0;
clearTimeout(this.timeouts[uid]);
delete this.timeouts[uid];
}
},
rearmTimeouts () {
const delay = 50;
let i = this.notifications.length * delay;
for (const notification of this.notifications) {
this.timeouts[notification.uid] = setTimeout(() => {
this.removeNotification(notification.uid);
delete this.timeouts[notification.uid];
}, (this.notificationsTimeout * 1000) + i);
i = i > delay ? i - delay : 0;
}
}
} }
}; };
</script> </script>

View File

@ -28,55 +28,30 @@
</ConfirmModal> </ConfirmModal>
</template> </template>
<script> <script setup lang="ts">
import { ref, Ref, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import ConfirmModal from '@/components/BaseConfirmModal';
import TextEditor from '@/components/BaseTextEditor';
import { useScratchpadStore } from '@/stores/scratchpad'; import { useScratchpadStore } from '@/stores/scratchpad';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import TextEditor from '@/components/BaseTextEditor.vue';
export default { const applicationStore = useApplicationStore();
name: 'TheScratchpad', const scratchpadStore = useScratchpadStore();
components: {
ConfirmModal,
TextEditor
},
emits: ['hide'],
setup () {
const applicationStore = useApplicationStore();
const scratchpadStore = useScratchpadStore();
const { notes } = storeToRefs(scratchpadStore); const { notes } = storeToRefs(scratchpadStore);
const { changeNotes } = scratchpadStore; const { changeNotes } = scratchpadStore;
const { hideScratchpad } = applicationStore;
return { const localNotes: Ref<string> = ref(notes.value as string);// TODO: temp
notes, const debounceTimeout: Ref<NodeJS.Timeout> = ref(null);
hideScratchpad: applicationStore.hideScratchpad,
changeNotes watch(localNotes, () => {
}; clearTimeout(debounceTimeout.value);
},
data () { debounceTimeout.value = setTimeout(() => {
return { changeNotes(localNotes.value);
localNotes: '', }, 200);
debounceTimeout: null });
};
},
watch: {
localNotes () {
clearTimeout(this.debounceTimeout);
this.debounceTimeout = setTimeout(() => {
this.changeNotes(this.localNotes);
}, 200);
}
},
created () {
this.localNotes = this.notes;
},
methods: {
hideModal () {
this.$emit('hide');
}
}
};
</script> </script>

View File

@ -55,7 +55,85 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { ref, Ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useApplicationStore } from '@/stores/application';
import { useConnectionsStore } from '@/stores/connections';
import { useWorkspacesStore } from '@/stores/workspaces';
import * as Draggable from 'vuedraggable';
import SettingBarContext from '@/components/SettingBarContext.vue';
import { ConnectionParams } from 'common/interfaces/antares';
import { computed } from '@vue/reactivity';
const applicationStore = useApplicationStore();
const connectionsStore = useConnectionsStore();
const workspacesStore = useWorkspacesStore();
const { updateStatus } = storeToRefs(applicationStore);
const { connections: getConnections } = storeToRefs(connectionsStore);
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const { showSettingModal, showScratchpad } = applicationStore;
const { getConnectionName, updateConnections } = connectionsStore;
const { getWorkspace, selectWorkspace } = workspacesStore;
const isContext: Ref<boolean> = ref(false);
const isDragging: Ref<boolean> = ref(false);
const contextEvent: Ref<Event> = ref(null);
const contextConnection: Ref<ConnectionParams> = ref(null);
const connections = computed({
get () {
return getConnections.value;
},
set (value) {
updateConnections(value);
}
});
const hasUpdates = computed(() => ['available', 'downloading', 'downloaded', 'link'].includes(updateStatus.value));
const contextMenu = (event: Event, connection: ConnectionParams) => {
contextEvent.value = event;
contextConnection.value = connection;
isContext.value = true;
};
const tooltipPosition = (e: Event) => {
const el = e.target ? e.target : e;
const fromTop = window.pageYOffset + (el as HTMLElement).getBoundingClientRect().top - ((el as HTMLElement).offsetHeight / 4);
(el as HTMLElement).querySelector<HTMLElement>('.ex-tooltip-content').style.top = `${fromTop}px`;
};
const getStatusBadge = (uid: string) => {
if (getWorkspace(uid)) {
const status = getWorkspace(uid).connectionStatus;
switch (status) {
case 'connected':
return 'badge badge-connected';
case 'connecting':
return 'badge badge-connecting';
case 'failed':
return 'badge badge-failed';
default:
return '';
}
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const dragStop = (e: any) => { // TODO: temp
isDragging.value = false;
setTimeout(() => {
tooltipPosition(e.originalEvent.target.parentNode);
}, 200);
};
</script>
<!-- <script>
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { useConnectionsStore } from '@/stores/connections'; import { useConnectionsStore } from '@/stores/connections';
@ -157,7 +235,7 @@ export default {
} }
} }
}; };
</script> </script> -->
<style lang="scss"> <style lang="scss">
#settingbar { #settingbar {

View File

@ -5,7 +5,7 @@
<img <img
v-if="!isMacOS" v-if="!isMacOS"
class="titlebar-logo" class="titlebar-logo"
src="@/images/logo.svg" :src="appIcon"
> >
</div> </div>
<div class="titlebar-elements titlebar-title"> <div class="titlebar-elements titlebar-title">
@ -52,79 +52,74 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { storeToRefs } from 'pinia';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import { getCurrentWindow } from '@electron/remote'; import { getCurrentWindow } from '@electron/remote';
import { useConnectionsStore } from '@/stores/connections'; import { useConnectionsStore } from '@/stores/connections';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import { storeToRefs } from 'pinia'; import { onUnmounted, ref } from 'vue';
import { computed } from '@vue/reactivity';
import { useI18n } from 'vue-i18n';
export default { const { t } = useI18n();
name: 'TheTitleBar',
setup () {
const { getConnectionName } = useConnectionsStore();
const workspacesStore = useWorkspacesStore();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); const { getConnectionName } = useConnectionsStore();
const workspacesStore = useWorkspacesStore();
const { getWorkspace } = workspacesStore; const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
return { const { getWorkspace } = workspacesStore;
getConnectionName,
selectedWorkspace,
getWorkspace
};
},
data () {
return {
w: getCurrentWindow(),
isMaximized: getCurrentWindow().isMaximized(),
isDevelopment: process.env.NODE_ENV === 'development',
isMacOS: process.platform === 'darwin'
};
},
computed: {
windowTitle () {
if (!this.selectedWorkspace) return '';
if (this.selectedWorkspace === 'NEW') return this.$t('message.createNewConnection');
const connectionName = this.getConnectionName(this.selectedWorkspace); const appIcon = require('@/images/logo.svg');
const workspace = this.getWorkspace(this.selectedWorkspace); const w = ref(getCurrentWindow());
const breadcrumbs = Object.values(workspace.breadcrumbs).filter(breadcrumb => breadcrumb) || [workspace.client]; const isMaximized = ref(getCurrentWindow().isMaximized());
const isDevelopment = ref(process.env.NODE_ENV === 'development');
const isMacOS = ref(process.platform === 'darwin');
return [connectionName, ...breadcrumbs].join(' • '); const windowTitle = computed(() => {
} if (!selectedWorkspace.value) return '';
}, if (selectedWorkspace.value === 'NEW') return t('message.createNewConnection');
created () {
window.addEventListener('resize', this.onResize); const connectionName = getConnectionName(selectedWorkspace.value);
}, const workspace = getWorkspace(selectedWorkspace.value);
unmounted () { const breadcrumbs = Object.values(workspace.breadcrumbs).filter(breadcrumb => breadcrumb) || [workspace.client];
window.removeEventListener('resize', this.onResize);
}, return [connectionName, ...breadcrumbs].join(' • ');
methods: { });
closeApp () {
ipcRenderer.send('close-app'); const closeApp = () => {
}, ipcRenderer.send('close-app');
minimizeApp () {
this.w.minimize();
},
toggleFullScreen () {
if (this.isMaximized)
this.w.unmaximize();
else
this.w.maximize();
},
openDevTools () {
this.w.openDevTools();
},
reload () {
this.w.reload();
},
onResize () {
this.isMaximized = this.w.isMaximized();
}
}
}; };
const minimizeApp = () => {
w.value.minimize();
};
const toggleFullScreen = () => {
if (isMaximized.value)
w.value.unmaximize();
else
w.value.maximize();
};
const openDevTools = () => {
w.value.webContents.openDevTools();
};
const reload = () => {
w.value.reload();
};
const onResize = () => {
isMaximized.value = w.value.isMaximized();
};
window.addEventListener('resize', onResize);
onUnmounted(() => {
window.removeEventListener('resize', onResize);
});
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -1,4 +1,8 @@
const arrayToFile = args => { export const arrayToFile = (args: {
type: 'csv' | 'json';
content: object[];
filename: string;
}) => {
let mime; let mime;
let content; let content;
@ -33,5 +37,3 @@ const arrayToFile = args => {
downloadLink.click(); downloadLink.click();
downloadLink.remove(); downloadLink.remove();
}; };
export default arrayToFile;

View File

@ -1,16 +1,17 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { toRaw } from 'vue'; import { toRaw } from 'vue';
/** /**
* @param {*} val * @param {*} val
* @param {Boolean} json converts the value in JSON object (default true) * @param {Boolean} json converts the value in JSON object (default true)
*/ */
export function unproxify (val, json = true) { export function unproxify (val: any, json = true): any {
if (json)// JSON conversion if (json)// JSON conversion
return JSON.parse(JSON.stringify(val)); return JSON.parse(JSON.stringify(val));
else if (Array.isArray(val))// If array else if (Array.isArray(val))// If array
return toRaw(val); return toRaw(val);
else if (typeof val === 'object') { // If object else if (typeof val === 'object') { // If object
const result = {}; const result: any = {};
for (const key in val) for (const key in val)
result[key] = toRaw(val[key]); result[key] = toRaw(val[key]);