├── .editorconfig ├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc ├── .npmrc ├── .nvmrc ├── .release-it.json ├── .vscode-test.mjs ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets ├── .gitkeep └── logo.svg ├── biome.json ├── commitlint.config.js ├── icon.png ├── images ├── json-flow-1.gif ├── json-flow-2.gif └── json-flow.png ├── index.html ├── l10n ├── bundle.l10n.de.json ├── bundle.l10n.es.json ├── bundle.l10n.fr.json ├── bundle.l10n.it.json └── bundle.l10n.pt-br.json ├── package-lock.json ├── package.json ├── package.nls.de.json ├── package.nls.es.json ├── package.nls.fr.json ├── package.nls.it.json ├── package.nls.json ├── package.nls.pt-br.json ├── postcss.config.js ├── schemas └── config.schema.json ├── src ├── app │ ├── configs │ │ ├── .gitkeep │ │ ├── constants.config.ts │ │ ├── extension.config.ts │ │ └── index.ts │ ├── controllers │ │ ├── .gitkeep │ │ ├── feedback.controller.ts │ │ ├── files.controller.ts │ │ ├── index.ts │ │ ├── json.controller.ts │ │ └── transform.controller.ts │ ├── helpers │ │ ├── .gitkeep │ │ ├── index.ts │ │ ├── json.helper.ts │ │ ├── security.helper.ts │ │ └── tree.helper.ts │ ├── interfaces │ │ ├── index.ts │ │ └── tree.interface.ts │ ├── models │ │ ├── .gitkeep │ │ ├── index.ts │ │ └── node.model.ts │ └── providers │ │ ├── .gitkeep │ │ ├── feedback.provider.ts │ │ ├── files.providers.ts │ │ ├── index.ts │ │ └── json.provider.ts ├── extension.ts └── test │ └── extension.test.ts ├── tailwind.config.js ├── tsconfig.doc.json ├── tsconfig.json ├── tsconfig.node.json ├── tsconfig.web.json ├── vite.config.ts ├── vsc-extension-quickstart.md └── webview ├── App.tsx ├── common.ts ├── components ├── CustomNode.tsx ├── Loading.css ├── Loading.tsx └── layout-elements.ts ├── index.css ├── main.tsx ├── tsconfig.json ├── types └── global.d.ts └── vite-env.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*.ts] 7 | charset = utf-8 8 | end_of_line = lf 9 | indent_size = 2 10 | indent_style = space 11 | quote_type = single 12 | spaces_around_brackets = inside 13 | trim_trailing_whitespace = true 14 | 15 | [*.md] 16 | max_line_length = off 17 | trim_trailing_whitespace = true 18 | 19 | [*.json] 20 | indent_size = 4 21 | indent_style = tab 22 | trim_trailing_whitespace = true 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # prettier v2 dictates LF 2 | # https://prettier.io/docs/en/options.html#end-of-line 3 | * text=auto eol=lf 4 | 5 | .vscode/*.json linguist-language=jsonc 6 | tslint.json linguist-language=jsonc 7 | tsconfig.json linguist-language=jsonc 8 | tsconfig.*.json linguist-language=jsonc 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ManuelGil] 4 | ko_fi: ManuelGil 5 | custom: 6 | ['https://paypal.me/ManuelFGil', 'https://www.buymeacoffee.com/ManuelGil'] 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode-test/ 2 | *.vsix 3 | compodoc/ 4 | dist 5 | node_modules 6 | out 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | lerna-debug.log* 16 | 17 | node_modules 18 | dist 19 | dist-ssr 20 | *.local 21 | 22 | # Editor directories and files 23 | .vscode/* 24 | !.vscode/extensions.json 25 | .idea 26 | .DS_Store 27 | *.suo 28 | *.ntvs* 29 | *.njsproj 30 | *.sln 31 | *.sw? -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit ${1} 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "./**/*.ts": [ 3 | "biome format --write", 4 | "biome lint --write", 5 | "git add ." 6 | ] 7 | } -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v22.10.0 2 | -------------------------------------------------------------------------------- /.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/release-it/schema/release-it.json", 3 | "git": { 4 | "commitMessage": "chore: :bookmark: release ${version}" 5 | }, 6 | "github": { 7 | "release": true 8 | }, 9 | "npm": { 10 | "publish": false 11 | }, 12 | "plugins": { 13 | "@release-it/keep-a-changelog": { 14 | "filename": "CHANGELOG.md" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.vscode-test.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@vscode/test-cli'; 2 | 3 | export default defineConfig({ 4 | files: 'out/test/**/*.test.js', 5 | }); 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "biomejs.biome", 6 | "shardulm94.trailing-spaces", 7 | "editorconfig.editorconfig", 8 | "usernamehw.errorlens", 9 | "kisstkondoros.vscode-gutter-preview" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off", 11 | "[typescript]": { 12 | "editor.defaultFormatter": "biomejs.biome" 13 | }, 14 | "[javascript]": { 15 | "editor.defaultFormatter": "biomejs.biome" 16 | }, 17 | "[typescriptreact]": { 18 | "editor.defaultFormatter": "biomejs.biome" 19 | }, 20 | "[javascriptreact]": { 21 | "editor.defaultFormatter": "biomejs.biome" 22 | }, 23 | "[html]": { 24 | "editor.defaultFormatter": "biomejs.biome" 25 | }, 26 | "[css]": { 27 | "editor.defaultFormatter": "biomejs.biome" 28 | } 29 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .editorconfig 2 | .gitattributes 3 | .gitignore 4 | .husky/** 5 | .lintstagedrc 6 | .vscode-test/** 7 | .vscode/** 8 | .yarnrc 9 | **/.vscode-test.* 10 | **/*.map 11 | **/*.ts 12 | **/eslint.config.mjs 13 | **/tsconfig.*.json 14 | **/tsconfig.json 15 | biome.json 16 | commitlint.config.js 17 | compodoc/** 18 | dist/** 19 | docs/** 20 | out/test/** 21 | src/** 22 | vsc-extension-quickstart.md 23 | webview/** 24 | yarn.lock 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "JSON Flow" extension will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.13.0] - 2025-01-16 9 | 10 | * feat: add error messages for cancelled operations in controllers ([ee5787a](https://github.com/ManuelGil/vscode-json-flow/commit/ee5787a)) 11 | 12 | ## [1.12.0] - 2025-01-15 13 | 14 | * chore: :bookmark: release 1.12.0 ([dbd5ed2](https://github.com/ManuelGil/vscode-json-flow/commit/dbd5ed2)) 15 | * chore: :bookmark: update release-it configuration and change changelog plugin ([18e2171](https://github.com/ManuelGil/vscode-json-flow/commit/18e2171)) 16 | * chore: 🔧 configure automated github releases with release-it ([a17b8f6](https://github.com/ManuelGil/vscode-json-flow/commit/a17b8f6)) 17 | * docs: add code generation section to README with supported languages and usage instructions ([d5dc9fe](https://github.com/ManuelGil/vscode-json-flow/commit/d5dc9fe)) 18 | * docs: enhance README with code generation instructions and localization updates ([f2af773](https://github.com/ManuelGil/vscode-json-flow/commit/f2af773)) 19 | * docs: update changelog format and add notable changes for recent features ([848f3f2](https://github.com/ManuelGil/vscode-json-flow/commit/848f3f2)) 20 | * docs: update changelog with notable changes and version history ([c94ee59](https://github.com/ManuelGil/vscode-json-flow/commit/c94ee59)) 21 | * docs: update localization files with new prompts for type or structure generation ([3abede5](https://github.com/ManuelGil/vscode-json-flow/commit/3abede5)) 22 | * feat: ✨ add transform controller and enhance localization for conversion features ([7b01a65](https://github.com/ManuelGil/vscode-json-flow/commit/7b01a65)) 23 | * feat: add release it changelog generation ([68b59d0](https://github.com/ManuelGil/vscode-json-flow/commit/68b59d0)) 24 | 25 | ## [1.11.0] - 2025-01-09 26 | 27 | * feat: ✨ update VSCode version requirement, add test configuration, and enhance project structure ([ba8dfc7](https://github.com/ManuelGil/vscode-json-flow/commit/ba8dfc7)) 28 | 29 | ## [1.10.0] - 2024-12-20 30 | 31 | * feat: ✨ add jsonFlow.enable configuration and enhance localization support ([fed5921](https://github.com/ManuelGil/vscode-json-flow/commit/fed5921)) 32 | 33 | ## [1.9.0] - 2024-11-27 34 | 35 | * feat: ✨ add webview configuration and enhance layout element properties ([7b30d3c](https://github.com/ManuelGil/vscode-json-flow/commit/7b30d3c)) 36 | 37 | ## [1.8.0] - 2024-11-24 38 | 39 | * feat: ✨ implement image saving functionality and enhance JSON controller ([3764e59](https://github.com/ManuelGil/vscode-json-flow/commit/3764e59)) 40 | 41 | ## [1.7.0] - 2024-11-22 42 | 43 | * feat: ✨ add new JSON Flow commands and context menus ([612aad1](https://github.com/ManuelGil/vscode-json-flow/commit/612aad1)) 44 | 45 | ## [1.6.0] - 2024-11-18 46 | 47 | * feat: ✨ update localization files and enhance file searching with fast-glob ([7139123](https://github.com/ManuelGil/vscode-json-flow/commit/7139123)) 48 | * chore: :lipstick: updte cover image ([22b0c0d](https://github.com/ManuelGil/vscode-json-flow/commit/22b0c0d)) 49 | * fix: 🐛 update exclusion patterns to replace hidden files with vendor directory in configuration ([11617d2](https://github.com/ManuelGil/vscode-json-flow/commit/11617d2)) 50 | 51 | ## [1.5.0] - 2024-11-17 52 | 53 | * chore: 🔧 update version to 1.5.0 and enhance README with Product Hunt link and additional images ([70265aa](https://github.com/ManuelGil/vscode-json-flow/commit/70265aa)) 54 | * feat: ✨ add layout direction configuration option and remove unused CSS ([c9ab641](https://github.com/ManuelGil/vscode-json-flow/commit/c9ab641)) 55 | * feat: ✨ layout persist orientation state across views ([3bff5c6](https://github.com/ManuelGil/vscode-json-flow/commit/3bff5c6)) 56 | * style: ✨ update CustomNode styling for improved layout and interaction ([a1c7ada](https://github.com/ManuelGil/vscode-json-flow/commit/a1c7ada)) 57 | * style: ✨ update package description for clarity and improve code formatting in App.tsx ([0e24ede](https://github.com/ManuelGil/vscode-json-flow/commit/0e24ede)) 58 | * refactor: ♻️ enhance type safety and improve layout node dimensions in tree helper and components ([43cc7ff](https://github.com/ManuelGil/vscode-json-flow/commit/43cc7ff)) 59 | 60 | ## [1.4.0] - 2024-11-13 61 | 62 | * feat: :sparkles: add configuration option to show values in JSON graph ([8167e84](https://github.com/ManuelGil/vscode-json-flow/commit/8167e84)) 63 | * feat: :sparkles: add tree interface and helper for JSON tree generation ([40c0c29](https://github.com/ManuelGil/vscode-json-flow/commit/40c0c29)) 64 | * refactor: ♻️ improve type safety and effect handling ([e3de34e](https://github.com/ManuelGil/vscode-json-flow/commit/e3de34e)) 65 | * refactor: ♻️ restructure tree generation logic and reintroduce type definitions ([52c67c2](https://github.com/ManuelGil/vscode-json-flow/commit/52c67c2)) 66 | * style: ✨ enhance button styling and layout in webview ([965fce6](https://github.com/ManuelGil/vscode-json-flow/commit/965fce6)) 67 | * add new layout ([80d8d4c](https://github.com/ManuelGil/vscode-json-flow/commit/80d8d4c)) 68 | 69 | ## [1.3.1] - 2024-11-10 70 | 71 | * feat: :sparkles: add loading component and improve preview initialization delay ([d2d24e5](https://github.com/ManuelGil/vscode-json-flow/commit/d2d24e5)) 72 | * feat: :sparkles: implement message handling for JSON updates in webview ([7827beb](https://github.com/ManuelGil/vscode-json-flow/commit/7827beb)) 73 | * style: :art: add body padding and customize react-flow component styles ([752c965](https://github.com/ManuelGil/vscode-json-flow/commit/752c965)) 74 | * style: :art: clean up code formatting and update package dependencies ([ad0bcee](https://github.com/ManuelGil/vscode-json-flow/commit/ad0bcee)) 75 | 76 | ## [1.3.0] - 2024-11-08 77 | 78 | * refactor: :recycle: clean up configuration files and improve code formatting ([7564bfd](https://github.com/ManuelGil/vscode-json-flow/commit/7564bfd)) 79 | * refactor: :recycle: remove unused helper functions and update package dependencies ([fab9138](https://github.com/ManuelGil/vscode-json-flow/commit/fab9138)) 80 | 81 | ## [1.2.1] - 2024-11-08 82 | 83 | * fix: :adhesive_bandage: fix localization for feedback options and update package descriptions ([f395dfc](https://github.com/ManuelGil/vscode-json-flow/commit/f395dfc)) 84 | 85 | ## [1.2.0] - 2024-11-08 86 | 87 | * feat: :sparkles: add localization support for German and Spanish languages ([634c871](https://github.com/ManuelGil/vscode-json-flow/commit/634c871)) 88 | * refactor: :recycle: update JSON handling to use jsonc format and remove unused parser ([8752d5c](https://github.com/ManuelGil/vscode-json-flow/commit/8752d5c)) 89 | 90 | ## [1.1.0] - 2024-11-07 91 | 92 | * feat: :sparkles: extend supported file types and enhance documentation for CSV and TSV formats ([c8ce799](https://github.com/ManuelGil/vscode-json-flow/commit/c8ce799)) 93 | 94 | ## [1.0.1] - 2024-11-06 95 | 96 | * fix: :adhesive_bandage: enhance JSON handling by adding file type detection ([71abe2f](https://github.com/ManuelGil/vscode-json-flow/commit/71abe2f)) 97 | 98 | ## [1.0.0-beta] - 2024-11-06 99 | 100 | * chore: :tada: initial commit ([945138b](https://github.com/ManuelGil/vscode-json-flow/commit/945138b)) 101 | * chore: update contributors list in README.md ([0193af9](https://github.com/ManuelGil/vscode-json-flow/commit/0193af9)) 102 | * chore: update extension description and keywords for improved clarity ([17ffafc](https://github.com/ManuelGil/vscode-json-flow/commit/17ffafc)) 103 | * chore: update project configuration files ([7316a10](https://github.com/ManuelGil/vscode-json-flow/commit/7316a10)) 104 | * feat: :sparkles: add convertToJson and copyContentAsJson methods ([2415393](https://github.com/ManuelGil/vscode-json-flow/commit/2415393)) 105 | * feat: :sparkles: add copyContent command to JSON Manager ([23bb8a8](https://github.com/ManuelGil/vscode-json-flow/commit/23bb8a8)) 106 | * feat: :sparkles: add getFileProperties command to JSON Manager ([17c884b](https://github.com/ManuelGil/vscode-json-flow/commit/17c884b)) 107 | * feat: :sparkles: add react app ([65e0b2b](https://github.com/ManuelGil/vscode-json-flow/commit/65e0b2b)) 108 | * feat: :sparkles: add support for JSON5 format in parsing logic and configuration ([26a70e0](https://github.com/ManuelGil/vscode-json-flow/commit/26a70e0)) 109 | * feat: :sparkles: add support for multiple file types in JSON Flow and implement parsing logic ([886e15d](https://github.com/ManuelGil/vscode-json-flow/commit/886e15d)) 110 | * feat: :sparkles: add webview ui toolkit ([8528830](https://github.com/ManuelGil/vscode-json-flow/commit/8528830)) 111 | * feat: :sparkles: implement JsonController for handling JSON previews and commands ([4d1534d](https://github.com/ManuelGil/vscode-json-flow/commit/4d1534d)) 112 | * feat: :sparkles: update files options to show a contextual menu ([963c477](https://github.com/ManuelGil/vscode-json-flow/commit/963c477)) 113 | * feat: :sparkles: update JSONProvider to read JSON content from file ([f9fff41](https://github.com/ManuelGil/vscode-json-flow/commit/f9fff41)) 114 | * feat: :technologist: improve react integration ([e6122c6](https://github.com/ManuelGil/vscode-json-flow/commit/e6122c6)) 115 | * feat: add controls ([8a226dc](https://github.com/ManuelGil/vscode-json-flow/commit/8a226dc)) 116 | * feat: add fixes ([181b39a](https://github.com/ManuelGil/vscode-json-flow/commit/181b39a)) 117 | * feat: add react flow ([8dc0b4c](https://github.com/ManuelGil/vscode-json-flow/commit/8dc0b4c)) 118 | * feat: add stylling ([51f25b7](https://github.com/ManuelGil/vscode-json-flow/commit/51f25b7)) 119 | * feat: fix recurive function ([53c5dba](https://github.com/ManuelGil/vscode-json-flow/commit/53c5dba)) 120 | * refactor: :fire: remove unused code in FilesController and JSONProvider ([976ba4c](https://github.com/ManuelGil/vscode-json-flow/commit/976ba4c)) 121 | * refactor: :recycle: update JSON Provider to show a Webview Panel ([7151531](https://github.com/ManuelGil/vscode-json-flow/commit/7151531)) 122 | * refactor: remove unused code and update JSONProvider to read JSON content from file ([f350cd0](https://github.com/ManuelGil/vscode-json-flow/commit/f350cd0)) 123 | * refactor: rename extension from "JSON Manager" to "JSON Flow" and update related documentation ([8f60e06](https://github.com/ManuelGil/vscode-json-flow/commit/8f60e06)) 124 | * build: :arrow_up: update dependencies and remove unused code ([9d25354](https://github.com/ManuelGil/vscode-json-flow/commit/9d25354)) 125 | * build: add webview path ([960fb18](https://github.com/ManuelGil/vscode-json-flow/commit/960fb18)) 126 | * fix: :rotating_light: fix compilation settings ([1ccbfa5](https://github.com/ManuelGil/vscode-json-flow/commit/1ccbfa5)) 127 | 128 | [unreleased]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.12.0...HEAD 129 | [1.12.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.11.0...v1.12.0 130 | [1.11.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.10.0...v1.11.0 131 | [1.10.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.9.0...v1.10.0 132 | [1.9.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.8.0...v1.9.0 133 | [1.8.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.7.0...v1.8.0 134 | [1.7.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.6.0...v1.7.0 135 | [1.6.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.5.0...v1.6.0 136 | [1.5.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.4.0...v1.5.0 137 | [1.4.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.3.1...v1.4.0 138 | [1.3.1]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.3.0...v1.3.1 139 | [1.3.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.2.1...v1.3.0 140 | [1.2.1]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.2.0...v1.2.1 141 | [1.2.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.1.0...v1.2.0 142 | [1.1.0]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.0.1...v1.1.0 143 | [1.0.1]: https://github.com/ManuelGil/vscode-json-flow/compare/v1.0.0-beta...v1.0.1 144 | [1.0.0-beta]: https://github.com/ManuelGil/vscode-json-flow/releases/tag/v1.0.0-beta 145 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | 19 | ## Code of Conduct 20 | 21 | ### Our Pledge 22 | 23 | In the interest of fostering an open and welcoming environment, we as 24 | contributors and maintainers pledge to making participation in our project and 25 | our community a harassment-free experience for everyone, regardless of age, body 26 | size, disability, ethnicity, gender identity and expression, level of experience, 27 | nationality, personal appearance, race, religion, or sexual identity and 28 | orientation. 29 | 30 | ### Our Standards 31 | 32 | Examples of behavior that contributes to creating a positive environment 33 | include: 34 | 35 | - Using welcoming and inclusive language 36 | - Being respectful of differing viewpoints and experiences 37 | - Gracefully accepting constructive criticism 38 | - Focusing on what is best for the community 39 | - Showing empathy towards other community members 40 | 41 | Examples of unacceptable behavior by participants include: 42 | 43 | - The use of sexualized language or imagery and unwelcome sexual attention or 44 | advances 45 | - Trolling, insulting/derogatory comments, and personal or political attacks 46 | - Public or private harassment 47 | - Publishing others' private information, such as a physical or electronic 48 | address, without explicit permission 49 | - Other conduct which could reasonably be considered inappropriate in a 50 | professional setting 51 | 52 | ### Our Responsibilities 53 | 54 | Project maintainers are responsible for clarifying the standards of acceptable 55 | behavior and are expected to take appropriate and fair corrective action in 56 | response to any instances of unacceptable behavior. 57 | 58 | Project maintainers have the right and responsibility to remove, edit, or 59 | reject comments, commits, code, wiki edits, issues, and other contributions 60 | that are not aligned to this Code of Conduct, or to ban temporarily or 61 | permanently any contributor for other behaviors that they deem inappropriate, 62 | threatening, offensive, or harmful. 63 | 64 | ### Scope 65 | 66 | This Code of Conduct applies both within project spaces and in public spaces 67 | when an individual is representing the project or its community. Examples of 68 | representing a project or community include using an official project e-mail 69 | address, posting via an official social media account, or acting as an appointed 70 | representative at an online or offline event. Representation of a project may be 71 | further defined and clarified by project maintainers. 72 | 73 | ### Enforcement 74 | 75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 76 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 77 | complaints will be reviewed and investigated and will result in a response that 78 | is deemed necessary and appropriate to the circumstances. The project team is 79 | obligated to maintain confidentiality with regard to the reporter of an incident. 80 | Further details of specific enforcement policies may be posted separately. 81 | 82 | Project maintainers who do not follow or enforce the Code of Conduct in good 83 | faith may face temporary or permanent repercussions as determined by other 84 | members of the project's leadership. 85 | 86 | ### Attribution 87 | 88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 89 | available at [http://contributor-covenant.org/version/1/4][version] 90 | 91 | [homepage]: http://contributor-covenant.org 92 | [version]: http://contributor-covenant.org/version/1/4/ 93 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Manuel Gil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSON Flow 2 | 3 | [![Visual Studio Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/imgildev.vscode-json-flow?style=for-the-badge&label=VS%20Marketplace&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-json-flow) 4 | [![Visual Studio Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/imgildev.vscode-json-flow?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-json-flow) 5 | [![Visual Studio Marketplace Downloads](https://img.shields.io/visual-studio-marketplace/d/imgildev.vscode-json-flow?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-json-flow) 6 | [![Visual Studio Marketplace Rating](https://img.shields.io/visual-studio-marketplace/r/imgildev.vscode-json-flow?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-json-flow&ssr=false#review-details) 7 | [![GitHub Repo stars](https://img.shields.io/github/stars/ManuelGil/vscode-json-flow?style=for-the-badge&logo=github)](https://github.com/ManuelGil/vscode-json-flow) 8 | [![GitHub license](https://img.shields.io/github/license/ManuelGil/vscode-json-flow?style=for-the-badge&logo=github)](https://github.com/ManuelGil/vscode-json-flow/blob/main/LICENSE) 9 | 10 | Transform your JSON files into interactive node-based graphs directly in Visual Studio Code. JSON Flow makes working with structured data effortless and visually intuitive, turning raw data into dynamic, interactive visualizations. Perfect for developers, analysts, and data enthusiasts who want to understand and navigate complex JSON structures with ease. 11 | 12 | [![JSON Flow](https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/main/images/json-flow.png)](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-json-flow) 13 | 14 | ## Table of Contents 15 | 16 | - [JSON Flow](#json-flow) 17 | - [Table of Contents](#table-of-contents) 18 | - [Requirements](#requirements) 19 | - [Features](#features) 20 | - [Interactive Data Visualization](#interactive-data-visualization) 21 | - [Enhanced JSON Management](#enhanced-json-management) 22 | - [Supported File Formats](#supported-file-formats) 23 | - [JSON Family](#json-family) 24 | - [YAML](#yaml) 25 | - [TOML](#toml) 26 | - [INI Format](#ini-format) 27 | - [Properties and Environment Files](#properties-and-environment-files) 28 | - [XML](#xml) 29 | - [CSV](#csv) 30 | - [TSV](#tsv) 31 | - [HCL](#hcl) 32 | - [File Explorer](#file-explorer) 33 | - [Usage](#usage) 34 | - [Project Settings](#project-settings) 35 | - [Code Generation from JSON](#code-generation-from-json) 36 | - [Supported Languages](#supported-languages) 37 | - [How to Use](#how-to-use) 38 | - [Example](#example) 39 | - [Development](#development) 40 | - [Getting Started](#getting-started) 41 | - [React Webview](#react-webview) 42 | - [Build](#build) 43 | - [Compile Webview](#compile-webview) 44 | - [VSXpert Template](#vsxpert-template) 45 | - [Other Extensions](#other-extensions) 46 | - [Contributing](#contributing) 47 | - [Code of Conduct](#code-of-conduct) 48 | - [Changelog](#changelog) 49 | - [Authors](#authors) 50 | - [License](#license) 51 | 52 | ## Requirements 53 | 54 | - VSCode 1.88.0 or later 55 | 56 | ## Features 57 | 58 | ### Interactive Data Visualization 59 | 60 | - **Node-Based Graphs**: Instantly visualize your JSON data as interactive node-based graphs, making complex structures easy to interpret and navigate. 61 | - **Dynamic Data Exploration**: Use zoom and navigation controls to explore your data in real-time, providing a seamless, intuitive way to dive into JSON structures. 62 | 63 | ### Enhanced JSON Management 64 | 65 | - **File Explorer**: Access and manage JSON files efficiently with the built-in file explorer, offering a range of organizational and file management tools. 66 | - **File Conversion**: Easily convert formats like YAML, TOML, INI, and others to JSON with a single click, streamlining your workflow and expanding compatibility. 67 | - **Show Selection as JSON**: Preview selected content in the JSON Flow view, simplifying data exploration and helping you make sense of your data at a glance. 68 | - **Copy Content to Clipboard**: Copy the content of the selected file to the clipboard, simplifying data sharing and integration with other tools. 69 | - **Copy Content as JSON**: Copy the content of the selected file as JSON, enabling seamless data transfer and integration with other applications. 70 | - **Get File Properties**: Quickly access the basic properties of the selected file, including path, language, and line count, streamlining file management and organization. 71 | 72 | ### Supported File Formats 73 | 74 | #### JSON Family 75 | 76 | - **`json`**: Standard JSON files for all your data needs. 77 | - **`jsonc`**: JSON with comments — great for configuration files that need explanations. 78 | - **`json5`**: A more relaxed JSON format, offering improved readability and flexibility. 79 | 80 | #### YAML 81 | 82 | - **`yaml`** & **`yml`**: Widely used for configuration files, CI/CD pipelines, cloud deployment settings, and more. 83 | 84 | #### TOML 85 | 86 | - **`toml`**: A user-friendly config file format, especially popular in Rust and other applications needing readability. 87 | 88 | #### INI Format 89 | 90 | - **`ini` & `cfg`**: Classic key-value format for app and system settings, widely used in software configurations. 91 | 92 | #### Properties and Environment Files 93 | 94 | - **`properties`**: Java-style configuration files, perfect for managing app settings. 95 | - **`env`**: Environment variable files commonly used for application configurations and secrets. 96 | 97 | #### XML 98 | 99 | - **`xml`**: A versatile, structured data format used in a variety of applications and document storage. 100 | 101 | #### CSV 102 | 103 | - **`csv`**: Comma-separated values, ideal for tabular data storage and exchange. 104 | 105 | #### TSV 106 | 107 | - **`tsv`**: Tab-separated values, another popular format for storing and sharing tabular data. 108 | 109 | #### HCL 110 | 111 | - **`hcl`**: HashiCorp Configuration Language, often used in DevOps tools like Terraform. 112 | 113 | ### File Explorer 114 | 115 | | Title | Purpose | 116 | | --- | --- | 117 | | Open File | Open the selected file | 118 | | Convert to JSON | Convert the selected file to JSON | 119 | | Convert to Type or Structure | Convert the selected file to a specific type or structure. See [Code Generation from JSON](#code-generation-from-json) for more details | 120 | | Copy Content to Clipboard | Copy the content of the selected file to the clipboard | 121 | | Copy Content as JSON | Copy the content of the selected file as JSON | 122 | | Get File Properties | Get the properties of the selected file | 123 | | Show Selection as JSON | Show the Selection in the JSON Flow view | 124 | 125 | ## Usage 126 | 127 | 1. Open a JSON file in Visual Studio Code. 128 | 129 | 2. Click on the JSON Flow icon in the top right corner of the editor. 130 | 131 | 3. The JSON Flow view will open, displaying your JSON data as an interactive node-based graph. 132 | 133 | 4. Click on the navigation buttons to zoom in and out, and explore your data in real-time. 134 | 135 | - **Zoom In**: Click on the `+` button to zoom in on the graph. 136 | - **Zoom Out**: Click on the `-` button to zoom out on the graph. 137 | 138 | ![JSON Flow Preview](https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/main/images/json-flow-1.gif) 139 | 140 | ![JSON Flow Menu](https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/main/images/json-flow-2.gif) 141 | 142 | ## Project Settings 143 | 144 | Configure your project by creating or updating a settings.json file at the project's root. If you already have a `.vscode/settings.json` file, skip the first two steps. 145 | 146 | 1. Open the command palette in VSCode: 147 | 148 | - `CTRL + SHIFT + P` (Windows) 149 | - `CMD + SHIFT + P` (Mac OS) 150 | 151 | 2. Type `Preferences: Open Workspace Settings (JSON)`. 152 | 153 | 3. In the `.vscode/settings.json` file, copy and paste the following settings: 154 | 155 | ```jsonc 156 | { 157 | "jsonFlow.enable": true, // Enable or disable the extension. Example: true, false 158 | "jsonFlow.files.include": [ 159 | "json", 160 | "jsonc" 161 | ], // The file extensions to watch for changes. Example: "json", "jsonc" 162 | "jsonFlow.files.exclude": [ 163 | "**/node_modules/**", 164 | "**/dist/**", 165 | "**/out/**", 166 | "**/build/**", 167 | "**/vendor/**" 168 | ], // The files to exclude from watching. Example: "**/node_modules/**", "**/dist/**", "**/out/**", "**/build/**", "**/vendor/**" 169 | "jsonFlow.files.showPath": true, // Show the path of the file in the file name. Example: "home.component.tsx (pages/home)" 170 | "jsonFlow.graph.showValues": true, // Show the values of the nodes in the graph. Example: "name: 'John Doe'" 171 | "jsonFlow.graph.nodeWidth": 200, // The width of the nodes in the graph. Example: 200 172 | "jsonFlow.graph.nodeHeight": 50, // The height of the nodes in the graph. Example: 50 173 | "jsonFlow.graph.nodeBorderColor": "white", // The border color of the nodes in the graph. Example: "white" 174 | "jsonFlow.graph.nodeColor": "white", // The color of the nodes in the graph. Example: "white" 175 | "jsonFlow.graph.edgeColor": "white", // The color of the edges in the graph. Example: "white" 176 | "jsonFlow.graph.layoutDirection": "TB", // The layout direction of the graph. Example: "TB", "LR" 177 | "jsonFlow.image.folder": "images", // The folder where the images will be saved. Example: "images" 178 | } 179 | ``` 180 | 181 | 4. **Restart VS Code** 182 | 183 | Your project is now set up to automatically format code upon saving. 184 | 185 | ## Code Generation from JSON 186 | 187 | Enhance your development workflow by generating code from JSON structures in various programming languages using the [quicktype](https://www.npmjs.com/package/quicktype) library. 188 | 189 | ### Supported Languages 190 | 191 | - TypeScript 192 | - Go 193 | - Rust 194 | - Python 195 | - Java 196 | - C# 197 | - Swift 198 | - Kotlin 199 | - Dart 200 | - C++ 201 | - Objective-C 202 | - PHP 203 | - Ruby 204 | - Scala 205 | - Elm 206 | - JSON Schema 207 | - Haskell 208 | - JavaScript 209 | - Flow 210 | - Prop-Types 211 | - Pike 212 | 213 | ### How to Use 214 | 215 | 1. **Open a JSON File**: Open the JSON file you wish to convert in Visual Studio Code. 216 | 217 | 2. **Right-Click on the Editor**: 218 | - Right-click on the editor to open the context menu. 219 | - Select the `Convert to Type or Structure` option. 220 | 221 | 3. **Select the Target Language**: Choose your desired programming language from the provided list. 222 | 223 | 4. **Provide a Type or Structure Name**: Enter a name for the class, structure, or interface that will represent the JSON data in the selected language. 224 | 225 | 5. **Review the Generated Code**: The extension will generate the corresponding code and display it in a new editor tab. You can review, copy, or save the code as needed. 226 | 227 | ### Example 228 | 229 | Given the following JSON: 230 | 231 | ```json 232 | { 233 | "name": "John Doe", 234 | "age": 30, 235 | "email": "john.doe@example.com" 236 | } 237 | ``` 238 | 239 | If you select TypeScript as the target language and name the type Person, the generated code will be: 240 | 241 | ```typescript 242 | export interface Person { 243 | name: string; 244 | age: number; 245 | email: string; 246 | } 247 | ``` 248 | 249 | This interface can be directly utilized in your TypeScript project to ensure proper type checking and IntelliSense support. 250 | 251 | ## Development 252 | 253 | For the development of this extension, you need to have Node.js installed on your machine. You can download it from the [official website](https://nodejs.org/). 254 | 255 | ### Getting Started 256 | 257 | 1. Clone the repository: 258 | 259 | ```bash 260 | git clone 261 | ``` 262 | 263 | 2. Install the dependencies: 264 | 265 | ```bash 266 | npm install 267 | ``` 268 | 269 | 3. Open the project in VSCode: 270 | 271 | ```bash 272 | code . 273 | ``` 274 | 275 | 4. Press `F5` to open a new window with the extension loaded. 276 | 5. Make your changes in the `src` directory. 277 | 278 | ### React Webview 279 | 280 | To test the extension in a webview, run the following command: 281 | 282 | ```bash 283 | npm run dev 284 | ``` 285 | 286 | This command will open a new window with the extension loaded. 287 | 288 | Make your changes in the `webview` directory. 289 | 290 | ## Build 291 | 292 | ### Compile Webview 293 | 294 | 1. Run the build command: 295 | 296 | ```bash 297 | npm run build 298 | ``` 299 | 300 | 2. Run the compile command: 301 | 302 | ```bash 303 | npm run compile 304 | ``` 305 | 306 | 3. The compiled files will be in the `out` directory. 307 | 4. Press `F5` to open a new window with the extension loaded. 308 | 309 | ## VSXpert Template 310 | 311 | This extension was created using [VSXpert](https://vsxpert.com), a template that helps you create Visual Studio Code extensions with ease. VSXpert provides a simple and easy-to-use structure to get you started quickly. 312 | 313 | ## Other Extensions 314 | 315 | - [Angular File Generator](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-angular-generator) 316 | - [NestJS File Generator](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-nestjs-generator) 317 | - [T3 Stack / NextJS / ReactJS File Generator](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-nextjs-generator) 318 | - [Auto Barrel](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-auto-barrel) 319 | - [CodeIgniter 4 Spark](https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-codeigniter4-spark) 320 | 321 | ## Contributing 322 | 323 | Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. 324 | 325 | ## Code of Conduct 326 | 327 | Please read [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) for details on our code of conduct. 328 | 329 | ## Changelog 330 | 331 | See [CHANGELOG.md](./CHANGELOG.md) 332 | 333 | ## Authors 334 | 335 | - **Manuel Gil** - _Owner_ - [ManuelGil](https://github.com/ManuelGil) 336 | - **Santiago Rey** - _Collaborator_ - [ksreyr](https://github.com/ksreyr) 337 | - **Andry Orellana** - _Collaborator_ - [AndryOre](https://github.com/AndryOre) 338 | 339 | See also the list of [contributors](https://github.com/ManuelGil/vscode-json-flow/contributors) who participated in this project. 340 | 341 | ## License 342 | 343 | JSON Flow is licensed under the MIT License - see the [MIT License](https://opensource.org/licenses/MIT) for details. 344 | -------------------------------------------------------------------------------- /assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/assets/.gitkeep -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, 4 | "files": { 5 | "include": ["src/**/*.ts", "webview/**/*.ts", "webview/**/*.tsx"], 6 | "ignoreUnknown": false, 7 | "ignore": [] 8 | }, 9 | "formatter": { 10 | "enabled": true, 11 | "useEditorconfig": true, 12 | "formatWithErrors": false, 13 | "indentStyle": "space", 14 | "indentWidth": 2, 15 | "lineEnding": "lf", 16 | "lineWidth": 80, 17 | "attributePosition": "auto", 18 | "bracketSpacing": true, 19 | "ignore": [ 20 | "./.vscode", 21 | "./compodoc", 22 | "./coverage", 23 | "./dist", 24 | "./docs", 25 | "./node_modules", 26 | "./out", 27 | "./tests", 28 | "**/commitlint.config.js" 29 | ] 30 | }, 31 | "organizeImports": { "enabled": true }, 32 | "linter": { 33 | "enabled": true, 34 | "rules": { 35 | "recommended": false, 36 | "complexity": { 37 | "noBannedTypes": "error", 38 | "noExtraBooleanCast": "error", 39 | "noMultipleSpacesInRegularExpressionLiterals": "error", 40 | "noUselessCatch": "error", 41 | "noUselessThisAlias": "error", 42 | "noUselessTypeConstraint": "error", 43 | "noWith": "error" 44 | }, 45 | "correctness": { 46 | "noConstAssign": "error", 47 | "noConstantCondition": "error", 48 | "noEmptyCharacterClassInRegex": "error", 49 | "noEmptyPattern": "error", 50 | "noGlobalObjectCalls": "error", 51 | "noInnerDeclarations": "error", 52 | "noInvalidBuiltinInstantiation": "error", 53 | "noInvalidConstructorSuper": "error", 54 | "noNewSymbol": "error", 55 | "noNonoctalDecimalEscape": "error", 56 | "noPrecisionLoss": "error", 57 | "noSelfAssign": "error", 58 | "noSetterReturn": "error", 59 | "noSwitchDeclarations": "error", 60 | "noUndeclaredVariables": "error", 61 | "noUnreachable": "error", 62 | "noUnreachableSuper": "error", 63 | "noUnsafeFinally": "error", 64 | "noUnsafeOptionalChaining": "error", 65 | "noUnusedLabels": "error", 66 | "noUnusedPrivateClassMembers": "error", 67 | "noUnusedVariables": "error", 68 | "useArrayLiterals": "off", 69 | "useExhaustiveDependencies": "warn", 70 | "useHookAtTopLevel": "error", 71 | "useIsNan": "error", 72 | "useValidForDirection": "error", 73 | "useYield": "error" 74 | }, 75 | "style": { 76 | "noNamespace": "error", 77 | "useAsConstAssertion": "error", 78 | "useBlockStatements": "warn", 79 | "useNamingConvention": { 80 | "level": "warn", 81 | "options": { "strictCase": false } 82 | }, 83 | "useThrowOnlyError": "warn" 84 | }, 85 | "suspicious": { 86 | "noAssignInExpressions": "error", 87 | "noAsyncPromiseExecutor": "error", 88 | "noCatchAssign": "error", 89 | "noClassAssign": "error", 90 | "noCompareNegZero": "error", 91 | "noControlCharactersInRegex": "error", 92 | "noDebugger": "error", 93 | "noDoubleEquals": "warn", 94 | "noDuplicateCase": "error", 95 | "noDuplicateClassMembers": "error", 96 | "noDuplicateObjectKeys": "error", 97 | "noDuplicateParameters": "error", 98 | "noEmptyBlockStatements": "error", 99 | "noExplicitAny": "error", 100 | "noExtraNonNullAssertion": "error", 101 | "noFallthroughSwitchClause": "error", 102 | "noFunctionAssign": "error", 103 | "noGlobalAssign": "error", 104 | "noImportAssign": "error", 105 | "noMisleadingCharacterClass": "error", 106 | "noMisleadingInstantiator": "error", 107 | "noPrototypeBuiltins": "error", 108 | "noRedeclare": "error", 109 | "noShadowRestrictedNames": "error", 110 | "noSparseArray": "error", 111 | "noUnsafeDeclarationMerging": "error", 112 | "noUnsafeNegation": "error", 113 | "useGetterReturn": "error", 114 | "useNamespaceKeyword": "error", 115 | "useValidTypeof": "error" 116 | } 117 | }, 118 | "ignore": [ 119 | "**/node_modules", 120 | "**/dist", 121 | "**/out", 122 | "**/*.d.ts", 123 | "**/vite.config.ts", 124 | "**/webview", 125 | "**/.vscode/", 126 | "**/compodoc/", 127 | "**/coverage/", 128 | "**/dist/", 129 | "**/docs/", 130 | "**/node_modules/", 131 | "**/out/", 132 | "**/tests/", 133 | "**/commitlint.config.js" 134 | ] 135 | }, 136 | "javascript": { 137 | "formatter": { 138 | "jsxQuoteStyle": "double", 139 | "quoteProperties": "preserve", 140 | "trailingCommas": "all", 141 | "semicolons": "always", 142 | "arrowParentheses": "always", 143 | "bracketSameLine": false, 144 | "quoteStyle": "single", 145 | "attributePosition": "auto", 146 | "bracketSpacing": true 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/icon.png -------------------------------------------------------------------------------- /images/json-flow-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/images/json-flow-1.gif -------------------------------------------------------------------------------- /images/json-flow-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/images/json-flow-2.gif -------------------------------------------------------------------------------- /images/json-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/images/json-flow.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JSON Preview 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /l10n/bundle.l10n.de.json: -------------------------------------------------------------------------------- 1 | { 2 | "No workspace folders are open. Please open a workspace folder to use this extension": "Keine Arbeitsbereichsordner sind geöffnet. Bitte öffnen Sie einen Arbeitsbereichsordner, um diese Erweiterung zu verwenden", 3 | "Select a workspace folder to use. This folder will be used to load workspace-specific configuration for the extension": "Wählen Sie einen Arbeitsbereichsordner aus, der verwendet werden soll. Dieser Ordner wird verwendet, um arbeitsbereichsspezifische Konfigurationen für die Erweiterung zu laden", 4 | "{0} is now enabled and ready to use": "{0} ist jetzt aktiviert und einsatzbereit", 5 | "{0} is now disabled": "{0} ist jetzt deaktiviert", 6 | "{0} is disabled in settings. Enable it to use its features": "{0} ist in den Einstellungen deaktiviert. Aktivieren Sie es, um seine Funktionen zu verwenden", 7 | "Welcome to {0} version {1}! The extension is now active": "Willkommen bei {0} Version {1}! Die Erweiterung ist jetzt aktiv", 8 | "New version of {0} is available. Check out the release notes for version {1}": "Eine neue Version von {0} ist verfügbar. Überprüfen Sie die Versionshinweise für Version {1}", 9 | "Release Notes": "Versionshinweise", 10 | "Dismiss": "Verwerfen", 11 | "No active editor!": "Kein aktiver Editor!", 12 | "No selection!": "Keine Auswahl!", 13 | "Operation cancelled!": "Vorgang abgebrochen!", 14 | "Error while finding files: {0}": "Fehler beim Suchen von Dateien: {0}", 15 | "Invalid file type!": "Ungültiger Dateityp!", 16 | "Error parsing {0}: {1}": "Fehler beim Parsen von {0}: {1}", 17 | "Content copied to clipboard": "Inhalt in die Zwischenablage kopiert", 18 | "Content copied as JSON to clipboard": "Inhalt als JSON in die Zwischenablage kopiert", 19 | "File Name: {0}\nLanguage: {1}\nLines: {2}\nVersion: {3}": "Dateiname: {0}\nSprache: {1}\nZeilen: {2}\nVersion: {3}", 20 | "Report Issues": "Probleme melden", 21 | "Rate Us": "Bewerten Sie uns", 22 | "No workspace folder available to save the image!": "Kein Arbeitsbereichsordner verfügbar, um das Bild zu speichern!", 23 | "Select a workspace folder to save the image": "Wählen Sie einen Arbeitsbereichsordner aus, um das Bild zu speichern", 24 | "Image saved to: {0}": "Bild gespeichert unter: {0}", 25 | "Enter the name of the type or structure generated": "Geben Sie den Namen des generierten Typs oder der Struktur ein", 26 | "Enter the name of the type or structure, e.g., User, Post, etc.": "Geben Sie den Namen des Typs oder der Struktur ein, z. B. Benutzer, Beitrag usw.", 27 | "The name of the type or structure is required!": "Der Name des Typs oder der Struktur ist erforderlich!" 28 | } 29 | -------------------------------------------------------------------------------- /l10n/bundle.l10n.es.json: -------------------------------------------------------------------------------- 1 | { 2 | "No workspace folders are open. Please open a workspace folder to use this extension": "No hay carpetas de espacio de trabajo abiertas. Abra una carpeta de espacio de trabajo para usar esta extensión", 3 | "Select a workspace folder to use. This folder will be used to load workspace-specific configuration for the extension": "Seleccione una carpeta de espacio de trabajo para usar. Esta carpeta se utilizará para cargar la configuración específica del espacio de trabajo para la extensión", 4 | "{0} is now enabled and ready to use": "{0} está ahora habilitado y listo para usar", 5 | "{0} is now disabled": "{0} está ahora deshabilitado", 6 | "{0} is disabled in settings. Enable it to use its features": "{0} está deshabilitado en la configuración. Habilítelo para usar sus funciones", 7 | "Welcome to {0} version {1}! The extension is now active": "¡Bienvenido a {0} versión {1}! La extensión ahora está activa", 8 | "New version of {0} is available. Check out the release notes for version {1}": "Hay disponible una nueva versión de {0}. Consulte las notas de la versión {1}", 9 | "Release Notes": "Notas de la versión", 10 | "Dismiss": "Descartar", 11 | "No active editor!": "¡No hay editor activo!", 12 | "No selection!": "¡No hay selección!", 13 | "Operation cancelled!": "¡Operación cancelada!", 14 | "Error while finding files: {0}": "Error al buscar archivos: {0}", 15 | "Invalid file type!": "¡Tipo de archivo no válido!", 16 | "Error parsing {0}: {1}": "Error al parsear {0}: {1}", 17 | "Content copied to clipboard": "Contenido copiado al portapapeles", 18 | "Content copied as JSON to clipboard": "Contenido copiado como JSON al portapapeles", 19 | "File Name: {0}\nLanguage: {1}\nLines: {2}\nVersion: {3}": "Nombre de archivo: {0}\nIdioma: {1}\nLíneas: {2}\nVersión: {3}", 20 | "Report Issues": "Reportar problemas", 21 | "Rate Us": "Califícanos", 22 | "No workspace folder available to save the image!": "¡No hay carpeta de espacio de trabajo disponible para guardar la imagen!", 23 | "Select a workspace folder to save the image": "Seleccione una carpeta de espacio de trabajo para guardar la imagen", 24 | "Image saved to: {0}": "Imagen guardada en: {0}", 25 | "Enter the name of the type or structure generated": "Introduzca el nombre del tipo o estructura generada", 26 | "Enter the name of the type or structure, e.g., User, Post, etc.": "Introduzca el nombre del tipo o estructura, por ejemplo, Usuario, Publicación, etc.", 27 | "The name of the type or structure is required!": "¡Se requiere el nombre del tipo o estructura!" 28 | } 29 | -------------------------------------------------------------------------------- /l10n/bundle.l10n.fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "No workspace folders are open. Please open a workspace folder to use this extension": "Aucun dossier d'espace de travail n'est ouvert. Veuillez ouvrir un dossier d'espace de travail pour utiliser cette extension", 3 | "Select a workspace folder to use. This folder will be used to load workspace-specific configuration for the extension": "Sélectionnez un dossier d'espace de travail à utiliser. Ce dossier sera utilisé pour charger la configuration spécifique à l'espace de travail pour l'extension", 4 | "{0} is now enabled and ready to use": "{0} est maintenant activé et prêt à être utilisé", 5 | "{0} is now disabled": "{0} est maintenant désactivé", 6 | "{0} is disabled in settings. Enable it to use its features": "{0} est désactivé dans les paramètres. Activez-le pour utiliser ses fonctionnalités", 7 | "Welcome to {0} version {1}! The extension is now active": "Bienvenue dans la version {0} {1} ! L'extension est maintenant active", 8 | "New version of {0} is available. Check out the release notes for version {1}": "Une nouvelle version de {0} est disponible. Consultez les notes de version pour la version {1}", 9 | "Release Notes": "Notes de version", 10 | "Dismiss": "Rejeter", 11 | "No active editor!": "Aucun éditeur actif!", 12 | "No selection!": "Aucune sélection!", 13 | "Operation cancelled!": "Opération annulée!", 14 | "Error while finding files: {0}": "Erreur lors de la recherche des fichiers : {0}", 15 | "Invalid file type!": "Type de fichier non valide!", 16 | "Error parsing {0}: {1}": "Erreur d'analyse de {0} : {1}", 17 | "Content copied to clipboard": "Contenu copié dans le presse-papiers", 18 | "Content copied as JSON to clipboard": "Contenu copié en tant que JSON dans le presse-papiers", 19 | "File Name: {0}\nLanguage: {1}\nLines: {2}\nVersion: {3}": "Nom du fichier : {0}\nLangue : {1}\nLignes : {2}\nVersion : {3}", 20 | "Report Issues": "Signaler des problèmes", 21 | "Rate Us": "Évaluez-nous", 22 | "No workspace folder available to save the image!": "Aucun dossier d'espace de travail disponible pour enregistrer l'image!", 23 | "Select a workspace folder to save the image": "Sélectionnez un dossier d'espace de travail pour enregistrer l'image", 24 | "Image saved to: {0}": "Image enregistrée sous : {0}", 25 | "Enter the name of the type or structure generated": "Entrez le nom du type ou de la structure généré", 26 | "Enter the name of the type or structure, e.g., User, Post, etc.": "Entrez le nom du type ou de la structure, par exemple, Utilisateur, Post, etc.", 27 | "The name of the type or structure is required!": "Le nom du type ou de la structure est requis!" 28 | } 29 | -------------------------------------------------------------------------------- /l10n/bundle.l10n.it.json: -------------------------------------------------------------------------------- 1 | { 2 | "No workspace folders are open. Please open a workspace folder to use this extension": "Nessuna cartella dello spazio di lavoro è aperta. Apri una cartella dello spazio di lavoro per utilizzare questa estensione", 3 | "Select a workspace folder to use. This folder will be used to load workspace-specific configuration for the extension": "Seleziona una cartella dello spazio di lavoro da utilizzare. Questa cartella verrà utilizzata per caricare la configurazione specifica dello spazio di lavoro per l'estensione", 4 | "{0} is now enabled and ready to use": "{0} è ora abilitato e pronto per l'uso", 5 | "{0} is now disabled": "{0} è ora disabilitato", 6 | "{0} is disabled in settings. Enable it to use its features": "{0} è disabilitato nelle impostazioni. Abilitalo per utilizzare le sue funzionalità", 7 | "Welcome to {0} version {1}! The extension is now active": "Benvenuto alla versione {0} {1}! L'estensione è ora attiva", 8 | "New version of {0} is available. Check out the release notes for version {1}": "È disponibile una nuova versione di {0}. Consulta le note sulla versione {1}", 9 | "Release Notes": "Note sulla versione", 10 | "Dismiss": "Ignora", 11 | "No active editor!": "Nessun editor attivo!", 12 | "No selection!": "Nessuna sele", 13 | "Operation cancelled!": "Operazione annullata!", 14 | "Error while finding files: {0}": "Errore durante la ricerca dei file: {0}", 15 | "Invalid file type!": "Tipo di file non valido!", 16 | "Error parsing {0}: {1}": "Errore durante l'analisi di {0}: {1}", 17 | "Content copied to clipboard": "Contenuto copiato negli appunti", 18 | "Content copied as JSON to clipboard": "Contenuto copiato come JSON negli appunti", 19 | "File Name: {0}\nLanguage: {1}\nLines: {2}\nVersion: {3}": "Nome file: {0}\nLingua: {1}\nRighe: {2}\nVersione: {3}", 20 | "Report Issues": "Segnala problemi", 21 | "Rate Us": "Valutaci", 22 | "No workspace folder available to save the image!": "Nessuna cartella dello spazio di lavoro disponibile per salvare l'immagine!", 23 | "Select a workspace folder to save the image": "Seleziona una cartella dello spazio di lavoro per salvare l'immagine", 24 | "Image saved to: {0}": "Immagine salvata in: {0}", 25 | "Enter the name of the type or structure generated": "Inserisci il nome del tipo o della struttura generata", 26 | "Enter the name of the type or structure, e.g., User, Post, etc.": "Inserisci il nome del tipo o della struttura, ad esempio, Utente, Post, ecc.", 27 | "The name of the type or structure is required!": "Il nome del tipo o della struttura è obbligatorio!" 28 | } 29 | -------------------------------------------------------------------------------- /l10n/bundle.l10n.pt-br.json: -------------------------------------------------------------------------------- 1 | { 2 | "No workspace folders are open. Please open a workspace folder to use this extension": "Nenhuma pasta de espaço de trabalho está aberta. Por favor, abra uma pasta de espaço de trabalho para usar esta extensão", 3 | "Select a workspace folder to use. This folder will be used to load workspace-specific configuration for the extension": "Selecione uma pasta de espaço de trabalho para usar. Esta pasta será usada para carregar a configuração específica do espaço de trabalho para a extensão", 4 | "{0} is now enabled and ready to use": "{0} está agora ativado e pronto para usar", 5 | "{0} is now disabled": "{0} está agora desativado", 6 | "{0} is disabled in settings. Enable it to use its features": "{0} está desativado nas configurações. Ative-o para usar suas funcionalidades", 7 | "Welcome to {0} version {1}! The extension is now active": "Bem-vindo à versão {0} {1}! A extensão está agora ativa", 8 | "New version of {0} is available. Check out the release notes for version {1}": "Nova versão de {0} está disponível. Confira as notas de lançamento para a versão {1}", 9 | "Release Notes": "Notas de lançamento", 10 | "Dismiss": "Dispensar", 11 | "No active editor!": "Nenhum editor ativo!", 12 | "No selection!": "Nenhuma seleção!", 13 | "Operation cancelled!": "Operação cancelada!", 14 | "Error while finding files: {0}": "Erro ao encontrar arquivos: {0}", 15 | "Invalid file type!": "Tipo de arquivo inválido!", 16 | "Error parsing {0}: {1}": "Erro ao analisar {0}: {1}", 17 | "Content copied to clipboard": "Conteúdo copiado para a área de transferência", 18 | "Content copied as JSON to clipboard": "Conteúdo copiado como JSON para a área de transferência", 19 | "File Name: {0}\nLanguage: {1}\nLines: {2}\nVersion: {3}": "Nome do arquivo: {0}\nIdioma: {1}\nLinhas: {2}\nVersão: {3}", 20 | "Report Issues": "Relatar problemas", 21 | "Rate Us": "Avalie-nos", 22 | "No workspace folder available to save the image!": "Nenhuma pasta de espaço de trabalho disponível para salvar a imagem!", 23 | "Select a workspace folder to save the image": "Selecione uma pasta de espaço de trabalho para salvar a imagem", 24 | "Image saved to: {0}": "Imagem salva em: {0}", 25 | "Enter the name of the type or structure generated": "Digite o nome do tipo ou estrutura gerada", 26 | "Enter the name of the type or structure, e.g., User, Post, etc.": "Digite o nome do tipo ou estrutura, por exemplo, Usuário, Postagem, etc.", 27 | "The name of the type or structure is required!": "O nome do tipo ou estrutura é obrigatório!" 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-json-flow", 3 | "displayName": "JSON Flow", 4 | "description": "Transform JSON into interactive graphs in VSCode - Free & Open Source", 5 | "version": "1.13.0", 6 | "icon": "icon.png", 7 | "license": "MIT", 8 | "publisher": "imgildev", 9 | "author": { 10 | "name": "Manuel Gil", 11 | "email": "support@imgil.dev", 12 | "url": "https://imgil.dev/" 13 | }, 14 | "sponsor": { 15 | "url": "https://github.com/sponsors/manuelgil" 16 | }, 17 | "engines": { 18 | "vscode": "^1.88.0" 19 | }, 20 | "categories": [ 21 | "Other" 22 | ], 23 | "keywords": [ 24 | "cfg", 25 | "csv", 26 | "data", 27 | "dotenv", 28 | "env", 29 | "explorer", 30 | "fileview", 31 | "flow view", 32 | "flow", 33 | "flowview", 34 | "graph view", 35 | "graph", 36 | "graphview", 37 | "hcl", 38 | "ini", 39 | "json flow", 40 | "json schema", 41 | "json view", 42 | "json-flow", 43 | "json-schema", 44 | "json-xml", 45 | "json", 46 | "json5", 47 | "jsonc", 48 | "jsonflow", 49 | "jsonschema", 50 | "jsonview", 51 | "live preview", 52 | "manager", 53 | "node", 54 | "nodes", 55 | "preview", 56 | "properties", 57 | "schema", 58 | "toml", 59 | "tree", 60 | "treeview", 61 | "tsv", 62 | "view", 63 | "visualizer", 64 | "vscode-extension", 65 | "vscode-json-flow", 66 | "vscode", 67 | "xml", 68 | "yaml", 69 | "yml" 70 | ], 71 | "homepage": "https://github.com/ManuelGil/vscode-json-flow", 72 | "repository": { 73 | "type": "git", 74 | "url": "https://github.com/ManuelGil/vscode-json-flow" 75 | }, 76 | "bugs": { 77 | "url": "https://github.com/ManuelGil/vscode-json-flow/issues" 78 | }, 79 | "activationEvents": [], 80 | "main": "./out/extension.js", 81 | "l10n": "./l10n", 82 | "contributes": { 83 | "configuration": { 84 | "title": "JSON Flow", 85 | "properties": { 86 | "jsonFlow.enable": { 87 | "type": "boolean", 88 | "default": true, 89 | "scope": "resource", 90 | "description": "%jsonFlow.enable%" 91 | }, 92 | "jsonFlow.files.include": { 93 | "type": "array", 94 | "default": [ 95 | "json", 96 | "jsonc", 97 | "json5", 98 | "cfg", 99 | "csv", 100 | "env", 101 | "hcl", 102 | "ini", 103 | "properties", 104 | "toml", 105 | "tsv", 106 | "xml", 107 | "yaml", 108 | "yml" 109 | ], 110 | "scope": "resource", 111 | "description": "%jsonFlow.files.include%" 112 | }, 113 | "jsonFlow.files.exclude": { 114 | "type": "array", 115 | "default": [ 116 | "**/node_modules/**", 117 | "**/dist/**", 118 | "**/out/**", 119 | "**/build/**", 120 | "**/vendor/**" 121 | ], 122 | "scope": "resource", 123 | "description": "%jsonFlow.files.exclude%" 124 | }, 125 | "jsonFlow.files.showPath": { 126 | "type": "boolean", 127 | "default": true, 128 | "scope": "resource", 129 | "description": "%jsonFlow.files.showPath%" 130 | }, 131 | "jsonFlow.graph.showValues": { 132 | "type": "boolean", 133 | "default": true, 134 | "scope": "resource", 135 | "description": "%jsonFlow.graph.showValues%" 136 | }, 137 | "jsonFlow.graph.nodeWidth": { 138 | "type": "number", 139 | "default": 200, 140 | "scope": "resource", 141 | "description": "%jsonFlow.graph.nodeWidth%" 142 | }, 143 | "jsonFlow.graph.nodeHeight": { 144 | "type": "number", 145 | "default": 50, 146 | "scope": "resource", 147 | "description": "%jsonFlow.graph.nodeHeight%" 148 | }, 149 | "jsonFlow.graph.nodeBorderColor": { 150 | "type": "string", 151 | "default": "white", 152 | "scope": "resource", 153 | "description": "%jsonFlow.graph.nodeBorderColor%" 154 | }, 155 | "jsonFlow.graph.nodeColor": { 156 | "type": "string", 157 | "default": "white", 158 | "scope": "resource", 159 | "description": "%jsonFlow.graph.nodeColor%" 160 | }, 161 | "jsonFlow.graph.edgeColor": { 162 | "type": "string", 163 | "default": "white", 164 | "scope": "resource", 165 | "description": "%jsonFlow.graph.edgeColor%" 166 | }, 167 | "jsonFlow.graph.layoutDirection": { 168 | "type": "string", 169 | "default": "TB", 170 | "enum": [ 171 | "TB", 172 | "LR" 173 | ], 174 | "scope": "resource", 175 | "description": "%jsonFlow.graph.layoutDirection%" 176 | }, 177 | "jsonFlow.image.folder": { 178 | "type": "string", 179 | "default": "json-flow/images", 180 | "scope": "resource", 181 | "description": "%jsonFlow.image.folder%" 182 | } 183 | } 184 | }, 185 | "commands": [ 186 | { 187 | "command": "jsonFlow.files.refreshList", 188 | "title": "%jsonFlow.files.refreshList%", 189 | "category": "JSON Flow", 190 | "icon": "$(refresh)" 191 | }, 192 | { 193 | "command": "jsonFlow.files.openFile", 194 | "title": "%jsonFlow.files.openFile%", 195 | "category": "JSON Flow" 196 | }, 197 | { 198 | "command": "jsonFlow.files.copyContent", 199 | "title": "%jsonFlow.files.copyContent%", 200 | "category": "JSON Flow" 201 | }, 202 | { 203 | "command": "jsonFlow.files.copyContentAsJson", 204 | "title": "%jsonFlow.files.copyContentAsJson%", 205 | "category": "JSON Flow" 206 | }, 207 | { 208 | "command": "jsonFlow.files.copyContentPartialAsJson", 209 | "title": "%jsonFlow.files.copyContentPartialAsJson%", 210 | "category": "JSON Flow" 211 | }, 212 | { 213 | "command": "jsonFlow.files.getFileProperties", 214 | "title": "%jsonFlow.files.getFileProperties%", 215 | "category": "JSON Flow" 216 | }, 217 | { 218 | "command": "jsonFlow.json.showPartialPreview", 219 | "title": "%jsonFlow.json.showPartialPreview%", 220 | "category": "JSON Flow" 221 | }, 222 | { 223 | "command": "jsonFlow.json.showPreview", 224 | "title": "%jsonFlow.json.showPreview%", 225 | "category": "JSON Flow" 226 | }, 227 | { 228 | "command": "jsonFlow.files.convertToJson", 229 | "title": "%jsonFlow.files.convertToJson%", 230 | "category": "JSON Flow" 231 | }, 232 | { 233 | "command": "jsonFlow.files.convertPartialToJson", 234 | "title": "%jsonFlow.files.convertPartialToJson%", 235 | "category": "JSON Flow" 236 | }, 237 | { 238 | "command": "jsonFlow.files.convertToType", 239 | "title": "%jsonFlow.files.convertToType%", 240 | "category": "JSON Flow" 241 | }, 242 | { 243 | "command": "jsonFlow.files.convertPartialToType", 244 | "title": "%jsonFlow.files.convertPartialToType%", 245 | "category": "JSON Flow" 246 | } 247 | ], 248 | "submenus": [ 249 | { 250 | "id": "jsonFlow.explorer.submenu", 251 | "label": "JSON Flow" 252 | }, 253 | { 254 | "id": "jsonFlow.editor.submenu", 255 | "label": "JSON Flow" 256 | } 257 | ], 258 | "menus": { 259 | "view/title": [ 260 | { 261 | "command": "jsonFlow.files.refreshList", 262 | "when": "view == jsonFlow.filesView", 263 | "group": "navigation" 264 | } 265 | ], 266 | "view/item/context": [ 267 | { 268 | "command": "jsonFlow.files.openFile", 269 | "when": "view == jsonFlow.filesView && viewItem =~ /.(json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml)/", 270 | "group": "1_navigation" 271 | }, 272 | { 273 | "command": "jsonFlow.files.convertToJson", 274 | "when": "view == jsonFlow.filesView && viewItem =~ /.(cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml)/", 275 | "group": "2_modification" 276 | }, 277 | { 278 | "command": "jsonFlow.files.convertToType", 279 | "when": "view == jsonFlow.filesView && viewItem =~ /.(json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml)/", 280 | "group": "2_modification" 281 | }, 282 | { 283 | "command": "jsonFlow.files.copyContent", 284 | "when": "view == jsonFlow.filesView && viewItem =~ /.(json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml)/", 285 | "group": "3_cutcopypaste@1" 286 | }, 287 | { 288 | "command": "jsonFlow.files.copyContentAsJson", 289 | "when": "view == jsonFlow.filesView && viewItem =~ /.(cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml)/", 290 | "group": "3_cutcopypaste@2" 291 | }, 292 | { 293 | "command": "jsonFlow.files.getFileProperties", 294 | "when": "view == jsonFlow.filesView && viewItem =~ /.(json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml)/", 295 | "group": "4_properties" 296 | } 297 | ], 298 | "explorer/context": [ 299 | { 300 | "submenu": "jsonFlow.explorer.submenu", 301 | "group": "2_workspace", 302 | "when": "resourceExtname =~ /json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/" 303 | } 304 | ], 305 | "editor/context": [ 306 | { 307 | "submenu": "jsonFlow.editor.submenu", 308 | "group": "1_modification", 309 | "when": "editorHasSelection" 310 | } 311 | ], 312 | "jsonFlow.explorer.submenu": [ 313 | { 314 | "command": "jsonFlow.json.showPreview", 315 | "title": "%jsonFlow.json.showPreview%", 316 | "group": "1_navigation" 317 | }, 318 | { 319 | "command": "jsonFlow.files.convertToJson", 320 | "title": "%jsonFlow.files.convertToJson%", 321 | "when": "resourceExtname =~ /cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 322 | "group": "2_modification" 323 | }, 324 | { 325 | "command": "jsonFlow.files.convertToType", 326 | "title": "%jsonFlow.files.convertToType%", 327 | "when": "resourceExtname =~ /json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 328 | "group": "2_modification" 329 | }, 330 | { 331 | "command": "jsonFlow.files.copyContent", 332 | "title": "%jsonFlow.files.copyContent%", 333 | "when": "resourceExtname =~ /json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 334 | "group": "3_cutcopypaste" 335 | }, 336 | { 337 | "command": "jsonFlow.files.copyContentAsJson", 338 | "title": "%jsonFlow.files.copyContentAsJson%", 339 | "when": "resourceExtname =~ /cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 340 | "group": "3_cutcopypaste" 341 | } 342 | ], 343 | "jsonFlow.editor.submenu": [ 344 | { 345 | "command": "jsonFlow.json.showPartialPreview", 346 | "title": "%jsonFlow.json.showPartialPreview%", 347 | "group": "1_view" 348 | }, 349 | { 350 | "command": "jsonFlow.files.convertPartialToJson", 351 | "title": "%jsonFlow.files.convertPartialToJson%", 352 | "when": "resourceExtname =~ /cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 353 | "group": "2_modification" 354 | }, 355 | { 356 | "command": "jsonFlow.files.convertPartialToType", 357 | "title": "%jsonFlow.files.convertPartialToType%", 358 | "when": "resourceExtname =~ /json|jsonc|json5|cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 359 | "group": "2_modification" 360 | }, 361 | { 362 | "command": "jsonFlow.files.copyContentPartialAsJson", 363 | "title": "%jsonFlow.files.copyContentPartialAsJson%", 364 | "when": "resourceExtname =~ /cfg|csv|env|hcl|ini|properties|toml|tsv|xml|yaml|yml/", 365 | "group": "3_cutcopypaste" 366 | } 367 | ] 368 | }, 369 | "viewsWelcome": [ 370 | { 371 | "view": "jsonFlow.filesView", 372 | "contents": "%viewsWelcome.jsonFlow.filesView%" 373 | } 374 | ], 375 | "viewsContainers": { 376 | "activitybar": [ 377 | { 378 | "id": "json-explorer", 379 | "title": "JSON Flow", 380 | "icon": "./assets/logo.svg" 381 | } 382 | ] 383 | }, 384 | "views": { 385 | "json-explorer": [ 386 | { 387 | "id": "jsonFlow.filesView", 388 | "name": "%jsonFlow.filesView%", 389 | "visibility": "visible" 390 | }, 391 | { 392 | "id": "jsonFlow.feedbackView", 393 | "name": "%jsonFlow.feedbackView%", 394 | "visibility": "visible" 395 | } 396 | ] 397 | }, 398 | "jsonValidation": [ 399 | { 400 | "fileMatch": ".vscode/settings.json", 401 | "url": "./schemas/config.schema.json" 402 | } 403 | ] 404 | }, 405 | "scripts": { 406 | "vscode:prepublish": "npm run build && npm run compile", 407 | "compile": "rimraf out && tsc -p ./ && cpy dist/* out/webview", 408 | "watch": "tsc -watch -p ./", 409 | "pretest": "npm run compile && npm run lint", 410 | "dev": "vite", 411 | "build": "tsc --p ./tsconfig.web.json && vite build", 412 | "preview": "vite preview", 413 | "format": "biome format --write", 414 | "lint": "biome lint --write", 415 | "lint:check": "biome check --write", 416 | "test": "vscode-test", 417 | "compodoc": "npx compodoc -p tsconfig.doc.json -d compodoc --theme readthedocs -s", 418 | "prepare": "husky", 419 | "release": "release-it" 420 | }, 421 | "dependencies": { 422 | "@vscode/webview-ui-toolkit": "^1.4.0", 423 | "@xyflow/react": "^12.3.4", 424 | "dotenv": "^16.4.5", 425 | "entitree-flex": "^0.4.1", 426 | "fast-glob": "^3.3.2", 427 | "fast-xml-parser": "^4.5.0", 428 | "hcl-parser": "^0.1.1", 429 | "html-to-image": "^1.11.11", 430 | "ini": "^5.0.0", 431 | "json5": "^2.2.3", 432 | "quicktype-core": "^23.0.170", 433 | "react": "^18.3.1", 434 | "react-dom": "^18.3.1", 435 | "toml": "^3.0.0", 436 | "yaml": "^2.6.0" 437 | }, 438 | "devDependencies": { 439 | "@biomejs/biome": "1.9.4", 440 | "@commitlint/cli": "^19.5.0", 441 | "@commitlint/config-conventional": "^19.5.0", 442 | "@compodoc/compodoc": "^1.1.26", 443 | "@release-it/keep-a-changelog": "^6.0.0", 444 | "@types/mocha": "^10.0.10", 445 | "@types/node": "^22.10.5", 446 | "@types/react": "^18.3.12", 447 | "@types/react-dom": "^18.3.1", 448 | "@types/vscode": "^1.88.0", 449 | "@typescript-eslint/eslint-plugin": "^8.17.0", 450 | "@typescript-eslint/parser": "^8.17.0", 451 | "@vitejs/plugin-react": "^4.3.3", 452 | "@vscode/l10n-dev": "^0.0.35", 453 | "@vscode/test-cli": "^0.0.10", 454 | "@vscode/test-electron": "^2.4.1", 455 | "autoprefixer": "^10.4.20", 456 | "cpy-cli": "^5.0.0", 457 | "eslint": "^9.16.0", 458 | "husky": "^9.1.6", 459 | "lint-staged": "^15.2.10", 460 | "postcss": "^8.4.47", 461 | "release-it": "^18.1.1", 462 | "rimraf": "^6.0.1", 463 | "tailwindcss": "^3.4.14", 464 | "typescript": "^5.7.2", 465 | "vite": "^5.4.10", 466 | "vscode-test": "^1.6.1" 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /package.nls.de.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsonFlow.enable": "JSON Flow aktivieren", 3 | "jsonFlow.files.include": "Glob-Muster, die im Paket enthalten sein sollen. Der Standardwert ist json und jsonc", 4 | "jsonFlow.files.exclude": "Glob-Muster, die aus dem Paket ausgeschlossen werden sollen. Der Standardwert ist node_modules, dist, out, build und alle versteckten Dateien", 5 | "jsonFlow.files.showPath": "Den Dateipfad im Namen der Liste der generierten Dateien anzeigen", 6 | "jsonFlow.graph.showValues": "Die Werte der Knoten im Diagramm anzeigen", 7 | "jsonFlow.graph.nodeWidth": "Breite der Knoten im Diagramm. Der Standardwert ist 200", 8 | "jsonFlow.graph.nodeHeight": "Höhe der Knoten im Diagramm. Der Standardwert ist 50", 9 | "jsonFlow.graph.nodeBorderColor": "Farbe des Knotenrahmens im Diagramm. Der Standardwert ist 'white'", 10 | "jsonFlow.graph.nodeColor": "Farbe des Knotenfülls im Diagramm. Der Standardwert ist 'white'", 11 | "jsonFlow.graph.edgeColor": "Farbe der Kanten im Diagramm. Der Standardwert ist 'white'", 12 | "jsonFlow.graph.layoutDirection": "Layoutrichtung des Diagramms. TB für von oben nach unten und LR für von links nach rechts", 13 | "jsonFlow.image.folder": "Ordner, in dem die Diagramme gespeichert werden. Der Standardwert ist json-flow/images", 14 | "jsonFlow.files.refreshList": "Liste aktualisieren", 15 | "jsonFlow.files.openFile": "Datei öffnen", 16 | "jsonFlow.files.convertToJson": "In JSON konvertieren", 17 | "jsonFlow.files.convertPartialToJson": "Auswahl in JSON konvertieren", 18 | "jsonFlow.files.convertToType": "In Typ oder Struktur umwandeln", 19 | "jsonFlow.files.convertPartialToType": "Auswahl in Typ oder Struktur umwandeln", 20 | "jsonFlow.files.copyContent": "Inhalt in Zwischenablage kopieren", 21 | "jsonFlow.files.copyContentAsJson": "Inhalt als JSON kopieren", 22 | "jsonFlow.files.copyContentPartialAsJson": "Auswahl als JSON kopieren", 23 | "jsonFlow.files.getFileProperties": "Dateieigenschaften abrufen", 24 | "jsonFlow.json.showPreview": "JSON-Vorschau anzeigen", 25 | "jsonFlow.json.showPartialPreview": "Auswahl als JSON anzeigen", 26 | "jsonFlow.filesView": "Dateiliste", 27 | "jsonFlow.feedbackView": "Hilfe und Feedback", 28 | "viewsWelcome.jsonFlow.filesView": "Um Dateien effektiv zu erfassen, stellen Sie sicher, dass Sie den Dateityp in den Einstellungen des Arbeitsbereichs einschließen.\n[Arbeitsbereichseinstellung öffnen](command:workbench.action.openWorkspaceSettingsFile)\nWeitere Informationen zur Verwendung von JSON Flow [finden Sie in unserer Dokumentation](https://github.com/ManuelGil/vscode-json-flow)." 29 | } 30 | -------------------------------------------------------------------------------- /package.nls.es.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsonFlow.enable": "Activar JSON Flow", 3 | "jsonFlow.files.include": "Patrones Glob para incluir en el paquete. El valor predeterminado es json y jsonc", 4 | "jsonFlow.files.exclude": "Patrones Glob para excluir del paquete. El valor predeterminado es node_modules, dist, out, build y cualquier archivo oculto", 5 | "jsonFlow.files.showPath": "Mostrar la ruta del archivo en el nombre de la lista de archivos generados", 6 | "jsonFlow.graph.showValues": "Mostrar los valores de los nodos en el gráfico", 7 | "jsonFlow.graph.nodeWidth": "Ancho de los nodos en el gráfico. El valor predeterminado es 200", 8 | "jsonFlow.graph.nodeHeight": "Altura de los nodos en el gráfico. El valor predeterminado es 50", 9 | "jsonFlow.graph.nodeBorderColor": "Color del borde de los nodos en el gráfico. El valor predeterminado es 'white'", 10 | "jsonFlow.graph.nodeColor": "Color de relleno de los nodos en el gráfico. El valor predeterminado es 'white'", 11 | "jsonFlow.graph.edgeColor": "Color de los bordes en el gráfico. El valor predeterminado es 'white'", 12 | "jsonFlow.graph.layoutDirection": "Dirección de diseño del gráfico. TB para arriba hacía abajo y LR para izquierda a derecha", 13 | "jsonFlow.image.folder": "Carpeta donde se guardarán los gráficos. El valor predeterminado es json-flow/images", 14 | "jsonFlow.files.refreshList": "Refrescar Lista", 15 | "jsonFlow.files.openFile": "Abrir Archivo", 16 | "jsonFlow.files.convertToJson": "Convertir a JSON", 17 | "jsonFlow.files.convertPartialToJson": "Convertir Selección a JSON", 18 | "jsonFlow.files.convertToType": "Convertir a Tipo o Estructura", 19 | "jsonFlow.files.convertPartialToType": "Convertir Selección a Tipo o Estructura", 20 | "jsonFlow.files.copyContent": "Copiar Contenido al Portapapeles", 21 | "jsonFlow.files.copyContentAsJson": "Copiar Contenido como JSON", 22 | "jsonFlow.files.copyContentPartialAsJson": "Copiar Selección como JSON", 23 | "jsonFlow.files.getFileProperties": "Obtener Propiedades del Archivo", 24 | "jsonFlow.json.showPreview": "Mostrar Vista Previa de JSON", 25 | "jsonFlow.json.showPartialPreview": "Mostrar Selección como JSON", 26 | "jsonFlow.filesView": "Lista de Archivos", 27 | "jsonFlow.feedbackView": "Ayuda y Comentarios", 28 | "viewsWelcome.jsonFlow.filesView": "Para capturar archivos de forma efectiva, asegúrese de incluir el tipo de archivo dentro de la configuración del espacio de trabajo.\n[Abrir Configuración del Espacio de Trabajo](command:workbench.action.openWorkspaceSettingsFile)\nPara obtener más información sobre cómo usar JSON Flow [lea nuestra documentación](https://github.com/ManuelGil/vscode-json-flow)." 29 | } 30 | -------------------------------------------------------------------------------- /package.nls.fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsonFlow.enable": "Activer JSON Flow", 3 | "jsonFlow.files.include": "Modèles globaux à inclure dans le paquet. La valeur par défaut est json et jsonc", 4 | "jsonFlow.files.exclude": "Modèles globaux à exclure du paquet. La valeur par défaut est node_modules, dist, out, build et tout fichier caché", 5 | "jsonFlow.files.showPath": "Afficher le chemin du fichier dans le nom de la liste des fichiers générés", 6 | "jsonFlow.graph.showValues": "Afficher les valeurs des nœuds dans le graphique", 7 | "jsonFlow.graph.nodeWidth": "Largeur des nœuds dans le graphique. La valeur par défaut est 200", 8 | "jsonFlow.graph.nodeHeight": "Hauteur des nœuds dans le graphique. La valeur par défaut est 50", 9 | "jsonFlow.graph.nodeBorderColor": "Couleur de la bordure des nœuds dans le graphique. La valeur par défaut est 'white'", 10 | "jsonFlow.graph.nodeColor": "Couleur de remplissage des nœuds dans le graphique. La valeur par défaut est 'white'", 11 | "jsonFlow.graph.edgeColor": "Couleur des bords dans le graphique. La valeur par défaut est 'white'", 12 | "jsonFlow.graph.layoutDirection": "Direction de la disposition du graphique. TB pour de haut en bas et LR pour de gauche à droite", 13 | "jsonFlow.image.folder": "Dossier où les graphiques seront enregistrés. La valeur par défaut est json-flow/images", 14 | "jsonFlow.files.refreshList": "Actualiser la liste", 15 | "jsonFlow.files.openFile": "Ouvrir le fichier", 16 | "jsonFlow.files.convertToJson": "Convertir en JSON", 17 | "jsonFlow.files.convertPartialToJson": "Convertir la sélection en JSON", 18 | "jsonFlow.files.convertToType": "Convertir en type ou structure", 19 | "jsonFlow.files.convertPartialToType": "Convertir la sélection en type ou structure", 20 | "jsonFlow.files.copyContent": "Copier le contenu dans le presse-papiers", 21 | "jsonFlow.files.copyContentAsJson": "Copier le contenu en tant que JSON", 22 | "jsonFlow.files.copyContentPartialAsJson": "Copier la sélection en tant que JSON", 23 | "jsonFlow.files.getFileProperties": "Obtenir les propriétés du fichier", 24 | "jsonFlow.json.showPreview": "Afficher l'aperçu JSON", 25 | "jsonFlow.json.showPartialPreview": "Afficher la sélection en tant que JSON", 26 | "jsonFlow.filesView": "Liste des fichiers", 27 | "jsonFlow.feedbackView": "Aide et retour", 28 | "viewsWelcome.jsonFlow.filesView": "Pour capturer efficacement des fichiers, assurez-vous d'inclure le type de fichier dans les paramètres de l'espace de travail.\n[Ouvrir les paramètres de l'espace de travail](command:workbench.action.openWorkspaceSettingsFile)\nPour en savoir plus sur l'utilisation de JSON Flow [lisez notre documentation](https://github.com/ManuelGil/vscode-json-flow)." 29 | } 30 | -------------------------------------------------------------------------------- /package.nls.it.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsonFlow.enable": "Abilita JSON Flow", 3 | "jsonFlow.files.include": "Modelli di glob da includere nel pacchetto. L'impostazione predefinita è json e jsonc", 4 | "jsonFlow.files.exclude": "Modelli di glob da escludere dal pacchetto. L'impostazione predefinita è node_modules, dist, out, build e qualsiasi file nascosto", 5 | "jsonFlow.files.showPath": "Mostra il percorso del file nel nome dell'elenco dei file generati", 6 | "jsonFlow.graph.showValues": "Mostra i valori dei nodi nel grafico", 7 | "jsonFlow.graph.nodeWidth": "Larghezza dei nodi nel grafico. Il valore predefinito è 200", 8 | "jsonFlow.graph.nodeHeight": "Altezza dei nodi nel grafico. Il valore predefinito è 50", 9 | "jsonFlow.graph.nodeBorderColor": "Colore del bordo dei nodi nel grafico. Il valore predefinito è 'white'", 10 | "jsonFlow.graph.nodeColor": "Colore di riempimento dei nodi nel grafico. Il valore predefinito è 'white'", 11 | "jsonFlow.graph.edgeColor": "Colore dei bordi nel grafico. Il valore predefinito è 'white'", 12 | "jsonFlow.graph.layoutDirection": "Direzione del layout del grafico. TB per dall'alto in basso e LR per da sinistra a destra", 13 | "jsonFlow.image.folder": "Cartella in cui verranno salvati i grafici. L'impostazione predefinita è json-flow/images", 14 | "jsonFlow.files.refreshList": "Aggiorna Elenco", 15 | "jsonFlow.files.openFile": "Apri File", 16 | "jsonFlow.files.convertToJson": "Converti in JSON", 17 | "jsonFlow.files.convertPartialToJson": "Converti Selezione in JSON", 18 | "jsonFlow.files.convertToType": "Converti in Tipo o Struttura", 19 | "jsonFlow.files.convertPartialToType": "Converti Selezione in Tipo o Struttura", 20 | "jsonFlow.files.copyContent": "Copia Contenuto negli Appunti", 21 | "jsonFlow.files.copyContentAsJson": "Copia Contenuto come JSON", 22 | "jsonFlow.files.copyContentPartialAsJson": "Copia Selezione come JSON", 23 | "jsonFlow.files.getFileProperties": "Ottieni Proprietà del File", 24 | "jsonFlow.json.showPreview": "Mostra Anteprima JSON", 25 | "jsonFlow.json.showPartialPreview": "Mostra Selezione come JSON", 26 | "jsonFlow.filesView": "Elenco dei File", 27 | "jsonFlow.feedbackView": "Aiuto e Feedback", 28 | "viewsWelcome.jsonFlow.filesView": "Per catturare efficacemente i file, assicurati di includere il tipo di file nelle impostazioni dello spazio di lavoro.\n[Apri Impostazioni dello Spazio di Lavoro](command:workbench.action.openWorkspaceSettingsFile)\nPer saperne di più su come utilizzare JSON Flow [leggi la nostra documentazione](https://github.com/ManuelGil/vscode-json-flow)." 29 | } 30 | -------------------------------------------------------------------------------- /package.nls.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsonFlow.enable": "Enable JSON Flow", 3 | "jsonFlow.files.include": "Glob patterns to include in the package. The default is json and jsonc", 4 | "jsonFlow.files.exclude": "Glob patterns to exclude from the package. The default is node_modules, dist, out, build, and any hidden files", 5 | "jsonFlow.files.showPath": "Show the path of the file in the name of the list of generated files", 6 | "jsonFlow.graph.showValues": "Show the values of the nodes in the graph", 7 | "jsonFlow.graph.nodeWidth": "Width of the nodes in the graph. The default is 200", 8 | "jsonFlow.graph.nodeHeight": "Height of the nodes in the graph. The default is 50", 9 | "jsonFlow.graph.nodeBorderColor": "Color of the border of the nodes in the graph. The default is 'white'", 10 | "jsonFlow.graph.nodeColor": "Color of the fill of the nodes in the graph. The default is 'white'", 11 | "jsonFlow.graph.edgeColor": "Color of the edges in the graph. The default is 'white'", 12 | "jsonFlow.graph.layoutDirection": "Graph layout direction. TB for top to bottom and LR for left to right", 13 | "jsonFlow.image.folder": "Folder where the graphs will be saved. The default is json-flow/images", 14 | "jsonFlow.files.refreshList": "Refresh List", 15 | "jsonFlow.files.openFile": "Open File", 16 | "jsonFlow.files.convertToJson": "Convert to JSON", 17 | "jsonFlow.files.convertPartialToJson": "Convert Selection to JSON", 18 | "jsonFlow.files.convertToType": "Convert to Type or Structure", 19 | "jsonFlow.files.convertPartialToType": "Convert Selection to Type or Structure", 20 | "jsonFlow.files.copyContent": "Copy Content to Clipboard", 21 | "jsonFlow.files.copyContentAsJson": "Copy Content as JSON", 22 | "jsonFlow.files.copyContentPartialAsJson": "Copy Selection as JSON", 23 | "jsonFlow.files.getFileProperties": "Get File Properties", 24 | "jsonFlow.json.showPreview": "Show JSON Preview", 25 | "jsonFlow.json.showPartialPreview": "Show Selection as JSON", 26 | "jsonFlow.filesView": "List of Files", 27 | "jsonFlow.feedbackView": "Help and Feedback", 28 | "viewsWelcome.jsonFlow.filesView": "To effectively capture files, ensure you include the file type within the workspace settings.\n[Open Workspace Setting](command:workbench.action.openWorkspaceSettingsFile)\nTo learn more about how to use the JSON Flow [read our docs](https://github.com/ManuelGil/vscode-json-flow)." 29 | } 30 | -------------------------------------------------------------------------------- /package.nls.pt-br.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsonFlow.enable": "Ativar JSON Flow", 3 | "jsonFlow.files.include": "Padrões Glob para incluir no pacote. O padrão é json e jsonc", 4 | "jsonFlow.files.exclude": "Padrões Glob para excluir do pacote. O padrão é node_modules, dist, out, build e quaisquer arquivos ocultos", 5 | "jsonFlow.files.showPath": "Mostrar o caminho do arquivo no nome da lista de arquivos gerados", 6 | "jsonFlow.graph.showValues": "Mostrar os valores dos nós no gráfico", 7 | "jsonFlow.graph.nodeWidth": "Largura dos nós no gráfico. O padrão é 200", 8 | "jsonFlow.graph.nodeHeight": "Altura dos nós no gráfico. O padrão é 50", 9 | "jsonFlow.graph.nodeBorderColor": "Cor da borda dos nós no gráfico. O padrão é 'white'", 10 | "jsonFlow.graph.nodeColor": "Cor do preenchimento dos nós no gráfico. O padrão é 'white'", 11 | "jsonFlow.graph.edgeColor": "Cor das bordas no gráfico. O padrão é 'white'", 12 | "jsonFlow.graph.layoutDirection": "Direção do layout do gráfico. TB para de cima para baixo e LR para da esquerda para a direita", 13 | "jsonFlow.image.folder": "Pasta onde os gráficos serão salvos. O padrão é json-flow/images", 14 | "jsonFlow.files.refreshList": "Atualizar Lista", 15 | "jsonFlow.files.openFile": "Abrir Arquivo", 16 | "jsonFlow.files.convertToJson": "Converter para JSON", 17 | "jsonFlow.files.convertPartialToJson": "Converter Seleção para JSON", 18 | "jsonFlow.files.convertToType": "Converter para Tipo ou Estrutura", 19 | "jsonFlow.files.convertPartialToType": "Converter Seleção para Tipo ou Estrutura", 20 | "jsonFlow.files.copyContent": "Copiar Conteúdo para a Área de Transferência", 21 | "jsonFlow.files.copyContentAsJson": "Copiar Conteúdo como JSON", 22 | "jsonFlow.files.copyContentPartialAsJson": "Copiar Seleção como JSON", 23 | "jsonFlow.files.getFileProperties": "Obter Propriedades do Arquivo", 24 | "jsonFlow.json.showPreview": "Mostrar Visualização JSON", 25 | "jsonFlow.json.showPartialPreview": "Mostrar Seleção como JSON", 26 | "jsonFlow.filesView": "Lista de Arquivos", 27 | "jsonFlow.feedbackView": "Ajuda e Feedback", 28 | "viewsWelcome.jsonFlow.filesView": "Para capturar efetivamente arquivos, certifique-se de incluir o tipo de arquivo nas configurações do espaço de trabalho.\n[Abrir Configurações do Espaço de Trabalho](command:workbench.action.openWorkspaceSettingsFile)\nPara saber mais sobre como usar o JSON Flow [leia nossa documentação](https://github.com/ManuelGil/vscode-json-flow)." 29 | } 30 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /schemas/config.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "jsonFlow.enable": { 6 | "type": "string", 7 | "default": "Enable JSON Flow", 8 | "description": "Enable JSON Flow" 9 | }, 10 | "jsonFlow.files.include": { 11 | "type": "array", 12 | "default": [ 13 | "json", 14 | "jsonc", 15 | "json5", 16 | "cfg", 17 | "csv", 18 | "env", 19 | "hcl", 20 | "ini", 21 | "properties", 22 | "toml", 23 | "tsv", 24 | "xml", 25 | "yaml", 26 | "yml" 27 | ], 28 | "scope": "resource", 29 | "description": "Glob patterns to include in the package." 30 | }, 31 | "jsonFlow.files.exclude": { 32 | "type": "array", 33 | "default": [ 34 | "**/node_modules/**", 35 | "**/dist/**", 36 | "**/out/**", 37 | "**/build/**", 38 | "**/vendor/**" 39 | ], 40 | "scope": "resource", 41 | "description": "Glob patterns to exclude from the package. The default is node_modules, dist, out, build, and any hidden files." 42 | }, 43 | "jsonFlow.files.showPath": { 44 | "type": "boolean", 45 | "default": true, 46 | "scope": "resource", 47 | "description": "Show the path of the file in the name of the list of generated files" 48 | }, 49 | "jsonFlow.graph.showValues": { 50 | "type": "boolean", 51 | "default": true, 52 | "scope": "resource", 53 | "description": "Show the values of the nodes in the graph" 54 | }, 55 | "jsonFlow.graph.nodeWidth": { 56 | "type": "number", 57 | "default": 200, 58 | "scope": "resource", 59 | "description": "Width of the nodes in the graph" 60 | }, 61 | "jsonFlow.graph.nodeHeight": { 62 | "type": "number", 63 | "default": 50, 64 | "scope": "resource", 65 | "description": "Height of the nodes in the graph" 66 | }, 67 | "jsonFlow.graph.nodeBorderColor": { 68 | "type": "string", 69 | "default": "white", 70 | "scope": "resource", 71 | "description": "Color of the border of the nodes in the graph" 72 | }, 73 | "jsonFlow.graph.nodeColor": { 74 | "type": "string", 75 | "default": "white", 76 | "scope": "resource", 77 | "description": "Color of the fill of the nodes in the graph" 78 | }, 79 | "jsonFlow.graph.edgeColor": { 80 | "type": "string", 81 | "default": "white", 82 | "scope": "resource", 83 | "description": "Color of the edges in the graph" 84 | }, 85 | "jsonFlow.graph.layoutDirection": { 86 | "type": "string", 87 | "default": "TB", 88 | "enum": ["TB", "LR"], 89 | "scope": "resource", 90 | "description": "The direction of the layout of the graph. TB is top to bottom, LR is left to right." 91 | }, 92 | "jsonFlow.image.folder": { 93 | "type": "string", 94 | "default": "json-flow/images", 95 | "scope": "resource", 96 | "description": "The folder where the graphs will be saved." 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/app/configs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/src/app/configs/.gitkeep -------------------------------------------------------------------------------- /src/app/configs/constants.config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * EXTENSION_ID: The unique identifier of the extension. 3 | * @type {string} 4 | * @public 5 | * @memberof Constants 6 | * @example 7 | * console.log(EXTENSION_ID); 8 | * 9 | * @returns {string} - The unique identifier of the extension 10 | */ 11 | export const EXTENSION_ID: string = 'jsonFlow'; 12 | 13 | /** 14 | * EXTENSION_NAME: The name of the extension. 15 | * @type {string} 16 | * @public 17 | * @memberof Constants 18 | * @example 19 | * console.log(EXTENSION_NAME); 20 | * 21 | * @returns {string} - The name of the extension 22 | */ 23 | export const EXTENSION_NAME: string = 'JSON Flow'; 24 | 25 | /** 26 | * USER_PUBLISHER: The publisher of the extension. 27 | * @type {string} 28 | * @public 29 | * @memberof Constants 30 | * @example 31 | * console.log(USER_PUBLISHER); 32 | * 33 | * @returns {string} - The publisher of the extension 34 | */ 35 | export const USER_PUBLISHER: string = 'imgildev'; 36 | 37 | /** 38 | * EXTENSION_REPOSITORY_URL: The repository URL of the extension. 39 | * @type {string} 40 | * @public 41 | * @memberof Constants 42 | * @example 43 | * console.log(EXTENSION_REPOSITORY_URL); 44 | * 45 | * @returns {string} - The repository URL of the extension 46 | */ 47 | export const EXTENSION_REPOSITORY_URL: string = 48 | 'https://github.com/ManuelGil/vscode-json-flow'; 49 | 50 | /** 51 | * EXTENSION_MARKETPLACE_URL: The marketplace URL of the extension. 52 | * @type {string} 53 | * @public 54 | * @memberof Constants 55 | * @example 56 | * console.log(EXTENSION_MARKETPLACE_URL); 57 | * 58 | * @returns {string} - The marketplace URL of the extension 59 | */ 60 | export const EXTENSION_MARKETPLACE_URL: string = 61 | 'https://marketplace.visualstudio.com/items?itemName=imgildev.vscode-json-flow'; 62 | 63 | /** 64 | * EXTENSION_BUGS_URL: The bugs URL of the extension. 65 | * @type {string} 66 | * @public 67 | * @memberof Constants 68 | * @example 69 | * console.log(EXTENSION_BUGS_URL); 70 | * 71 | * @returns {string} - The bugs URL of the extension 72 | */ 73 | export const EXTENSION_BUGS_URL: string = 74 | 'https://github.com/ManuelGil/vscode-json-flow/issues'; 75 | 76 | /** 77 | * INCLUDE: The files to include. 78 | * @type {string[]} 79 | * @public 80 | * @memberof Constants 81 | * @example 82 | * console.log(INCLUDE); 83 | * 84 | * @returns {string[]} - The files to include 85 | */ 86 | export const INCLUDE: string[] = [ 87 | 'json', 88 | 'jsonc', 89 | 'json5', 90 | 'cfg', 91 | 'csv', 92 | 'env', 93 | 'hcl', 94 | 'ini', 95 | 'properties', 96 | 'toml', 97 | 'tsv', 98 | 'xml', 99 | 'yaml', 100 | 'yml', 101 | ]; 102 | 103 | /** 104 | * EXCLUDE: The files to exclude. 105 | * @type {string[]} 106 | * @public 107 | * @memberof Constants 108 | * @example 109 | * console.log(EXCLUDE); 110 | * 111 | * @returns {string[]} - The files to exclude 112 | */ 113 | export const EXCLUDE: string[] = [ 114 | '**/node_modules/**', 115 | '**/dist/**', 116 | '**/out/**', 117 | '**/build/**', 118 | '**/vendor/**', 119 | ]; 120 | 121 | /** 122 | * SHOW_PATH: Whether to show the path or not. 123 | * @type {boolean} 124 | * @public 125 | * @memberof Constants 126 | * @example 127 | * console.log(SHOW_PATH); 128 | * 129 | * @returns {boolean} - Whether to show the path or not 130 | */ 131 | export const SHOW_PATH: boolean = true; 132 | 133 | /** 134 | * SHOW_VALUES: Whether to show the values or not. 135 | * @type {boolean} 136 | * @public 137 | * @memberof Constants 138 | * @example 139 | * console.log(SHOW_VALUES); 140 | * 141 | * @returns {boolean} - Whether to show the values or not 142 | */ 143 | export const SHOW_VALUES: boolean = true; 144 | 145 | /** 146 | * NODE_WIDTH: The node width. 147 | * @type {number} 148 | * @public 149 | * @memberof Constants 150 | * @example 151 | * console.log(NODE_WIDTH); 152 | * 153 | * @returns {number} - The node width 154 | */ 155 | export const NODE_WIDTH: number = 200; 156 | 157 | /** 158 | * NODE_HEIGHT: The node height. 159 | * @type {number} 160 | * @public 161 | * @memberof Constants 162 | * @example 163 | * console.log(NODE_HEIGHT); 164 | * 165 | * @returns {number} - The node height 166 | */ 167 | export const NODE_HEIGHT: number = 50; 168 | 169 | /** 170 | * NODE_BORDER_COLOR: The node border color. 171 | * @type {string} 172 | * @public 173 | * @memberof Constants 174 | * @example 175 | * console.log(NODE_BORDER_COLOR); 176 | * 177 | * @returns {string} - The node border color 178 | */ 179 | export const NODE_BORDER_COLOR = 'white'; 180 | 181 | /** 182 | * NODE_COLOR: The node color. 183 | * @type {string} 184 | * @public 185 | * @memberof Constants 186 | * @example 187 | * console.log(NODE_COLOR); 188 | * 189 | * @returns {string} - The node color 190 | */ 191 | export const NODE_COLOR = 'white'; 192 | 193 | /** 194 | * EDGE_COLOR: The edge color. 195 | * @type {string} 196 | * @public 197 | * @memberof Constants 198 | * @example 199 | * console.log(EDGE_COLOR); 200 | * 201 | * @returns {string} - The edge color 202 | */ 203 | export const EDGE_COLOR = 'white'; 204 | 205 | /** 206 | * LAYOUT_DIRECTION: The layout direction. 207 | * @type {string} 208 | * @public 209 | * @memberof Constants 210 | * @example 211 | * console.log(LAYOUT_DIRECTION); 212 | * 213 | * @returns {string} - The layout direction 214 | */ 215 | export const LAYOUT_DIRECTION: 'TB' | 'LR' = 'TB'; 216 | 217 | /** 218 | * IMAGE_FOLDER: The image folder. 219 | * @type {string} 220 | * @public 221 | * @memberof Constants 222 | * @example 223 | * console.log(IMAGE_FOLDER); 224 | * 225 | * @returns {string} - The image folder 226 | */ 227 | export const IMAGE_FOLDER: string = 'json-flow/images'; 228 | -------------------------------------------------------------------------------- /src/app/configs/extension.config.ts: -------------------------------------------------------------------------------- 1 | import { WorkspaceConfiguration } from 'vscode'; 2 | 3 | import { 4 | EDGE_COLOR, 5 | EXCLUDE, 6 | IMAGE_FOLDER, 7 | INCLUDE, 8 | LAYOUT_DIRECTION, 9 | NODE_BORDER_COLOR, 10 | NODE_COLOR, 11 | NODE_HEIGHT, 12 | NODE_WIDTH, 13 | SHOW_PATH, 14 | SHOW_VALUES, 15 | } from './constants.config'; 16 | 17 | /** 18 | * The Config class. 19 | * 20 | * @class 21 | * @classdesc The class that represents the configuration of the extension. 22 | * @export 23 | * @public 24 | * @property {WorkspaceConfiguration} config - The workspace configuration 25 | * @property {boolean} enable - Whether the extension is enabled or not 26 | * @property {string[]} include - The files to include 27 | * @property {string[]} exclude - The files to exclude 28 | * @property {boolean} showPath - Whether to show the path or not 29 | * @property {boolean} showValues - Whether to show the values or not 30 | * @property {number} nodeWidth - The node width 31 | * @property {number} nodeHeight - The node height 32 | * @property {string} nodeBorderColor - The node border color 33 | * @property {string} nodeColor - The node color 34 | * @property {string} edgeColor - The edge color 35 | * @property {'TB' | 'LR'} layoutDirection - The layout direction 36 | * @property {string} imageFolder - The image folder 37 | * @example 38 | * const config = new Config(workspace.getConfiguration()); 39 | * console.log(config.include); 40 | * console.log(config.exclude); 41 | */ 42 | export class ExtensionConfig { 43 | // ----------------------------------------------------------------- 44 | // Properties 45 | // ----------------------------------------------------------------- 46 | 47 | // Public properties 48 | /** 49 | * Whether the extension is enabled or not. 50 | * @type {boolean} 51 | * @public 52 | * @memberof ExtensionConfig 53 | * @example 54 | * const config = new ExtensionConfig(workspace.getConfiguration()); 55 | * console.log(config.enable); 56 | */ 57 | enable: boolean; 58 | 59 | /** 60 | * The files to include. 61 | * @type {string[]} 62 | * @public 63 | * @memberof Config 64 | * @example 65 | * const config = new Config(workspace.getConfiguration()); 66 | * console.log(config.include); 67 | */ 68 | include: string[]; 69 | /** 70 | * The files to exclude. 71 | * @type {string[]} 72 | * @public 73 | * @memberof Config 74 | * @example 75 | * const config = new Config(workspace.getConfiguration()); 76 | * console.log(config.exclude); 77 | */ 78 | exclude: string[]; 79 | /** 80 | * Whether to show the path or not. 81 | * @type {boolean} 82 | * @public 83 | * @memberof Config 84 | * @example 85 | * const config = new Config(workspace.getConfiguration()); 86 | * console.log(config.showPath); 87 | */ 88 | showPath: boolean; 89 | /** 90 | * Whether to show the values or not. 91 | * @type {boolean} 92 | * @public 93 | * @memberof Config 94 | * @example 95 | * const config = new Config(workspace.getConfiguration()); 96 | * console.log(config.showValues); 97 | */ 98 | showValues: boolean; 99 | /** 100 | * The node width. 101 | * @type {number} 102 | * @public 103 | * @memberof Config 104 | * @example 105 | * const config = new Config(workspace.getConfiguration()); 106 | * console.log(config.nodeWidth); 107 | */ 108 | nodeWidth: number; 109 | /** 110 | * The node height. 111 | * @type {number} 112 | * @public 113 | * @memberof Config 114 | * @example 115 | * const config = new Config(workspace.getConfiguration()); 116 | * console.log(config.nodeHeight); 117 | */ 118 | nodeHeight: number; 119 | /** 120 | * The node border color. 121 | * @type {string} 122 | * @public 123 | * @memberof Config 124 | * @example 125 | * const config = new Config(workspace.getConfiguration()); 126 | * console.log(config.nodeBorderColor); 127 | */ 128 | nodeBorderColor: string; 129 | /** 130 | * The node color. 131 | * @type {string} 132 | * @public 133 | * @memberof Config 134 | * @example 135 | * const config = new Config(workspace.getConfiguration()); 136 | * console.log(config.nodeColor); 137 | */ 138 | nodeColor: string; 139 | /** 140 | * The edge color. 141 | * @type {string} 142 | * @public 143 | * @memberof Config 144 | * @example 145 | * const config = new Config(workspace.getConfiguration()); 146 | * console.log(config.edgeColor); 147 | */ 148 | edgeColor: string; 149 | /** 150 | * The layout direction. 151 | * @type {'TB' | 'LR'} 152 | * @public 153 | * @memberof Config 154 | * @example 155 | * const config = new Config(workspace.getConfiguration()); 156 | * console.log(config.layoutDirection); 157 | */ 158 | layoutDirection: 'TB' | 'LR'; 159 | /** 160 | * The image folder. 161 | * @type {string} 162 | * @public 163 | * @memberof Config 164 | * @example 165 | * const config = new Config(workspace.getConfiguration()); 166 | * console.log(config.imageFolder); 167 | */ 168 | imageFolder: string; 169 | 170 | // ----------------------------------------------------------------- 171 | // Constructor 172 | // ----------------------------------------------------------------- 173 | 174 | /** 175 | * Constructor for the Config class. 176 | * 177 | * @constructor 178 | * @param {WorkspaceConfiguration} config - The workspace configuration 179 | * @public 180 | * @memberof Config 181 | */ 182 | constructor(readonly config: WorkspaceConfiguration) { 183 | this.enable = config.get('enable', true); 184 | this.include = config.get('files.include', INCLUDE); 185 | this.exclude = config.get('files.exclude', EXCLUDE); 186 | this.showPath = config.get('files.showPath', SHOW_PATH); 187 | this.showValues = config.get('graph.showValues', SHOW_VALUES); 188 | this.nodeWidth = config.get('graph.nodeWidth', NODE_WIDTH); 189 | this.nodeHeight = config.get('graph.nodeHeight', NODE_HEIGHT); 190 | this.nodeBorderColor = config.get( 191 | 'graph.nodeBorderColor', 192 | NODE_BORDER_COLOR, 193 | ); 194 | this.nodeColor = config.get('graph.nodeColor', NODE_COLOR); 195 | this.edgeColor = config.get('graph.edgeColor', EDGE_COLOR); 196 | this.layoutDirection = config.get<'TB' | 'LR'>( 197 | 'graph.layoutDirection', 198 | LAYOUT_DIRECTION, 199 | ); 200 | this.imageFolder = config.get('image.folder', IMAGE_FOLDER); 201 | } 202 | 203 | // ----------------------------------------------------------------- 204 | // Methods 205 | // ----------------------------------------------------------------- 206 | 207 | // Public methods 208 | /** 209 | * The update method. 210 | * 211 | * @function update 212 | * @param {WorkspaceConfiguration} config - The workspace configuration 213 | * @public 214 | * @memberof Config 215 | * @example 216 | * const config = new Config(workspace.getConfiguration()); 217 | * config.update(workspace.getConfiguration()); 218 | */ 219 | update(config: WorkspaceConfiguration): void { 220 | this.enable = config.get('enable', this.enable); 221 | this.include = config.get('files.include', this.include); 222 | this.exclude = config.get('files.exclude', this.exclude); 223 | this.showPath = config.get('files.showPath', this.showPath); 224 | this.showValues = config.get('graph.showValues', this.showValues); 225 | this.nodeWidth = config.get('graph.nodeWidth', this.nodeWidth); 226 | this.nodeHeight = config.get('graph.nodeHeight', this.nodeHeight); 227 | this.nodeBorderColor = config.get( 228 | 'graph.nodeBorderColor', 229 | this.nodeBorderColor, 230 | ); 231 | this.nodeColor = config.get('graph.nodeColor', this.nodeColor); 232 | this.edgeColor = config.get('graph.edgeColor', this.edgeColor); 233 | this.layoutDirection = config.get<'TB' | 'LR'>( 234 | 'graph.layoutDirection', 235 | this.layoutDirection, 236 | ); 237 | this.imageFolder = config.get('image.folder', this.imageFolder); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/app/configs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants.config'; 2 | export * from './extension.config'; 3 | -------------------------------------------------------------------------------- /src/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/src/app/controllers/.gitkeep -------------------------------------------------------------------------------- /src/app/controllers/feedback.controller.ts: -------------------------------------------------------------------------------- 1 | import { Uri, env } from 'vscode'; 2 | 3 | import { EXTENSION_BUGS_URL, EXTENSION_MARKETPLACE_URL } from '../configs'; 4 | 5 | /** 6 | * The FeedbackController class. 7 | * 8 | * @class 9 | * @classdesc The class that represents the feedback controller. 10 | * @export 11 | * @public 12 | * @example 13 | * const controller = new FeedbackController(); 14 | */ 15 | export class FeedbackController { 16 | // ----------------------------------------------------------------- 17 | // Methods 18 | // ----------------------------------------------------------------- 19 | 20 | // Public methods 21 | /** 22 | * The reportIssues method. 23 | * 24 | * @function reportIssues 25 | * @public 26 | * @memberof FeedbackController 27 | * 28 | * @returns {void} - No return value 29 | */ 30 | reportIssues(): void { 31 | env.openExternal(Uri.parse(EXTENSION_BUGS_URL)); 32 | } 33 | 34 | /** 35 | * The rateUs method. 36 | * 37 | * @function rateUs 38 | * @public 39 | * @memberof FeedbackController 40 | * 41 | * @returns {void} - No return value 42 | */ 43 | rateUs(): void { 44 | env.openExternal( 45 | Uri.parse(`${EXTENSION_MARKETPLACE_URL}&ssr=false#review-details`), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/app/controllers/files.controller.ts: -------------------------------------------------------------------------------- 1 | import fg from 'fast-glob'; 2 | import { Range, ThemeIcon, Uri, env, l10n, window, workspace } from 'vscode'; 3 | 4 | import { EXTENSION_ID, ExtensionConfig } from '../configs'; 5 | import { FileType, isFileTypeSupported, parseJSONContent } from '../helpers'; 6 | import { NodeModel } from '../models'; 7 | 8 | /** 9 | * The FilesController class. 10 | * 11 | * @class 12 | * @classdesc The class that represents the list files controller. 13 | * @export 14 | * @public 15 | * @property {ExtensionConfig} config - The configuration object 16 | * @example 17 | * const controller = new FilesController(config); 18 | */ 19 | export class FilesController { 20 | // ----------------------------------------------------------------- 21 | // Constructor 22 | // ----------------------------------------------------------------- 23 | 24 | /** 25 | * Constructor for the FilesController class 26 | * 27 | * @constructor 28 | * @param {ExtensionConfig} config - The configuration object 29 | * @public 30 | * @memberof FilesController 31 | */ 32 | constructor(readonly config: ExtensionConfig) {} 33 | 34 | // ----------------------------------------------------------------- 35 | // Methods 36 | // ----------------------------------------------------------------- 37 | 38 | // Public methods 39 | /** 40 | * The getFiles method. 41 | * 42 | * @function getFiles 43 | * @public 44 | * @async 45 | * @memberof FilesController 46 | * @example 47 | * controller.getFiles(); 48 | * 49 | * @returns {Promise} - The list of files 50 | */ 51 | async getFiles(): Promise { 52 | // Get the files in the folder 53 | let folders: string[] = []; 54 | let files: Uri[] = []; 55 | 56 | if (!workspace.workspaceFolders) { 57 | const message = l10n.t('Operation cancelled!'); 58 | window.showErrorMessage(message); 59 | return; 60 | } 61 | 62 | folders = workspace.workspaceFolders.map((folder) => folder.uri.fsPath); 63 | 64 | const { include, exclude } = this.config; 65 | 66 | const includedFilePatterns = `**/*.{${include.join(',')}}`; 67 | const excludedFilePatterns = Array.isArray(exclude) ? exclude : [exclude]; 68 | 69 | for (const folder of folders) { 70 | const result = await this.findFiles( 71 | folder, 72 | [includedFilePatterns], 73 | excludedFilePatterns, 74 | ); 75 | 76 | files.push(...result); 77 | } 78 | 79 | if (files.length !== 0) { 80 | const nodes: NodeModel[] = []; 81 | 82 | files.sort((a, b) => a.path.localeCompare(b.path)); 83 | 84 | for (const file of files) { 85 | const document = await workspace.openTextDocument(file); 86 | 87 | const path = workspace.asRelativePath(document.fileName); 88 | let filename = path.split('/').pop(); 89 | 90 | if (filename && this.config.showPath) { 91 | const folder = path.split('/').slice(0, -1).join('/'); 92 | 93 | filename += folder ? ` (${folder})` : ' (root)'; 94 | } 95 | 96 | nodes.push( 97 | new NodeModel( 98 | filename ?? 'Untitled', 99 | new ThemeIcon('file'), 100 | { 101 | command: `${EXTENSION_ID}.json.showPreview`, 102 | title: 'Open Preview', 103 | arguments: [document.uri], 104 | }, 105 | document.uri, 106 | document.fileName, 107 | ), 108 | ); 109 | } 110 | 111 | return nodes; 112 | } 113 | 114 | return; 115 | } 116 | 117 | /** 118 | * The openFile method. 119 | * 120 | * @function openFile 121 | * @param {NodeModel} node - The node model 122 | * @public 123 | * @memberof FilesController 124 | * @example 125 | * controller.openFile('file:///path/to/file'); 126 | * 127 | * @returns {Promise} - The promise 128 | */ 129 | openFile(node: NodeModel) { 130 | if (node.resourceUri) { 131 | workspace.openTextDocument(node.resourceUri).then((filename) => { 132 | window.showTextDocument(filename); 133 | }); 134 | } 135 | } 136 | 137 | /** 138 | * The copyContent method. 139 | * 140 | * @function copyContent 141 | * @param {NodeModel} node - The node model 142 | * @public 143 | * @memberof FilesController 144 | * @example 145 | * controller.copyContent('file:///path/to/file'); 146 | * 147 | * @returns {void} - The promise 148 | */ 149 | copyContent(node: NodeModel) { 150 | if (node.resourceUri) { 151 | workspace.openTextDocument(node.resourceUri).then((document) => { 152 | const message = l10n.t('Content copied to clipboard'); 153 | env.clipboard.writeText(document.getText()); 154 | window.showInformationMessage(message); 155 | }); 156 | } 157 | } 158 | 159 | /** 160 | * The copyContentAsJson method. 161 | * 162 | * @function copyContentAsJson 163 | * @param {NodeModel | Uri} node - The node model 164 | * @public 165 | * @memberof FilesController 166 | * @example 167 | * controller.copyContentAsJson('file:///path/to/file'); 168 | * 169 | * @returns {void} - The promise 170 | */ 171 | copyContentAsJson(node: NodeModel) { 172 | if (node) { 173 | // Get the resource URI 174 | const resourceUri = node instanceof NodeModel ? node.resourceUri : node; 175 | 176 | // Check if the resource URI is valid 177 | if (!resourceUri) { 178 | const message = l10n.t('Operation cancelled!'); 179 | window.showErrorMessage(message); 180 | return; 181 | } 182 | 183 | // Open the text document 184 | workspace.openTextDocument(resourceUri).then(async (document) => { 185 | // Get the language ID and file name 186 | const { languageId, fileName } = document; 187 | 188 | // Determine the file type, defaulting to 'json' if unsupported 189 | let fileType = languageId; 190 | 191 | if (!isFileTypeSupported(fileType)) { 192 | const fileExtension = fileName.split('.').pop(); 193 | 194 | fileType = fileExtension; 195 | } 196 | 197 | // Parse JSON content 198 | const jsonContent = parseJSONContent( 199 | document.getText(), 200 | fileType as FileType, 201 | ); 202 | 203 | // Check if the content is null 204 | if (jsonContent === null) { 205 | return; 206 | } 207 | 208 | // Copy the JSON content to the clipboard 209 | env.clipboard.writeText(JSON.stringify(jsonContent, null, 2)); 210 | 211 | // Show the message 212 | const message = l10n.t('Content copied as JSON to clipboard'); 213 | window.showInformationMessage(message); 214 | }); 215 | } 216 | } 217 | 218 | /** 219 | * The copyContentPartialAsJson method. 220 | * 221 | * @function copyContentPartialAsJson 222 | * @public 223 | * @memberof FilesController 224 | * @example 225 | * controller.copyContentPartialAsJson(); 226 | * 227 | * @returns {void} - The promise 228 | */ 229 | copyContentPartialAsJson() { 230 | // Get the active text editor 231 | const editor = window.activeTextEditor; 232 | 233 | // Check if there is an active editor 234 | if (!editor) { 235 | const message = l10n.t('No active editor!'); 236 | window.showErrorMessage(message); 237 | return; 238 | } 239 | 240 | // Check if there is a selection 241 | const selection = editor.selection; 242 | 243 | if (selection.isEmpty) { 244 | const message = l10n.t('No selection!'); 245 | window.showErrorMessage(message); 246 | return; 247 | } 248 | 249 | // Get the selection range 250 | const selectionRange = new Range( 251 | selection.start.line, 252 | selection.start.character, 253 | selection.end.line, 254 | selection.end.character, 255 | ); 256 | 257 | // Get the language ID and file name 258 | const { languageId, fileName } = editor.document; 259 | 260 | let fileType = languageId; 261 | 262 | let text = editor.document.getText(selectionRange); 263 | 264 | if ( 265 | [ 266 | 'javascript', 267 | 'javascriptreact', 268 | 'typescript', 269 | 'typescriptreact', 270 | ].includes(fileType) 271 | ) { 272 | fileType = 'json'; 273 | 274 | text = text 275 | .replace(/'([^']+)'/g, '"$1"') 276 | .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') 277 | .replace(/,*\s*\n*\]/g, ']') 278 | .replace(/{\s*\n*/g, '{') 279 | .replace(/,*\s*\n*};*/g, '}'); 280 | } 281 | 282 | if (!isFileTypeSupported(fileType)) { 283 | const fileExtension = fileName.split('.').pop(); 284 | 285 | fileType = isFileTypeSupported(fileExtension) ? fileExtension : 'jsonc'; 286 | } 287 | 288 | // Parse JSON content 289 | const jsonContent = parseJSONContent(text, fileType as FileType); 290 | 291 | // Check if the JSON content is null 292 | if (jsonContent === null) { 293 | return; 294 | } 295 | 296 | // Copy the JSON content to the clipboard 297 | env.clipboard.writeText(JSON.stringify(jsonContent, null, 2)); 298 | 299 | // Show the message 300 | const message = l10n.t('Content copied as JSON to clipboard'); 301 | window.showInformationMessage(message); 302 | } 303 | 304 | /** 305 | * The getFileProperties method. 306 | * 307 | * @function getFileProperties 308 | * @param {NodeModel} node - The node model 309 | * @public 310 | * @memberof FilesController 311 | * @example 312 | * controller.getFileProperties('file:///path/to/file'); 313 | * 314 | * @returns {void} - The promise 315 | */ 316 | getFileProperties(node: NodeModel) { 317 | if (node.resourceUri) { 318 | workspace.openTextDocument(node.resourceUri).then(async (document) => { 319 | const { fileName, languageId, lineCount, version } = document; 320 | 321 | // Show the message 322 | const message = l10n.t( 323 | 'File Name: {0}\nLanguage: {1}\nLines: {2}\nVersion: {3}', 324 | [fileName, languageId, lineCount, version], 325 | ); 326 | 327 | await window.showInformationMessage(message, { modal: true }); 328 | }); 329 | } 330 | } 331 | 332 | // Private methods 333 | /** 334 | * The findFiles method. 335 | * 336 | * @function findFiles 337 | * @param {string} baseDir - The base directory 338 | * @param {string[]} include - The include pattern 339 | * @param {string[]} exclude - The exclude pattern 340 | * @private 341 | * @async 342 | * @memberof FilesController 343 | * @example 344 | * controller.findFiles('baseDir', ['include'], ['exclude']); 345 | * 346 | * @returns {Promise} - The promise with the files 347 | */ 348 | private async findFiles( 349 | baseDir: string, 350 | include: string[], // Include patterns 351 | exclude: string[], // Exclude patterns 352 | allowRecursion: boolean = true, // Toggle recursive search 353 | ): Promise { 354 | // Configure fast-glob options 355 | const options = { 356 | cwd: baseDir, // Set base directory for searching 357 | absolute: true, // Ensure paths are absolute 358 | onlyFiles: true, // Match only files, not directories 359 | dot: true, // Include files and directories starting with a dot 360 | deep: allowRecursion ? undefined : 1, // Toggle recursion 361 | ignore: exclude, // Exclude patterns 362 | }; 363 | 364 | try { 365 | // Use fast-glob to find matching files 366 | const filePaths = await fg(include, options); 367 | 368 | // Convert file paths to VS Code Uri objects 369 | return filePaths.sort().map((filePath) => Uri.file(filePath)); 370 | } catch (error) { 371 | const message = l10n.t('Error while finding files: {0}', [error]); 372 | window.showErrorMessage(message); 373 | return []; 374 | } 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /src/app/controllers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './feedback.controller'; 2 | export * from './files.controller'; 3 | export * from './json.controller'; 4 | export * from './transform.controller'; 5 | -------------------------------------------------------------------------------- /src/app/controllers/json.controller.ts: -------------------------------------------------------------------------------- 1 | import { existsSync, mkdirSync, writeFileSync } from 'fs'; 2 | import { dirname, join } from 'path'; 3 | import { ExtensionContext, Range, Uri, l10n, window, workspace } from 'vscode'; 4 | import { ExtensionConfig } from '../configs'; 5 | import { 6 | FileType, 7 | generateTree, 8 | isFileTypeSupported, 9 | parseJSONContent, 10 | } from '../helpers'; 11 | import { JSONProvider } from '../providers'; 12 | 13 | /** 14 | * The JsonController class. 15 | * 16 | * @class 17 | * @classdesc The class that represents the JSON controller. 18 | * @export 19 | * @public 20 | * @property {ExtensionContext} context - The extension context 21 | * @example 22 | * const controller = new JsonController(context); 23 | */ 24 | export class JsonController { 25 | // ----------------------------------------------------------------- 26 | // Properties 27 | // ----------------------------------------------------------------- 28 | 29 | // Public properties 30 | /** 31 | * The webview configuration. 32 | * 33 | * @public 34 | * @memberof JsonController 35 | * @type {any} 36 | */ 37 | static webviewConfiguration: { [key: string]: string | number }; 38 | 39 | /** 40 | * The image folder. 41 | * 42 | * @public 43 | * @memberof JsonController 44 | * @type {string} 45 | */ 46 | static imageFolder: string; 47 | 48 | // Private properties 49 | /** 50 | * The preview delay constant. 51 | * @type {number} 52 | * @private 53 | * @memberof JsonController 54 | * @example 55 | * private _processingDelay: number = 1000; 56 | */ 57 | private _processingDelay: number = 1000; // Delay constant for preview initialization 58 | 59 | // ----------------------------------------------------------------- 60 | // Constructor 61 | // ----------------------------------------------------------------- 62 | 63 | /** 64 | * Constructor for the JsonController class 65 | * 66 | * @constructor 67 | * @param {ExtensionContext} context - The extension context 68 | * @public 69 | * @memberof JsonController 70 | */ 71 | constructor( 72 | readonly context: ExtensionContext, 73 | readonly config: ExtensionConfig, 74 | ) { 75 | // Set the webview configuration 76 | JsonController.webviewConfiguration = { 77 | nodeWidth: config.nodeWidth, 78 | nodeHeight: config.nodeHeight, 79 | nodeBorderColor: config.nodeBorderColor, 80 | nodeColor: config.nodeColor, 81 | edgeColor: config.edgeColor, 82 | layoutDirection: config.layoutDirection, 83 | }; 84 | // Set the image folder 85 | JsonController.imageFolder = config.imageFolder; 86 | } 87 | 88 | // ----------------------------------------------------------------- 89 | // Methods 90 | // ----------------------------------------------------------------- 91 | 92 | // Public methods 93 | /** 94 | * The showPreview method. 95 | * 96 | * @function showPreview 97 | * @param {Uri} uri - The URI of the file 98 | * @public 99 | * @memberof JsonController 100 | * @example 101 | * controller.showPreview(uri); 102 | * 103 | * @returns {void} 104 | */ 105 | showPreview(uri: Uri): void { 106 | // Open the text document 107 | workspace.openTextDocument(uri.fsPath).then((document) => { 108 | // Get the language ID and file name 109 | const { languageId, fileName } = document; 110 | 111 | // Determine the file type, defaulting to 'json' if unsupported 112 | let fileType = languageId; 113 | 114 | if (!isFileTypeSupported(fileType)) { 115 | const fileExtension = fileName.split('.').pop(); 116 | 117 | fileType = fileExtension; 118 | } 119 | 120 | // Parse JSON content 121 | const jsonContent = parseJSONContent( 122 | document.getText(), 123 | fileType as FileType, 124 | ); 125 | 126 | // Check if the JSON content is null 127 | if (jsonContent === null) { 128 | return; 129 | } 130 | 131 | // Derive the file name for the preview panel title 132 | const displayName = fileName.split(/[\\/]/).pop() || 'JSON Flow'; 133 | 134 | // Initialize the webview panel 135 | const panel = JSONProvider.createPanel(this.context.extensionUri); 136 | 137 | panel.title = displayName; 138 | 139 | const data = generateTree(jsonContent, this.config.showValues); 140 | 141 | const layoutDirection = this.config.layoutDirection; 142 | 143 | // Post the message to the webview with a delay 144 | setTimeout(() => { 145 | panel.webview.postMessage({ 146 | type: 'setJson', 147 | layoutDirection, 148 | data, 149 | }); 150 | }, this._processingDelay); 151 | }); 152 | } 153 | 154 | /** 155 | * The showPartialPreview method. 156 | * 157 | * @function showPartialPreview 158 | * @public 159 | * @memberof JsonController 160 | * @example 161 | * controller.showPartialPreview(); 162 | * 163 | * @returns {void} 164 | */ 165 | showPartialPreview(): void { 166 | // Get the active text editor 167 | const editor = window.activeTextEditor; 168 | 169 | // Check if there is an active editor 170 | if (!editor) { 171 | const message = l10n.t('No active editor!'); 172 | window.showErrorMessage(message); 173 | return; 174 | } 175 | 176 | // Check if there is a selection 177 | const selection = editor.selection; 178 | 179 | if (selection.isEmpty) { 180 | const message = l10n.t('No selection!'); 181 | window.showErrorMessage(message); 182 | return; 183 | } 184 | 185 | // Get the selection range 186 | const selectionRange = new Range( 187 | selection.start.line, 188 | selection.start.character, 189 | selection.end.line, 190 | selection.end.character, 191 | ); 192 | 193 | // Get the language ID and file name 194 | const { languageId, fileName } = editor.document; 195 | 196 | let fileType = languageId; 197 | 198 | let text = editor.document.getText(selectionRange); 199 | 200 | if ( 201 | [ 202 | 'javascript', 203 | 'javascriptreact', 204 | 'typescript', 205 | 'typescriptreact', 206 | ].includes(fileType) 207 | ) { 208 | fileType = 'json'; 209 | 210 | text = text 211 | .replace(/'([^']+)'/g, '"$1"') 212 | .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') 213 | .replace(/,*\s*\n*\]/g, ']') 214 | .replace(/{\s*\n*/g, '{') 215 | .replace(/,*\s*\n*};*/g, '}'); 216 | } 217 | 218 | if (!isFileTypeSupported(fileType)) { 219 | const fileExtension = fileName.split('.').pop(); 220 | 221 | fileType = isFileTypeSupported(fileExtension) ? fileExtension : 'jsonc'; 222 | } 223 | 224 | // Parse JSON content 225 | const jsonContent = parseJSONContent(text, fileType as FileType); 226 | 227 | // Check if the JSON content is null 228 | if (jsonContent === null) { 229 | return; 230 | } 231 | 232 | // Derive the file name for the preview panel title 233 | const displayName = fileName.split(/[\\/]/).pop() || 'JSON Flow'; 234 | 235 | // Initialize the webview panel 236 | const panel = JSONProvider.createPanel(this.context.extensionUri); 237 | 238 | panel.title = displayName; 239 | 240 | const data = generateTree(jsonContent, this.config.showValues); 241 | 242 | const layoutDirection = this.config.layoutDirection; 243 | 244 | // Post the message to the webview with a delay 245 | setTimeout(() => { 246 | panel.webview.postMessage({ 247 | type: 'setJson', 248 | layoutDirection, 249 | data, 250 | }); 251 | }, this._processingDelay); 252 | } 253 | 254 | /** 255 | * The saveImage method. 256 | * 257 | * @function saveImage 258 | * @param {string} dataUrl - The data URL 259 | * @public 260 | * @memberof JsonController 261 | * @example 262 | * controller.saveImage(dataUrl); 263 | * 264 | * @returns {Promise} 265 | */ 266 | static async saveImage(data: string): Promise { 267 | const base64Data = data.replace(/^data:image\/png;base64,/, ''); // Remove metadata 268 | const buffer = Buffer.from(base64Data, 'base64'); // Convert base64 to binary 269 | 270 | // Generate a random filename with the date and time as a prefix and the .png extension 271 | // The filename won't be have a special characters or spaces to avoid issues 272 | const fileName = `json-flow-${new Date().toISOString().replace(/[^0-9]/g, '')}.png`; 273 | 274 | // Define the file path 275 | let filePath: string; 276 | 277 | // Get the workspace folders 278 | const workspaceFolders = workspace.workspaceFolders; 279 | if (!workspaceFolders || workspaceFolders.length === 0) { 280 | window.showErrorMessage( 281 | l10n.t('No workspace folder available to save the image!'), 282 | ); 283 | return; 284 | } 285 | 286 | // Optionally, prompt the user to select a workspace folder if multiple are available 287 | if (workspaceFolders.length === 1) { 288 | filePath = join( 289 | workspaceFolders[0].uri.fsPath, 290 | this.imageFolder, 291 | fileName, 292 | ); 293 | } else { 294 | // await window.showWorkspaceFolderPick({placeHolder}); 295 | const folder = await window.showWorkspaceFolderPick({ 296 | placeHolder: l10n.t('Select a workspace folder to save the image'), 297 | }); 298 | 299 | if (!folder) { 300 | const message = l10n.t('Operation cancelled!'); 301 | window.showErrorMessage(message); 302 | return; 303 | } 304 | 305 | // Save the file in the selected workspace folder 306 | filePath = join(folder.uri.fsPath, this.imageFolder, fileName); 307 | } 308 | 309 | // Create the directory if it doesn't exist 310 | if (!existsSync(dirname(filePath))) { 311 | await mkdirSync(dirname(filePath), { recursive: true }); 312 | } 313 | 314 | // Write the file to the disk 315 | writeFileSync(filePath, buffer); 316 | 317 | // Show a message to the user 318 | window.showInformationMessage(l10n.t('Image saved to: {0}', filePath)); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/app/controllers/transform.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | InputData, 3 | jsonInputForTargetLanguage, 4 | quicktype, 5 | } from 'quicktype-core'; 6 | import { Range, Uri, l10n, window, workspace } from 'vscode'; 7 | import { FileType, isFileTypeSupported, parseJSONContent } from '../helpers'; 8 | import { NodeModel } from '../models'; 9 | 10 | /** 11 | * The TransformController class. 12 | * 13 | * @class 14 | * @classdesc The class that represents the example controller. 15 | * @export 16 | * @public 17 | * @example 18 | * const controller = new TransformController(); 19 | */ 20 | export class TransformController { 21 | // ----------------------------------------------------------------- 22 | // Methods 23 | // ----------------------------------------------------------------- 24 | 25 | // Public methods 26 | 27 | /** 28 | * The convertToJson method. 29 | * 30 | * @function convertToJson 31 | * @param {NodeModel | Uri} node - The node model 32 | * @public 33 | * @memberof FilesController 34 | * @example 35 | * controller.convertToJson('file:///path/to/file'); 36 | * 37 | * @returns {void} - The promise 38 | */ 39 | convertToJson(node: NodeModel | Uri) { 40 | if (node) { 41 | // Get the resource URI 42 | const resourceUri = node instanceof NodeModel ? node.resourceUri : node; 43 | 44 | // Check if the resource URI is valid 45 | if (!resourceUri) { 46 | const message = l10n.t('Operation cancelled!'); 47 | window.showErrorMessage(message); 48 | return; 49 | } 50 | 51 | // Open the text document 52 | workspace.openTextDocument(resourceUri).then(async (document) => { 53 | // Get the language ID and file name 54 | const { languageId, fileName } = document; 55 | 56 | // Determine the file type, defaulting to 'json' if unsupported 57 | let fileType = languageId; 58 | 59 | if (!isFileTypeSupported(fileType)) { 60 | const fileExtension = fileName.split('.').pop(); 61 | 62 | fileType = fileExtension; 63 | } 64 | 65 | // Parse JSON content 66 | const jsonContent = parseJSONContent( 67 | document.getText(), 68 | fileType as FileType, 69 | ); 70 | 71 | // Check if the content is null 72 | if (jsonContent === null) { 73 | return; 74 | } 75 | 76 | // Open the JSON document 77 | const jsonDocument = await workspace.openTextDocument({ 78 | language: 'json', 79 | content: JSON.stringify(jsonContent, null, 2), 80 | }); 81 | 82 | // Show the JSON document 83 | window.showTextDocument(jsonDocument); 84 | }); 85 | } 86 | } 87 | 88 | /** 89 | * The convertPartialToJson method. 90 | * 91 | * @function convertPartialToJson 92 | * @public 93 | * @memberof FilesController 94 | * @example 95 | * controller.convertPartialToJson(); 96 | * 97 | * @returns {void} - The promise 98 | */ 99 | async convertPartialToJson() { 100 | // Get the active text editor 101 | const editor = window.activeTextEditor; 102 | 103 | // Check if there is an active editor 104 | if (!editor) { 105 | const message = l10n.t('No active editor!'); 106 | window.showErrorMessage(message); 107 | return; 108 | } 109 | 110 | // Check if there is a selection 111 | const selection = editor.selection; 112 | 113 | if (selection.isEmpty) { 114 | const message = l10n.t('No selection!'); 115 | window.showErrorMessage(message); 116 | return; 117 | } 118 | 119 | // Get the selection range 120 | const selectionRange = new Range( 121 | selection.start.line, 122 | selection.start.character, 123 | selection.end.line, 124 | selection.end.character, 125 | ); 126 | 127 | // Get the language ID and file name 128 | const { languageId, fileName } = editor.document; 129 | 130 | let fileType = languageId; 131 | 132 | let text = editor.document.getText(selectionRange); 133 | 134 | if ( 135 | [ 136 | 'javascript', 137 | 'javascriptreact', 138 | 'typescript', 139 | 'typescriptreact', 140 | ].includes(fileType) 141 | ) { 142 | fileType = 'jsonc'; 143 | 144 | text = text 145 | .replace(/'([^']+)'/g, '"$1"') 146 | .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') 147 | .replace(/,*\s*\n*\]/g, ']') 148 | .replace(/{\s*\n*/g, '{') 149 | .replace(/,*\s*\n*};*/g, '}'); 150 | } 151 | 152 | if (!isFileTypeSupported(fileType)) { 153 | const fileExtension = fileName.split('.').pop(); 154 | 155 | fileType = isFileTypeSupported(fileExtension) ? fileExtension : 'jsonc'; 156 | } 157 | 158 | // Parse JSON content 159 | const jsonContent = parseJSONContent(text, fileType as FileType); 160 | 161 | // Check if the JSON content is null 162 | if (jsonContent === null) { 163 | return; 164 | } 165 | 166 | // Open the JSON document 167 | const jsonDocument = await workspace.openTextDocument({ 168 | language: 'json', 169 | content: JSON.stringify(jsonContent, null, 2), 170 | }); 171 | 172 | // Show the JSON document 173 | window.showTextDocument(jsonDocument); 174 | } 175 | 176 | /** 177 | * The convertToType method. 178 | * 179 | * @function convertToType 180 | * @param {NodeModel | Uri} node - The node model 181 | * @param {string} targetLanguage - The target language 182 | * @public 183 | * @memberof FilesController 184 | * @example 185 | * controller.convertToType('file:///path/to/file', 'typescript'); 186 | * 187 | * @returns {void} - The promise 188 | */ 189 | async convertToType(node: NodeModel | Uri, targetLanguage: string) { 190 | if (node) { 191 | // Get the resource URI 192 | const resourceUri = node instanceof NodeModel ? node.resourceUri : node; 193 | 194 | // Check if the resource URI is valid 195 | if (!resourceUri) { 196 | const message = l10n.t('Operation cancelled!'); 197 | window.showErrorMessage(message); 198 | return; 199 | } 200 | 201 | // Open the text document 202 | workspace.openTextDocument(resourceUri).then(async (document) => { 203 | // Get the language ID and file name 204 | const { languageId, fileName } = document; 205 | 206 | // Determine the file type, defaulting to 'json' if unsupported 207 | let fileType = languageId; 208 | 209 | if (!isFileTypeSupported(fileType)) { 210 | const fileExtension = fileName.split('.').pop(); 211 | 212 | fileType = fileExtension; 213 | } 214 | 215 | // Parse JSON content 216 | const jsonContent = parseJSONContent( 217 | document.getText(), 218 | fileType as FileType, 219 | ); 220 | 221 | // Check if the content is null 222 | if (jsonContent === null) { 223 | return; 224 | } 225 | 226 | // Get the name of the type or structure generated 227 | const typeName = await window.showInputBox({ 228 | prompt: l10n.t('Enter the name of the type or structure generated'), 229 | placeHolder: l10n.t( 230 | 'Enter the name of the type or structure, e.g., User, Post, etc.', 231 | ), 232 | value: undefined, 233 | validateInput: (value) => { 234 | if (!value) { 235 | return l10n.t('The name of the type or structure is required!'); 236 | } 237 | 238 | return; 239 | }, 240 | }); 241 | 242 | if (!typeName) { 243 | const message = l10n.t('Operation cancelled!'); 244 | window.showErrorMessage(message); 245 | return; 246 | } 247 | 248 | // Create an instance of JSONInput 249 | const jsonInput = jsonInputForTargetLanguage(targetLanguage); 250 | 251 | // Add the JSON content to the JSONInput instance 252 | await jsonInput.addSource({ 253 | name: typeName, 254 | samples: [JSON.stringify(jsonContent)], 255 | }); 256 | 257 | // Create an instance of InputData 258 | const inputData = new InputData(); 259 | inputData.addInput(jsonInput); 260 | 261 | // Generate the target language 262 | const { lines } = await quicktype({ 263 | inputData, 264 | lang: targetLanguage, 265 | }); 266 | 267 | // Open the JSON document 268 | const jsonDocument = await workspace.openTextDocument({ 269 | language: this.mapLanguageId(targetLanguage), 270 | content: lines.join('\n'), 271 | }); 272 | 273 | // Show the JSON document 274 | window.showTextDocument(jsonDocument); 275 | }); 276 | } 277 | } 278 | 279 | /** 280 | * The convertPartialToType method. 281 | * 282 | * @function convertPartialToType 283 | * @param {string} targetLanguage - The target language 284 | * @public 285 | * @memberof FilesController 286 | * @example 287 | * controller.convertPartialToType('typescript'); 288 | * 289 | * @returns {void} - The promise 290 | */ 291 | async convertPartialToType(targetLanguage: string) { 292 | // Get the active text editor 293 | const editor = window.activeTextEditor; 294 | 295 | // Check if there is an active editor 296 | if (!editor) { 297 | const message = l10n.t('No active editor!'); 298 | window.showErrorMessage(message); 299 | return; 300 | } 301 | 302 | // Check if there is a selection 303 | const selection = editor.selection; 304 | 305 | if (selection.isEmpty) { 306 | const message = l10n.t('No selection!'); 307 | window.showErrorMessage(message); 308 | return; 309 | } 310 | 311 | // Get the selection range 312 | const selectionRange = new Range( 313 | selection.start.line, 314 | selection.start.character, 315 | selection.end.line, 316 | selection.end.character, 317 | ); 318 | 319 | // Get the language ID and file name 320 | const { languageId, fileName } = editor.document; 321 | 322 | let fileType = languageId; 323 | 324 | let text = editor.document.getText(selectionRange); 325 | 326 | if ( 327 | [ 328 | 'javascript', 329 | 'javascriptreact', 330 | 'typescript', 331 | 'typescriptreact', 332 | ].includes(fileType) 333 | ) { 334 | fileType = 'jsonc'; 335 | 336 | text = text 337 | .replace(/'([^']+)'/g, '"$1"') 338 | .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') 339 | .replace(/,*\s*\n*\]/g, ']') 340 | .replace(/{\s*\n*/g, '{') 341 | .replace(/,*\s*\n*};*/g, '}'); 342 | } 343 | 344 | if (!isFileTypeSupported(fileType)) { 345 | const fileExtension = fileName.split('.').pop(); 346 | 347 | fileType = isFileTypeSupported(fileExtension) ? fileExtension : 'jsonc'; 348 | } 349 | 350 | // Parse JSON content 351 | const jsonContent = parseJSONContent(text, fileType as FileType); 352 | 353 | // Check if the JSON content is null 354 | if (jsonContent === null) { 355 | return; 356 | } 357 | 358 | // Get the name of the type or structure generated 359 | const typeName = await window.showInputBox({ 360 | prompt: l10n.t('Enter the name of the type or structure generated'), 361 | placeHolder: l10n.t( 362 | 'Enter the name of the type or structure, e.g., User, Post, etc.', 363 | ), 364 | value: undefined, 365 | validateInput: (value) => { 366 | if (!value) { 367 | return l10n.t('The name of the type or structure is required!'); 368 | } 369 | 370 | return; 371 | }, 372 | }); 373 | 374 | if (!typeName) { 375 | const message = l10n.t('Operation cancelled!'); 376 | window.showErrorMessage(message); 377 | return; 378 | } 379 | 380 | // Create an instance of JSONInput 381 | const jsonInput = jsonInputForTargetLanguage(targetLanguage); 382 | 383 | // Add the JSON content to the JSONInput instance 384 | await jsonInput.addSource({ 385 | name: typeName, 386 | samples: [JSON.stringify(jsonContent)], 387 | }); 388 | 389 | // Create an instance of InputData 390 | const inputData = new InputData(); 391 | inputData.addInput(jsonInput); 392 | 393 | // Generate the target language 394 | const { lines } = await quicktype({ 395 | inputData, 396 | lang: targetLanguage, 397 | }); 398 | 399 | // Open the JSON document 400 | const jsonDocument = await workspace.openTextDocument({ 401 | language: this.mapLanguageId(targetLanguage), 402 | content: lines.join('\n'), 403 | }); 404 | 405 | // Show the JSON document 406 | window.showTextDocument(jsonDocument); 407 | } 408 | 409 | // Private methods 410 | /** 411 | * The mapLanguageId method. 412 | * 413 | * @function mapLanguageId 414 | * @param {string} targetLanguage - The target language 415 | * @private 416 | * @memberof TransformController 417 | * @example 418 | * const languageId = mapLanguageId('typescript'); 419 | * 420 | * @returns {string} - The language ID 421 | */ 422 | mapLanguageId(targetLanguage: string): string { 423 | switch (targetLanguage) { 424 | case 'ruby': 425 | return 'ruby'; 426 | case 'javascript': 427 | return 'javascript'; 428 | case 'flow': 429 | return 'javascript'; 430 | case 'rust': 431 | return 'rust'; 432 | case 'kotlin': 433 | return 'kotlin'; 434 | case 'dart': 435 | return 'dart'; 436 | case 'python': 437 | return 'python'; 438 | case 'csharp': 439 | return 'csharp'; 440 | case 'go': 441 | return 'go'; 442 | case 'cpp': 443 | return 'cpp'; 444 | case 'java': 445 | return 'java'; 446 | case 'scala': 447 | return 'scala'; 448 | case 'typescript': 449 | return 'typescript'; 450 | case 'swift': 451 | return 'swift'; 452 | case 'objective-c': 453 | return 'objective-c'; 454 | case 'elm': 455 | return 'elm'; 456 | case 'json-schema': 457 | return 'json'; 458 | case 'pike': 459 | return 'pike'; 460 | case 'prop-types': 461 | return 'javascript'; 462 | case 'haskell': 463 | return 'haskell'; 464 | case 'php': 465 | return 'php'; 466 | default: 467 | return 'plaintext'; 468 | } 469 | } 470 | } 471 | -------------------------------------------------------------------------------- /src/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/src/app/helpers/.gitkeep -------------------------------------------------------------------------------- /src/app/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './json.helper'; 2 | export * from './security.helper'; 3 | export * from './tree.helper'; 4 | -------------------------------------------------------------------------------- /src/app/helpers/json.helper.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { XMLParser } from 'fast-xml-parser'; 3 | import hcl from 'hcl-parser'; 4 | import * as ini from 'ini'; 5 | import json5 from 'json5'; 6 | import * as toml from 'toml'; 7 | import { l10n, window } from 'vscode'; 8 | import * as yaml from 'yaml'; 9 | 10 | /** 11 | * The FileType type. 12 | * 13 | * @type {FileType} 14 | */ 15 | export type FileType = 16 | | 'csv' 17 | | 'dockercompose' 18 | | 'env' 19 | | 'hcl' 20 | | 'ini' 21 | | 'json' 22 | | 'json5' 23 | | 'jsonc' 24 | | 'properties' 25 | | 'toml' 26 | | 'tsv' 27 | | 'xml' 28 | | 'yaml' 29 | | 'yml'; 30 | 31 | /** 32 | * Type guard to verify if a value is a valid FileType. 33 | * 34 | * @param value - The value to check. 35 | * @returns {value is FileType} - True if the value is a valid FileType, false otherwise. 36 | */ 37 | export const isFileTypeSupported = (value: unknown): value is FileType => { 38 | const validFileTypes: FileType[] = [ 39 | 'csv', 40 | 'dockercompose', 41 | 'env', 42 | 'hcl', 43 | 'ini', 44 | 'json', 45 | 'json5', 46 | 'jsonc', 47 | 'properties', 48 | 'toml', 49 | 'tsv', 50 | 'xml', 51 | 'yaml', 52 | 'yml', 53 | ]; 54 | 55 | return validFileTypes.includes(value as FileType); 56 | }; 57 | 58 | /** 59 | * The parseJSONContent function. 60 | * 61 | * @function parseJSONContent 62 | * @param {string} content - The content to parse 63 | * @param {FileType} type - The type of content 64 | * @returns {object | null} - The parsed content 65 | */ 66 | export const parseJSONContent = ( 67 | content: string, 68 | type: FileType, 69 | ): object | null => { 70 | try { 71 | switch (type) { 72 | case 'json': 73 | case 'jsonc': 74 | case 'json5': 75 | return json5.parse(content); 76 | 77 | case 'dockercompose': 78 | case 'yaml': 79 | case 'yml': 80 | return yaml.parse(content); 81 | 82 | case 'toml': 83 | return toml.parse(content); 84 | 85 | case 'ini': 86 | case 'properties': 87 | return ini.parse(content); 88 | 89 | case 'env': 90 | return dotenv.parse(content); 91 | 92 | case 'xml': { 93 | const parser = new XMLParser(); 94 | return parser.parse(content); 95 | } 96 | 97 | case 'hcl': 98 | return hcl.parse(content); 99 | 100 | case 'csv': { 101 | const rows = content.trim().split('\n'); 102 | const headers = rows[0].split(',').map((row) => row.replace('\r', '')); 103 | return rows.slice(1).map((row) => { 104 | const values = row.split(','); 105 | return headers.reduce((acc, header, index) => { 106 | acc[header] = values[index]; 107 | return acc; 108 | }, {}); 109 | }); 110 | } 111 | 112 | case 'tsv': { 113 | const rows = content 114 | .trim() 115 | .split('\n') 116 | .map((row) => row.replace('\r', '')); 117 | const headers = rows[0].split('\t'); 118 | return rows.slice(1).map((row) => { 119 | const values = row.split('\t'); 120 | return headers.reduce((acc, header, index) => { 121 | acc[header] = values[index]; 122 | return acc; 123 | }, {}); 124 | }); 125 | } 126 | 127 | default: { 128 | const message = l10n.t('Invalid file type!'); 129 | window.showErrorMessage(message); 130 | return null; 131 | } 132 | } 133 | } catch (error) { 134 | const message = l10n.t('Error parsing {0}: {1}', [ 135 | type.toUpperCase(), 136 | error.message, 137 | ]); 138 | 139 | window.showErrorMessage(message); 140 | return null; 141 | } 142 | }; 143 | -------------------------------------------------------------------------------- /src/app/helpers/security.helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides protection against directory traversal. 3 | * 4 | * @param {string} filename - The filename to sanitize 5 | * @example 6 | * sanitizeFilename('foo.bar'); 7 | * 8 | * @returns {string} - The sanitized filename 9 | */ 10 | export const sanitizeFilename = (filename: string): string => { 11 | return filename.replace(/[^a-z0-9.]/gi, '_').toLowerCase(); 12 | }; 13 | 14 | /** 15 | * Strips HTML tags from a string. 16 | * 17 | * @param {string} html - The HTML to strip 18 | * @example 19 | * stripHtmlTags('

