├── .gitignore ├── icon.png ├── .vscodeignore ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── CHANGELOG.md ├── src ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts └── extension.ts ├── tsconfig.json ├── .eslintrc.json ├── LICENSE ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | *.log -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/albbus-stack/t3-cua-tools/HEAD/icon.png -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | src/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | -------------------------------------------------------------------------------- /.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 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "t3-cua-tools" extension will be documented in this file. 4 | 5 | ## [0.0.1] 6 | 7 | - Initial release with 3 commands: 8 | - `t3-cua-tools.newScreen` 9 | - `t3-cua-tools.newComponent` 10 | - `t3-cua-tools.newRoute` 11 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | "terminal.integrated.defaultProfile.windows": null 12 | } 13 | -------------------------------------------------------------------------------- /src/test/suite/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 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2020" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "out", 21 | "dist", 22 | "**/*.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /.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": ["--extensionDevelopmentPath=${workspaceFolder}"], 13 | "outFiles": ["${workspaceFolder}/out/**/*.js"], 14 | "preLaunchTask": "${defaultBuildTask}" 15 | }, 16 | { 17 | "name": "Extension Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "args": [ 21 | "--extensionDevelopmentPath=${workspaceFolder}", 22 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 23 | ], 24 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"], 25 | "preLaunchTask": "${defaultBuildTask}" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 albbus-stack 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "t3-cua-tools", 3 | "displayName": "t3-cua-tools", 4 | "description": "A set of tools to help you create new screens, components and routes for your CUA project.", 5 | "icon": "icon.png", 6 | "version": "1.0.3", 7 | "license": "MIT", 8 | "publisher": "albbus-stack", 9 | "author": { 10 | "name": "Alberto Del Buono Paolini", 11 | "url": "https://github.com/albbus-stack" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/albbus-stack/t3-cua-tools" 16 | }, 17 | "engines": { 18 | "vscode": "^1.74.0" 19 | }, 20 | "categories": [ 21 | "Other" 22 | ], 23 | "activationEvents": [ 24 | "onCommand:t3-cua-tools.newScreen" 25 | ], 26 | "main": "./out/extension.js", 27 | "contributes": { 28 | "commands": [ 29 | { 30 | "command": "t3-cua-tools.newScreen", 31 | "title": "t3-cua-tools: New Screen" 32 | }, 33 | { 34 | "command": "t3-cua-tools.newComponent", 35 | "title": "t3-cua-tools: New Component" 36 | }, 37 | { 38 | "command": "t3-cua-tools.newRoute", 39 | "title": "t3-cua-tools: New API Route" 40 | } 41 | ] 42 | }, 43 | "scripts": { 44 | "vscode:prepublish": "npm run compile", 45 | "compile": "tsc -p ./", 46 | "watch": "tsc -watch -p ./", 47 | "pretest": "npm run compile && npm run lint", 48 | "lint": "eslint src --ext ts", 49 | "test": "node ./out/test/runTest.js" 50 | }, 51 | "devDependencies": { 52 | "@types/vscode": "^1.74.0", 53 | "@types/glob": "^8.0.0", 54 | "@types/mocha": "^10.0.1", 55 | "@types/node": "16.x", 56 | "@typescript-eslint/eslint-plugin": "^5.45.0", 57 | "@typescript-eslint/parser": "^5.45.0", 58 | "eslint": "^8.28.0", 59 | "glob": "^8.0.3", 60 | "mocha": "^10.1.0", 61 | "typescript": "^4.9.3", 62 | "@vscode/test-electron": "^2.2.0" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # t3-cua-tools 2 | 3 | ![Typescript](https://shields.io/badge/TypeScript-3178C6?logo=TypeScript&logoColor=FFF&style=flat-square) 4 | ![Code](https://shields.io/badge/VSCode-00495c?logo=visual-studio-code&logoColor=FFF&style=flat-square) 5 | 6 |

7 | ⚠  This repo has been moved under the t4-app monorepo  ⚠ 8 |

