diff --git a/package.json b/package.json index 85350e51..29fa205c 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "figue": "^1.2.0", "fuse.js": "^6.6.2", "highlight.js": "^11.7.0", + "iarna-toml-esm": "^3.0.5", "json5": "^2.2.3", "jwt-decode": "^3.1.2", "libphonenumber-js": "^1.10.28", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2bd9f52c..7cf4914b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ dependencies: highlight.js: specifier: ^11.7.0 version: 11.7.0 + iarna-toml-esm: + specifier: ^3.0.5 + version: 3.0.5 json5: specifier: ^2.2.3 version: 2.2.3 @@ -4759,6 +4762,10 @@ packages: /electron-to-chromium@1.4.433: resolution: {integrity: sha512-MGO1k0w1RgrfdbLVwmXcDhHHuxCn2qRgR7dYsJvWFKDttvYPx6FNzCGG0c/fBBvzK2LDh3UV7Tt9awnHnvAAUQ==} + /emitter-component@1.1.1: + resolution: {integrity: sha512-G+mpdiAySMuB7kesVRLuyvYRqDmshB7ReKEVuyBPkzQlmiDiLrt7hHHIy4Aff552bgknVN7B2/d3lzhGO5dvpQ==} + dev: false + /emmet@2.4.2: resolution: {integrity: sha512-YgmsMkhUgzhJMgH5noGudfxqrQn1bapvF0y7C1e7A0jWFImsRrrvVslzyZz0919NED/cjFOpVWx7c973V+2S/w==} dependencies: @@ -6059,6 +6066,12 @@ packages: ms: 2.1.3 dev: false + /iarna-toml-esm@3.0.5: + resolution: {integrity: sha512-CgeDbPohnFG827UoRaCqKxJ8idiIDZDWlcHf5hUReQnZ8jHnNnhN4QJFiY12fKvr0LvuDuKAimqQfrmQnacbtw==} + dependencies: + stream: 0.0.2 + dev: false + /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -8197,6 +8210,12 @@ packages: duplexer: 0.1.2 dev: true + /stream@0.0.2: + resolution: {integrity: sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g==} + dependencies: + emitter-component: 1.1.1 + dev: false + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -9414,7 +9433,6 @@ packages: /workbox-cacheable-response@6.6.0: resolution: {integrity: sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==} - deprecated: workbox-background-sync@6.6.0 dependencies: workbox-core: 6.6.0 dev: true diff --git a/src/shims.d.ts b/src/shims.d.ts index fc76e210..f3db1b7e 100644 --- a/src/shims.d.ts +++ b/src/shims.d.ts @@ -14,3 +14,8 @@ declare module '~icons/*' { const component: FunctionalComponent; export default component; } + +declare module 'iarna-toml-esm' { + export const parse: (toml: string) => any; + export const stringify: (obj: any) => string; +} \ No newline at end of file diff --git a/src/tools/index.ts b/src/tools/index.ts index 4c3caa62..22b3b53a 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,6 +1,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 tomlToJson } from './toml-to-json'; import { tool as jsonToCsv } from './json-to-csv'; import { tool as cameraRecorder } from './camera-recorder'; import { tool as listConverter } from './list-converter'; @@ -80,6 +81,7 @@ export const toolsByCategory: ToolCategory[] = [ yamlToJson, jsonToYaml, listConverter, + tomlToJson, ], }, { diff --git a/src/tools/toml-to-json/index.ts b/src/tools/toml-to-json/index.ts new file mode 100644 index 00000000..653b432f --- /dev/null +++ b/src/tools/toml-to-json/index.ts @@ -0,0 +1,13 @@ +import { defineTool } from '../tool'; + +import BracketIcon from '~icons/mdi/code-brackets'; + +export const tool = defineTool({ + name: 'TOML to JSON', + path: '/toml-to-json', + description: 'Parse and convert TOML to JSON.', + keywords: ['toml', 'json', 'convert', 'online', 'transform', 'parser'], + component: () => import('./toml-to-json.vue'), + icon: BracketIcon, + createdAt: new Date('2023-06-23'), +}); diff --git a/src/tools/toml-to-json/toml-to-json.e2e.spec.ts b/src/tools/toml-to-json/toml-to-json.e2e.spec.ts new file mode 100644 index 00000000..5925c188 --- /dev/null +++ b/src/tools/toml-to-json/toml-to-json.e2e.spec.ts @@ -0,0 +1,40 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Tool - TOML to JSON', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/toml-to-json'); + }); + + test('Has correct title', async ({ page }) => { + await expect(page).toHaveTitle('TOML to JSON - IT Tools'); + }); + + test('TOML is parsed and outputs clean JSON', async ({ page }) => { + await page.getByTestId('input').fill(` +foo = "bar" + +# This is a comment + +[list] + name = "item" +[list.another] + key = "value" + `.trim()); + + const generatedJson = await page.getByTestId('area-content').innerText(); + + expect(generatedJson.trim()).toEqual( + ` +{ + "foo": "bar", + "list": { + "name": "item", + "another": { + "key": "value" + } + } +} + `.trim(), + ); + }); +}); diff --git a/src/tools/toml-to-json/toml-to-json.vue b/src/tools/toml-to-json/toml-to-json.vue new file mode 100644 index 00000000..8c6dbfe2 --- /dev/null +++ b/src/tools/toml-to-json/toml-to-json.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/tools/toml-to-json/toml.services.ts b/src/tools/toml-to-json/toml.services.ts new file mode 100644 index 00000000..476fda74 --- /dev/null +++ b/src/tools/toml-to-json/toml.services.ts @@ -0,0 +1,8 @@ +import { parse as parseToml } from 'iarna-toml-esm'; +import { isNotThrowing } from '../../utils/boolean'; + +export { isValidToml }; + +function isValidToml(toml: string): boolean { + return isNotThrowing(() => parseToml(toml)); +}