mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-14 01:46:52 -04:00
parent
318fb6efb9
commit
3aa887ce54
9 changed files with 321 additions and 9 deletions
|
@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter';
|
|||
import { tool as base64StringConverter } from './base64-string-converter';
|
||||
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
||||
import { tool as emailNormalizer } from './email-normalizer';
|
||||
import { tool as jsonSizeAnalyzer } from './json-size-analyzer';
|
||||
|
||||
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
||||
|
||||
|
@ -147,6 +148,7 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
crontabGenerator,
|
||||
jsonViewer,
|
||||
jsonMinify,
|
||||
jsonSizeAnalyzer,
|
||||
jsonToCsv,
|
||||
sqlPrettify,
|
||||
chmodCalculator,
|
||||
|
|
12
src/tools/json-size-analyzer/index.ts
Normal file
12
src/tools/json-size-analyzer/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { FileAnalytics } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Json Size Analyzer',
|
||||
path: '/json-size-analyzer',
|
||||
description: 'Measure JSON nodes relative weights',
|
||||
keywords: ['json', 'size', 'analyzer'],
|
||||
component: () => import('./json-size-analyzer.vue'),
|
||||
icon: FileAnalytics,
|
||||
createdAt: new Date('2024-07-14'),
|
||||
});
|
13
src/tools/json-size-analyzer/json-analyzer.d.ts
vendored
Normal file
13
src/tools/json-size-analyzer/json-analyzer.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
declare module 'json-analyzer' {
|
||||
export default function analyze({
|
||||
json,
|
||||
verbose,
|
||||
maxDepth,
|
||||
target,
|
||||
}: {
|
||||
json: any,
|
||||
verbose: boolean,
|
||||
maxDepth: number,
|
||||
target: string,
|
||||
});
|
||||
}
|
113
src/tools/json-size-analyzer/json-size-analyzer.service.test.ts
Normal file
113
src/tools/json-size-analyzer/json-size-analyzer.service.test.ts
Normal file
|
@ -0,0 +1,113 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { getJsonUsageTreeNodes } from './json-size-analyzer.service';
|
||||
|
||||
describe('json-size-analyzer', () => {
|
||||
describe('getJsonUsageTreeNodes', () => {
|
||||
it('return correct tree nodes structures', () => {
|
||||
expect(getJsonUsageTreeNodes([{ a: [1, 2, 3] }, { b: 'a' }])).to.deep.eq({
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
key: '$.[0].a.[0]',
|
||||
label: '$.[0].a.[0]: 1 B(26 B gzip)',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
key: '$.[0].a.[1]',
|
||||
label: '$.[0].a.[1]: 1 B(24 B gzip)',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
key: '$.[0].a.[2]',
|
||||
label: '$.[0].a.[2]: 1 B(25 B gzip)',
|
||||
},
|
||||
],
|
||||
key: '$.[0].a',
|
||||
label: '$.[0].a: 7 B(35 B gzip) ; 28.000% of parent ; biggest child node: \'0\'',
|
||||
},
|
||||
],
|
||||
key: '$.[0]',
|
||||
label: '$.[0]: 13 B(43 B gzip) ; 52.000% of parent ; biggest child node: \'a\'',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
key: '$.[1].b',
|
||||
label: '$.[1].b: 1 B(25 B gzip)',
|
||||
},
|
||||
],
|
||||
key: '$.[1]',
|
||||
label: '$.[1]: 9 B(34 B gzip) ; 36.000% of parent ; biggest child node: \'b\'',
|
||||
},
|
||||
],
|
||||
key: '$',
|
||||
label: '$: 25 B(61 B gzip) ; 100.00% of parent ; biggest child node: \'0\'',
|
||||
});
|
||||
expect(getJsonUsageTreeNodes({ a: { b: [1, 2, 3], c: 12 } })).to.deep.eq({
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
key: '$.a.b.[0]',
|
||||
label: '$.a.b.[0]: 1 B(26 B gzip)',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
key: '$.a.b.[1]',
|
||||
label: '$.a.b.[1]: 1 B(24 B gzip)',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
key: '$.a.b.[2]',
|
||||
label: '$.a.b.[2]: 1 B(25 B gzip)',
|
||||
},
|
||||
],
|
||||
key: '$.a.b',
|
||||
label: '$.a.b: 7 B(35 B gzip) ; 26.923% of parent ; biggest child node: \'0\'',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
key: '$.a.c',
|
||||
label: '$.a.c: 2 B(24 B gzip)',
|
||||
},
|
||||
],
|
||||
key: '$.a',
|
||||
label: '$.a: 20 B(50 B gzip) ; 76.923% of parent ; biggest child node: \'b\'',
|
||||
},
|
||||
],
|
||||
key: '$',
|
||||
label: '$: 26 B(63 B gzip) ; 100.00% of parent ; biggest child node: \'a\'',
|
||||
});
|
||||
expect(getJsonUsageTreeNodes({ a: { b: 'azerty', c: 'ueop' } })).to.deep.eq({
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
key: '$.a.b',
|
||||
label: '$.a.b: 6 B(30 B gzip)',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
key: '$.a.c',
|
||||
label: '$.a.c: 4 B(29 B gzip)',
|
||||
},
|
||||
],
|
||||
key: '$.a',
|
||||
label: '$.a: 25 B(51 B gzip) ; 80.645% of parent ; biggest child node: \'b\'',
|
||||
},
|
||||
],
|
||||
key: '$',
|
||||
label: '$: 31 B(61 B gzip) ; 100.00% of parent ; biggest child node: \'a\'',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
51
src/tools/json-size-analyzer/json-size-analyzer.service.ts
Normal file
51
src/tools/json-size-analyzer/json-size-analyzer.service.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import jsonAnalyzer from 'json-analyzer';
|
||||
|
||||
export interface Meta {
|
||||
__meta__: {
|
||||
size?: {
|
||||
value: number
|
||||
raw: string
|
||||
gzip: string
|
||||
}
|
||||
number_of_childs?: number
|
||||
parent_relative_percentage?: string
|
||||
biggest_node_child: string
|
||||
}
|
||||
}
|
||||
export type AnalysisNode = {
|
||||
[key: string]: object & Meta
|
||||
} & Meta;
|
||||
|
||||
export type TreeNode = {
|
||||
key: string
|
||||
label: string
|
||||
children: Array<TreeNode>
|
||||
} & Record<string, unknown>;
|
||||
|
||||
function getTreeNodes(obj: AnalysisNode, parentName: string): TreeNode {
|
||||
const childNodes = Object.entries(obj)
|
||||
.filter(([key, v]) => key !== '__meta__' && typeof v === 'object')
|
||||
.map(([k, v]) => ({
|
||||
key: (Number.isNaN(Number.parseInt(k, 10)) ? `.${k}` : `.[${k}]`),
|
||||
value: v as AnalysisNode,
|
||||
}));
|
||||
const biggest_child_node = obj.__meta__.biggest_node_child ? ` ; biggest child node: '${obj.__meta__.biggest_node_child}'` : '';
|
||||
const parent_relative_percentage = obj.__meta__.parent_relative_percentage ? ` ; ${obj.__meta__.parent_relative_percentage} of parent` : '';
|
||||
return {
|
||||
key: parentName,
|
||||
label: obj.__meta__
|
||||
? `${parentName}: ${obj.__meta__.size?.raw}(${obj.__meta__.size?.gzip} gzip)${parent_relative_percentage}${biggest_child_node}`
|
||||
: parentName,
|
||||
children: childNodes.map(childNode => getTreeNodes(childNode.value, parentName + childNode.key)),
|
||||
};
|
||||
}
|
||||
|
||||
export function getJsonUsageTreeNodes(jsonObj: any, maxDepth: number = 100, targetNode: string = ''): TreeNode {
|
||||
const analysis = jsonAnalyzer({
|
||||
json: jsonObj,
|
||||
verbose: true,
|
||||
maxDepth,
|
||||
target: targetNode,
|
||||
});
|
||||
return getTreeNodes(analysis, '$');
|
||||
}
|
68
src/tools/json-size-analyzer/json-size-analyzer.vue
Normal file
68
src/tools/json-size-analyzer/json-size-analyzer.vue
Normal file
|
@ -0,0 +1,68 @@
|
|||
<script setup lang="ts">
|
||||
import JSON5 from 'json5';
|
||||
import { getJsonUsageTreeNodes } from './json-size-analyzer.service';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
|
||||
const json = ref('{"a": 1, "b": [1,2,3]}');
|
||||
const maxDepth = ref(100);
|
||||
const target = ref('');
|
||||
|
||||
const jsonSizes = computed(() => {
|
||||
const jsonObj = JSON5.parse(json.value);
|
||||
if (!jsonObj) {
|
||||
return null;
|
||||
}
|
||||
return [getJsonUsageTreeNodes(jsonObj, maxDepth.value - 1, target.value)];
|
||||
});
|
||||
const searchInAnalysis = ref('');
|
||||
|
||||
const jsonValidation = useValidation({
|
||||
source: json,
|
||||
rules: [
|
||||
{
|
||||
validator: (v) => {
|
||||
return JSON5.parse(v);
|
||||
},
|
||||
message: 'Provided JSON is not valid.',
|
||||
},
|
||||
],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="max-width: 600px;">
|
||||
<c-card title="Input" mb-2>
|
||||
<c-input-text
|
||||
v-model:value="json"
|
||||
label="JSON"
|
||||
multiline
|
||||
placeholder="Put your JSON data here..."
|
||||
rows="5"
|
||||
:validation="jsonValidation"
|
||||
mb-2
|
||||
/>
|
||||
|
||||
<n-form-item label="Max Depth:" label-placement="left">
|
||||
<n-input-number v-model:value="maxDepth" :min="0" w-full />
|
||||
</n-form-item>
|
||||
|
||||
<c-input-text
|
||||
v-model:value="target"
|
||||
label="Target Node"
|
||||
placeholder="Where to start the analyze (ie, a[0].b.c)"
|
||||
mb-2
|
||||
/>
|
||||
</c-card>
|
||||
|
||||
<c-card v-if="jsonSizes" title="Analysis">
|
||||
<n-input v-model:value="searchInAnalysis" placeholder="Search in result" />
|
||||
<n-tree
|
||||
:show-irrelevant-nodes="false"
|
||||
:pattern="searchInAnalysis"
|
||||
:default-expand-all="true"
|
||||
:data="jsonSizes"
|
||||
block-line
|
||||
/>
|
||||
</c-card>
|
||||
</div>
|
||||
</template>
|
Loading…
Add table
Add a link
Reference in a new issue