9 | 10 | This is a VSCode extension that consists of a set of tools for apps created with the create-t3-universal-app tool or cloned from the [CUA](https://github.com/chen-rn/CUA) (create-universal-app) template. This is also fully compatible with the latest version of CUA that's using Expo Router. 11 | 12 | The public extension is live on the VSCode marketplace [here](https://marketplace.visualstudio.com/items?itemName=albbus-stack.t3-cua-tools). 13 | 14 | ## Usage 15 | 16 | ### New Screen 17 | 18 | Input the new screen name in CapitalizedCamelCase (i.e. the name that you would have used for the screen component). Subsequently this command will generate a new `screen.tsx` file under the directory `packages/app/features/{ScreenName}`, add the generated component to the stack navigator in `packages/app/navigation/native/index.tsx`, add a new route in `packages/app/provider/navigation/index.tsx` and add a new `index.tsx` under `apps/nextjs/pages/{ScreenName}` importing your new screen in Nextjs. After that it will open the new `screen.tsx` file for you to modify. 19 | 20 | ### New Component 21 | 22 | Input the new component name in CapitalizedCamelCase. Subsequently this command will generate a new component under the `packages/ui/src/components` folder. After that it will open the new `{ComponentName}.tsx` file for you to modify. 23 | 24 | ### New API Route 25 | 26 | Input the new API route name in lowercaseCamelCase. Subsequently this command will generate a new router in the `packages/api/src/router` folder and add that to the `index.ts` router. After that it will open the new `{routeName.ts}` file for you to modify. 27 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import { TextEncoder } from "util"; 2 | import * as fs from "fs"; 3 | import * as vscode from "vscode"; 4 | import * as path from "path"; 5 | 6 | const isWithExpoRouter = async (workspaceFolder: vscode.WorkspaceFolder) => { 7 | let folderUri = path.join( 8 | workspaceFolder.uri.fsPath, 9 | "packages", 10 | "app", 11 | "navigation", 12 | "native" 13 | ); 14 | 15 | return !fs.existsSync(folderUri); 16 | }; 17 | 18 | export function activate(context: vscode.ExtensionContext) { 19 | const disposableScreen = vscode.commands.registerCommand( 20 | "t3-cua-tools.newScreen", 21 | async () => { 22 | const screenName = await vscode.window.showInputBox({ 23 | placeHolder: "NewScreen", 24 | prompt: "Enter the name of the new screen", 25 | }); 26 | // Check if the user input is not empty 27 | if (!screenName || screenName.includes(" ")) { 28 | vscode.window.showInformationMessage( 29 | `Enter a valid screen name. You entered: ${screenName}` 30 | ); 31 | return; 32 | } 33 | 34 | const isStaticRoute = await vscode.window 35 | .showQuickPick(["Static Route", "Dynamic Route"], { 36 | placeHolder: "What type of route does this screen depend on?", 37 | }) 38 | .then((result) => result === "Static Route"); 39 | 40 | let parameterName = undefined; 41 | if (!isStaticRoute) { 42 | parameterName = await vscode.window.showInputBox({ 43 | placeHolder: "id", 44 | prompt: "Enter the name of the dynamic route parameter", 45 | }); 46 | // Check if the user input is not empty 47 | if (!parameterName || parameterName.includes(" ")) { 48 | vscode.window.showInformationMessage( 49 | `Enter a valid parameter name. You entered: ${parameterName}` 50 | ); 51 | return; 52 | } 53 | } 54 | 55 | // Get the active workspace folder 56 | const workspaceFolder = vscode.workspace.workspaceFolders 57 | ? vscode.workspace.workspaceFolders[0] 58 | : undefined; 59 | if (!workspaceFolder) { 60 | vscode.window.showInformationMessage( 61 | "No workspace folder is open. Please open a workspace folder and try again." 62 | ); 63 | return; 64 | } 65 | 66 | const folderUri = vscode.Uri.file( 67 | path.join( 68 | workspaceFolder.uri.fsPath, 69 | "packages", 70 | "app", 71 | "features", 72 | screenName.toLowerCase() 73 | ) 74 | ); 75 | const fileUri = vscode.Uri.file( 76 | path.join(folderUri.fsPath, "screen.tsx") 77 | ); 78 | 79 | // Create the new screen folder 80 | vscode.workspace.fs.createDirectory(folderUri); 81 | 82 | // Create the new screen file 83 | let screenFileData = new TextEncoder().encode( 84 | `import { Paragraph, YStack } from "@my/ui";\nimport React from "react";\n\nexport function ${ 85 | screenName + "Screen" 86 | }() {\n return (\n \n \n ${screenName.toLowerCase()}\n \n \n );\n} ` 87 | ); 88 | if (!isStaticRoute) { 89 | screenFileData = new TextEncoder().encode( 90 | `import { Paragraph, YStack } from "@my/ui";\nimport React from "react";\nimport { createParam } from "solito";\n\nconst { useParam } = createParam<{ ${parameterName!.toLowerCase()}: string }>()\n\nexport function ${ 91 | screenName + "Screen" 92 | }() {\n const [${parameterName!.toLowerCase()}] = useParam('${parameterName!.toLowerCase()}')\n\n return (\n \n \n {\`${parameterName!.toLowerCase()}: \${${parameterName!.toLowerCase()}}\`}\n \n \n );\n} ` 93 | ); 94 | } 95 | await vscode.workspace.fs.writeFile(fileUri, screenFileData); 96 | 97 | // Check to see if this is an app created with the expo router template 98 | const withExpoRouter = await isWithExpoRouter(workspaceFolder); 99 | 100 | if (!withExpoRouter) { 101 | // Same for navigation/native/index.tsx 102 | const navigationFileUri = vscode.Uri.file( 103 | path.join( 104 | workspaceFolder.uri.fsPath, 105 | "packages", 106 | "app", 107 | "navigation", 108 | "native", 109 | "index.tsx" 110 | ) 111 | ); 112 | 113 | const navigationIndex = await vscode.workspace.openTextDocument( 114 | navigationFileUri 115 | ); 116 | const navContents = navigationIndex.getText(); 117 | 118 | const newImport = `import { ${ 119 | screenName + "Screen" 120 | } } from "../../features/${screenName.toLowerCase()}/screen";\n`; 121 | const startingCreateStack = navContents.lastIndexOf("import"); 122 | let newRoute = ` ${screenName.toLowerCase()}: undefined;\n`; 123 | if (!isStaticRoute) { 124 | newRoute = ` "${screenName.toLowerCase()}": {\n ${parameterName!.toLowerCase()}:string;\n };\n`; 125 | } 126 | const closingCreateStack = navContents.indexOf("}>();"); 127 | const newStackScreen = ` \n`; 130 | const closingNavIndex = navContents.indexOf(""); 131 | 132 | const newNavContents = 133 | navContents.substring(0, startingCreateStack) + 134 | newImport + 135 | navContents.substring(startingCreateStack, closingCreateStack) + 136 | newRoute + 137 | navContents.substring(closingCreateStack, closingNavIndex) + 138 | newStackScreen + 139 | navContents.substring(closingNavIndex); 140 | 141 | // Write the new contents to the navigation file 142 | const newNavFileData = new TextEncoder().encode(newNavContents); 143 | vscode.workspace.fs.writeFile(navigationFileUri, newNavFileData); 144 | 145 | // Same for provider/navigation/index.tsx 146 | const navigationProviderFileUri = vscode.Uri.file( 147 | path.join( 148 | workspaceFolder.uri.fsPath, 149 | "packages", 150 | "app", 151 | "provider", 152 | "navigation", 153 | "index.tsx" 154 | ) 155 | ); 156 | 157 | const navigationProviderIndex = await vscode.workspace.openTextDocument( 158 | navigationProviderFileUri 159 | ); 160 | const navProviderContents = navigationProviderIndex.getText(); 161 | 162 | let newNavRoute = ` ${screenName.toLowerCase()}: "${screenName.toLowerCase()}",\n`; 163 | if (!isStaticRoute) { 164 | newNavRoute = ` ${screenName.toLowerCase()}: "${screenName.toLowerCase()}/:${parameterName!.toLowerCase()}",\n`; 165 | } 166 | const closingScreenObject = navProviderContents.indexOf( 167 | "},", 168 | navProviderContents.indexOf("screens: {") 169 | ); 170 | 171 | const newNavProviderContents = 172 | navProviderContents.substring(0, closingScreenObject) + 173 | newNavRoute + 174 | navProviderContents.substring(closingScreenObject); 175 | 176 | // Write the new contents to the navigation file 177 | const newNavProviderFileData = new TextEncoder().encode( 178 | newNavProviderContents 179 | ); 180 | vscode.workspace.fs.writeFile( 181 | navigationProviderFileUri, 182 | newNavProviderFileData 183 | ); 184 | } else { 185 | // In the case that this is an expo-router app 186 | let expoFolderUri = vscode.Uri.file( 187 | path.join(workspaceFolder.uri.fsPath, "apps", "expo", "app") 188 | ); 189 | let expoFileUri = vscode.Uri.file( 190 | path.join(expoFolderUri.fsPath, `${screenName.toLowerCase()}.tsx`) 191 | ); 192 | 193 | if (!isStaticRoute) { 194 | expoFolderUri = vscode.Uri.file( 195 | path.join( 196 | workspaceFolder.uri.fsPath, 197 | "apps", 198 | "expo", 199 | "app", 200 | screenName.toLowerCase() 201 | ) 202 | ); 203 | 204 | expoFileUri = vscode.Uri.file( 205 | path.join( 206 | expoFolderUri.fsPath, 207 | `[${parameterName!.toLowerCase()}].tsx` 208 | ) 209 | ); 210 | } 211 | 212 | // Create the new screen folder 213 | vscode.workspace.fs.createDirectory(expoFolderUri); 214 | 215 | // Create the new screen file 216 | const screenFileData = new TextEncoder().encode( 217 | `import { ${ 218 | screenName + "Screen" 219 | } } from "app/features/${screenName.toLowerCase()}/screen";\n\nexport default function () {\n return <${ 220 | screenName + "Screen" 221 | }/>\n}\n` 222 | ); 223 | await vscode.workspace.fs.writeFile(expoFileUri, screenFileData); 224 | } 225 | 226 | // This is common between the two app templates 227 | // Same for apps/nextjs/pages 228 | const nextFolderUri = vscode.Uri.file( 229 | path.join( 230 | workspaceFolder.uri.fsPath, 231 | "apps", 232 | "nextjs", 233 | "pages", 234 | screenName.toLowerCase() 235 | ) 236 | ); 237 | let nextFileUri = vscode.Uri.file( 238 | path.join(nextFolderUri.fsPath, "index.tsx") 239 | ); 240 | 241 | if (!isStaticRoute) { 242 | nextFileUri = vscode.Uri.file( 243 | path.join( 244 | nextFolderUri.fsPath, 245 | `[${parameterName!.toLowerCase()}].tsx` 246 | ) 247 | ); 248 | } 249 | 250 | // Create the new nextjs folder 251 | vscode.workspace.fs.createDirectory(nextFolderUri); 252 | 253 | // Create the new nextjs file 254 | const nextFileData = new TextEncoder().encode( 255 | `import { ${ 256 | screenName + "Screen" 257 | } } from 'app/features/${screenName.toLowerCase()}/screen'\n\nexport default ${ 258 | screenName + "Screen" 259 | }\n` 260 | ); 261 | await vscode.workspace.fs.writeFile(nextFileUri, nextFileData); 262 | 263 | // Open the screen.tsx file 264 | const newScreenDocument = await vscode.workspace.openTextDocument( 265 | fileUri 266 | ); 267 | 268 | // Show it in the editor 269 | vscode.window.showTextDocument(newScreenDocument); 270 | } 271 | ); 272 | 273 | const disposableComponent = vscode.commands.registerCommand( 274 | "t3-cua-tools.newComponent", 275 | async () => { 276 | const componentName = await vscode.window.showInputBox({ 277 | placeHolder: "NewComponent", 278 | prompt: "Enter the name of the new component", 279 | }); 280 | // Check if the user input is not empty 281 | if (!componentName || componentName.includes(" ")) { 282 | // Do something with the user input 283 | vscode.window.showInformationMessage( 284 | `Enter a valid component name. You entered: ${componentName}` 285 | ); 286 | return; 287 | } 288 | 289 | // Get the active workspace folder 290 | const workspaceFolder = vscode.workspace.workspaceFolders 291 | ? vscode.workspace.workspaceFolders[0] 292 | : undefined; 293 | if (!workspaceFolder) { 294 | vscode.window.showInformationMessage( 295 | "No workspace folder is open. Please open a workspace folder and try again." 296 | ); 297 | return; 298 | } 299 | 300 | const newFileUri = vscode.Uri.file( 301 | path.join( 302 | workspaceFolder.uri.fsPath, 303 | "packages", 304 | "ui", 305 | "src", 306 | "components", 307 | componentName + ".tsx" 308 | ) 309 | ); 310 | 311 | // Create the new component file 312 | const componentFileData = new TextEncoder().encode( 313 | `import { Paragraph, YStack } from "@my/ui";\nimport React from "react";\n\nexport function ${componentName}() {\n return (\n \n \n ${componentName}\n \n \n );\n} ` 314 | ); 315 | await vscode.workspace.fs.writeFile(newFileUri, componentFileData); 316 | 317 | // Open the {componentName}.tsx file 318 | const newComponentDocument = await vscode.workspace.openTextDocument( 319 | newFileUri 320 | ); 321 | 322 | // Show it in the editor 323 | vscode.window.showTextDocument(newComponentDocument); 324 | } 325 | ); 326 | 327 | const disposableRoute = vscode.commands.registerCommand( 328 | "t3-cua-tools.newRoute", 329 | async () => { 330 | const routeName = await vscode.window.showInputBox({ 331 | placeHolder: "newRoute", 332 | prompt: "Enter the name of the new route", 333 | }); 334 | // Check if the user input is not empty 335 | if (!routeName || routeName.includes(" ")) { 336 | // Do something with the user input 337 | vscode.window.showInformationMessage( 338 | `Enter a valid route name. You entered: ${routeName}` 339 | ); 340 | return; 341 | } 342 | 343 | // Get the active workspace folder 344 | const workspaceFolder = vscode.workspace.workspaceFolders 345 | ? vscode.workspace.workspaceFolders[0] 346 | : undefined; 347 | if (!workspaceFolder) { 348 | vscode.window.showInformationMessage( 349 | "No workspace folder is open. Please open a workspace folder and try again." 350 | ); 351 | return; 352 | } 353 | 354 | const newFileUri = vscode.Uri.file( 355 | path.join( 356 | workspaceFolder.uri.fsPath, 357 | "packages", 358 | "api", 359 | "src", 360 | "router", 361 | routeName + ".ts" 362 | ) 363 | ); 364 | 365 | // Create the new route file 366 | const routeFileData = new TextEncoder().encode( 367 | `import { protectedProcedure, publicProcedure, router } from "../trpc";\n\nexport const ${routeName}Router = router({\n\n});\n` 368 | ); 369 | await vscode.workspace.fs.writeFile(newFileUri, routeFileData); 370 | 371 | const routerIndexFileUri = vscode.Uri.file( 372 | path.join( 373 | workspaceFolder.uri.fsPath, 374 | "packages", 375 | "api", 376 | "src", 377 | "router", 378 | "index.ts" 379 | ) 380 | ); 381 | 382 | const navigationProviderIndex = await vscode.workspace.openTextDocument( 383 | routerIndexFileUri 384 | ); 385 | const RouterContents = navigationProviderIndex.getText(); 386 | 387 | const newImport = `import { ${routeName}Router } from "./${routeName}";\n`; 388 | const lastImportIndex = RouterContents.lastIndexOf("import"); 389 | const newRoute = ` ${routeName}: ${routeName}Router,\n`; 390 | const closingRouterObject = RouterContents.indexOf("});"); 391 | 392 | const newRouterContents = 393 | RouterContents.substring(0, lastImportIndex) + 394 | newImport + 395 | RouterContents.substring(lastImportIndex, closingRouterObject) + 396 | newRoute + 397 | RouterContents.substring(closingRouterObject); 398 | 399 | // Write the new contents to the navigation file 400 | const newRouterFileData = new TextEncoder().encode(newRouterContents); 401 | vscode.workspace.fs.writeFile(routerIndexFileUri, newRouterFileData); 402 | 403 | // Open the {componentName}.tsx file 404 | const newRouteDocument = await vscode.workspace.openTextDocument( 405 | newFileUri 406 | ); 407 | 408 | // Show it in the editor 409 | vscode.window.showTextDocument(newRouteDocument); 410 | } 411 | ); 412 | 413 | context.subscriptions.push(disposableScreen); 414 | context.subscriptions.push(disposableComponent); 415 | context.subscriptions.push(disposableRoute); 416 | } 417 | 418 | // this method is called when your extension is deactivated 419 | export function deactivate() {} 420 | --------------------------------------------------------------------------------