foo

'); 20 | * 21 | * @returns {string} - The stripped HTML 22 | */ 23 | export const stripHtmlTags = (html: string): string => { 24 | return html.replace(/<[^>]*>/g, ''); 25 | }; 26 | 27 | /** 28 | * Escapes a string for use in HTML. 29 | * @param {string} str - The string to escape 30 | * @example 31 | * escapeHtml('

foo

'); 32 | * 33 | * @returns {string} - The escaped string 34 | */ 35 | export const escapeHtml = (str: string): string => { 36 | return str.replace(//g, '>'); 37 | }; 38 | 39 | /** 40 | * Escapes a string for use in JavaScript. 41 | * @param {string} str - The string to escape 42 | * @example 43 | * escapeJs('foo "bar"'); 44 | * 45 | * @returns {string} - The escaped string 46 | */ 47 | export const escapeJs = (str: string): string => { 48 | return str.replace(/'/g, "\\'").replace(/"/g, '\\"'); 49 | }; 50 | 51 | /** 52 | * Escapes a string for use in a URL. 53 | * 54 | * @param {string} str - The string to escape 55 | * @example 56 | * escapeUrl('foo bar'); 57 | * 58 | * @returns {string} - The escaped string 59 | */ 60 | export const escapeUrl = (str: string): string => { 61 | return encodeURIComponent(str); 62 | }; 63 | 64 | /** 65 | * Escapes a string for use in a regular expression. 66 | * 67 | * @param {string} str - The string to escape 68 | * @example 69 | * escapeRegExp('foo.bar'); 70 | * 71 | * @returns {string} - The escaped string 72 | */ 73 | export const escapeRegExp = (str: string): string => { 74 | return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 75 | }; 76 | 77 | /** 78 | * Returns a random nonce. 79 | * 80 | * @example 81 | * const nonce = getNonce(); 82 | * 83 | * @returns {string} - The nonce 84 | */ 85 | export const getNonce = () => { 86 | let text = ''; 87 | const possible = 88 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 89 | for (let i = 0; i < 32; i++) { 90 | text += possible.charAt(Math.floor(Math.random() * possible.length)); 91 | } 92 | return text; 93 | }; 94 | -------------------------------------------------------------------------------- /src/app/helpers/tree.helper.ts: -------------------------------------------------------------------------------- 1 | import { Tree } from '../interfaces'; 2 | 3 | export const generateTree = ( 4 | json: object, 5 | showValues: boolean = true, 6 | ): Tree => { 7 | const tree: Tree = {}; 8 | let currentId = 1; 9 | 10 | // Initialize the queue with the root node 11 | const queue: { id: number; name: string; data: unknown }[] = [ 12 | { id: currentId, name: 'root', data: json }, 13 | ]; 14 | 15 | // Process each item in the queue 16 | while (queue.length > 0) { 17 | const { id, name, data } = queue.shift()!; 18 | 19 | // Create the current node and add it to the tree 20 | tree[id] = { id: id.toString(), name }; 21 | 22 | // Determine if the node has children 23 | if (typeof data === 'object' && data !== null) { 24 | const children: number[] = []; 25 | 26 | // Add each property or array item to the queue 27 | for (const [key, value] of Object.entries(data)) { 28 | currentId += 1; 29 | children.push(currentId); 30 | 31 | // Add to the queue with an incremented ID 32 | queue.push({ id: currentId, name: key, data: value }); 33 | } 34 | 35 | tree[id].children = children; 36 | } else if (showValues) { 37 | // If it's a primitive value and showValues is true, add it as a leaf node 38 | currentId += 1; 39 | tree[currentId] = { id: currentId.toString(), name: data.toString() }; 40 | tree[id].children = [currentId]; 41 | } 42 | } 43 | 44 | return tree; 45 | }; 46 | -------------------------------------------------------------------------------- /src/app/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tree.interface'; 2 | -------------------------------------------------------------------------------- /src/app/interfaces/tree.interface.ts: -------------------------------------------------------------------------------- 1 | export interface TreeNode { 2 | id: string; 3 | name: string; 4 | children?: number[]; 5 | } 6 | 7 | export interface Tree { 8 | [key: number]: TreeNode; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/src/app/models/.gitkeep -------------------------------------------------------------------------------- /src/app/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from './node.model'; 2 | -------------------------------------------------------------------------------- /src/app/models/node.model.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Command, 3 | ThemeIcon, 4 | TreeItem, 5 | TreeItemCollapsibleState, 6 | TreeItemLabel, 7 | Uri, 8 | } from 'vscode'; 9 | 10 | /** 11 | * The Node class 12 | * 13 | * @class 14 | * @classdesc The class that represents a node in the tree view. 15 | * @export 16 | * @public 17 | * @extends {TreeItem} 18 | * @property {string | TreeItemLabel} label - The label 19 | * @property {string | Uri | { light: Uri; dark: Uri } | ThemeIcon} [iconPath] - The icon path 20 | * @property {Command} [command] - The command 21 | * @property {Uri} [resourceUri] - The resource URI 22 | * @property {string} [contextValue] - The context value 23 | * @property {Node[]} [children] - The children 24 | * @example 25 | * const node = new Node('About Us', TreeItemCollapsibleState.None, 'about', { 26 | * title: 'About Us', 27 | * command: 'extension-stater-kit.aboutUs', 28 | * }); 29 | * 30 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeItem 31 | */ 32 | export class NodeModel extends TreeItem { 33 | // ----------------------------------------------------------------- 34 | // Properties 35 | // ----------------------------------------------------------------- 36 | 37 | // Public properties 38 | /** 39 | * The children. 40 | * @type {NodeModel[]} 41 | * @public 42 | * @memberof NodeModel 43 | * @example 44 | * node.children = []; 45 | */ 46 | children?: NodeModel[]; 47 | 48 | // ----------------------------------------------------------------- 49 | // Constructor 50 | // ----------------------------------------------------------------- 51 | 52 | /** 53 | * The constructor 54 | * 55 | * @constructor 56 | * @param {string | TreeItemLabel} label - The label 57 | * @param {string | Uri | { light: Uri; dark: Uri } | ThemeIcon} [iconPath] - The icon path 58 | * @param {Command} [command] - The command 59 | * @param {Uri} [resourceUri] - The resource URI 60 | * @param {string} [contextValue] - The context value 61 | * @param {NodeModel[]} [children] - The children 62 | * @example 63 | * const node = new Node('About Us', new ThemeIcon('info'), { 64 | * title: 'About Us', 65 | * command: 'extension-stater-kit.aboutUs', 66 | * }); 67 | */ 68 | constructor( 69 | readonly label: string | TreeItemLabel, 70 | readonly iconPath?: string | Uri | { light: Uri; dark: Uri } | ThemeIcon, 71 | readonly command?: Command, 72 | readonly resourceUri?: Uri, 73 | readonly contextValue?: string, 74 | children?: NodeModel[], 75 | ) { 76 | super( 77 | label, 78 | children 79 | ? TreeItemCollapsibleState.Expanded 80 | : TreeItemCollapsibleState.None, 81 | ); 82 | this.iconPath = iconPath; 83 | this.resourceUri = resourceUri; 84 | this.command = command; 85 | this.contextValue = contextValue; 86 | this.children = children; 87 | } 88 | 89 | // ----------------------------------------------------------------- 90 | // Methods 91 | // ----------------------------------------------------------------- 92 | 93 | // Public methods 94 | /** 95 | * The setChildren method 96 | * 97 | * @function setChildren 98 | * @param {NodeModel[]} children - The children 99 | * @public 100 | * @memberof NodeModel 101 | * @example 102 | * node.setChildren([]); 103 | * 104 | * @returns {void} The result 105 | */ 106 | setChildren(children: NodeModel[]): void { 107 | this.collapsibleState = TreeItemCollapsibleState.Expanded; 108 | this.children = children; 109 | } 110 | 111 | /** 112 | * The hasChildren method 113 | * 114 | * @function hasChildren 115 | * @public 116 | * @memberof NodeModel 117 | * @example 118 | * const hasChildren = node.hasChildren(); 119 | * 120 | * @returns {boolean} The result 121 | */ 122 | hasChildren(): boolean { 123 | return !!(this.children && this.children.length); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/app/providers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ManuelGil/vscode-json-flow/d6515cd6b0259e893793e999deafcef49df6082f/src/app/providers/.gitkeep -------------------------------------------------------------------------------- /src/app/providers/feedback.provider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Event, 3 | EventEmitter, 4 | l10n, 5 | ProviderResult, 6 | ThemeIcon, 7 | TreeDataProvider, 8 | TreeItem, 9 | } from 'vscode'; 10 | 11 | import { EXTENSION_ID } from '../configs'; 12 | import { FeedbackController } from '../controllers'; 13 | import { NodeModel } from '../models'; 14 | 15 | /** 16 | * The FeedbackProvider class 17 | * 18 | * @class 19 | * @classdesc The class that represents the feedback provider. 20 | * @export 21 | * @public 22 | * @implements {TreeDataProvider} 23 | * @property {EventEmitter} _onDidChangeTreeData - The onDidChangeTreeData event emitter 24 | * @property {Event} onDidChangeTreeData - The onDidChangeTreeData event 25 | * @property {FeedbackController} controller - The feedback controller 26 | * @example 27 | * const provider = new FeedbackProvider(); 28 | * 29 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider 30 | */ 31 | export class FeedbackProvider implements TreeDataProvider { 32 | // ----------------------------------------------------------------- 33 | // Properties 34 | // ----------------------------------------------------------------- 35 | 36 | // Public properties 37 | /** 38 | * The onDidChangeTreeData event. 39 | * @type {Event} 40 | * @public 41 | * @memberof FeedbackProvider 42 | * @example 43 | * readonly onDidChangeTreeData: Event; 44 | * this.onDidChangeTreeData = this._onDidChangeTreeData.event; 45 | * 46 | * @see https://code.visualstudio.com/api/references/vscode-api#Event 47 | */ 48 | readonly onDidChangeTreeData: Event; 49 | 50 | // Private properties 51 | /** 52 | * The onDidChangeTreeData event emitter. 53 | * @type {EventEmitter} 54 | * @private 55 | * @memberof FeedbackProvider 56 | * @example 57 | * this._onDidChangeTreeData = new EventEmitter(); 58 | * this.onDidChangeTreeData = this._onDidChangeTreeData.event; 59 | * 60 | * @see https://code.visualstudio.com/api/references/vscode-api#EventEmitter 61 | */ 62 | private _onDidChangeTreeData: EventEmitter< 63 | NodeModel | undefined | null | void 64 | >; 65 | 66 | // ----------------------------------------------------------------- 67 | // Constructor 68 | // ----------------------------------------------------------------- 69 | 70 | /** 71 | * Constructor for the FeedbackProvider class 72 | * 73 | * @constructor 74 | * @public 75 | * @memberof FeedbackProvider 76 | */ 77 | constructor(readonly controller: FeedbackController) { 78 | this._onDidChangeTreeData = new EventEmitter< 79 | NodeModel | undefined | null | void 80 | >(); 81 | this.onDidChangeTreeData = this._onDidChangeTreeData.event; 82 | } 83 | 84 | // ----------------------------------------------------------------- 85 | // Methods 86 | // ----------------------------------------------------------------- 87 | 88 | // Public methods 89 | /** 90 | * Returns the tree item for the supplied element. 91 | * 92 | * @function getTreeItem 93 | * @param {NodeModel} element - The element 94 | * @public 95 | * @memberof FeedbackProvider 96 | * @example 97 | * const treeItem = provider.getTreeItem(element); 98 | * 99 | * @returns {TreeItem | Thenable} - The tree item 100 | * 101 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider 102 | */ 103 | // biome-ignore lint/correctness/noUndeclaredVariables: we dont control vscode's api 104 | getTreeItem(element: NodeModel): TreeItem | Thenable { 105 | return element; 106 | } 107 | 108 | /** 109 | * Returns the children for the supplied element. 110 | * 111 | * @function getChildren 112 | * @param {NodeModel} [element] - The element 113 | * @public 114 | * @memberof FeedbackProvider 115 | * @example 116 | * const children = provider.getChildren(element); 117 | * 118 | * @returns {ProviderResult} - The children 119 | * 120 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider 121 | */ 122 | getChildren(element?: NodeModel): ProviderResult { 123 | if (element) { 124 | return element.children; 125 | } 126 | 127 | return this.getFeedbacks(); 128 | } 129 | 130 | /** 131 | * Refreshes the tree data. 132 | * 133 | * @function refresh 134 | * @public 135 | * @memberof FeedbackProvider 136 | * @example 137 | * provider.refresh(); 138 | * 139 | * @returns {void} - No return value 140 | */ 141 | refresh(): void { 142 | this._onDidChangeTreeData.fire(); 143 | } 144 | 145 | // Private methods 146 | /** 147 | * Returns the feedbacks. 148 | * 149 | * @function getFeedbacks 150 | * @private 151 | * @memberof FeedbackProvider 152 | * @example 153 | * const feedbacks = this.getFeedbacks(); 154 | * 155 | * @returns {NodeModel[]} - The feedbacks 156 | */ 157 | private getFeedbacks(): NodeModel[] { 158 | return [ 159 | new NodeModel(l10n.t('Report Issues'), new ThemeIcon('bug'), { 160 | title: 'Report Issues', 161 | command: `${EXTENSION_ID}.feedback.reportIssues`, 162 | }), 163 | new NodeModel(l10n.t('Rate Us'), new ThemeIcon('star'), { 164 | title: 'Rate Us', 165 | command: `${EXTENSION_ID}.feedback.rateUs`, 166 | }), 167 | ]; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/app/providers/files.providers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Event, 3 | EventEmitter, 4 | ProviderResult, 5 | ThemeIcon, 6 | TreeDataProvider, 7 | TreeItem, 8 | } from 'vscode'; 9 | 10 | import { FilesController } from '../controllers'; 11 | import { NodeModel } from '../models'; 12 | 13 | /** 14 | * The FilesProvider class 15 | * 16 | * @class 17 | * @classdesc The class that represents the files provider. 18 | * @export 19 | * @public 20 | * @implements {TreeDataProvider} 21 | * @property {EventEmitter} _onDidChangeTreeData - The onDidChangeTreeData event emitter 22 | * @property {Event} onDidChangeTreeData - The onDidChangeTreeData event 23 | * @property {filesController} controller - The files controller 24 | * @example 25 | * const provider = new FilesProvider(); 26 | * 27 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider 28 | */ 29 | export class FilesProvider implements TreeDataProvider { 30 | // ----------------------------------------------------------------- 31 | // Properties 32 | // ----------------------------------------------------------------- 33 | 34 | // Public properties 35 | /** 36 | * The onDidChangeTreeData event. 37 | * @type {Event} 38 | * @public 39 | * @memberof FilesProvider 40 | * @example 41 | * readonly onDidChangeTreeData: Event; 42 | * this.onDidChangeTreeData = this._onDidChangeTreeData.event; 43 | * 44 | * @see https://code.visualstudio.com/api/references/vscode-api#Event 45 | */ 46 | readonly onDidChangeTreeData: Event; 47 | 48 | // Private properties 49 | /** 50 | * The onDidChangeTreeData event emitter. 51 | * @type {EventEmitter} 52 | * @private 53 | * @memberof FilesProvider 54 | * @example 55 | * this._onDidChangeTreeData = new EventEmitter(); 56 | * this.onDidChangeTreeData = this._onDidChangeTreeData.event; 57 | * 58 | * @see https://code.visualstudio.com/api/references/vscode-api#EventEmitter 59 | */ 60 | private _onDidChangeTreeData: EventEmitter< 61 | NodeModel | undefined | null | void 62 | >; 63 | 64 | // ----------------------------------------------------------------- 65 | // Constructor 66 | // ----------------------------------------------------------------- 67 | 68 | /** 69 | * Constructor for the FilesProvider class 70 | * 71 | * @constructor 72 | * @public 73 | * @memberof FilesProvider 74 | */ 75 | constructor(readonly controller: FilesController) { 76 | this._onDidChangeTreeData = new EventEmitter< 77 | NodeModel | undefined | null | void 78 | >(); 79 | this.onDidChangeTreeData = this._onDidChangeTreeData.event; 80 | } 81 | 82 | // ----------------------------------------------------------------- 83 | // Methods 84 | // ----------------------------------------------------------------- 85 | 86 | // Public methods 87 | /** 88 | * Returns the tree item for the supplied element. 89 | * 90 | * @function getTreeItem 91 | * @param {NodeModel} element - The element 92 | * @public 93 | * @memberof FilesProvider 94 | * @example 95 | * const treeItem = provider.getTreeItem(element); 96 | * 97 | * @returns {TreeItem | Thenable} - The tree item 98 | * 99 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider 100 | */ 101 | // biome-ignore lint/correctness/noUndeclaredVariables: we dont control vscode's api 102 | getTreeItem(element: NodeModel): TreeItem | Thenable { 103 | return element; 104 | } 105 | 106 | /** 107 | * Returns the children for the supplied element. 108 | * 109 | * @function getChildren 110 | * @param {NodeModel} [element] - The element 111 | * @public 112 | * @memberof FilesProvider 113 | * @example 114 | * const children = provider.getChildren(element); 115 | * 116 | * @returns {ProviderResult} - The children 117 | * 118 | * @see https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider 119 | */ 120 | getChildren(element?: NodeModel): ProviderResult { 121 | if (element) { 122 | return element.children; 123 | } 124 | 125 | return this.getListFiles(); 126 | } 127 | 128 | /** 129 | * Refreshes the tree data. 130 | * 131 | * @function refresh 132 | * @public 133 | * @memberof FeedbackProvider 134 | * @example 135 | * provider.refresh(); 136 | * 137 | * @returns {void} - No return value 138 | */ 139 | refresh(): void { 140 | this._onDidChangeTreeData.fire(); 141 | } 142 | 143 | // Private methods 144 | /** 145 | * Gets the list of files. 146 | * 147 | * @function getListFiles 148 | * @private 149 | * @memberof FilesProvider 150 | * @example 151 | * const files = provider.getListFiles(); 152 | * 153 | * @returns {Promise} - The list of files 154 | */ 155 | private async getListFiles(): Promise { 156 | const files = await this.controller.getFiles(); 157 | 158 | if (!files) { 159 | return; 160 | } 161 | 162 | const nodes: NodeModel[] = []; 163 | 164 | const fileTypes = this.controller.config.include; 165 | 166 | for (const fileType of fileTypes) { 167 | const children = files.filter((file) => 168 | file.label.toString().includes(`.${fileType}`), 169 | ); 170 | 171 | if (children.length !== 0) { 172 | const node = new NodeModel( 173 | `${fileType}: ${children.length}`, 174 | new ThemeIcon('folder-opened'), 175 | undefined, 176 | undefined, 177 | fileType, 178 | children, 179 | ); 180 | 181 | nodes.push(node); 182 | } 183 | } 184 | 185 | if (nodes.length === 0) { 186 | return; 187 | } 188 | 189 | return nodes; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/app/providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './feedback.provider'; 2 | export * from './files.providers'; 3 | export * from './json.provider'; 4 | -------------------------------------------------------------------------------- /src/app/providers/json.provider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Disposable, 3 | Uri, 4 | ViewColumn, 5 | Webview, 6 | WebviewOptions, 7 | WebviewPanel, 8 | window, 9 | } from 'vscode'; 10 | 11 | import { EXTENSION_ID } from '../configs'; 12 | import { JsonController } from '../controllers'; 13 | import { getNonce } from '../helpers'; 14 | 15 | /** 16 | * The JSONProvider class. 17 | * 18 | * @class 19 | * @classdesc The class that represents the json provider. 20 | * @export 21 | * @public 22 | * @property {string} static viewType - The view type 23 | * @property {WebviewView} [_view] - The view 24 | * @property {OpenAIService} [openAISservice] - The OpenAI service 25 | * @example 26 | * const provider = new JSONProvider(extensionUri); 27 | */ 28 | export class JSONProvider { 29 | // ----------------------------------------------------------------- 30 | // Properties 31 | // ----------------------------------------------------------------- 32 | 33 | // Public properties 34 | /** 35 | * The current provider. 36 | * 37 | * @public 38 | * @static 39 | * @memberof JSONProvider 40 | * @type {JSONProvider | undefined} 41 | */ 42 | static currentProvider: JSONProvider | undefined; 43 | 44 | /** 45 | * The view type. 46 | * 47 | * @public 48 | * @static 49 | * @memberof JSONProvider 50 | * @type {string} 51 | */ 52 | static readonly viewType: string = `${EXTENSION_ID}.jsonView`; 53 | 54 | // Private properties 55 | /** 56 | * The disposables. 57 | * 58 | * @private 59 | * @memberof JSONProvider 60 | * @type {Disposable[]} 61 | */ 62 | private _disposables: Disposable[] = []; 63 | 64 | // ----------------------------------------------------------------- 65 | // Constructor 66 | // ----------------------------------------------------------------- 67 | 68 | /** 69 | * Constructor for the JSONProvider class. 70 | * 71 | * @constructor 72 | * @param {WebviewPanel} _panel - The webview panel 73 | * @param {Uri} _extensionUri - The extension URI 74 | * @public 75 | * @memberof JSONProvider 76 | */ 77 | private constructor( 78 | private readonly _panel: WebviewPanel, 79 | private readonly _extensionUri: Uri, 80 | ) { 81 | this._update(); 82 | 83 | this._panel.onDidDispose(() => this.dispose(), null, this._disposables); 84 | 85 | this._panel.webview.onDidReceiveMessage( 86 | (message) => { 87 | switch (message.type) { 88 | case 'onSaveImage': 89 | JsonController.saveImage(message.data); 90 | break; 91 | 92 | default: 93 | break; 94 | } 95 | }, 96 | null, 97 | this._disposables, 98 | ); 99 | 100 | this._panel.onDidChangeViewState( 101 | () => { 102 | if (this._panel.visible) { 103 | this._update(); 104 | } 105 | }, 106 | null, 107 | this._disposables, 108 | ); 109 | } 110 | 111 | // ----------------------------------------------------------------- 112 | // Methods 113 | // ----------------------------------------------------------------- 114 | 115 | // Public methods 116 | /** 117 | * The createPanel method. 118 | * 119 | * @function createPanel 120 | * @param {Uri} extensionUri - The extension URI 121 | * @param {Uri} json - The JSON URI 122 | * @public 123 | * @static 124 | * @memberof JSONProvider 125 | * @example 126 | * JSONProvider.createPanel(extensionUri); 127 | * 128 | * @returns {WebviewPanel} 129 | */ 130 | static createPanel(extensionUri: Uri): WebviewPanel { 131 | if (JSONProvider.currentProvider) { 132 | JSONProvider.currentProvider._panel.webview.postMessage({ 133 | type: 'clearJson', 134 | }); 135 | 136 | JSONProvider.currentProvider._panel.reveal(ViewColumn.One); 137 | 138 | return JSONProvider.currentProvider._panel; 139 | } 140 | 141 | const panel = window.createWebviewPanel( 142 | JSONProvider.viewType, 143 | 'JSON Flow', 144 | ViewColumn.One, 145 | this.getWebviewOptions(extensionUri), 146 | ); 147 | 148 | JSONProvider.currentProvider = new JSONProvider(panel, extensionUri); 149 | 150 | return panel; 151 | } 152 | 153 | /** 154 | * The getWebviewOptions method. 155 | * 156 | * @function getWebviewOptions 157 | * @param {Uri} extensionUri - The extension URI 158 | * @public 159 | * @static 160 | * @memberof JSONProvider 161 | * @example 162 | * const options = JSONProvider.getWebviewOptions(extensionUri); 163 | * 164 | * @returns {WebviewOptions} - The webview options 165 | */ 166 | static getWebviewOptions(extensionUri: Uri): WebviewOptions { 167 | return { 168 | enableScripts: true, 169 | localResourceRoots: [Uri.joinPath(extensionUri, './out/webview')], 170 | }; 171 | } 172 | 173 | /** 174 | * The revive method. 175 | * 176 | * @function revive 177 | * @param {WebviewPanel} panel - The webview panel 178 | * @param {Uri} extensionUri - The extension URI 179 | * @public 180 | * @static 181 | * @memberof JSONProvider 182 | * @example 183 | * JSONProvider.revive(panel, extensionUri); 184 | * 185 | * @returns {void} 186 | */ 187 | static revive(panel: WebviewPanel, extensionUri: Uri): void { 188 | JSONProvider.currentProvider = new JSONProvider(panel, extensionUri); 189 | } 190 | 191 | /** 192 | * The dispose method. 193 | * 194 | * @function dispose 195 | * @public 196 | * @memberof JSONProvider 197 | * @example 198 | * provider.dispose(); 199 | * 200 | * @returns {void} 201 | */ 202 | dispose() { 203 | JSONProvider.currentProvider = undefined; 204 | 205 | this._panel.dispose(); 206 | 207 | while (this._disposables.length) { 208 | const x = this._disposables.pop(); 209 | if (x) { 210 | x.dispose(); 211 | } 212 | } 213 | } 214 | 215 | // Private methods 216 | /** 217 | * The _update method. 218 | * 219 | * @function _update 220 | * @private 221 | * @memberof JSONProvider 222 | * @example 223 | * provider._update(); 224 | * 225 | * @returns {void} 226 | */ 227 | private _update(): void { 228 | const webview = this._panel.webview; 229 | 230 | this._panel.webview.html = this._getHtmlForWebview(webview); 231 | } 232 | 233 | /** 234 | * The _getHtmlForWebview method. 235 | * 236 | * @function _getHtmlForWebview 237 | * @param {Webview} webview - The webview 238 | * @private 239 | * @memberof JSONProvider 240 | * @example 241 | * const html = provider._getHtmlForWebview(webview); 242 | * 243 | * @returns {string} - The HTML for the webview 244 | */ 245 | private _getHtmlForWebview(webview: Webview): string { 246 | // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview. 247 | const scriptUri = webview.asWebviewUri( 248 | Uri.joinPath(this._extensionUri, './out/webview', 'main.js'), 249 | ); 250 | 251 | // Do the same for the stylesheet. 252 | const styleMainUri = webview.asWebviewUri( 253 | Uri.joinPath(this._extensionUri, './out/webview', 'main.css'), 254 | ); 255 | 256 | // Use a nonce to only allow a specific script to be run. 257 | const nonce = getNonce(); 258 | 259 | return ` 260 | 261 | 262 | 263 | 264 | 269 | 274 | 275 | 276 | 277 | 278 | 279 | JSON Flow 280 | 281 | 282 |
283 | 284 | 297 | 298 | 299 | `; 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /src/test/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./index.html', './webview/**/*.{js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /tsconfig.doc.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src/**/*.ts", 4 | "webview/**/*.{ts,tsx}", 5 | ], 6 | "exclude": [ 7 | "src/test/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "target": "ES2021", 5 | "outDir": "out", 6 | "lib": ["ES2021", "DOM"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | /* Linting */ 10 | "strict": false /* enable all strict type-checking options */, 11 | /* Additional Checks */ 12 | "noImplicitReturns": false /* Report error when not all code paths in function return a value. */, 13 | "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, 14 | "noUnusedParameters": true /* Report errors on unused parameters. */ 15 | }, 16 | "include": ["src/**/*"], 17 | "exclude": ["node_modules", ".vscode-test"] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.web.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "target": "ES2021", 5 | "lib": [ 6 | "ES2021", 7 | "DOM", 8 | "DOM.Iterable" 9 | ], 10 | "sourceMap": true, 11 | "rootDir": "webview", 12 | "useDefineForClassFields": true, 13 | "skipLibCheck": true, 14 | /* Bundler mode */ 15 | "moduleResolution": "bundler", 16 | "allowImportingTsExtensions": true, 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "noEmit": true, 20 | "jsx": "react-jsx", 21 | /* Linting */ 22 | "strict": true /* enable all strict type-checking options */, 23 | "baseUrl": "./webview", 24 | "paths": { 25 | "*": [ 26 | "types/*" 27 | ] 28 | } 29 | }, 30 | "include": [ 31 | "webview/**/*" 32 | ], 33 | "exclude": [ 34 | "node_modules" 35 | ], 36 | "references": [ 37 | { 38 | "path": "./tsconfig.node.json" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | build: { 8 | minify: true, 9 | rollupOptions: { 10 | output: { 11 | entryFileNames: 'main.js', 12 | assetFileNames: 'main.css', 13 | }, 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | - This folder contains all of the files necessary for your extension. 6 | - `package.json` - this is the manifest file in which you declare your extension and command. 7 | - The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | - `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | - The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | - We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | - Press `F5` to open a new window with your extension loaded. 15 | - Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | - Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | - Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | - You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | - You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | 26 | - You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 27 | 28 | ## Run tests 29 | 30 | - Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 31 | - Press `F5` to run the tests in a new window with your extension loaded. 32 | - See the output of the test result in the debug console. 33 | - Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 34 | - The provided test runner will only consider files matching the name pattern `**.test.ts`. 35 | - You can create folders inside the `test` folder to structure your tests any way you want. 36 | 37 | ## Go further 38 | 39 | - Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 40 | - [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 41 | - Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 42 | -------------------------------------------------------------------------------- /webview/App.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Background, 3 | Connection, 4 | ConnectionLineType, 5 | Controls, 6 | Edge, 7 | MiniMap, 8 | Node, 9 | Panel, 10 | ReactFlow, 11 | addEdge, 12 | useEdgesState, 13 | useNodesState, 14 | } from '@xyflow/react'; 15 | import '@xyflow/react/dist/style.css'; 16 | import * as htmlToImage from 'html-to-image'; 17 | import { useCallback, useEffect, useRef, useState } from 'react'; 18 | import { Direction, StateType } from './common'; 19 | import CustomNode from './components/CustomNode'; 20 | import Loading from './components/Loading'; 21 | import { layoutElements } from './components/layout-elements'; 22 | 23 | // @ts-ignore 24 | // biome-ignore lint/correctness/noUndeclaredVariables: vscode is a global variable 25 | const vscode = acquireVsCodeApi(); 26 | 27 | const nodeTypes = { 28 | custom: CustomNode, 29 | }; 30 | 31 | const LayoutFlow = () => { 32 | const jsonState: StateType = vscode.getState(); 33 | const [json, setJson] = useState(jsonState?.json ?? null); 34 | const [layoutDirection, setLayoutDirection] = useState( 35 | jsonState?.layoutDirection ?? 'TB' 36 | ); 37 | const [nodes, setNodes, onNodesChange] = useNodesState([]); 38 | const [edges, setEdges, onEdgesChange] = useEdgesState([]); 39 | const flowContainerRef = useRef(null); 40 | 41 | useEffect(() => { 42 | const handleMessage = (event: MessageEvent) => { 43 | const message = event.data; 44 | 45 | switch (message.type) { 46 | case 'clearJson': { 47 | setJson(null); 48 | vscode.setState(null); 49 | break; 50 | } 51 | 52 | case 'setJson': { 53 | setJson(message.data); 54 | setLayoutDirection(message.layoutDirection); 55 | vscode.setState({ 56 | ...vscode.getState(), 57 | json: message.data, 58 | layoutDirection: message.layoutDirection, 59 | }); 60 | break; 61 | } 62 | 63 | default: { 64 | break; 65 | } 66 | } 67 | }; 68 | 69 | window.addEventListener('message', handleMessage); 70 | return () => window.removeEventListener('message', handleMessage); 71 | }, []); 72 | 73 | useEffect(() => { 74 | if (json) { 75 | const treeRootId = 1; 76 | const { nodes: layoutedNodes, edges: layoutedEdges } = layoutElements( 77 | json, 78 | treeRootId, 79 | layoutDirection 80 | ); 81 | setNodes(layoutedNodes); 82 | setEdges(layoutedEdges); 83 | } 84 | }, [json, layoutDirection, setNodes, setEdges]); 85 | 86 | const onConnect = useCallback( 87 | (params: Connection) => 88 | setEdges((eds) => 89 | addEdge( 90 | { ...params, type: ConnectionLineType.SmoothStep, animated: true }, 91 | eds 92 | ) 93 | ), 94 | [setEdges] 95 | ); 96 | 97 | const onLayout = useCallback( 98 | (direction: Direction) => { 99 | if (!json) { 100 | return; 101 | } 102 | 103 | setLayoutDirection(direction); 104 | vscode.setState({ 105 | ...vscode.getState(), 106 | layoutDirection: direction, 107 | }); 108 | 109 | const treeRootId = 1; 110 | const { nodes: layoutedNodes, edges: layoutedEdges } = layoutElements( 111 | json, 112 | treeRootId, 113 | direction 114 | ); 115 | 116 | setNodes([...layoutedNodes]); 117 | setEdges([...layoutedEdges]); 118 | }, 119 | [json, setNodes, setEdges] 120 | ); 121 | 122 | const handleSaveImage = async () => { 123 | if (flowContainerRef.current) { 124 | try { 125 | // Temporarily hide the controls 126 | const controls = flowContainerRef.current.querySelectorAll( 127 | '.react-flow__panel, .react-flow__controls, .react-flow__minimap, .react-flow__background' 128 | ); 129 | controls.forEach((control) => { 130 | (control as HTMLElement).style.display = 'none'; 131 | }); 132 | 133 | const dataUrl = await htmlToImage.toPng(flowContainerRef.current); 134 | 135 | // Show the controls again 136 | controls.forEach((control) => { 137 | (control as HTMLElement).style.display = 'block'; 138 | }); 139 | 140 | // Send the generated image to the VS Code extension 141 | vscode.postMessage({ type: 'onSaveImage', data: dataUrl }); 142 | } catch (error) { 143 | console.error('Error generating image:', error); 144 | } 145 | } 146 | }; 147 | 148 | if (!json) { 149 | return ; 150 | } 151 | 152 | return ( 153 |
154 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
175 | ); 176 | }; 177 | 178 | export default LayoutFlow; 179 | -------------------------------------------------------------------------------- /webview/common.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '@xyflow/react'; 2 | import React from 'react'; 3 | 4 | export enum Orientation { 5 | Vertical = 'vertical', 6 | Horizontal = 'horizontal', 7 | } 8 | 9 | let webviewConfiguration; 10 | 11 | if (!window.webviewConfiguration) { 12 | webviewConfiguration = { 13 | nodeWidth: 200, 14 | nodeHeight: 50, 15 | nodeBorderColor: 'white', 16 | nodeColor: 'white', 17 | edgeColor: 'white', 18 | orientation: Orientation.Vertical, 19 | }; 20 | } else { 21 | webviewConfiguration = { 22 | ...window.webviewConfiguration, 23 | orientation: 24 | window.webviewConfiguration.layoutDirection === 'LR' 25 | ? Orientation.Horizontal 26 | : Orientation.Vertical, 27 | }; 28 | } 29 | 30 | export const config = webviewConfiguration; 31 | 32 | export const nodeStyle: React.CSSProperties = { 33 | minHeight: config.nodeHeight, 34 | minWidth: config.nodeWidth, 35 | borderColor: config.nodeBorderColor, 36 | color: config.nodeColor, 37 | }; 38 | 39 | export const edgeStyle: React.CSSProperties = { 40 | stroke: config.edgeColor, 41 | }; 42 | 43 | export const entitreeSettings = { 44 | clone: true, 45 | enableFlex: true, 46 | firstDegreeSpacing: 100, 47 | nextAfterAccessor: 'spouses', 48 | nextAfterSpacing: 100, 49 | nextBeforeAccessor: 'siblings', 50 | nextBeforeSpacing: 100, 51 | nodeHeight: config.nodeHeight, 52 | nodeWidth: config.nodeWidth, 53 | orientation: config.orientation, 54 | rootX: 0, 55 | rootY: 0, 56 | secondDegreeSpacing: 100, 57 | sourcesAccessor: 'parents', 58 | sourceTargetSpacing: 100, 59 | targetsAccessor: 'children', 60 | }; 61 | 62 | export type Direction = 'TB' | 'LR'; 63 | 64 | export type StateType = { 65 | json: Record | null; 66 | layoutDirection: Direction; 67 | }; 68 | 69 | export interface Coordinates { 70 | x: number; 71 | y: number; 72 | } 73 | 74 | export interface BaseNode { 75 | id: string; 76 | name: string; 77 | isSpouse?: boolean; 78 | isSibling?: boolean; 79 | x?: number; 80 | y?: number; 81 | children?: string[]; 82 | parents?: string[]; 83 | siblings?: string[]; 84 | spouses?: string[]; 85 | } 86 | 87 | export interface Tree extends BaseNode { 88 | [key: string]: unknown; 89 | } 90 | 91 | export interface EntitreeNode extends BaseNode { 92 | x: number; 93 | y: number; 94 | } 95 | 96 | export interface EntitreeEdge { 97 | source: BaseNode; 98 | target: BaseNode; 99 | } 100 | 101 | export interface LayoutNode { 102 | id: string; 103 | type: string; 104 | width: number; 105 | height: number; 106 | position: Coordinates; 107 | sourcePosition: Position; 108 | targetPosition: Position; 109 | data: { 110 | label: string; 111 | direction: Direction; 112 | isRoot: boolean; 113 | [key: string]: unknown; 114 | }; 115 | } 116 | 117 | export interface LayoutEdge { 118 | id: string; 119 | source: string; 120 | target: string; 121 | type: string; 122 | animated: boolean; 123 | sourceHandle: Position; 124 | targetHandle: Position; 125 | style: React.CSSProperties; 126 | } 127 | 128 | export interface EntitreeResult { 129 | nodes: EntitreeNode[]; 130 | rels: EntitreeEdge[]; 131 | } 132 | 133 | export interface LayoutResult { 134 | nodes: LayoutNode[]; 135 | edges: LayoutEdge[]; 136 | } 137 | 138 | export interface NodeData { 139 | isSpouse?: boolean; 140 | isSibling?: boolean; 141 | isRoot?: boolean; 142 | label: string; 143 | direction: 'TB' | 'LR'; 144 | children?: string[]; 145 | siblings?: string[]; 146 | spouses?: string[]; 147 | [key: string]: unknown; 148 | } 149 | 150 | export interface NodeProps { 151 | data: NodeData; 152 | } 153 | -------------------------------------------------------------------------------- /webview/components/CustomNode.tsx: -------------------------------------------------------------------------------- 1 | import { Handle, Position } from '@xyflow/react'; 2 | import React, { memo } from 'react'; 3 | import { NodeProps, nodeStyle } from '../common'; 4 | 5 | const { Top, Bottom, Left, Right } = Position; 6 | 7 | const CustomNode: React.FC = memo(({ data }) => { 8 | const { isSpouse, isSibling, label, direction } = data; 9 | 10 | const isTreeHorizontal = direction === 'LR'; 11 | 12 | const getTargetPosition = (): Position => { 13 | if (isSpouse) { 14 | return isTreeHorizontal ? Top : Left; 15 | } else if (isSibling) { 16 | return isTreeHorizontal ? Bottom : Right; 17 | } 18 | return isTreeHorizontal ? Left : Top; 19 | }; 20 | 21 | const isRootNode = data?.isRoot; 22 | const hasChildren = !!data?.children?.length; 23 | const hasSiblings = !!data?.siblings?.length; 24 | const hasSpouses = !!data?.spouses?.length; 25 | 26 | return ( 27 |
28 | {/* For children */} 29 | {hasChildren && ( 30 | 35 | )} 36 | 37 | {/* For spouses */} 38 | {hasSpouses && ( 39 | 44 | )} 45 | 46 | {/* For siblings */} 47 | {hasSiblings && ( 48 | 53 | )} 54 | 55 | {/* Target Handle */} 56 | {!isRootNode && ( 57 | 62 | )} 63 |
64 | {label} 65 |
66 |
67 | ); 68 | }); 69 | 70 | // Nombre para DevTools 71 | CustomNode.displayName = 'CustomNode'; 72 | 73 | export default CustomNode; 74 | -------------------------------------------------------------------------------- /webview/components/Loading.css: -------------------------------------------------------------------------------- 1 | .loading { 2 | height: 4px; 3 | background-color: rgba(5, 114, 206, 0.2); 4 | width: 100%; 5 | overflow: hidden; 6 | margin: auto; 7 | } 8 | 9 | .loading-bar { 10 | width: 100%; 11 | height: 100%; 12 | background-color: rgb(5, 114, 206); 13 | animation: indeterminateAnimation 1s infinite linear; 14 | transform-origin: 0% 50%; 15 | } 16 | 17 | @keyframes indeterminateAnimation { 18 | 0% { 19 | transform: translateX(0) scaleX(0); 20 | } 21 | 40% { 22 | transform: translateX(0) scaleX(0.4); 23 | } 24 | 100% { 25 | transform: translateX(100%) scaleX(0.5); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /webview/components/Loading.tsx: -------------------------------------------------------------------------------- 1 | import './Loading.css'; 2 | 3 | const Loading = () => { 4 | return ( 5 |
6 |
7 |
8 | ); 9 | }; 10 | 11 | export default Loading; 12 | -------------------------------------------------------------------------------- /webview/components/layout-elements.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '@xyflow/react'; 2 | import { layoutFromMap } from 'entitree-flex'; 3 | import { 4 | Direction, 5 | EntitreeResult, 6 | LayoutEdge, 7 | LayoutNode, 8 | LayoutResult, 9 | Orientation, 10 | Tree, 11 | config, 12 | edgeStyle, 13 | entitreeSettings, 14 | } from '../common'; 15 | 16 | const { Top, Bottom, Left, Right } = Position; 17 | 18 | export const layoutElements = ( 19 | tree: Record, 20 | rootId: number, 21 | direction: Direction = 'TB', 22 | ): LayoutResult => { 23 | const isTreeHorizontal = direction === 'LR'; 24 | 25 | const { nodes: entitreeNodes, rels: entitreeEdges }: EntitreeResult = 26 | layoutFromMap(rootId, tree, { 27 | ...entitreeSettings, 28 | orientation: isTreeHorizontal 29 | ? Orientation.Horizontal 30 | : Orientation.Vertical, 31 | }); 32 | 33 | const nodes: LayoutNode[] = []; 34 | const edges: LayoutEdge[] = []; 35 | 36 | entitreeEdges.forEach((edge) => { 37 | const sourceNode = edge.source.id; 38 | const targetNode = edge.target.id; 39 | 40 | const newEdge: LayoutEdge = { 41 | id: 'e' + sourceNode + targetNode, 42 | source: sourceNode, 43 | target: targetNode, 44 | type: 'smoothstep', 45 | animated: true, 46 | sourceHandle: Position.Bottom, 47 | targetHandle: Position.Top, 48 | style: edgeStyle, 49 | }; 50 | 51 | const isTargetSpouse = !!edge.target.isSpouse; 52 | const isTargetSibling = !!edge.target.isSibling; 53 | 54 | if (isTargetSpouse) { 55 | newEdge.sourceHandle = isTreeHorizontal ? Bottom : Right; 56 | newEdge.targetHandle = isTreeHorizontal ? Top : Left; 57 | } else if (isTargetSibling) { 58 | newEdge.sourceHandle = isTreeHorizontal ? Top : Left; 59 | newEdge.targetHandle = isTreeHorizontal ? Bottom : Right; 60 | } else { 61 | newEdge.sourceHandle = isTreeHorizontal ? Right : Bottom; 62 | newEdge.targetHandle = isTreeHorizontal ? Left : Top; 63 | } 64 | 65 | edges.push(newEdge); 66 | }); 67 | 68 | entitreeNodes.forEach((node) => { 69 | const newNode: LayoutNode = { 70 | id: node.id, 71 | type: 'custom', 72 | width: config.nodeWidth, 73 | height: config.nodeHeight, 74 | position: { 75 | x: node.x, 76 | y: node.y, 77 | }, 78 | sourcePosition: Position.Bottom, 79 | targetPosition: Position.Top, 80 | data: { 81 | label: node.name, 82 | direction, 83 | isRoot: node.id === `${rootId}`, 84 | ...node, 85 | }, 86 | }; 87 | 88 | const isSpouse = !!node.isSpouse; 89 | const isSibling = !!node.isSibling; 90 | 91 | if (isSpouse) { 92 | newNode.sourcePosition = isTreeHorizontal ? Bottom : Right; 93 | newNode.targetPosition = isTreeHorizontal ? Top : Left; 94 | } else if (isSibling) { 95 | newNode.sourcePosition = isTreeHorizontal ? Top : Left; 96 | newNode.targetPosition = isTreeHorizontal ? Bottom : Right; 97 | } else { 98 | newNode.sourcePosition = isTreeHorizontal ? Right : Bottom; 99 | newNode.targetPosition = isTreeHorizontal ? Left : Top; 100 | } 101 | 102 | nodes.push(newNode); 103 | }); 104 | 105 | return { nodes, edges }; 106 | }; 107 | -------------------------------------------------------------------------------- /webview/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | padding: 0; 7 | } 8 | 9 | .react-flow { 10 | --xy-controls-button-color-default: #545454; 11 | --xy-minimap-background-color-default: rgba(255, 255, 255, 0.1); 12 | } 13 | 14 | .react-flow__minimap { 15 | display: block; 16 | } 17 | 18 | .node__content { 19 | display: flex; 20 | justify-content: center; 21 | align-items: center; 22 | border-width: 1px; 23 | border-style: solid; 24 | border-radius: 5px; 25 | padding: 10px; 26 | line-height: 2em; 27 | overflow: hidden; 28 | text-overflow: ellipsis; 29 | white-space: nowrap; 30 | word-break: break-all; 31 | } 32 | 33 | .node__content:hover { 34 | height: max-content; 35 | border-width: 1px; 36 | border-style: solid; 37 | border-color: var(--vscode-focusBorder) !important; 38 | background-color: var(--vscode-editor-background); 39 | overflow: visible; 40 | white-space: normal; 41 | } 42 | 43 | button { 44 | border: none; 45 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 46 | height: 25px; 47 | width: 125px; 48 | border-radius: 2px; 49 | text-align: center; 50 | outline: 1px solid transparent; 51 | outline-offset: 2px !important; 52 | color: var(--vscode-button-foreground); 53 | background: var(--vscode-button-background); 54 | } 55 | 56 | button:hover { 57 | cursor: pointer; 58 | background: var(--vscode-button-hoverBackground); 59 | } 60 | 61 | button:focus { 62 | outline-color: var(--vscode-focusBorder); 63 | } 64 | -------------------------------------------------------------------------------- /webview/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import App from './App.tsx'; 4 | import './index.css'; 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /webview/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.web.json", 3 | "references": [ 4 | { 5 | "path": "../tsconfig.node.json" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /webview/types/global.d.ts: -------------------------------------------------------------------------------- 1 | // global.d.ts 2 | export {}; 3 | 4 | declare global { 5 | interface Window { 6 | webviewConfiguration: { 7 | nodeWidth: number; 8 | nodeHeight: number; 9 | nodeBorderColor: string; 10 | nodeColor: string; 11 | edgeColor: string; 12 | layoutDirection: string; 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /webview/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | --------------------------------------------------------------------------------