From d9772b1daca4096ae36c239cc3b74040772beae7 Mon Sep 17 00:00:00 2001 From: ManuelGil Date: Wed, 21 Feb 2024 08:17:50 -0500 Subject: [PATCH] feat: :sparkles: add Convert to TypeScript feature and update file handling logic --- CHANGELOG.md | 13 +++ package.json | 24 ++++++ src/app/controllers/example.controller.ts | 90 +++++++++++++++++++- src/app/controllers/list-files.controller.ts | 2 +- src/app/providers/list-files.providers.ts | 32 ++++--- src/extension.ts | 23 +++-- 6 files changed, 164 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef39579..863765e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `covertToTS` method to `example.controller.ts` file to convert a JSON Schema to TypeScript +- Add Convert to TypeScript command to convert a JSON Schema to TypeScript + +### Changed + +- Update `package.json` to include the Convert to TypeScript command in the contributes section + +### Fixed + +- Fix `getListFiles` method in `list-files.provider.ts` file to show a message when there are no files + ## [1.4.0] - 2024-02-18 ### Added diff --git a/package.json b/package.json index 72e5a42..2c0957c 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,11 @@ "title": "Get Files in Folder", "category": "MyExtension" }, + { + "command": "extension-starter-kit.convertToTS", + "title": "Convert JSON to TypeScript", + "category": "MyExtension" + }, { "command": "extension-starter-kit.feedback.aboutUs", "title": "About Us", @@ -172,6 +177,10 @@ { "id": "extension-starter-kit.explorer.submenu", "label": "MyExtension" + }, + { + "id": "extension-starter-kit.editor.submenu", + "label": "MyExtension" } ], "menus": { @@ -195,12 +204,26 @@ "when": "explorerViewletFocus && explorerResourceIsFolder && !explorerResourceIsRoot" } ], + "editor/context": [ + { + "submenu": "extension-starter-kit.editor.submenu", + "group": "1_modification", + "when": "editorHasSelection" + } + ], "extension-starter-kit.explorer.submenu": [ { "command": "extension-starter-kit.getFilesInFolder", "alt": "Get Files in Folder", "group": "extension-starter-kit@1" } + ], + "extension-starter-kit.editor.submenu": [ + { + "command": "extension-starter-kit.convertToTS", + "alt": "Convert JSON to TypeScript", + "group": "extension-starter-kit@2" + } ] }, "viewsWelcome": [ @@ -284,6 +307,7 @@ "vscode-test": "^1.5.0" }, "dependencies": { + "json-to-ts": "^1.7.0", "openai": "^4.26.1" } } diff --git a/src/app/controllers/example.controller.ts b/src/app/controllers/example.controller.ts index f1b6f39..d037afe 100644 --- a/src/app/controllers/example.controller.ts +++ b/src/app/controllers/example.controller.ts @@ -1,4 +1,5 @@ -import { Uri } from 'vscode'; +import JsonToTS from 'json-to-ts'; +import { Range, TextEditor, Uri, window, workspace } from 'vscode'; // Import the Config and helper functions import { ExtensionConfig } from '../configs'; @@ -7,6 +8,7 @@ import { getPath, getRelativePath, saveFile, + showError, showMessage, } from '../helpers'; @@ -100,7 +102,7 @@ export class ExampleController { }); // If files are found, save them to a file - if (files.length > 0) { + if (files.length !== 0) { // Write the content to a file const result = await saveFile( folder, @@ -114,4 +116,88 @@ export class ExampleController { } } } + + /** + * The convertToTS method. + * + * @function convertToTS + * @public + * @async + * @memberof ConvertController + * @example + * await controller.convertToTS(); + * + * @returns {Promise} The result + */ + async convertToTS(): Promise { + let editor; + + if (workspace.workspaceFolders) { + editor = window.activeTextEditor; + } else { + showError('No text editor is active.'); + return; + } + + const selection = editor?.selection; + + if (selection && !selection.isEmpty) { + const selectionRange = new Range( + selection.start.line, + selection.start.character, + selection.end.line, + selection.end.character, + ); + + const text = editor?.document.getText(selectionRange) || ''; + + const jsonSchema = this.tryParseJSONObject(text); + + if (!jsonSchema) { + showError('Invalid JSON Schema!'); + return; + } + + const tsSchema = JsonToTS(jsonSchema) + .map((itf) => `export ${itf}\n`) + .join('\n'); + + const document = await workspace.openTextDocument({ + language: 'typescript', + content: tsSchema, + }); + + return await window.showTextDocument(document); + } + + showError('No text is selected!'); + return; + } + + // Private methods + /** + * The tryParseJSONObject method. + * + * @private + * @memberof ConvertController + * @param {string} str - The string to parse + * @returns {boolean | object} The result + * @example + * const object = controller.tryParseJSONObject(str); + * + * @returns {boolean | object} The result + */ + private tryParseJSONObject(str: string): boolean | object { + try { + var object = JSON.parse(str); + + if (object && typeof object === 'object') { + return object; + } + } catch (e) { + return false; + } + + return false; + } } diff --git a/src/app/controllers/list-files.controller.ts b/src/app/controllers/list-files.controller.ts index 390c3dd..171bbb8 100644 --- a/src/app/controllers/list-files.controller.ts +++ b/src/app/controllers/list-files.controller.ts @@ -66,7 +66,7 @@ export class ListFilesController { maxResults, }); - if (files.length > 0) { + if (files.length !== 0) { let nodes: NodeModel[] = []; files.sort((a, b) => a.path.localeCompare(b.path)); diff --git a/src/app/providers/list-files.providers.ts b/src/app/providers/list-files.providers.ts index 90b60ec..2b31893 100644 --- a/src/app/providers/list-files.providers.ts +++ b/src/app/providers/list-files.providers.ts @@ -149,13 +149,13 @@ export class ListFilesProvider implements TreeDataProvider { * @example * const files = provider.getListFiles(); * - * @returns {Promise} - The list of files + * @returns {Promise} - The list of files */ - private async getListFiles(): Promise { + private async getListFiles(): Promise { const files = await this.controller.getFiles(); if (!files) { - return []; + return; } const nodes: NodeModel[] = []; @@ -166,15 +166,23 @@ export class ListFilesProvider implements TreeDataProvider { const children = files.filter((file) => file.label.toString().endsWith(`.${fileType}`), ); - const node = new NodeModel( - `${fileType}: ${children.length}`, - new ThemeIcon('folder-opened'), - undefined, - undefined, - fileType, - children, - ); - nodes.push(node); + + if (children.length !== 0) { + const node = new NodeModel( + `${fileType}: ${children.length}`, + new ThemeIcon('folder-opened'), + undefined, + undefined, + fileType, + children, + ); + + nodes.push(node); + } + } + + if (nodes.length === 0) { + return; } return nodes; diff --git a/src/extension.ts b/src/extension.ts index 8e63510..63d1117 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,7 +3,7 @@ import * as vscode from 'vscode'; // Import the Configs, Controllers, and Providers -import { ExtensionConfig, EXTENSION_ID } from './app/configs'; +import { EXTENSION_ID, ExtensionConfig } from './app/configs'; import { ExampleController, FeedbackController, @@ -20,11 +20,15 @@ import { OpenAIService } from './app/services'; // your extension is activated the very first time the command is executed export function activate(context: vscode.ExtensionContext) { // The code you place here will be executed every time your command is executed - let resource: vscode.Uri | null = null; + let resource: + | vscode.Uri + | vscode.TextDocument + | vscode.WorkspaceFolder + | undefined; // Get the resource for the workspace if (vscode.workspace.workspaceFolders) { - resource = vscode.workspace.workspaceFolders[0].uri; + resource = vscode.workspace.workspaceFolders[0]; } // ----------------------------------------------------------------- @@ -33,7 +37,7 @@ export function activate(context: vscode.ExtensionContext) { // Get the configuration for the extension const config = new ExtensionConfig( - vscode.workspace.getConfiguration(EXTENSION_ID, resource ?? null), + vscode.workspace.getConfiguration(EXTENSION_ID, resource), ); // ----------------------------------------------------------------- @@ -64,7 +68,16 @@ export function activate(context: vscode.ExtensionContext) { (args) => exampleController.getFilesInFolder(args), ); - context.subscriptions.push(disposableHelloWorld, disposableGetFilesInFolder); + const disposableConvertToTS = vscode.commands.registerCommand( + `${EXTENSION_ID}.convertToTS`, + () => exampleController.convertToTS(), + ); + + context.subscriptions.push( + disposableHelloWorld, + disposableGetFilesInFolder, + disposableConvertToTS, + ); // ----------------------------------------------------------------- // Register ListFilesController