This commit is contained in:
sharevb 2024-05-13 17:07:03 +08:00 committed by GitHub
commit 55234c118b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 278 additions and 11 deletions

10
components.d.ts vendored
View file

@ -50,6 +50,7 @@ declare module '@vue/runtime-core' {
'CModal.demo': typeof import('./src/ui/c-modal/c-modal.demo.vue')['default']
CModalValue: typeof import('./src/ui/c-modal-value/c-modal-value.vue')['default']
'CModalValue.demo': typeof import('./src/ui/c-modal-value/c-modal-value.demo.vue')['default']
CMonacoEditor: typeof import('./src/ui/c-monaco-editor/c-monaco-editor.vue')['default']
CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']
ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
@ -107,6 +108,7 @@ declare module '@vue/runtime-core' {
Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']
Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']
JsonLinter: typeof import('./src/tools/json-linter/json-linter.vue')['default']
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default']
JsonToToml: typeof import('./src/tools/json-to-toml/json-to-toml.vue')['default']
@ -126,25 +128,23 @@ declare module '@vue/runtime-core' {
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
NA: typeof import('naive-ui')['NA']
NAlert: typeof import('naive-ui')['NAlert']
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
NCode: typeof import('naive-ui')['NCode']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDivider: typeof import('naive-ui')['NDivider']
NEllipsis: typeof import('naive-ui')['NEllipsis']
NFormItem: typeof import('naive-ui')['NFormItem']
NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid']
NH1: typeof import('naive-ui')['NH1']
NH3: typeof import('naive-ui')['NH3']
NIcon: typeof import('naive-ui')['NIcon']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NLabel: typeof import('naive-ui')['NLabel']
NLayout: typeof import('naive-ui')['NLayout']
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NMenu: typeof import('naive-ui')['NMenu']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSpin: typeof import('naive-ui')['NSpin']
NSwitch: typeof import('naive-ui')['NSwitch']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']

View file

@ -35,6 +35,7 @@
"release": "node ./scripts/release.mjs"
},
"dependencies": {
"@guolao/vue-monaco-editor": "^1.4.1",
"@it-tools/bip39": "^0.0.4",
"@it-tools/oggen": "^1.3.0",
"@sindresorhus/slugify": "^2.2.1",
@ -65,6 +66,7 @@
"iarna-toml-esm": "^3.0.5",
"ibantools": "^4.3.3",
"json5": "^2.2.3",
"jsonlint-mod": "^1.7.6",
"jwt-decode": "^3.1.2",
"libphonenumber-js": "^1.10.28",
"lodash": "^4.17.21",

66
pnpm-lock.yaml generated
View file

@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false
dependencies:
'@guolao/vue-monaco-editor':
specifier: ^1.4.1
version: 1.5.1(monaco-editor@0.43.0)(vue@3.3.4)
'@it-tools/bip39':
specifier: ^0.0.4
version: 0.0.4
@ -95,6 +98,9 @@ dependencies:
json5:
specifier: ^2.2.3
version: 2.2.3
jsonlint-mod:
specifier: ^1.7.6
version: 1.7.6
jwt-decode:
specifier: ^3.1.2
version: 3.1.2
@ -2150,6 +2156,22 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@guolao/vue-monaco-editor@1.5.1(monaco-editor@0.43.0)(vue@3.3.4):
resolution: {integrity: sha512-nhbQHDAwsxrdH/yitcrBgAkN8Cae0IEiYe/M3LWK8bSJRfapkbMyfTHE6Gcxsxa/6efSUZAPDo8dJWBDx5GZyA==}
peerDependencies:
'@vue/composition-api': ^1.7.1
monaco-editor: '>=0.43.0'
vue: ^2.6.14 || >=3.0.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
'@monaco-editor/loader': 1.4.0(monaco-editor@0.43.0)
monaco-editor: 0.43.0
vue: 3.3.4
vue-demi: 0.14.7(vue@3.3.4)
dev: false
/@humanwhocodes/config-array@0.11.10:
resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
engines: {node: '>=10.10.0'}
@ -2417,6 +2439,15 @@ packages:
resolution: {integrity: sha512-mrC4y8n88BYvgcgzq9bvTlDgFyi2zuvzmPilRvRc3Uz1iIvq8mDhxJ0rHKFUNzPEScpDvJdIujqiDrulMqiudA==}
dev: true
/@monaco-editor/loader@1.4.0(monaco-editor@0.43.0):
resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==}
peerDependencies:
monaco-editor: '>= 0.21.0 < 1'
dependencies:
monaco-editor: 0.43.0
state-local: 1.0.7
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -3351,7 +3382,7 @@ packages:
dependencies:
'@unhead/dom': 0.5.1
'@unhead/schema': 0.5.1
'@vueuse/shared': 10.7.2(vue@3.3.4)
'@vueuse/shared': 10.9.0(vue@3.3.4)
unhead: 0.5.1
vue: 3.3.4
transitivePeerDependencies:
@ -3993,10 +4024,10 @@ packages:
- vue
dev: false
/@vueuse/shared@10.7.2(vue@3.3.4):
resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==}
/@vueuse/shared@10.9.0(vue@3.3.4):
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
dependencies:
vue-demi: 0.14.6(vue@3.3.4)
vue-demi: 0.14.7(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
@ -4006,6 +4037,10 @@ packages:
resolution: {integrity: sha512-P1A1vRGFBhITco8Iw4/hvnDYoE/SoVrd71dW1pBFdXJb3vP+pBtoOuhbEKy0ROJGOyzQuqvFibcwzyLlWMqNiQ==}
dev: false
/JSV@4.0.2:
resolution: {integrity: sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==}
dev: false
/abab@2.0.6:
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
dev: true
@ -6606,6 +6641,16 @@ packages:
graceful-fs: 4.2.11
dev: true
/jsonlint-mod@1.7.6:
resolution: {integrity: sha512-oGuk6E1ehmIpw0w9ttgb2KsDQQgGXBzZczREW8OfxEm9eCQYL9/LCexSnh++0z3AiYGcXpBgqDSx9AAgzl/Bvg==}
engines: {node: '>= 0.6'}
hasBin: true
dependencies:
JSV: 4.0.2
chalk: 2.4.2
underscore: 1.13.6
dev: false
/jsonpointer@5.0.1:
resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
engines: {node: '>=0.10.0'}
@ -8196,6 +8241,10 @@ packages:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
dev: true
/state-local@1.0.7:
resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
dev: false
/std-env@3.3.3:
resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==}
dev: true
@ -8632,6 +8681,10 @@ packages:
mlly: 1.4.2
dev: true
/underscore@1.13.6:
resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==}
dev: false
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
dev: true
@ -9151,8 +9204,8 @@ packages:
vue: 3.3.4
dev: false
/vue-demi@0.14.6(vue@3.3.4):
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
/vue-demi@0.14.7(vue@3.3.4):
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
@ -9442,6 +9495,7 @@ packages:
/workbox-google-analytics@7.0.0:
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
dependencies:
workbox-background-sync: 7.0.0
workbox-core: 7.0.0

