├── .gitignore ├── dbt-logo.png ├── .vscodeignore ├── .vscode ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── CHANGELOG.md ├── tsconfig.json ├── .eslintrc.json ├── README.md ├── src └── extension.ts ├── vsc-extension-quickstart.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | -------------------------------------------------------------------------------- /dbt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henriblancke/vscode-dbt-formatter/HEAD/dbt-logo.png -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 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": ["dbaeumer.vscode-eslint"] 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "vscode-dbt-formatter" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": ["es6"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true, 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": true 12 | }, 13 | "exclude": ["node_modules", ".vscode-test"] 14 | } 15 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": ["@typescript-eslint"], 9 | "rules": { 10 | "@typescript-eslint/class-name-casing": "warn", 11 | "@typescript-eslint/semi": "warn", 12 | "curly": "warn", 13 | "eqeqeq": "warn", 14 | "no-throw-literal": "warn", 15 | "semi": "off" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.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 | } 12 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-dbt-formatter 2 | 3 | ## Features 4 | 5 | Format SQL and Jinja flavored SQL with ease. This extension uses [dbt-formatter](https://github.com/henriblancke/dbt-formatter) to format your dbt models and macros. This extension depends on [vscode-dbt](https://github.com/bastienboutonnet/vscode-dbt). 6 | 7 | ## Extension Settings 8 | 9 | - `dbt-formatter.dialect`: the SQL dialect you want to use (currently only `default` is available) 10 | - `dbt-formatter.upper`: Uppercase all reserved sql words. 11 | - `dbt-formatter.camelCase`: Allow tokens identified as words to be camelcased (handy when using with `lowerWords`) 12 | - `dbt-formatter.lowerWords`: Lowercase all tokens identified as words (think columns, cte names etc, ...) 13 | 14 | ## Release Notes 15 | 16 | ### 1.0.0 17 | 18 | Initial release of vscode-dbt-formatter 19 | -------------------------------------------------------------------------------- /.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 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "${defaultBuildTask}" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "${defaultBuildTask}" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import dbtFormatter from "dbt-formatter"; 3 | 4 | interface FormatterOptions { 5 | sql: string; 6 | indent: number; 7 | upper: boolean; 8 | newline: boolean; 9 | lowerWords: boolean; 10 | allowCamelcase: boolean; 11 | } 12 | 13 | const getDocumentRange = (document: vscode.TextDocument): vscode.Range => { 14 | const lastLineId = document.lineCount - 1; 15 | return new vscode.Range( 16 | 0, 17 | 0, 18 | lastLineId, 19 | document.lineAt(lastLineId).text.length 20 | ); 21 | }; 22 | 23 | const newLineConfig = (options: vscode.FormattingOptions): boolean => { 24 | if (options.insertFinalNewline === undefined) { 25 | if (options.trimFinalNewlines === undefined) { 26 | return true; 27 | } 28 | 29 | return !options.trimFinalNewlines; 30 | } 31 | 32 | return options.insertFinalNewline === true; 33 | }; 34 | 35 | const getConfig = (options: vscode.FormattingOptions): FormatterOptions => ({ 36 | lowerWords: vscode.workspace 37 | .getConfiguration("dbt-formatter") 38 | .get("lowerWords", true), 39 | upper: vscode.workspace.getConfiguration("dbt-formatter").get("upper", true), 40 | allowCamelcase: vscode.workspace 41 | .getConfiguration("dbt-formatter") 42 | .get("camelCase", true), 43 | sql: vscode.workspace 44 | .getConfiguration("dbt-formatter") 45 | .get("dialect", "default"), 46 | indent: options.tabSize, 47 | newline: newLineConfig(options), 48 | }); 49 | 50 | export function activate(context: vscode.ExtensionContext) { 51 | const disposable = vscode.languages.registerDocumentFormattingEditProvider( 52 | [{ language: "sql" }, { language: "jinja-sql" }], 53 | { provideDocumentFormattingEdits } 54 | ); 55 | context.subscriptions.push(disposable); 56 | } 57 | 58 | export async function provideDocumentFormattingEdits( 59 | document: vscode.TextDocument, 60 | options: vscode.FormattingOptions, 61 | token: vscode.CancellationToken 62 | ): Promise { 63 | const edits: vscode.TextEdit[] = []; 64 | 65 | if (document.lineCount >= 1) { 66 | let firstLine = document.lineAt(0); 67 | 68 | // check for ignore text 69 | if (firstLine.text.indexOf("dbt-formatter-ignore") === -1) { 70 | const text = document.getText(); 71 | const formatted = dbtFormatter(text, getConfig(options)); 72 | if (formatted && formatted.length > 0) { 73 | const replacement = vscode.TextEdit.replace( 74 | getDocumentRange(document), 75 | formatted 76 | ); 77 | edits.push(replacement); 78 | } 79 | } 80 | } 81 | 82 | return edits; 83 | } 84 | 85 | // this method is called when your extension is deactivated 86 | export function deactivate() {} 87 | -------------------------------------------------------------------------------- /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 | 25 | ## Explore the API 26 | 27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 28 | 29 | ## Run tests 30 | 31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 32 | * Press `F5` to run the tests in a new window with your extension loaded. 33 | * See the output of the test result in the debug console. 34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-dbt-formatter", 3 | "displayName": "dbt formatter", 4 | "description": "Formatter for jinja-flavored sql used with dbt.", 5 | "version": "1.0.1", 6 | "publisher": "henriblancke", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/henriblancke/vscode-dbt-formatter" 10 | }, 11 | "icon": "dbt-logo.png", 12 | "keywords": [ 13 | "dbt", 14 | "DBT", 15 | "SQL", 16 | "sql", 17 | "jinja-sql", 18 | "Formatting" 19 | ], 20 | "engines": { 21 | "vscode": "^1.42.0" 22 | }, 23 | "categories": [ 24 | "Programming Languages", 25 | "Formatters", 26 | "Other" 27 | ], 28 | "activationEvents": [ 29 | "onLanguage:sql", 30 | "onLanguage:jinja-sql" 31 | ], 32 | "contributes": { 33 | "languages": [ 34 | { 35 | "id": "sql", 36 | "aliases": [ 37 | "SQL", 38 | "sql" 39 | ], 40 | "extensions": [ 41 | "sql" 42 | ] 43 | }, 44 | { 45 | "id": "jinja-sql", 46 | "aliases": [ 47 | "jinja-sql" 48 | ], 49 | "extensions": [ 50 | "sql" 51 | ] 52 | } 53 | ], 54 | "configuration": { 55 | "type": "object", 56 | "title": "dbt-formatter configuration", 57 | "properties": { 58 | "dbt-formatter.dialect": { 59 | "type": "string", 60 | "default": "default", 61 | "description": "The sql dialect you want to use, currently only default is available" 62 | }, 63 | "dbt-formatter.upper": { 64 | "type": "boolean", 65 | "default": true, 66 | "description": "Formats sql reserved words to be uppercase when set to true" 67 | }, 68 | "dbt-formatter.camelCase": { 69 | "type": "boolean", 70 | "default": true, 71 | "description": "Allows column names to be camel cased when lowerWords is set to true" 72 | }, 73 | "dbt-formatter.lowerWords": { 74 | "type": "boolean", 75 | "default": true, 76 | "description": "Lowercase all non-reserved words" 77 | } 78 | } 79 | } 80 | }, 81 | "main": "./out/extension.js", 82 | "scripts": { 83 | "compile": "tsc -p ./", 84 | "lint": "eslint src --ext ts", 85 | "watch": "tsc -watch -p ./", 86 | "pretest": "npm run compile && npm run lint", 87 | "test": "node ./out/test/runTest.js", 88 | "vscode:prepublish": "npm run compile", 89 | "vscode:publish": "vsce publish" 90 | }, 91 | "devDependencies": { 92 | "@types/glob": "^7.1.1", 93 | "@types/mocha": "^7.0.1", 94 | "@types/node": "^12.11.7", 95 | "@types/vscode": "^1.42.0", 96 | "eslint": "^6.8.0", 97 | "@typescript-eslint/parser": "^2.18.0", 98 | "@typescript-eslint/eslint-plugin": "^2.18.0", 99 | "glob": "^7.1.6", 100 | "mocha": "^7.0.1", 101 | "typescript": "^3.7.5", 102 | "vscode-test": "^1.3.0" 103 | }, 104 | "dependencies": { 105 | "dbt-formatter": "^1.2.0" 106 | }, 107 | "extensionDependencies": [ 108 | "bastienboutonnet.vscode-dbt" 109 | ] 110 | } --------------------------------------------------------------------------------