diff --git a/components.d.ts b/components.d.ts index f2c3146f..4f89a5b3 100644 --- a/components.d.ts +++ b/components.d.ts @@ -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'] diff --git a/package.json b/package.json index b8b1eeee..455fd6ad 100644 --- a/package.json +++ b/package.json @@ -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", @@ -51,6 +52,7 @@ "change-case": "^4.1.2", "colord": "^2.9.3", "composerize-ts": "^0.6.2", + "composeverter": "^1.7.2", "country-code-lookup": "^0.1.0", "cron-validator": "^1.3.1", "cronstrue": "^2.26.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd6c38c9..b0bf9bb3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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 @@ -53,6 +56,9 @@ dependencies: composerize-ts: specifier: ^0.6.2 version: 0.6.2 + composeverter: + specifier: ^1.7.2 + version: 1.7.2 country-code-lookup: specifier: ^0.1.0 version: 0.1.0 @@ -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 @@ -4051,6 +4082,14 @@ packages: - supports-color dev: true + /ajv-errors@3.0.0(ajv@8.12.0): + resolution: {integrity: sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==} + peerDependencies: + ajv: ^8.0.1 + dependencies: + ajv: 8.12.0 + dev: false + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -4067,7 +4106,6 @@ packages: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - dev: true /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} @@ -4560,6 +4598,15 @@ packages: yamljs: 0.3.0 dev: false + /composeverter@1.7.2: + resolution: {integrity: sha512-gRSCkSU8wJQvmTHQ23wBd2gCdUsns95k3lL7YszZBu5EyA3eac46mI7nVgvk1pZTM0mOmj/E5yurtdYkuVNZRA==} + dependencies: + ajv: 8.12.0 + ajv-errors: 3.0.0(ajv@8.12.0) + core-js: 2.6.12 + yaml: 1.10.2 + dev: false + /concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} @@ -4613,6 +4660,12 @@ packages: browserslist: 4.22.1 dev: true + /core-js@2.6.12: + resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} + deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. + requiresBuild: true + dev: false + /country-code-lookup@0.1.0: resolution: {integrity: sha512-IOI66HEG+8bXfWPy+sTzuN7161vmDZOHg1wgIPFf3WfD73FeLajnn6C+fnxOIa9RL1WRBDMXQQWW/FOaOYaQ3w==} dev: false @@ -6571,7 +6624,6 @@ packages: /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true /json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -7666,7 +7718,6 @@ packages: /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} - dev: true /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -7814,7 +7865,6 @@ packages: /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - dev: true /require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} @@ -8196,6 +8246,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 @@ -8913,7 +8967,6 @@ packages: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 - dev: true /url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} @@ -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 @@ -9579,6 +9632,11 @@ packages: yaml: 2.2.1 dev: true + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: false + /yaml@2.2.1: resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} engines: {node: '>= 14'} diff --git a/src/main.ts b/src/main.ts index 36ba3b7f..cdd79132 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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); diff --git a/src/tools/docker-compose-validator/composeverter.d.ts b/src/tools/docker-compose-validator/composeverter.d.ts new file mode 100644 index 00000000..e2f06ab5 --- /dev/null +++ b/src/tools/docker-compose-validator/composeverter.d.ts @@ -0,0 +1,19 @@ +declare module 'composeverter' { + interface Configuration { + expandVolumes?: boolean; + expandPorts?: boolean; + indent?: number; + } + interface DockerComposeValidatioError { + line?: number; + message: string; + helpLink?: string; + } + export function validateDockerComposeToCommonSpec(content: string): DockerComposeValidatioError[]; + export function migrateFromV2xToV3x(content: string, configuration?: Configuration = null): string; + export function migrateFromV3xToV2x(content: string, configuration?: Configuration = null): string; + export function migrateFromV1ToV2x(content: string, configuration?: Configuration = null): string; + export function migrateToCommonSpec(content: string, configuration?: Configuration = null): string; + export function migrateFromV2xToV3x(content: string, configuration?: Configuration = null): string; + export function getDockerComposeSchemaWithoutFormats(): object; + } \ No newline at end of file diff --git a/src/tools/docker-compose-validator/docker-compose-validator.vue b/src/tools/docker-compose-validator/docker-compose-validator.vue new file mode 100644 index 00000000..ba02ecb4 --- /dev/null +++ b/src/tools/docker-compose-validator/docker-compose-validator.vue @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + {{ message.message }} ( + See Docker Compose help + ) + + + + + + + Validation successful! + + + + diff --git a/src/tools/docker-compose-validator/index.ts b/src/tools/docker-compose-validator/index.ts new file mode 100644 index 00000000..60e0a88d --- /dev/null +++ b/src/tools/docker-compose-validator/index.ts @@ -0,0 +1,12 @@ +import { BrandDocker } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Docker Compose Validator', + path: '/docker-compose-validator', + description: 'Validate Docker Compose files against CommonSpec schema', + keywords: ['docker', 'compose', 'validator', 'commonspec'], + component: () => import('./docker-compose-validator.vue'), + icon: BrandDocker, + createdAt: new Date('2024-01-25'), +}); diff --git a/src/tools/index.ts b/src/tools/index.ts index aa861c93..a6d82892 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -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 dockerComposeValidator } from './docker-compose-validator'; import { tool as pdfSignatureChecker } from './pdf-signature-checker'; import { tool as numeronymGenerator } from './numeronym-generator'; import { tool as macAddressGenerator } from './mac-address-generator'; @@ -146,6 +147,7 @@ export const toolsByCategory: ToolCategory[] = [ sqlPrettify, chmodCalculator, dockerRunToDockerComposeConverter, + dockerComposeValidator, xmlFormatter, yamlViewer, ], diff --git a/src/ui/c-monaco-editor/c-monaco-editor.vue b/src/ui/c-monaco-editor/c-monaco-editor.vue new file mode 100644 index 00000000..e3b53437 --- /dev/null +++ b/src/ui/c-monaco-editor/c-monaco-editor.vue @@ -0,0 +1,124 @@ + + + + + + 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)" + /> +