View file

@ -2,6 +2,9 @@ import { createApp } from 'vue';
import { createPinia } from 'pinia';
import { createHead } from '@vueuse/head';
import { install as VueMonacoEditorPlugin, loader } from '@guolao/vue-monaco-editor';
import * as monaco from 'monaco-editor';
import { registerSW } from 'virtual:pwa-register';
import { plausible } from './plugins/plausible.plugin';
@ -13,10 +16,14 @@ import App from './App.vue';
import router from './router';
import { i18nPlugin } from './plugins/i18n.plugin';
// loaded monaco-editor from `node_modules`
loader.config({ monaco });
registerSW();
const app = createApp(App);
app.use(VueMonacoEditorPlugin);
app.use(createPinia());
app.use(createHead());
app.use(i18nPlugin);

View file

@ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer';
import { tool as textToUnicode } from './text-to-unicode';
import { tool as safelinkDecoder } from './safelink-decoder';
import { tool as jsonLinter } from './json-linter';
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
@ -142,6 +143,7 @@ export const toolsByCategory: ToolCategory[] = [
crontabGenerator,
jsonViewer,
jsonMinify,
jsonLinter,
jsonToCsv,
sqlPrettify,
chmodCalculator,

View file

@ -0,0 +1,12 @@
import { Braces } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'JSON Linter',
path: '/json-linter',
description: 'Check and lint JSON content',
keywords: ['json', 'linter', 'check'],
component: () => import('./json-linter.vue'),
icon: Braces,
createdAt: new Date('2024-03-20'),
});

View file

