├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── README.md ├── package.json ├── screenshots ├── icon.png ├── settings.png └── usage.png ├── src ├── commands │ ├── commands.ts │ └── index.ts ├── extension.ts └── utils │ ├── editor-helper.ts │ ├── errors.ts │ ├── file-manager.ts │ ├── file-name.ts │ └── index.ts ├── tsconfig.json └── webpack.config.js /.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": [ 13 | "warn", 14 | { 15 | "selector": "import", 16 | "format": [ "camelCase", "PascalCase" ] 17 | } 18 | ], 19 | "@typescript-eslint/semi": "warn", 20 | "curly": "warn", 21 | "eqeqeq": "warn", 22 | "no-throw-literal": "warn", 23 | "semi": "off" 24 | }, 25 | "ignorePatterns": [ 26 | "out", 27 | "dist", 28 | "**/*.d.ts" 29 | ] 30 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test 4 | *.vsix 5 | dist 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "all" 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": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher", "ms-vscode.extension-test-runner"] 5 | } 6 | -------------------------------------------------------------------------------- /.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}/dist/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.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 | "dist": false // set this to true to hide the "dist" folder with the compiled JS files 6 | }, 7 | "search.exclude": { 8 | "out": true, // set this to false to include "out" folder in search results 9 | "dist": true // set this to false to include "dist" folder in search results 10 | }, 11 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 12 | "typescript.tsc.autoDetect": "off" 13 | } -------------------------------------------------------------------------------- /.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": "$ts-webpack-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never", 13 | "group": "watchers" 14 | }, 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | } 19 | }, 20 | { 21 | "type": "npm", 22 | "script": "watch-tests", 23 | "problemMatcher": "$tsc-watch", 24 | "isBackground": true, 25 | "presentation": { 26 | "reveal": "never", 27 | "group": "watchers" 28 | }, 29 | "group": "build" 30 | }, 31 | { 32 | "label": "tasks: watch-tests", 33 | "dependsOn": [ 34 | "npm: watch", 35 | "npm: watch-tests" 36 | ], 37 | "problemMatcher": [] 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | node_modules/** 5 | src/** 6 | .gitignore 7 | .yarnrc 8 | webpack.config.js 9 | vsc-extension-quickstart.md 10 | **/tsconfig.json 11 | **/.eslintrc.json 12 | **/*.map 13 | **/*.ts 14 | **/.vscode-test.* 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 0.4.1 (2024-04-22) 4 | 5 | **Refactor** 6 | 7 | - show update notification only once 8 | 9 | ## 0.4.0 (2024-04-20) 10 | 11 | - deprecate commands that export the files to index.dart in favor of the extension settings 12 | - add extension settings for: 13 | - export file name (default: dir_name.dart) 14 | - recursive export option (iterate through directories recursively to create global export file) 15 | - ignore patterns for files (glob patterns) 16 | - update extension's dependencies 17 | 18 | ## 0.3.1 (2021-12-21) 19 | 20 | - Update Name 21 | 22 | ## 0.3.0 (2021-12-21) 23 | 24 | - Ignore `.g.dart` and `.freezed.dart` files 25 | - Update dependencies 26 | 27 | ## 0.2.1 (2020-12-14) 28 | 29 | - Code cleanup and activation fix 30 | 31 | ## 0.2.0 (2020-12-14) 32 | 33 | - Adding 2 new commands to export Dart files to `dir_name.dart` 🚀 34 | 35 | ## 0.1.0 - 0.1.3 36 | 37 | - Initial release 🌱 (ported from create-index extension) 38 | - Exporting Dart files to `index.dart` 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dart Barrel Export File Generator 2 | 3 | [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=orestesgaolin.dart-export-index) 4 | 5 | ## Features 6 | 7 | ![Usage](./screenshots/usage.png) 8 | 9 | This extension includes following commands: 10 | 11 | - _Export Dart files in current directory export file_ 12 | - export file name configurable in settings 13 | - can be run recursively 14 | - will create `export_file_name.dart` file exporting all the Dart files in the current directory e.g. `widgets.dart` if run within _widgets_ directory 15 | - _Export (add) current Dart file to export file_ (export file name configurable in settings) 16 | - will add current file to `export_file_name.dart` in the current directory 17 | 18 | ## Extension Settings 19 | 20 | ![Usage](./screenshots/settings.png) 21 | 22 | This extension contributes the following settings: 23 | 24 | - `dartBarrelExportFileGenerator.exportFileName`: export file name (default: `dir_name.dart`) 25 | - `dartBarrelExportFileGenerator.recursiveExport`: iterate through directories recursively to create global export file (default: `false`) 26 | - `dartBarrelExportFileGenerator.ignorePatterns`: ignore files (glob patterns) 27 | 28 | ## Source 29 | 30 | Source code available on [GitHub](https://github.com/orestesgaolin/create-index). 31 | 32 | This is a fork of [create-index](https://github.com/tsugitta/create-index). 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dart-export-index", 3 | "displayName": "Dart Barrel Export File Generator", 4 | "description": "Create barrel file that exports the files in current directory. This allows for importing whole folders in batch instead of importing each file one by one. Creates index.dart and dir_name.dart.", 5 | "icon": "screenshots/icon.png", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/orestesgaolin/dart-export-index" 9 | }, 10 | "version": "0.4.1", 11 | "publisher": "orestesgaolin", 12 | "engines": { 13 | "vscode": "^1.88.0" 14 | }, 15 | "categories": [ 16 | "Other" 17 | ], 18 | "main": "./dist/extension.js", 19 | "contributes": { 20 | "commands": [ 21 | { 22 | "command": "extension.addCurrentFileToIndexDart", 23 | "title": "Export (add) current Dart file to index.dart (deprecated)" 24 | }, 25 | { 26 | "command": "extension.addCurrentFileToIndexDartDirName", 27 | "title": "Export (add) current Dart file to export file" 28 | }, 29 | { 30 | "command": "extension.exportDartFilesInCurrentDirectory", 31 | "title": "Export Dart files in current directory to index.dart (deprecated)" 32 | }, 33 | { 34 | "command": "extension.exportDartFilesInCurrentDirectoryDirName", 35 | "title": "Export Dart files in current directory export file" 36 | } 37 | ], 38 | "configuration": { 39 | "title": "Dart Barrel Export File Generator", 40 | "properties": { 41 | "dartBarrelExportFileGenerator.exportFileName": { 42 | "type": "string", 43 | "default": "dir_name.dart", 44 | "markdownDescription": "Name of the file to which exports are written.\n\nLeave empty or `dir_name.dart` to export to default location. Use any other name to export to desired file. Keep the file extension e.g. `.dart` or `.e.dart`. File is overwritten on each command run." 45 | }, 46 | "dartBarrelExportFileGenerator.recursiveExport": { 47 | "type": "boolean", 48 | "default": false, 49 | "markdownDescription": "Enable recursive export of files from subdirectories.\n\nIt will result with a top-most export file that will include files from subdirectories. They will be referenced using their corresponding export files, e.g. `feature.dart` will export `subdirectory/subdirectory.dart` and not individual files from the `subdirectory`." 50 | }, 51 | "dartBarrelExportFileGenerator.ignorePatterns": { 52 | "type": "array", 53 | "items": { 54 | "type": "string" 55 | }, 56 | "default": [ 57 | "*.g.dart", 58 | "*.part.dart", 59 | "*.freezed.dart" 60 | ], 61 | "markdownDescription": "Glob patterns for files and directories to ignore during export.\n\nPatterns are matched against relative paths from the current working directory. Paths are not matched against file in subdirectories so `/**/` may not work." 62 | } 63 | } 64 | } 65 | }, 66 | "scripts": { 67 | "vscode:prepublish": "npm run package", 68 | "compile": "webpack", 69 | "watch": "webpack --watch", 70 | "package": "webpack --mode production --devtool hidden-source-map", 71 | "compile-tests": "tsc -p . --outDir out", 72 | "watch-tests": "tsc -p . -w --outDir out", 73 | "pretest": "npm run compile-tests && npm run compile && npm run lint", 74 | "lint": "eslint src --ext ts", 75 | "test": "vscode-test" 76 | }, 77 | "devDependencies": { 78 | "@types/mocha": "^10.0.6", 79 | "@types/node": "18.x", 80 | "@types/vscode": "^1.88.0", 81 | "@typescript-eslint/eslint-plugin": "^7.4.0", 82 | "@typescript-eslint/parser": "^7.4.0", 83 | "@vscode/test-cli": "^0.0.8", 84 | "@vscode/test-electron": "^2.3.9", 85 | "eslint": "^8.57.0", 86 | "ts-loader": "^9.5.1", 87 | "typescript": "^5.3.3", 88 | "webpack": "^5.91.0", 89 | "webpack-cli": "^5.1.4" 90 | }, 91 | "dependencies": { 92 | "glob": "^10.3.12" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /screenshots/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orestesgaolin/dart-export-index/83854abd6bceaa67f140efb9fe01fd7a1a6c2a00/screenshots/icon.png -------------------------------------------------------------------------------- /screenshots/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orestesgaolin/dart-export-index/83854abd6bceaa67f140efb9fe01fd7a1a6c2a00/screenshots/settings.png -------------------------------------------------------------------------------- /screenshots/usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orestesgaolin/dart-export-index/83854abd6bceaa67f140efb9fe01fd7a1a6c2a00/screenshots/usage.png -------------------------------------------------------------------------------- /src/commands/commands.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as vscode from 'vscode'; 3 | import { 4 | fileIsOpened, 5 | fileIsSaved, 6 | getCurrentFilePath, 7 | } from '../utils/editor-helper'; 8 | import { ApplicationError } from '../utils/errors'; 9 | import { 10 | createFileIfNotExists, 11 | clearFile, 12 | getDartFilesAndDirectories, 13 | getDirectoryNameFromDirectory, 14 | writeLineAndSort, 15 | } from '../utils/file-manager'; 16 | 17 | 18 | export const addCurrentFileToDartExportFile = () => { 19 | try { 20 | const filePath = getFilePath(); 21 | 22 | if (filePath === null) { 23 | throw new ApplicationError('Could not get current file path'); 24 | } 25 | 26 | if (!filePath.endsWith('.dart')) { 27 | throw new ApplicationError('The file is not Dart file.'); 28 | } 29 | 30 | const config = vscode.workspace.getConfiguration('dartBarrelExportFileGenerator'); 31 | const exportFileName = config.get('exportFileName'); 32 | 33 | const directory = path.dirname(filePath); 34 | const exportFilePath = getExportFilePathFromDirectory(directory, exportFileName); 35 | 36 | if (filePath === exportFilePath) { 37 | throw new ApplicationError('The file is the index file itself.'); 38 | } 39 | 40 | createFileIfNotExists(exportFilePath); 41 | 42 | const exportationLine = getExportationLine(filePath); 43 | writeLineAndSort(exportFilePath, exportationLine); 44 | } catch (err) { 45 | if (err instanceof ApplicationError) { 46 | vscode.window.showErrorMessage(err.message); 47 | return; 48 | } 49 | 50 | throw err; 51 | } 52 | }; 53 | 54 | export const exportDartFilesInCurrentDirectoryDirName = () => { 55 | try { 56 | const config = vscode.workspace.getConfiguration('dartBarrelExportFileGenerator'); 57 | 58 | const filePath = getFilePath(); 59 | if (filePath === null) { 60 | throw new ApplicationError('Could not get current file path'); 61 | } 62 | console.log(`filePath: ${filePath}`); 63 | const directory = path.dirname(filePath); 64 | exportDartFilesFromDirectory(directory, config); 65 | 66 | } catch (err) { 67 | if (err instanceof ApplicationError) { 68 | vscode.window.showErrorMessage(err.message); 69 | return; 70 | } 71 | 72 | throw err; 73 | } 74 | }; 75 | 76 | async function exportDartFilesFromDirectory(directory: string, config: vscode.WorkspaceConfiguration) { 77 | const exportFileNameConfig = config.get('exportFileName') || 'dir_name.dart'; 78 | const ignorePatterns = config.get('ignorePatterns') || []; 79 | const recursiveExport = config.get('recursiveExport') || false; 80 | 81 | console.log(`exportFileName: ${exportFileNameConfig}`); 82 | console.log(`ignorePatterns: ${ignorePatterns}`); 83 | console.log(`recursiveExport: ${recursiveExport}`); 84 | 85 | // Define the index file path for the current directory 86 | const exportFilePath = getExportFilePathFromDirectory(directory, exportFileNameConfig); 87 | createFileIfNotExists(exportFilePath); 88 | clearFile(exportFilePath); 89 | 90 | // Get all Dart files and directories except the index file itself 91 | const { dartFiles, directories } = getDartFilesAndDirectories(directory, ignorePatterns, exportFilePath); 92 | 93 | // Write export lines for Dart files in the current directory 94 | dartFiles.forEach(file => { 95 | const exportationLine = getExportationLine(file); 96 | writeLineAndSort(exportFilePath, exportationLine); 97 | }); 98 | 99 | if (recursiveExport) { 100 | // Recursively handle subdirectories and add their exports to the current index 101 | for (const subdirectory of directories) { 102 | const basename = path.basename(subdirectory); 103 | const subExportFilePath = getExportFilePathFromDirectory(subdirectory, exportFileNameConfig); 104 | await exportDartFilesFromDirectory(subdirectory, config); // Recurse into subdirectory 105 | 106 | // export dir_name/dir_name.dart or any other file name 107 | // can be taken from 2 last parts of exportFilePath 108 | const subExportFileName = subExportFilePath.split('/').slice(-2).join('/'); 109 | const exportationLine = `export '${subExportFileName}';`; 110 | writeLineAndSort(exportFilePath, exportationLine); 111 | } 112 | } 113 | } 114 | 115 | const getFilePath = (): string | null => { 116 | if (!fileIsOpened()) { 117 | throw new ApplicationError('No file is opened. Make sure to execute this command in a Dart file.'); 118 | } 119 | 120 | if (!fileIsSaved()) { 121 | throw new ApplicationError('The file is not saved yet. Save the file before executing this command.'); 122 | } 123 | 124 | return getCurrentFilePath(); 125 | }; 126 | 127 | const getExportFilePathFromDirectory = (directory: string, exportFileName: string | undefined): string => { 128 | let shouldUseDirectoryName = exportFileName === undefined 129 | || exportFileName === '' 130 | || exportFileName === null 131 | || exportFileName === 'dir_name.dart'; 132 | 133 | if (shouldUseDirectoryName) { 134 | const directoryName = getDirectoryNameFromDirectory(directory); 135 | return path.join(directory, `${directoryName}.dart`); 136 | } 137 | 138 | return path.join(directory, `${exportFileName}`); 139 | }; 140 | 141 | const getExportationLine = (filePath: string): string => { 142 | const fileName = path.basename(filePath); 143 | return `export '${fileName}';`; 144 | }; 145 | -------------------------------------------------------------------------------- /src/commands/index.ts: -------------------------------------------------------------------------------- 1 | export * from './commands'; 2 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as commands from './commands'; 3 | 4 | const extensionId = 'orestesgaolin.dart-export-index'; 5 | 6 | export function activate(context: vscode.ExtensionContext) { 7 | const showInfoNotification = vscode.commands.registerCommand('extension.showInfo', async () => { 8 | const selection = await vscode.window.showInformationMessage('Extension has been updated. Recursive export and ignore patters are now available. Check the extension settings for details.', 'Open settings'); 9 | 10 | if (selection) { 11 | await vscode.commands.executeCommand('workbench.action.openSettings', 'dartBarrelExportFileGenerator'); 12 | } 13 | }); 14 | 15 | const addCurrentFileDirName = vscode.commands.registerCommand( 16 | 'extension.addCurrentFileToIndexDartDirName', 17 | () => { 18 | commands.addCurrentFileToDartExportFile(); 19 | }, 20 | ); 21 | 22 | const exportAllFilesDirName = vscode.commands.registerCommand( 23 | 'extension.exportDartFilesInCurrentDirectoryDirName', 24 | () => { 25 | commands.exportDartFilesInCurrentDirectoryDirName(); 26 | }, 27 | ); 28 | 29 | context.subscriptions.push(addCurrentFileDirName); 30 | context.subscriptions.push(exportAllFilesDirName); 31 | context.subscriptions.push(showInfoNotification); 32 | // show notification on start 33 | 34 | const previousVersion = context.globalState.get(extensionId); 35 | const currentVersion = vscode.extensions.getExtension(extensionId)!.packageJSON.version; 36 | // store latest version 37 | context.globalState.update(extensionId, currentVersion); 38 | 39 | if (previousVersion === undefined) { 40 | vscode.commands.executeCommand('extension.showInfo'); 41 | } 42 | } 43 | 44 | export function deactivate() { } 45 | -------------------------------------------------------------------------------- /src/utils/editor-helper.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { ApplicationError } from './errors'; 3 | 4 | export const fileIsOpened = (): boolean => { 5 | return !!vscode.window.activeTextEditor; 6 | }; 7 | 8 | 9 | /// Returns true if the current file is saved, false otherwise 10 | export const fileIsSaved = (): boolean => { 11 | if (!fileIsOpened) { 12 | return false; 13 | } 14 | 15 | const editor = vscode.window.activeTextEditor; 16 | 17 | if (editor === undefined) { 18 | throw new ApplicationError('No active editor available'); 19 | } 20 | 21 | const document = editor.document; 22 | return !document.isUntitled; 23 | }; 24 | 25 | 26 | /// Returns the current file path or null if the file is not opened or not saved 27 | export const getCurrentFilePath = (): string | null => { 28 | if (!(fileIsOpened() && fileIsSaved())) { 29 | return null; 30 | }; 31 | 32 | const editor = vscode.window.activeTextEditor; 33 | 34 | if (editor === undefined) { 35 | throw new ApplicationError('No active editor available'); 36 | } 37 | 38 | return editor.document.fileName; 39 | }; 40 | -------------------------------------------------------------------------------- /src/utils/errors.ts: -------------------------------------------------------------------------------- 1 | export class ApplicationError implements Error { 2 | public name = 'ApplicationError'; 3 | 4 | constructor(public message: string) { } 5 | 6 | public toString() { 7 | return `${this.name}: ${this.message}`; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/file-manager.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | import { ApplicationError } from './errors'; 4 | import glob = require('glob'); 5 | 6 | export const fileExists = (filePath: string): boolean => { 7 | return fs.existsSync(filePath); 8 | }; 9 | 10 | export const createFile = (filePath: string): void => { 11 | if (fileExists(filePath)) { 12 | throw new FileAlreadyExistsError(`${filePath} already exists`); 13 | } 14 | 15 | fs.appendFileSync(filePath, '', 'utf-8'); 16 | }; 17 | 18 | export const listFiles = (dirPath: string): string[] => { 19 | return fs.readdirSync(dirPath); 20 | }; 21 | 22 | export const createFileIfNotExists = (filePath: string): void => { 23 | if (fileExists(filePath)) { 24 | return; 25 | } 26 | 27 | createFile(filePath); 28 | }; 29 | 30 | export const clearFile = (filePath: string): void => { 31 | if (fileExists(filePath)) { 32 | fs.writeFileSync(filePath, ''); 33 | } 34 | }; 35 | 36 | export const getDartFilesAndDirectories = ( 37 | directory: string, 38 | ignorePatterns: string[], 39 | exportFilePath: string 40 | ): { dartFiles: string[], directories: string[] } => { 41 | const ignorePatternsToUse = ignorePatterns.map(pattern => path.join(directory, pattern)); 42 | 43 | const dartFiles = glob.sync(`${directory}/*.dart`, { ignore: [...ignorePatternsToUse, exportFilePath] }); 44 | const directories = fs.readdirSync(directory, { withFileTypes: true }) 45 | .filter(dirent => dirent.isDirectory()) 46 | .map(dirent => path.join(directory, dirent.name)); 47 | 48 | return { dartFiles, directories }; 49 | }; 50 | 51 | export const getDirectoryNameFromDirectory = (directory: string): string => { 52 | const elements = directory.split('/'); 53 | return elements[elements.length - 1]; 54 | }; 55 | 56 | export const getLines = (filePath: string): string[] => { 57 | return fs.readFileSync(filePath, 'utf-8').split('\n'); 58 | }; 59 | 60 | export const writeFile = (filePath: string, data: string): void => { 61 | fs.writeFileSync(filePath, data); 62 | }; 63 | 64 | export const writeLineAndSort = (filePath: string, line: string): void => { 65 | const lines = getLines(filePath).filter(l => l !== ''); 66 | 67 | if (!lines.includes(line)) { 68 | lines.push(line); 69 | } 70 | 71 | lines.sort(); 72 | const written = `${lines.join('\n')}\n`; 73 | 74 | writeFile(filePath, written); 75 | }; 76 | 77 | export class FileAlreadyExistsError extends ApplicationError { } 78 | -------------------------------------------------------------------------------- /src/utils/file-name.ts: -------------------------------------------------------------------------------- 1 | export const getExtension = (filePath: string): string | null => { 2 | const match = filePath.match(/.*\.(.+)/); 3 | 4 | if (!match) { 5 | return null; 6 | } 7 | 8 | return match[1]; 9 | }; 10 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './errors'; 2 | export * from './file-manager'; 3 | export * from './editor-helper'; 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "lib": [ 6 | "ES2022" 7 | ], 8 | "sourceMap": true, 9 | "rootDir": "src", 10 | "strict": true /* enable all strict type-checking options */ 11 | /* Additional Checks */ 12 | // "noImplicitReturns": true, /* 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 | "exclude": [ 17 | "node_modules", 18 | ".vscode-test" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | //@ts-check 8 | /** @typedef {import('webpack').Configuration} WebpackConfig **/ 9 | 10 | /** @type WebpackConfig */ 11 | const extensionConfig = { 12 | target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 13 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 14 | 15 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 16 | output: { 17 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 18 | path: path.resolve(__dirname, 'dist'), 19 | filename: 'extension.js', 20 | libraryTarget: 'commonjs2' 21 | }, 22 | externals: { 23 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 24 | // modules added here also need to be added in the .vscodeignore file 25 | }, 26 | resolve: { 27 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 28 | extensions: ['.ts', '.js'] 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.ts$/, 34 | exclude: /node_modules/, 35 | use: [ 36 | { 37 | loader: 'ts-loader' 38 | } 39 | ] 40 | } 41 | ] 42 | }, 43 | devtool: 'nosources-source-map', 44 | infrastructureLogging: { 45 | level: "log", // enables logging required for problem matchers 46 | }, 47 | }; 48 | module.exports = [ extensionConfig ]; --------------------------------------------------------------------------------