@ -0,0 +1,55 @@
<script setup lang="ts">
import linter from 'jsonlint-mod';
const jsonContent = ref(
`{
a: True;
b=5
}`,
);
const conversionError = computed(() => {
try {
linter.parse(jsonContent.value);
return null;
}
catch (e: any) {
return e.toString();
}
});
const MONACO_EDITOR_OPTIONS = {
automaticLayout: true,
formatOnType: true,
formatOnPaste: true,
};
</script>
<template>
<div>
<c-label label="Paste your JSON file content:">
<div relative w-full>
<c-monaco-editor
v-model:value="jsonContent"
theme="vs-dark"
language="yaml"
height="250px"
:options="MONACO_EDITOR_OPTIONS"
/>
</div>
</c-label>
<div v-if="conversionError">
<n-alert title="The following errors occured" type="error" mt-5>
<pre>
{{ conversionError }}
</pre>
</n-alert>
</div>
<div v-else>
<n-alert type="success" mt-5>
Validation successful!
</n-alert>
</div>
</div>
</template>

11
src/tools/json-linter/jsonlint-mod.d.ts vendored Normal file
View file

@ -0,0 +1,11 @@
declare module 'jsonlint-mod'{
/**
* Parse a JSON string to Typescript Object. If there is an error will print it
* as human readible.
*
* Please use `import * as jsonlint from 'jsonlint';`. Instead of,
* `import {parse} from 'jsonlint';`. Otherwise, it cannot reference to the
* correct instance.
*/
export function parse(str: string): Record<string, unknown>;
}

View file

@ -0,0 +1,124 @@
<script setup lang="ts">
import * as monacoEditor from 'monaco-editor';
import type { MonacoEditor } from '@guolao/vue-monaco-editor';
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
import { useStyleStore } from '@/stores/style.store';
const props = withDefaults(defineProps<EditorProps>(), {
theme: 'vs',
options: () => ({}),
overrideServices: () => ({}),
saveViewState: true,
width: '100%',
height: '100%',
});
const emits = defineEmits<{
(e: 'update:value', value: string | undefined): void
(e: 'beforeMount', monaco: MonacoEditor): void
(e: 'mount', editor: monacoEditor.editor.IStandaloneCodeEditor, monaco: MonacoEditor): void
(e: 'change', value: string | undefined, event: monacoEditor.editor.IModelContentChangedEvent): void
(e: 'validate', markers: monacoEditor.editor.IMarker[]): void
}>();
interface MonacoEnvironment {
getWorker(_: any, label: string): Worker
}
// eslint-disable-next-line @typescript-eslint/no-namespace
declare module globalThis {
let MonacoEnvironment: MonacoEnvironment;
}
const value = useVModel(props, 'value', emits);
globalThis.MonacoEnvironment = {
getWorker(_: any, label: string) {
if (label === 'json') {
return new JsonWorker();
}
if (label === 'css' || label === 'scss' || label === 'less') {
return new CssWorker();
}
if (label === 'html' || label === 'handlebars' || label === 'razor') {
return new HtmlWorker();
}
if (label === 'typescript' || label === 'javascript') {
return new TsWorker();
}
return new EditorWorker();
},
};
export interface EditorProps {
defaultValue?: string
defaultPath?: string
defaultLanguage?: string
value?: string
language?: string
path?: string
/* === */
theme: 'vs' | string
line?: number
options?: monacoEditor.editor.IStandaloneEditorConstructionOptions
overrideServices?: monacoEditor.editor.IEditorOverrideServices
saveViewState?: boolean
/* === */
width?: number | string
height?: number | string
className?: string
}
monacoEditor.editor.defineTheme('it-tools-dark', {
base: 'vs-dark',
inherit: true,
rules: [],
colors: {
'editor.background': '#00000000',
},
});
monacoEditor.editor.defineTheme('it-tools-light', {
base: 'vs',
inherit: true,
rules: [],
colors: {
'editor.background': '#00000000',
},
});
const styleStore = useStyleStore();
watch(
() => styleStore.isDarkTheme,
isDarkTheme => monacoEditor.editor.setTheme(isDarkTheme ? 'it-tools-dark' : 'it-tools-light'),
{ immediate: true },
);
const attrs = useAttrs();
const inheritedAttrs = { ...attrs, ...props };
</script>
<script lang="ts">
export default {
inheritAttrs: false,
};
</script>
<template>
<vue-monaco-editor
v-bind="inheritedAttrs"
v-model:value="value"
@before-mount="(monaco: MonacoEditor) => emits('beforeMount', monaco)"
@mount="(editor: monacoEditor.editor.IStandaloneCodeEditor, monaco: MonacoEditor) => emits('mount', editor, monaco)"
@change="(value: string | undefined, event: monacoEditor.editor.IModelContentChangedEvent) => emits('change', value, event)"
@validate="(markers: monacoEditor.editor.IMarker[]) => emits('validate', markers)"
/>
</template>