├── .gitattributes ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md ├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── appveyor.yml ├── icon.png ├── package-lock.json ├── package.json ├── schemas ├── autoprefixerrc.schema.json ├── cleancssrc.schema.json └── terserrc.schema.json ├── src ├── config.ts ├── css.ts ├── es6-css-minify.d.ts ├── extension.ts ├── fs.ts ├── js.ts ├── json.ts ├── minify-document.ts ├── minify-selection.ts ├── output.ts ├── status-bar.ts ├── test │ ├── runTest.ts │ ├── suite │ │ ├── config.test.ts │ │ ├── extension.test.ts │ │ ├── fs.test.ts │ │ ├── index.ts │ │ ├── minify.test.ts │ │ └── test_utils.ts │ └── workspace │ │ ├── .autoprefixerrc │ │ ├── .cleancssrc │ │ ├── .uglifyrc │ │ ├── .vscode │ │ └── settings.json │ │ ├── css │ │ ├── footer.css │ │ └── main.css │ │ ├── dist │ │ └── css │ │ │ └── .gitkeep │ │ ├── js │ │ ├── aaa.main.js │ │ └── syntax.error.js │ │ └── json │ │ └── data.json └── utils.ts ├── tsconfig.json ├── tsconfig.webpack.json ├── tslint.json └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: olback 2 | custom: "https://paypal.me/olback" 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Version [e.g. 22] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: General questions, whys and hows. 4 | 5 | --- 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | /dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | 7 | # Test files 8 | *.min.js 9 | *.min.js.map 10 | *.min.css 11 | *.min.css.map 12 | *.minified.* 13 | *.minified.*.map 14 | .ignoreme 15 | report.*.*.*.*.*.json 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | dist: bionic 4 | 5 | os: 6 | - osx 7 | - linux 8 | 9 | services: 10 | - xvfb 11 | 12 | before_install: 13 | - if [ $TRAVIS_OS_NAME == "linux" ]; then 14 | export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; 15 | fi 16 | 17 | language: node_js 18 | node_js: 19 | - "10" 20 | 21 | cache: 22 | directories: 23 | - "node_modules" 24 | 25 | install: 26 | - npm install 27 | 28 | script: 29 | - npm test 30 | -------------------------------------------------------------------------------- /.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 | // "--disable-extensions", 15 | "${workspaceRoot}/src/test/workspace", 16 | "--extensionDevelopmentPath=${workspaceRoot}" 17 | ], 18 | "outFiles": [ 19 | "${workspaceFolder}/dist/**/*.js" 20 | ], 21 | "preLaunchTask": "npm: watch" 22 | }, 23 | { 24 | "name": "Extension Tests", 25 | "type": "extensionHost", 26 | "request": "launch", 27 | "runtimeExecutable": "${execPath}", 28 | "args": [ 29 | "--disable-extensions", 30 | "${workspaceRoot}/src/test/workspace", 31 | "--extensionDevelopmentPath=${workspaceRoot}", 32 | "--extensionTestsPath=${workspaceRoot}/out/test/suite" 33 | ], 34 | "outFiles": [ 35 | "${workspaceFolder}/dist/**/*.js" 36 | ], 37 | "preLaunchTask": "npm: compile" 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /.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 | "editor.tabSize": 4, 12 | "editor.detectIndentation": false 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": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "silent" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | }, 19 | { 20 | "type": "npm", 21 | "script": "compile", 22 | "isBackground": false, 23 | "presentation": { 24 | "reveal": "always" 25 | }, 26 | "group": { 27 | "kind": "test", 28 | "isDefault": true 29 | } 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .github/** 4 | out/** 5 | src/** 6 | .gitignore 7 | .gitattributes 8 | vsc-extension-quickstart.md 9 | **/tsconfig.json 10 | **/tsconfig.test.json 11 | **/tslint.json 12 | **/*.map 13 | **/*.ts 14 | webpack.config.js 15 | .ignoreme 16 | report.*.*.*.*.*.json 17 | 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 3.3.2 2 | * Bump terser to `4.6.2`. 3 | 4 | ## 3.3.1 5 | * Bumb required VS Code version to `1.30.0`. 6 | 7 | ## 3.3.0 8 | * Added ability to minify file from explorer (file list to the left). Fixes #90. 9 | * Fixed issue #92. (Thanks @Tim-Veestraeten) 10 | * Added file watcher for config files. 11 | * Fixed #93. 12 | 13 | ## 3.2.0 14 | * Added language and auto-complete support for `.autoprefixerrc`, `.cleancssrc`, `.uglifyrc` and `.terserrc`. 15 | * Added `Minify: Export Configuration` command. 16 | 17 | ## 3.1.1 18 | * Removed console.log. 19 | * Hopefully fixed issue #78 (Thanks @CubeRanch) 20 | 21 | ## 3.1.0 22 | * Fixed issue #84. (Thanks @0arra0) 23 | * Fixed issue #83. (Thanks @CubeRanch) 24 | * Fixed error in package.json. 25 | 26 | ## 3.0.3 27 | * Fixed issue #81. 28 | 29 | ## 3.0.2 30 | * Issue #78 fixed. (Thanks @CubeRanch) 31 | * Minify button is always visible by default. Button visibility can be set to either `"always"`, `"never"` or `"auto"`. 32 | 33 | ## 3.0.1 34 | * Issue #76 fixed. (Thanks @EvlBlackmask) 35 | 36 | ## 3.0.0 37 | * Complete re-write. The extension is now divided into multiple files. This makes it easier to maintain. 38 | * Bump dependency versions. (Closes #74) 39 | * You can now see warnings and errors directly from clean-css and terser. 40 | * No breaking changes from `2.7.0`. 41 | * `es6-css-minify.hideButton` is set to `true` by default. 42 | * New settigns: 43 | - `es6-css-minify.showLogOnWarning` Show output if there are any warnings. Defualt: `true`. 44 | - `es6-css-minify.showLogOnError` Show output if there are any errors. Defualt: `true`. 45 | - `es6-css-minify.onSaveDelay` Delay in milliseconds before the file is minified. Default: `0` 46 | - `es6-css-minify.enableAutoprefixerSelection` Enable autoprefixer when minifying a selection. Default: `false` 47 | - `es6-css-minify.autoprefixerConfigFile` Specify a autoprefixer config file. Default: `".autoprefixerrc"` 48 | 49 | ## 2.7.0 50 | * Fixed issue #57. (Thanks for the PR @MuTsunTsai) 51 | 52 | ## 2.6.0 53 | * Package extension with Webpack to improve performance. See #66. 54 | 55 | ## 2.5.0 56 | * Implemented JSON minification. See #54. 57 | 58 | ## 2.4.0 59 | * Implemented Autoprefixer as requested in Issue#59. This can be enabled in the config. 60 | 61 | ## 2.3.0 62 | * Implemented 'Minify selection' as requested by @dwelle in issue#56. 63 | 64 | ## 2.2.0 65 | * Implemented postfix. [See this PR](https://github.com/olback/es6-css-minify/pull/51) 66 | 67 | ## 2.1.0 68 | * You no longer have to run `Minify: Reload config` when updating your config. It's done automatically. 69 | * Hide Minify button when the filetype isn't supported. This can be enable by changing `es6-css-minify.hideButton` to `true`. 70 | * Use [terser](https://www.npmjs.com/package/terser) instead of uglify-es since it's deprecated. (#46) 71 | * Inform the user when Javascript minify fails about syntax errors. (#45) 72 | 73 | ## 2.0.3 74 | * Merged PR #36 75 | * Fixed bug #35 76 | 77 | ## 2.0.2 78 | * Added some tests. 79 | * You can no longer minify minified files 80 | 81 | ## 2.0.1 82 | * Fixed bug #28 83 | 84 | ## 2.0.0 85 | * Rewritten in Typescript 86 | * Fixed bugs #24, #26, #27 87 | * Changed default value of `es6-css-minify.minifyOnSave` to `no` 88 | 89 | ## 0.1.6 90 | * Added feature from issue #23 91 | * Changed default value of `es6-css-minify.minifyOnSave` to `exists` 92 | 93 | ## 0.1.5 94 | * Fixed issue #19 95 | 96 | ## 0.1.4 97 | * Reference original file in sourcemap instead of minified file 98 | 99 | ## 0.1.3 100 | * Fixed issue #18 (Windows) 101 | 102 | ## 0.1.2 103 | * Fixed js sourcemap url #16 104 | * Sourcemap sources fixed #15 105 | 106 | ## 0.1.1 107 | * Added "exists" as an option to `es6-css-minify.minifyOnSave` 108 | * Change the JavaScript Mapping URL. `es6-css-minify.jsMapUrl` 109 | 110 | ## 0.1.0 111 | * Source map support. Enable/Disable in settings 112 | 113 | ## 0.0.11 114 | * Fixed bug #10 115 | 116 | ## 0.0.10 117 | * README changes 118 | 119 | ## 0.0.9 120 | * Added support for uglify-es and clean-css config files! 121 | 122 | ## 0.0.8 123 | * Attempt two on fixing the issue! 124 | 125 | ## 0.0.7 126 | * Failed attempt to fix the plugin 127 | 128 | ## 0.0.6 129 | * Minify JS on save bug fixed 130 | 131 | ## 0.0.5 132 | * Typo 133 | 134 | ## 0.0.4 135 | * Fixed issue #5 136 | * Added support for minify on save 137 | * Settings 138 | 139 | ## 0.0.3 140 | * Fixed issue #3 141 | 142 | ## 0.0.2 143 | * Fixed issue #1 144 | 145 | ## 0.0.1 146 | * Initial release! 147 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Edwin 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 | # Archived - Feel free to fork and upload to VSC Marketplace. 2 | 3 | # JS & CSS Minifier 4 | 5 | [![Visual Studio Marketplace](https://vsmarketplacebadge.apphb.com/installs-short/olback.es6-css-minify.svg)](https://marketplace.visualstudio.com/items?itemName=olback.es6-css-minify) 6 | [![rating](https://vsmarketplacebadge.apphb.com/rating-star/olback.es6-css-minify.svg)](https://marketplace.visualstudio.com/items?itemName=olback.es6-css-minify) 7 | [![Visual Studio Marketplace](https://vsmarketplacebadge.apphb.com/version/olback.es6-css-minify.svg)](https://marketplace.visualstudio.com/items?itemName=olback.es6-css-minify) 8 | [![GitHub package version](https://img.shields.io/github/package-json/v/olback/es6-css-minify/3.0.svg?style=flat&logo=github&label=Github%20(This%20branch))](https://github.com/olback/es6-css-minify/tree/3.0) 9 | 10 | If you found this extension useful and want to support further development, please consider [donating](https://www.paypal.me/olback). 11 | 12 | # [Help wanted - New maintainer(s)!](https://github.com/olback/es6-css-minify/issues/140) 13 | 14 | | OS | Status | 15 | |----| ------ | 16 | | Linux & MacOS | [![Build Status](https://travis-ci.com/olback/es6-css-minify.svg?branch=3.0)](https://travis-ci.com/olback/es6-css-minify) | 17 | | Windows | [![Build status](https://ci.appveyor.com/api/projects/status/9xa8j6tq3vstixj2/branch/3.0?svg=true)](https://ci.appveyor.com/project/olback/es6-css-minify/branch/3.0) | 18 | 19 | A simple Javascript & CSS minifier. 20 | A `Minify` button should appear in the status bar when opening a `.js` or a `.css` file. You can also run `Minify: Document` by clicking `F1` or `CTRL+SHIFT+P`. 21 | 22 | ### Loading custom configs 23 | By default the extension will look for `.uglifyrc`, `.cleancssrc` and `.autoprefixerrc`. 24 | You can change the paths in settings. After changing settings in any of the config files, make sure to reload with `Minify: Reload config`. If the reload fails, make sure you don't have syntax errors in your config. If you want to go back to the default config, rename/delete your config file(s). 25 | 26 | The config parsed by the extension is just passed to terser, clean-css or autoprefixer. If the output is diffrent from what you expected, please confirm that the issue is with the extension and not terser, clean-css or autoprefixer before opening an issue. 27 | 28 | ### Minify on save, `disabled` by default! 29 | Minify on save can be enabled in settings. 30 | 31 | ### Generate source maps 32 | Source maps can be generated by changing `es6-css-minify.genCSSmap` and `es6-css-minify.genJSmap` respectively. 33 | 34 | #### Dependencies: 35 | * [terser](https://www.npmjs.com/package/terser) 36 | * [clean-css](https://www.npmjs.com/package/clean-css) 37 | * [autoprefixer](https://github.com/postcss/autoprefixer) 38 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against the latest version of this Node.js version 2 | environment: 3 | nodejs_version: "10" 4 | 5 | # Install scripts. (runs after repo cloning) 6 | install: 7 | # Get the latest stable version of Node.js 8 | - ps: Install-Product node $env:nodejs_version 9 | # install modules 10 | - npm install 11 | 12 | # Post-install test scripts. 13 | test_script: 14 | # Output useful info for debugging. 15 | - npm test 16 | 17 | # Don't actually build. 18 | build: off 19 | 20 | # branches: 21 | # only: 22 | # - "3.0" 23 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olback/es6-css-minify/51ef98605b238218d8e2e28a6185dd691d5ca109/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-css-minify", 3 | "displayName": "JS & CSS Minifier (Minify)", 4 | "description": "Easily Minify ES5/ES6/ES7/ES8 and CSS. Supports minify on save, minify selection & custom configurations!", 5 | "version": "3.3.3", 6 | "publisher": "olback", 7 | "icon": "icon.png", 8 | "galleryBanner": { 9 | "color": "#333", 10 | "theme": "dark" 11 | }, 12 | "license": "SEE LICENSE IN LICENSE.md", 13 | "homepage": "https://github.com/olback/es6-css-minify", 14 | "bugs": "https://github.com/olback/es6-css-minify/issues", 15 | "qna": "https://github.com/olback/es6-css-minify/issues/new?template=question.md", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/olback/es6-css-minify.git" 19 | }, 20 | "author": { 21 | "name": "olback", 22 | "email": "es6-css-minify@olback.net" 23 | }, 24 | "keywords": [ 25 | "ECMA Script", 26 | "CSS", 27 | "js", 28 | "javascript", 29 | "minify" 30 | ], 31 | "categories": [ 32 | "Other" 33 | ], 34 | "engines": { 35 | "vscode": "^1.30.0" 36 | }, 37 | "activationEvents": [ 38 | "onCommand:es6-css-minify.loadConfig", 39 | "onCommand:es6-css-minify.minify", 40 | "onCommand:es6-css-minify.minifySelection", 41 | "onCommand:es6-css-minify.minifyExplorer", 42 | "onCommand:es6-css-minify.exportConfig", 43 | "onLanguage:css", 44 | "onLanguage:javascript", 45 | "onLanguage:json", 46 | "workspaceContains:**/*.css", 47 | "workspaceContains:**/*.js", 48 | "workspaceContains:**/*.json" 49 | ], 50 | "main": "./dist/extension", 51 | "contributes": { 52 | "languages": [ 53 | { 54 | "id": "json", 55 | "aliases": [ 56 | "json", 57 | "Json", 58 | "JSON" 59 | ], 60 | "extensions": [ 61 | ".autoprefixerrc", 62 | ".cleancssrc", 63 | ".uglifyrc", 64 | ".terserrc" 65 | ] 66 | } 67 | ], 68 | "jsonValidation": [ 69 | { 70 | "fileMatch": ".autoprefixerrc", 71 | "url": "./schemas/autoprefixerrc.schema.json" 72 | }, 73 | { 74 | "fileMatch": ".cleancssrc", 75 | "url": "./schemas/cleancssrc.schema.json" 76 | }, 77 | { 78 | "fileMatch": ".uglifyrc", 79 | "url": "./schemas/terserrc.schema.json" 80 | }, 81 | { 82 | "fileMatch": ".terserrc", 83 | "url": "./schemas/terserrc.schema.json" 84 | } 85 | ], 86 | "commands": [ 87 | { 88 | "command": "es6-css-minify.loadConfig", 89 | "title": "Minify: Reload config" 90 | }, 91 | { 92 | "command": "es6-css-minify.minify", 93 | "title": "Minify: Document" 94 | }, 95 | { 96 | "command": "es6-css-minify.minifySelection", 97 | "title": "Minify: Selection" 98 | }, 99 | { 100 | "command": "es6-css-minify.minifyExplorer", 101 | "title": "Minify: File" 102 | }, 103 | { 104 | "command": "es6-css-minify.exportConfig", 105 | "title": "Minify: Export Configuration" 106 | } 107 | ], 108 | "configuration": { 109 | "type": "object", 110 | "title": "JS & CSS Minifier", 111 | "properties": { 112 | "es6-css-minify.minifyOnSave": { 113 | "type": "string", 114 | "description": "Automatically minify file when saving. Set to \"yes\" to always minify, \"no\" to never minify, \"exists\" to only minify if a minified version already exists.", 115 | "default": "no", 116 | "enum": [ 117 | "yes", 118 | "no", 119 | "exists" 120 | ] 121 | }, 122 | "es6-css-minify.hideButton": { 123 | "type": "string", 124 | "description": "Hide the minify button in the status bar.\n\"always\": Always hidden\n\"never\": Always visible. Even when minification is not supported.\n\"auto\": Hide the button when minification is not available. This is not 100% reliable.", 125 | "default": "never", 126 | "enum": [ 127 | "always", 128 | "never", 129 | "auto" 130 | ] 131 | }, 132 | "es6-css-minify.showLogOnWarning": { 133 | "type": "boolean", 134 | "description": "Show log if minification is successful but has warnings.", 135 | "default": true 136 | }, 137 | "es6-css-minify.showLogOnError": { 138 | "type": "boolean", 139 | "description": "When minification fails, show log with warnings and errors.", 140 | "default": true 141 | }, 142 | "es6-css-minify.onSaveDelay": { 143 | "type": "number", 144 | "description": "The amount of milliseconds to wait before minifying after a save. This might be needed on slower systems. Setting this to 0 disables the timeout. You should never have to set this to over 50.", 145 | "default": 0 146 | }, 147 | "es6-css-minify.uglifyConfigFile": { 148 | "type": "string", 149 | "description": "If this file exists, overwrite uglify-es settings with the ones specified in this file. For more info visit https://www.npmjs.com/package/uglify-es#minify-options-structure.", 150 | "default": ".uglifyrc" 151 | }, 152 | "es6-css-minify.genJSmap": { 153 | "description": "Generate JavaScript sourcemap files. Setting this to null will give control to js.sourceMap.", 154 | "default": false, 155 | "enum": [ 156 | true, 157 | false, 158 | null 159 | ] 160 | }, 161 | "es6-css-minify.jsMapSource": { 162 | "type": "string", 163 | "description": "Prefix for sources in map files.", 164 | "default": "" 165 | }, 166 | "es6-css-minify.jsMinPath": { 167 | "type": "string", 168 | "description": "Where to save the minified file.\nDefault: '' - saves in the same directory.\n'/' - Save in workspace root.", 169 | "default": "" 170 | }, 171 | "es6-css-minify.jsPostfix": { 172 | "type": "string", 173 | "description": "Filename postfix", 174 | "default": "min" 175 | }, 176 | "es6-css-minify.js": { 177 | "type": "object", 178 | "description": "Terser/Uglify-es settings. For more info visit https://www.npmjs.com/package/terser#minify-options.", 179 | "default": { 180 | "mangle": false, 181 | "compress": { 182 | "unused": false 183 | }, 184 | "output": { 185 | "quote_style": 0 186 | }, 187 | "warnings": true 188 | } 189 | }, 190 | "es6-css-minify.cleancssConfigFile": { 191 | "type": "string", 192 | "description": "If this file exists, overwrite clean-css settings with the ones specified in this file. For more info visit https://www.npmjs.com/package/clean-css.", 193 | "default": ".cleancssrc" 194 | }, 195 | "es6-css-minify.genCSSmap": { 196 | "description": "Generate CSS sourcemap files. Setting this to null will give control to css.sourceMap.", 197 | "default": false, 198 | "enum": [ 199 | true, 200 | false, 201 | null 202 | ] 203 | }, 204 | "es6-css-minify.cssMapSource": { 205 | "type": "string", 206 | "description": "Prefix for sources in map files.", 207 | "default": "" 208 | }, 209 | "es6-css-minify.cssMinPath": { 210 | "type": "string", 211 | "description": "Where to save the minified file.\nDefault: '' - saves in the same directory.\n'/' - Save in workspace root.", 212 | "default": "" 213 | }, 214 | "es6-css-minify.cssPostfix": { 215 | "type": "string", 216 | "description": "Filename postfix", 217 | "default": "min" 218 | }, 219 | "es6-css-minify.css": { 220 | "type": "object", 221 | "description": "Clean-CSS settings. For more info visit https://www.npmjs.com/package/clean-css.", 222 | "properties": { 223 | "rebase": { 224 | "description": "", 225 | "type": "boolean", 226 | "default": false 227 | } 228 | }, 229 | "default": { 230 | "rebase": false 231 | } 232 | }, 233 | "es6-css-minify.enableAutoprefixer": { 234 | "type": "boolean", 235 | "description": "Enable autoprefixer?", 236 | "default": false 237 | }, 238 | "es6-css-minify.enableAutoprefixerSelection": { 239 | "type": "boolean", 240 | "description": "Enable autoprefixer for selection minification?", 241 | "default": false 242 | }, 243 | "es6-css-minify.autoprefixer": { 244 | "type": "object", 245 | "description": "Autoprefixer options object. For more info visit https://github.com/postcss/autoprefixer#options", 246 | "default": {} 247 | }, 248 | "es6-css-minify.autoprefixerConfigFile": { 249 | "type": "string", 250 | "description": "", 251 | "default": ".autoprefixerrc" 252 | } 253 | } 254 | }, 255 | "menus": { 256 | "editor/context": [ 257 | { 258 | "command": "es6-css-minify.minify", 259 | "group": "es6-css-minify", 260 | "when": "editorLangId == javascript || editorLangId == css" 261 | }, 262 | { 263 | "command": "es6-css-minify.minifySelection", 264 | "group": "es6-css-minify", 265 | "when": "editorLangId == javascript && editorHasSelection" 266 | }, 267 | { 268 | "command": "es6-css-minify.minifySelection", 269 | "group": "es6-css-minify", 270 | "when": "editorLangId == css && editorHasSelection" 271 | }, 272 | { 273 | "command": "es6-css-minify.minifySelection", 274 | "group": "es6-css-minify", 275 | "when": "editorLangId == json && editorHasSelection" 276 | } 277 | ], 278 | "explorer/context": [ 279 | { 280 | "command": "es6-css-minify.minifyExplorer", 281 | "group": "es6-css-minify", 282 | "when": "resourceLangId == javascript || resourceLangId == css" 283 | } 284 | ] 285 | } 286 | }, 287 | "scripts": { 288 | "vscode:prepublish": "npm test && npm run compile", 289 | "compile": "node --max-old-space-size=1024 node_modules/webpack/bin/webpack --mode production", 290 | "watch": "node node_modules/webpack/bin/webpack --mode development --watch", 291 | "pretest": "npm run compile && npm run ts:compile", 292 | "ts:compile": "tsc -p ./", 293 | "test": "node --max-old-space-size=1024 ./out/test/runTest.js", 294 | "lint": "tslint -p ./" 295 | }, 296 | "devDependencies": { 297 | "@types/autoprefixer": "^9.6.1", 298 | "@types/clean-css": "^4.2.1", 299 | "@types/glob": "^7.1.1", 300 | "@types/mocha": "^5.2.6", 301 | "@types/node": "^10.14.18", 302 | "@types/vscode": "^1.30.0", 303 | "@types/webpack": "^4.39.1", 304 | "autoprefixer": "^9.6.1", 305 | "clean-css": "^4.2.1", 306 | "cross-env": "^5.2.1", 307 | "fork-ts-checker-webpack-plugin": "^1.5.0", 308 | "glob": "^7.1.4", 309 | "mocha": "^6.1.4", 310 | "terser": "^4.6.2", 311 | "ts-loader": "^6.1.0", 312 | "tslint": "^5.20.0", 313 | "typescript": "^3.6.3", 314 | "vscode-test": "^1.2.0", 315 | "webpack": "^4.39.3", 316 | "webpack-cli": "^3.3.8" 317 | }, 318 | "dependencies": {} 319 | } -------------------------------------------------------------------------------- /schemas/autoprefixerrc.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "description": "Autoprefixer options schema for es6-css-minify", 4 | "type": "object", 5 | "properties": { 6 | "env": { 7 | "type": "string", 8 | "description": "Environment for Browserslist." 9 | }, 10 | "cascade": { 11 | "type": "boolean", 12 | "description": "Should Autoprefixer use Visual Cascade, if CSS is uncompressed.", 13 | "default": true 14 | }, 15 | "add": { 16 | "type": "boolean", 17 | "description": "Should Autoprefixer add prefixes.", 18 | "default": true 19 | }, 20 | "remove": { 21 | "type": "boolean", 22 | "description": "Should Autoprefixer [remove outdated] prefixes.", 23 | "default": true 24 | }, 25 | "supports": { 26 | "type": "boolean", 27 | "description": "Should Autoprefixer add prefixes for @supports parameters.", 28 | "default": true 29 | }, 30 | "flexbox": { 31 | "description": "Should Autoprefixer add prefixes for flexbox properties. With \"no-2009\" value Autoprefixer will add prefixes only for final and IE 10 versions of specification.", 32 | "default": true, 33 | "oneOf": [ 34 | { 35 | "type": "string", 36 | "enum": [ 37 | "no-2009" 38 | ] 39 | }, 40 | { 41 | "type": "boolean" 42 | } 43 | ] 44 | }, 45 | "grid": { 46 | "description": "Should Autoprefixer add IE 10-11 prefixes for Grid Layout properties?", 47 | "default": false, 48 | "oneOf": [ 49 | { 50 | "type": "boolean", 51 | "enum": [ 52 | false 53 | ] 54 | }, 55 | { 56 | "type": "string", 57 | "enum": [ 58 | "autoplace", 59 | "no-autoplace" 60 | ] 61 | } 62 | ] 63 | }, 64 | "stats": { 65 | "type": "object", 66 | "description": "Custom usage statistics for > 10% in my stats browsers query.", 67 | "default": {} 68 | }, 69 | "overrideBrowserslist": { 70 | "type": "array", 71 | "description": "See https://github.com/browserslist/browserslist#queries for available queries and default value.", 72 | "default": [ 73 | "defaults" 74 | ] 75 | }, 76 | "ignoreUnknownVersions": { 77 | "type": "boolean", 78 | "description": "Do not raise error on unknown browser version in Browserslist config.", 79 | "default": false 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /schemas/cleancssrc.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "description": "Clean-CSS options schema for es6-css-minify", 4 | "type": "object", 5 | "properties": { 6 | "compatibility": { 7 | "description": "Controls compatibility mode used.", 8 | "default": "ie10+", 9 | "oneOf": [ 10 | { 11 | "type": "string", 12 | "enum": [ 13 | "*", 14 | "ie10+", 15 | "ie9", 16 | "ie8", 17 | "ie7" 18 | ] 19 | }, 20 | { 21 | "type": "object", 22 | "properties": { 23 | "colors": { 24 | "type": "object", 25 | "properties": { 26 | "opacity": { 27 | "description": "Controls `rgba()` / `hsla()` color support.", 28 | "type": "boolean", 29 | "default": true 30 | } 31 | } 32 | }, 33 | "properties": { 34 | "type": "object", 35 | "properties": { 36 | "backgroundClipMerging": { 37 | "description": "Controls background-clip merging into shorthand.", 38 | "type": "boolean", 39 | "default": true 40 | }, 41 | "backgroundOriginMerging": { 42 | "description": "Controls background-origin merging into shorthand.", 43 | "type": "boolean", 44 | "default": true 45 | }, 46 | "backgroundSizeMerging": { 47 | "description": "Controls background-size merging into shorthand.", 48 | "type": "boolean", 49 | "default": true 50 | }, 51 | "colors": { 52 | "description": "Controls color optimizations.", 53 | "type": "boolean", 54 | "default": true 55 | }, 56 | "ieBangHack": { 57 | "description": "Controls keeping IE bang hack.", 58 | "type": "boolean", 59 | "default": false 60 | }, 61 | "ieFilters": { 62 | "description": "Controls keeping IE `filter` / `-ms-filter`.", 63 | "type": "boolean", 64 | "default": false 65 | }, 66 | "iePrefixHack": { 67 | "description": "Controls keeping IE prefix hack.", 68 | "type": "boolean", 69 | "default": false 70 | }, 71 | "ieSuffixHack": { 72 | "description": "Controls keeping IE suffix hack.", 73 | "type": "boolean", 74 | "default": false 75 | }, 76 | "merging": { 77 | "description": "Controls property merging based on understandability.", 78 | "type": "boolean", 79 | "default": true 80 | }, 81 | "shorterLengthUnits": { 82 | "description": "Controls shortening pixel units into `pc`, `pt`, or `in` units.", 83 | "type": "boolean", 84 | "default": false 85 | }, 86 | "spaceAfterClosingBrace": { 87 | "description": "Controls keeping space after closing brace - `url() no-repeat` into `url()no-repeat`.", 88 | "type": "boolean", 89 | "default": true 90 | }, 91 | "urlQuotes": { 92 | "description": "Controls keeping quoting inside `url()`.", 93 | "type": "boolean", 94 | "default": false 95 | }, 96 | "zeroUnits": { 97 | "description": "Controls removal of units `0` value.", 98 | "type": "boolean", 99 | "default": true 100 | } 101 | } 102 | }, 103 | "selectors": { 104 | "type": "object", 105 | "properties": { 106 | "adjacentSpace": { 107 | "description": "Controls extra space before `nav` element.", 108 | "type": "boolean", 109 | "default": false 110 | }, 111 | "ie7Hack": { 112 | "description": "Controls removal of IE7 selector hacks, e.g. `*+html...`.", 113 | "type": "boolean", 114 | "default": true 115 | }, 116 | "mergeablePseudoClasses": { 117 | "description": "Controls a whitelist of mergeable pseudo classes.", 118 | "type": "array", 119 | "default": [] 120 | }, 121 | "mergeablePseudoElements": { 122 | "description": "Controls a whitelist of mergeable pseudo elements.", 123 | "type": "array", 124 | "default": [] 125 | }, 126 | "mergeLimit": { 127 | "description": "Controls maximum number of selectors in a single rule (since 4.1.0).", 128 | "type": "number", 129 | "default": 8192 130 | }, 131 | "multiplePseudoMerging": { 132 | "description": "Controls merging of rules with multiple pseudo classes / elements (since 4.1.0).", 133 | "type": "boolean", 134 | "default": true 135 | } 136 | } 137 | }, 138 | "units": { 139 | "type": "object", 140 | "properties": { 141 | "ch": { 142 | "description": "Controls treating `ch` as a supported unit.", 143 | "type": "boolean", 144 | "default": true 145 | }, 146 | "in": { 147 | "description": "Controls treating `in` as a supported unit.", 148 | "type": "boolean", 149 | "default": true 150 | }, 151 | "pc": { 152 | "description": "Controls treating `pc` as a supported unit.", 153 | "type": "boolean", 154 | "default": true 155 | }, 156 | "pt": { 157 | "description": "Controls treating `pt` as a supported unit.", 158 | "type": "boolean", 159 | "default": true 160 | }, 161 | "rem": { 162 | "description": "Controls treating `rem` as a supported unit.", 163 | "type": "boolean", 164 | "default": true 165 | }, 166 | "vh": { 167 | "description": "Controls treating `vh` as a supported unit.", 168 | "type": "boolean", 169 | "default": true 170 | }, 171 | "vm": { 172 | "description": "Controls treating `vm` as a supported unit.", 173 | "type": "boolean", 174 | "default": true 175 | }, 176 | "vmax": { 177 | "description": "Controls treating `vmax` as a supported unit.", 178 | "type": "boolean", 179 | "default": true 180 | }, 181 | "vmin": { 182 | "description": "Controls treating `vmin` as a supported unit.", 183 | "type": "boolean", 184 | "default": true 185 | } 186 | } 187 | } 188 | } 189 | } 190 | ] 191 | }, 192 | "format": { 193 | "description": "Controls output CSS formatting.", 194 | "default": false, 195 | "oneOf": [ 196 | { 197 | "type": "boolean", 198 | "enum": [ 199 | false 200 | ] 201 | }, 202 | { 203 | "type": "string", 204 | "enum": [ 205 | "beautify", 206 | "keep-breaks" 207 | ] 208 | }, 209 | { 210 | "type": "object", 211 | "properties": { 212 | "breaks": { 213 | "description": "Controls where to insert breaks.", 214 | "type": "object", 215 | "properties": { 216 | "afterAtRule": { 217 | "description": "Controls if a line break comes after an at-rule; e.g. `@charset`; defaults to `false`.", 218 | "type": "boolean", 219 | "default": false 220 | }, 221 | "afterBlockBegins": { 222 | "description": "Controls if a line break comes after a block begins; e.g. `@media`; defaults to `false`.", 223 | "type": "boolean", 224 | "default": false 225 | }, 226 | "afterBlockEnds": { 227 | "description": "Controls if a line break comes after a block ends, defaults to `false`.", 228 | "type": "boolean", 229 | "default": false 230 | }, 231 | "afterComment": { 232 | "description": "Controls if a line break comes after a comment; defaults to `false`.", 233 | "type": "boolean", 234 | "default": false 235 | }, 236 | "afterProperty": { 237 | "description": "Controls if a line break comes after a property; defaults to `false`.", 238 | "type": "boolean", 239 | "default": false 240 | }, 241 | "afterRuleBegins": { 242 | "description": "Controls if a line break comes after a rule begins; defaults to `false`.", 243 | "type": "boolean", 244 | "default": false 245 | }, 246 | "afterRuleEnds": { 247 | "description": "Controls if a line break comes after a rule ends; defaults to `false`.", 248 | "type": "boolean", 249 | "default": false 250 | }, 251 | "beforeBlockEnds": { 252 | "description": "Controls if a line break comes before a block ends; defaults to `false`.", 253 | "type": "boolean", 254 | "default": false 255 | }, 256 | "betweenSelectors": { 257 | "description": "Controls if a line break comes between selectors; defaults to `false`.", 258 | "type": "boolean", 259 | "default": false 260 | } 261 | } 262 | }, 263 | "breakWith": { 264 | "description": "Controls the new line character, can be `'\\r\\n'` or `'\\n'` (aliased as `'windows'` and `'unix'` or `'crlf'` and `'lf'`); defaults to system one, so former on Windows and latter on Unix.", 265 | "type": "string", 266 | "enum": [ 267 | "\n", 268 | "\r\n", 269 | "windows", 270 | "unix", 271 | "crlf", 272 | "lf" 273 | ] 274 | }, 275 | "indentBy": { 276 | "description": "Controls number of characters to indent with.", 277 | "type": "number", 278 | "default": 0 279 | }, 280 | "indentWith": { 281 | "description": "Controls a character to indent with.", 282 | "type": "string", 283 | "default": "space", 284 | "enum": [ 285 | "space", 286 | "tab" 287 | ] 288 | }, 289 | "spaces": { 290 | "description": "Controls where to insert spaces.", 291 | "type": "object", 292 | "properties": { 293 | "aroundSelectorRelation": { 294 | "description": "Controls if spaces come around selector relations; e.g. `div > a`; defaults to `false`.", 295 | "type": "boolean", 296 | "default": false 297 | }, 298 | "beforeBlockBegins": { 299 | "description": "Controls if a space comes before a block begins; e.g. `.block {`; defaults to `false`.", 300 | "type": "boolean", 301 | "default": false 302 | }, 303 | "beforeValue": { 304 | "description": "Controls if a space comes before a value; e.g. `width: 1rem`; defaults to `false`.", 305 | "type": "boolean", 306 | "default": false 307 | } 308 | } 309 | }, 310 | "wrapAt": { 311 | "description": "Controls maximum line length.", 312 | "default": false, 313 | "oneOf": [ 314 | { 315 | "type": "boolean", 316 | "enum": [ 317 | false 318 | ] 319 | }, 320 | { 321 | "type": "number" 322 | } 323 | ] 324 | } 325 | } 326 | } 327 | ] 328 | }, 329 | "inline": { 330 | "description": "Controls @import inlining rules.", 331 | "default": ["local"], 332 | "oneOf": [ 333 | { 334 | "type": "boolean", 335 | "enum": [ 336 | false 337 | ] 338 | }, 339 | { 340 | "type": "array", 341 | "uniqueItems": true, 342 | "items": [ 343 | { 344 | "type": "string", 345 | "enum": [ 346 | "local", 347 | "remote", 348 | "all", 349 | "none" 350 | ] 351 | }, 352 | { 353 | "type": "string" 354 | } 355 | ] 356 | } 357 | ] 358 | }, 359 | "inlineRequest": { 360 | "description": "Controls extra options for inlining remote @import rules, can be any of https://nodejs.org/api/http.html#http_http_request_options_callback.", 361 | "type": "object" 362 | }, 363 | "inlineTimeout": { 364 | "description": "Controls number of milliseconds after which inlining a remote @import fails.", 365 | "type": "number", 366 | "default": 5000 367 | }, 368 | "level": { 369 | "description": "Controls optimization level used. See https://github.com/jakubpawlowicz/clean-css#optimization-levels for examples.", 370 | "default": 1, 371 | "oneOf": [ 372 | { 373 | "type": "number", 374 | "default": 1, 375 | "enum": [ 376 | 0, 377 | 1, 378 | 2 379 | ] 380 | }, 381 | { 382 | "type": "object", 383 | "properties": { 384 | "1": { 385 | "description": "Level 1 optimization settings.", 386 | "type": "object", 387 | "properties": { 388 | "cleanupCharsets": { 389 | "description": "Controls `@charset` moving to the front of a stylesheet; defaults to `true`.", 390 | "type": "boolean", 391 | "default": true 392 | }, 393 | "normalizeUrls": { 394 | "description": "Controls URL normalization; defaults to `true`.", 395 | "type": "boolean", 396 | "default": true 397 | }, 398 | "optimizeBackground": { 399 | "description": "Controls `background` property optimizations; defaults to `true`.", 400 | "type": "boolean", 401 | "default": true 402 | }, 403 | "optimizeBorderRadius": { 404 | "description": "Controls `border-radius` property optimizations; defaults to `true`.", 405 | "type": "boolean", 406 | "default": true 407 | }, 408 | "optimizeFilter": { 409 | "description": "Controls `filter` property optimizations; defaults to `true`.", 410 | "type": "boolean", 411 | "default": true 412 | }, 413 | "optimizeFont": { 414 | "description": "Controls `font` property optimizations; defaults to `true`.", 415 | "type": "boolean", 416 | "default": true 417 | }, 418 | "optimizeFontWeight": { 419 | "description": "Controls `font-weight` property optimizations; defaults to `true`.", 420 | "type": "boolean", 421 | "default": true 422 | }, 423 | "optimizeOutline": { 424 | "description": "Controls `outline` property optimizations; defaults to `true`.", 425 | "type": "boolean", 426 | "default": true 427 | }, 428 | "removeEmpty": { 429 | "description": "Controls removing empty rules and nested blocks; defaults to `true`.", 430 | "type": "boolean", 431 | "default": true 432 | }, 433 | "removeNegativePaddings": { 434 | "description": "Controls removing negative paddings; defaults to `true`.", 435 | "type": "boolean", 436 | "default": true 437 | }, 438 | "removeQuotes": { 439 | "description": "Controls removing quotes when unnecessary; defaults to `true`.", 440 | "type": "boolean", 441 | "default": true 442 | }, 443 | "removeWhitespace": { 444 | "description": "Controls removing unused whitespace; defaults to `true`.", 445 | "type": "boolean", 446 | "default": true 447 | }, 448 | "replaceMultipleZeros": { 449 | "description": "Contols removing redundant zeros; defaults to `true`.", 450 | "type": "boolean", 451 | "default": true 452 | }, 453 | "replaceTimeUnits": { 454 | "description": "Controls replacing time units with shorter values; defaults to `true`.", 455 | "type": "boolean", 456 | "default": true 457 | }, 458 | "replaceZeroUnits": { 459 | "description": "Controls replacing zero values with units; defaults to `true`.", 460 | "type": "boolean", 461 | "default": true 462 | }, 463 | "roundingPrecision": { 464 | "description": "Rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false`.", 465 | "type": "boolean", 466 | "default": false 467 | }, 468 | "selectorsSortingMethod": { 469 | "description": "Denotes selector sorting method.", 470 | "type": "string", 471 | "default": "standard", 472 | "enum": [ 473 | "natural", 474 | "standard", 475 | "none" 476 | ] 477 | }, 478 | "specialComments": { 479 | "description": "Denotes a number of /*! ... */ comments preserved.", 480 | "type": "string", 481 | "default": "all" 482 | }, 483 | "tidyAtRules": { 484 | "description": "Controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `true`.", 485 | "type": "boolean", 486 | "default": true 487 | }, 488 | "tidyBlockScopes": { 489 | "description": "Controls block scopes (e.g. `@media`) optimizing; defaults to `true`.", 490 | "type": "boolean", 491 | "default": true 492 | }, 493 | "tidySelectors": { 494 | "description": "Controls selectors optimizing; defaults to `true`,.", 495 | "type": "boolean", 496 | "default": true 497 | }, 498 | "semicolonAfterLastProperty": { 499 | "description": "Controls removing trailing semicolons in rule; defaults to `false` - means remove.", 500 | "type": "boolean", 501 | "default": false 502 | } 503 | } 504 | }, 505 | "2": { 506 | "description": "Level 2 optimization settings.", 507 | "type": "object", 508 | "properties": { 509 | "mergeAdjacentRules": { 510 | "description": "Controls adjacent rules merging; defaults to true.", 511 | "type": "boolean", 512 | "default": true 513 | }, 514 | "mergeIntoShorthands": { 515 | "description": "Controls merging properties into shorthands; defaults to true.", 516 | "type": "boolean", 517 | "default": true 518 | }, 519 | "mergeMedia": { 520 | "description": "Controls `@media` merging; defaults to true.", 521 | "type": "boolean", 522 | "default": true 523 | }, 524 | "mergeNonAdjacentRules": { 525 | "description": "Controls non-adjacent rule merging; defaults to true.", 526 | "type": "boolean", 527 | "default": true 528 | }, 529 | "mergeSemantically": { 530 | "description": "Controls semantic merging; defaults to false.", 531 | "type": "boolean", 532 | "default": false 533 | }, 534 | "overrideProperties": { 535 | "description": "Controls property overriding based on understandability; defaults to true.", 536 | "type": "boolean", 537 | "default": true 538 | }, 539 | "removeEmpty": { 540 | "description": "Controls removing empty rules and nested blocks; defaults to `true`.", 541 | "type": "boolean", 542 | "default": true 543 | }, 544 | "reduceNonAdjacentRules": { 545 | "description": "Controls non-adjacent rule reducing; defaults to true.", 546 | "type": "boolean", 547 | "default": true 548 | }, 549 | "removeDuplicateFontRules": { 550 | "description": "Controls duplicate `@font-face` removing; defaults to true.", 551 | "type": "boolean", 552 | "default": true 553 | }, 554 | "removeDuplicateMediaBlocks": { 555 | "description": "Controls duplicate `@media` removing; defaults to true.", 556 | "type": "boolean", 557 | "default": true 558 | }, 559 | "removeDuplicateRules": { 560 | "description": "Controls duplicate rules removing; defaults to true.", 561 | "type": "boolean", 562 | "default": true 563 | }, 564 | "removeUnusedAtRules": { 565 | "description": "Controls unused at rule removing; defaults to false (available since 4.1.0).", 566 | "type": "boolean", 567 | "default": false 568 | }, 569 | "restructureRules": { 570 | "description": "Controls rule restructuring; defaults to false.", 571 | "type": "boolean", 572 | "default": false 573 | }, 574 | "skipProperties": { 575 | "description": "Controls which properties won't be optimized, defaults to `[]` which means all will be optimized (since 4.1.0).", 576 | "type": "array", 577 | "default": [] 578 | } 579 | } 580 | } 581 | } 582 | } 583 | ] 584 | }, 585 | "rebase": { 586 | "description": "Controls URL rebasing.", 587 | "type": "boolean", 588 | "default": true 589 | }, 590 | "rebaseTo": { 591 | "description": "Controls a directory to which all URLs are rebased, most likely the directory under which the output file will live. Defaults to the current directory.", 592 | "type": "string" 593 | }, 594 | "sourceMapInlineSources": { 595 | "description": "Controls embedding sources inside a source map's sourcesContent field.", 596 | "type": "boolean", 597 | "default": false 598 | }, 599 | "sourceMap": { 600 | "description": "Controls whether an output source map is built.", 601 | "type": "boolean", 602 | "default": false 603 | } 604 | } 605 | } 606 | -------------------------------------------------------------------------------- /schemas/terserrc.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "description": "Terser/Uglify-es options schema for es6-css-minify", 4 | "type": "object", 5 | "properties": { 6 | "parse": { 7 | "description": "Parse options.", 8 | "type": "object", 9 | "default": {}, 10 | "properties": { 11 | "bare_returns": { 12 | "description": "Support top level return statements.", 13 | "type": "boolean", 14 | "default": false 15 | }, 16 | "ecma": { 17 | "description": "Specify one of 5, 6, 7 or 8. Note: this setting is not presently enforced except for ES8 optional trailing commas in function parameter lists and calls with ecma 8.", 18 | "type": "number", 19 | "default": 8, 20 | "enum": [ 21 | 5, 22 | 6, 23 | 7, 24 | 8 25 | ] 26 | }, 27 | "html5_comments": { 28 | "description": "HTML5 comments.", 29 | "type": "boolean", 30 | "default": true 31 | }, 32 | "shebang": { 33 | "description": "Support #!command as the first line.", 34 | "type": "boolean", 35 | "default": true 36 | } 37 | } 38 | }, 39 | "compress": { 40 | "description": "Compress options.", 41 | "type": "object", 42 | "default": {}, 43 | "properties": { 44 | "arrows": { 45 | "description": "Converts ()=>{return x} to ()=>x. Class and object literal methods will also be converted to arrow expressions if the resultant code is shorter: m(){return x} becomes m:()=>x.", 46 | "type": "boolean", 47 | "default": true 48 | }, 49 | "arguments": { 50 | "description": "Replace arguments[index] with function parameter name whenever possible.", 51 | "type": "boolean", 52 | "default": false 53 | }, 54 | "booleans": { 55 | "description": "Various optimizations for boolean context, for example !!a ? b : c → a ? b : c.", 56 | "type": "boolean", 57 | "default": true 58 | }, 59 | "booleans_as_integers": { 60 | "description": "Turn booleans into 0 and 1, also makes comparisons with booleans use == and != instead of === and !==.", 61 | "type": "boolean", 62 | "default": false 63 | }, 64 | "collapse_vars": { 65 | "description": "Collapse single-use non-constant variables, side effects permitting.", 66 | "type": "boolean", 67 | "default": true 68 | }, 69 | "comparisons": { 70 | "description": "Apply certain optimizations to binary nodes, e.g. !(a <= b) → a > b (only when unsafe_comps), attempts to negate binary nodes, e.g. a = !b && !c && !d && !e → a=!(b||c||d||e) etc.", 71 | "type": "boolean", 72 | "default": true 73 | }, 74 | "computed_props": { 75 | "description": "Transforms constant computed properties into regular ones: {[\"computed\"]: 1} is converted to {computed: 1}.", 76 | "type": "boolean", 77 | "default": true 78 | }, 79 | "conditionals": { 80 | "description": "Apply optimizations for if-s and conditional expressions.", 81 | "type": "boolean", 82 | "default": true 83 | }, 84 | "dead_code": { 85 | "description": "Remove unreachable code.", 86 | "type": "boolean", 87 | "default": true 88 | }, 89 | "defaults": { 90 | "description": "Pass false to disable most default enabled compress transforms. Useful when you only want to enable a few compress options while disabling the rest.", 91 | "type": "boolean", 92 | "default": true 93 | }, 94 | "directives": { 95 | "description": "Remove redundant or non-standard directives.", 96 | "type": "boolean", 97 | "default": true 98 | }, 99 | "drop_console": { 100 | "description": "Pass true to discard calls to console.* functions. If you wish to drop a specific function call such as console.info and/or retain side effects from function arguments after dropping the function call then use pure_funcs instead.", 101 | "type": "boolean", 102 | "default": false 103 | }, 104 | "drop_debugger": { 105 | "description": "Remove debugger; statements.", 106 | "type": "boolean", 107 | "default": true 108 | }, 109 | "evaluate": { 110 | "description": "Attempt to evaluate constant expressions.", 111 | "type": "boolean", 112 | "default": true 113 | }, 114 | "expression": { 115 | "description": "Pass true to preserve completion values from terminal statements without return, e.g. in bookmarklets.", 116 | "type": "boolean", 117 | "default": false 118 | }, 119 | "hoist_funs": { 120 | "description": "Hoist function declarations.", 121 | "type": "boolean", 122 | "default": false 123 | }, 124 | "hoist_props": { 125 | "description": "Hoist properties from constant object and array literals into regular variables subject to a set of constraints. For example: var o={p:1, q:2}; f(o.p, o.q); is converted to f(1, 2);. Note: hoist_props works best with mangle enabled, the compress option passes set to 2 or higher, and the compress option toplevel enabled.", 126 | "type": "boolean", 127 | "default": true 128 | }, 129 | "hoist_vars": { 130 | "description": "Hoist var declarations (this is false by default because it seems to increase the size of the output in general).", 131 | "type": "boolean", 132 | "default": false 133 | }, 134 | "if_return": { 135 | "description": "Optimizations for if/return and if/continue.", 136 | "type": "boolean", 137 | "default": true 138 | }, 139 | "join_vars": { 140 | "description": "Join consecutive var statements.", 141 | "type": "boolean", 142 | "default": true 143 | }, 144 | "keep_fargs": { 145 | "description": "Prevents the compressor from discarding unused function arguments. You need this for code which relies on Function.length.", 146 | "type": "boolean", 147 | "default": true 148 | }, 149 | "keep_infinity": { 150 | "description": "Pass true to prevent Infinity from being compressed into 1/0, which may cause performance issues on Chrome.", 151 | "type": "boolean", 152 | "default": false 153 | }, 154 | "loops": { 155 | "description": "Optimizations for do, while and for loops when we can statically determine the condition.", 156 | "type": "boolean", 157 | "default": true 158 | }, 159 | "module": { 160 | "description": "Pass true when compressing an ES6 module. Strict mode is implied and the toplevel option as well.", 161 | "type": "boolean", 162 | "default": false 163 | }, 164 | "negate_iife": { 165 | "description": "Negate \"Immediately-Called Function Expressions\" where the return value is discarded, to avoid the parens that the code generator would insert.", 166 | "type": "boolean", 167 | "default": true 168 | }, 169 | "properties": { 170 | "description": "Rewrite property access using the dot notation, for example foo[\"bar\"] → foo.bar.", 171 | "type": "boolean", 172 | "default": true 173 | }, 174 | "reduce_vars": { 175 | "description": "Improve optimization on variables assigned with and used as constant values.", 176 | "type": "boolean", 177 | "default": true 178 | }, 179 | "sequences": { 180 | "description": "Join consecutive simple statements using the comma operator. May be set to a positive integer to specify the maximum number of consecutive comma sequences that will be generated. If this option is set to true then the default sequences limit is 200. Set option to false or 0 to disable. The smallest sequences length is 2. A sequences value of 1 is grandfathered to be equivalent to true and as such means 200. On rare occasions the default sequences limit leads to very slow compress times in which case a value of 20 or less is recommended.", 181 | "type": "boolean", 182 | "default": true 183 | }, 184 | "side_effects": { 185 | "description": "Pass false to disable potentially dropping function calls marked as \"pure\". A function call is marked as \"pure\" if a comment annotation /*@__PURE__*/ or /*#__PURE__*/ immediately precedes the call. For example: /*@__PURE__*/foo();.", 186 | "type": "boolean", 187 | "default": true 188 | }, 189 | "switches": { 190 | "description": "De-duplicate and remove unreachable switch branches.", 191 | "type": "boolean", 192 | "default": true 193 | }, 194 | "typeofs": { 195 | "description": "Transforms typeof foo == \"undefined\" into foo === void 0. Note: recommend to set this value to false for IE10 and earlier versions due to known issues.", 196 | "type": "boolean", 197 | "default": true 198 | }, 199 | "unsafe": { 200 | "description": "Apply \"unsafe\" transformations (https://www.npmjs.com/package/terser#the-unsafe-compress-option).", 201 | "type": "boolean", 202 | "default": false 203 | }, 204 | "unsafe_arrows": { 205 | "description": "Convert ES5 style anonymous function expressions to arrow functions if the function body does not reference this. Note: it is not always safe to perform this conversion if code relies on the the function having a prototype, which arrow functions lack. This transform requires that the ecma compress option is set to 6 or greater.", 206 | "type": "boolean", 207 | "default": false 208 | }, 209 | "unsafe_comps": { 210 | "description": "Reverse < and <= to > and >= to allow improved compression. This might be unsafe when an at least one of two operands is an object with computed values due the use of methods like get, or valueOf. This could cause change in execution order after operands in the comparison are switching. Compression only works if both comparisons and unsafe_comps are both set to true.", 211 | "type": "boolean", 212 | "default": false 213 | }, 214 | "unsafe_Function": { 215 | "description": "Compress and mangle Function(args, code) when both args and code are string literals.", 216 | "type": "boolean", 217 | "default": false 218 | }, 219 | "unsafe_math": { 220 | "description": "Optimize numerical expressions like 2 * x * 3 into 6 * x, which may give imprecise floating point results.", 221 | "type": "boolean", 222 | "default": false 223 | }, 224 | "unsafe_methods": { 225 | "description": "Converts { m: function(){} } to { m(){} }. ecma must be set to 6 or greater to enable this transform. If unsafe_methods is a RegExp then key/value pairs with keys matching the RegExp will be converted to concise methods. Note: if enabled there is a risk of getting a \" is not a constructor\" TypeError should any code try to new the former function.", 226 | "type": "boolean", 227 | "default": false 228 | }, 229 | "unsafe_proto": { 230 | "description": "Optimize expressions like Array.prototype.slice.call(a) into [].slice.call(a).", 231 | "type": "boolean", 232 | "default": false 233 | }, 234 | "unsafe_regexp": { 235 | "description": "Enable substitutions of variables with RegExp values the same way as if they are constants.", 236 | "type": "boolean", 237 | "default": false 238 | }, 239 | "unsafe_undefined": { 240 | "description": "Substitute void 0 if there is a variable named undefined in scope (variable name will be mangled, typically reduced to a single character).", 241 | "type": "boolean", 242 | "default": false 243 | }, 244 | "warnings": { 245 | "description": "Display warnings when dropping unreachable code or unused declarations etc.", 246 | "type": "boolean", 247 | "default": false 248 | }, 249 | "ecma": { 250 | "description": "Pass 6 or greater to enable compress options that will transform ES5 code into smaller ES6+ equivalent forms.", 251 | "type": "number", 252 | "default": 5, 253 | "enum": [ 254 | 5, 255 | 6, 256 | 7, 257 | 8 258 | ] 259 | }, 260 | "global_defs": { 261 | "description": "See https://www.npmjs.com/package/terser#conditional-compilation.", 262 | "type": "object", 263 | "default": {} 264 | }, 265 | "inline": { 266 | "description": "inline calls to function with simple/return statement:\n0 -- disabled inlining\n1 -- inline simple functions\n2 -- inline functions with arguments\n3 -- inline functions with arguments and variables", 267 | "type": "number", 268 | "enum": [ 269 | 0, 270 | 1, 271 | 2, 272 | 3 273 | ] 274 | }, 275 | "keep_classnames": { 276 | "description": "Pass true to prevent the compressor from discarding class names. Pass a regular expression to only keep class names matching that regex. See also: the keep_classnames mangle option.", 277 | "default": false, 278 | "oneOf": [ 279 | { 280 | "type": "boolean" 281 | }, 282 | { 283 | "type": "string" 284 | } 285 | ] 286 | }, 287 | "keep_fnames": { 288 | "description": "Pass true to prevent the compressor from discarding function names. Pass a regular expression to only keep function names matching that regex. Useful for code relying on Function.prototype.name. See also: the keep_fnames mangle option.", 289 | "default": false, 290 | "oneOf": [ 291 | { 292 | "type": "boolean" 293 | }, 294 | { 295 | "type": "string" 296 | } 297 | ] 298 | }, 299 | "passes": { 300 | "description": "The maximum number of times to run compress. In some cases more than one pass leads to further compressed code. Keep in mind more passes will take more time.", 301 | "type": "number", 302 | "default": 1 303 | }, 304 | "pure_funcs": { 305 | "description": "You can pass an array of names and Terser will assume that those functions do not produce side effects. DANGER: will not check if the name is redefined in scope. An example case here, for instance var q = Math.floor(a/b). If variable q is not used elsewhere, Terser will drop it, but will still keep the Math.floor(a/b), not knowing what it does. You can pass pure_funcs: [ 'Math.floor' ] to let it know that this function won't produce any side effect, in which case the whole statement would get discarded. The current implementation adds some overhead (compression will be slower).", 306 | "type": "array", 307 | "default": null, 308 | "uniqueItems": true, 309 | "contains": { 310 | "type": "string", 311 | "default": [] 312 | } 313 | }, 314 | "toplevel": { 315 | "description": "Drop unreferenced functions (\"funcs\") and/or variables (\"vars\") in the top level scope (false by default, true to drop both unreferenced functions and variables).", 316 | "default": false, 317 | "enum": [ 318 | true, 319 | false, 320 | "funcs", 321 | "vars" 322 | ] 323 | }, 324 | "top_retain": { 325 | "description": "Prevent specific toplevel functions and variables from unused removal (can be array, comma-separated, RegExp or function. Implies toplevel).", 326 | "default": null, 327 | "oneOf": [ 328 | { 329 | "type": "string" 330 | }, 331 | { 332 | "type": "array", 333 | "uniqueItems": true, 334 | "contains": { 335 | "type": "string" 336 | } 337 | } 338 | ] 339 | }, 340 | "pure_getters": { 341 | "description": "If you pass true for this, Terser will assume that object property access (e.g. foo.bar or foo[\"bar\"]) doesn't have any side effects. Specify \"strict\" to treat foo.bar as side-effect-free only when foo is certain to not throw, i.e. not null or undefined.", 342 | "default": "strict", 343 | "enum": [ 344 | true, 345 | false, 346 | "strict" 347 | ] 348 | }, 349 | "unused": { 350 | "description": "Drop unreferenced functions and variables (simple direct variable assignments do not count as references unless set to \"keep_assign\").", 351 | "default": true, 352 | "enum": [ 353 | true, 354 | false, 355 | "keep_assign" 356 | ] 357 | } 358 | } 359 | }, 360 | "mangle": { 361 | "description": "Mangle options.", 362 | "default": true, 363 | "oneOf": [ 364 | { 365 | "type": "boolean" 366 | }, 367 | { 368 | "type": "object", 369 | "properties": { 370 | "eval": { 371 | "description": "Pass true to mangle names visible in scopes where eval or with are used.", 372 | "type": "boolean", 373 | "default": false 374 | }, 375 | "keep_classnames": { 376 | "description": "Pass true to not mangle class names. Pass a regular expression to only keep class names matching that regex. See also: https://www.npmjs.com/package/terser#compress-options.", 377 | "type": "boolean", 378 | "default": false 379 | }, 380 | "keep_fnames": { 381 | "description": "Pass true to not mangle function names. Pass a regular expression to only keep class names matching that regex. Useful for code relying on Function.prototype.name. See also: https://www.npmjs.com/package/terser#compress-options.", 382 | "type": "boolean", 383 | "default": false 384 | }, 385 | "module": { 386 | "description": "Pass true an ES6 modules, where the toplevel scope is not the global scope. Implies toplevel.", 387 | "type": "boolean", 388 | "default": false 389 | }, 390 | "reserved": { 391 | "description": " Pass an array of identifiers that should be excluded from mangling. Example: [\"foo\", \"bar\"].", 392 | "type": "array", 393 | "default": [], 394 | "uniqueItems": true, 395 | "contains": { 396 | "type": "string" 397 | } 398 | }, 399 | "toplevel": { 400 | "description": "Pass true to mangle names declared in the top level scope.", 401 | "type": "boolean", 402 | "default": false 403 | }, 404 | "safari10": { 405 | "description": "Pass true to work around the Safari 10 loop iterator bug \"Cannot declare a let variable twice\". See also: https://www.npmjs.com/package/terser#output-options.", 406 | "type": "boolean", 407 | "default": false 408 | }, 409 | "properties": { 410 | "description": "Mangle property options.", 411 | "type": "object", 412 | "properties": { 413 | "builtins": { 414 | "description": "Use true to allow the mangling of builtin DOM properties. Not recommended to override this setting.", 415 | "type": "boolean", 416 | "default": false 417 | }, 418 | "debug": { 419 | "description": "Mangle names with the original name still present. Pass an empty string \"\" to enable, or a non-empty string to set the debug suffix.", 420 | "default": false, 421 | "oneOf": [ 422 | { 423 | "type": "string" 424 | }, 425 | { 426 | "type": "boolean" 427 | } 428 | ] 429 | }, 430 | "keep_quoted": { 431 | "description": "Only mangle unquoted property names. true -- Quoted property names are automatically reserved and any unquoted property names will not be mangled. \"strict\" -- Advanced, all unquoted property names are mangled unless explicitly reserved.", 432 | "default": false, 433 | "enum": [ 434 | true, 435 | false, 436 | "strict" 437 | ] 438 | }, 439 | "regex": { 440 | "description": "Pass a RegExp literal or pattern string to only mangle property matching the regular expression. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp", 441 | "type": "string", 442 | "default": null 443 | }, 444 | "reserved": { 445 | "description": "Do not mangle property names listed in the reserved array.", 446 | "type": "array", 447 | "default": [], 448 | "uniqueItems": true, 449 | "contains": { 450 | "type": "string" 451 | } 452 | }, 453 | "undeclared": { 454 | "description": "Mangle those names when they are accessed as properties of known top level variables but their declarations are never found in input code. May be useful when only minifying parts of a project. See https://github.com/terser/terser/issues/397 for more details.", 455 | "type": "boolean", 456 | "default": false 457 | } 458 | } 459 | } 460 | } 461 | } 462 | ] 463 | }, 464 | "output": { 465 | "description": "Output options.", 466 | "type": "object", 467 | "default": {}, 468 | "properties": { 469 | "ascii_only": { 470 | "description": "Escape Unicode characters in strings and regexps (affects directives with non-ascii characters becoming invalid).", 471 | "type": "boolean", 472 | "default": false 473 | }, 474 | "beautify": { 475 | "description": "Whether to actually beautify the output. Passing -b will set this to true, but you might need to pass -b even when you want to generate minified code, in order to specify additional arguments, so you can use -b beautify=false to override it.", 476 | "type": "boolean", 477 | "default": true 478 | }, 479 | "braces": { 480 | "description": "Always insert braces in if, for, do, while or with statements, even if their body is a single statement.", 481 | "type": "boolean", 482 | "default": false 483 | }, 484 | "comments": { 485 | "description": "Pass true or \"all\" to preserve all comments, \"some\" to preserve some comments, a regular expression string (e.g. /^!/) or a function.", 486 | "default": false, 487 | "oneOf": [ 488 | { 489 | "enum": [ 490 | "some", 491 | "all" 492 | ] 493 | }, 494 | { 495 | "type": "boolean" 496 | }, 497 | { 498 | "type": "string" 499 | } 500 | ] 501 | }, 502 | "ecma": { 503 | "description": "Set output printing mode. Set ecma to 6 or greater to emit shorthand object properties - i.e.: {a} instead of {a: a}. The ecma option will only change the output in direct control of the beautifier. Non-compatible features in the abstract syntax tree will still be output as is. For example: an ecma setting of 5 will not convert ES6+ code to ES5.", 504 | "type": "number", 505 | "default": 5, 506 | "enum": [ 507 | 5, 508 | 6, 509 | 7, 510 | 8 511 | ] 512 | }, 513 | "indent_level": { 514 | "description": "The amount of spaces to every indent should be.", 515 | "type": "number", 516 | "default": 4 517 | }, 518 | "indent_start": { 519 | "description": "Prefix all lines by that many spaces.", 520 | "type": "number", 521 | "default": 0 522 | }, 523 | "inline_script": { 524 | "description": "Escape HTML comments and the slash in occurrences of in strings.", 525 | "type": "boolean", 526 | "default": true 527 | }, 528 | "keep_quoted_props": { 529 | "description": "When turned on, prevents stripping quotes from property names in object literals.", 530 | "type": "boolean", 531 | "default": false 532 | }, 533 | "max_line_len": { 534 | "description": "Maximum line length (for minified code).", 535 | "default": false, 536 | "oneOf": [ 537 | { 538 | "type": "boolean", 539 | "enum": [false] 540 | }, 541 | { 542 | "type": "number" 543 | } 544 | ] 545 | }, 546 | "preamble": { 547 | "description": "When passed it must be a string and it will be prepended to the output literally. The source map will adjust for this text. Can be used to insert a comment containing licensing information, for example.", 548 | "type": "string", 549 | "default": null 550 | }, 551 | "quote_keys": { 552 | "description": "Pass true to quote all keys in literal objects.", 553 | "type": "boolean", 554 | "default": false 555 | }, 556 | "quote_style": { 557 | "description": "preferred quote style for strings (affects quoted property names and directives as well):\n0 -- prefers double quotes, switches to single quotes when there are more double quotes in the string itself. 0 is best for gzip size.\n1 -- always use single quotes\n2 -- always use double quotes\n3 -- always use the original quotes", 558 | "type": "number", 559 | "default": 0, 560 | "enum": [ 561 | 0, 562 | 1, 563 | 2, 564 | 3 565 | ] 566 | }, 567 | "safari10": { 568 | "description": "Set this option to true to work around the Safari 10/11 await bug https://bugs.webkit.org/show_bug.cgi?id=176685. See also: https://www.npmjs.com/package/terser#mangle-options.", 569 | "type": "boolean", 570 | "default": false 571 | }, 572 | "semicolons": { 573 | "description": "Separate statements with semicolons. If you pass false then whenever possible we will use a newline instead of a semicolon, leading to more readable output of minified code (size before gzip could be smaller; size after gzip insignificantly larger).", 574 | "type": "boolean", 575 | "default": true 576 | }, 577 | "shebang": { 578 | "description": "Preserve shebang #! in preamble (bash scripts).", 579 | "type": "boolean", 580 | "default": true 581 | }, 582 | "webkit": { 583 | "description": "Enable workarounds for WebKit bugs. PhantomJS users should set this option to true.", 584 | "type": "boolean", 585 | "default": false 586 | }, 587 | "wrap_iife": { 588 | "description": "Pass true to wrap immediately invoked function expressions. See https://github.com/mishoo/UglifyJS2/issues/640 for more details.", 589 | "type": "boolean", 590 | "default": false 591 | }, 592 | "wrap_func_args": { 593 | "description": "pass false if you do not want to wrap function expressions that are passed as arguments, in parenthesis. See https://github.com/nolanlawson/optimize-js for more details.", 594 | "type": "boolean", 595 | "default": true 596 | } 597 | } 598 | }, 599 | "ecma": { 600 | "description": "Pass 5, 6, 7 or 8 to override parse, compress and output's ecma options.", 601 | "type": "number", 602 | "enum": [ 603 | 5, 604 | 6, 605 | 7, 606 | 8 607 | ] 608 | }, 609 | "keep_classnames": { 610 | "description": "Pass true to prevent discarding or mangling of class names. Pass a regular expression to only keep class names matching that regex.", 611 | "default": false, 612 | "oneOf": [ 613 | { 614 | "type": "boolean" 615 | }, 616 | { 617 | "type": "string" 618 | } 619 | ] 620 | }, 621 | "keep_fnames": { 622 | "description": "Pass true to prevent discarding or mangling of function names. Pass a regular expression to only keep class names matching that regex. Useful for code relying on Function.prototype.name. If the top level minify option keep_classnames is undefined it will be overridden with the value of the top level minify option keep_fnames.", 623 | "default": false, 624 | "oneOf": [ 625 | { 626 | "type": "boolean" 627 | }, 628 | { 629 | "type": "string" 630 | } 631 | ] 632 | }, 633 | "ie8": { 634 | "description": "Set to true to support IE8.", 635 | "type": "boolean", 636 | "default": false 637 | }, 638 | "module": { 639 | "description": " Use when minifying an ES6 module. \"use strict\" is implied and names can be mangled on the top scope. If compress or mangle is enabled then the toplevel option will be enabled.", 640 | "type": "boolean", 641 | "default": false 642 | }, 643 | "safari10": { 644 | "description": "Pass true to work around Safari 10/11 bugs in loop scoping and await. See safari10 options in mangle and output for details.", 645 | "type": "boolean", 646 | "default": false 647 | }, 648 | "toplevel": { 649 | "description": "Set to true if you wish to enable top level variable and function name mangling and to drop unused variables and functions.", 650 | "type": "boolean", 651 | "default": false 652 | }, 653 | "warnings": { 654 | "description": "Pass true to return compressor warnings in result.warnings. Use the value \"verbose\" for more detailed warnings.", 655 | "default": false, 656 | "oneOf": [ 657 | { 658 | "type": "boolean" 659 | }, 660 | { 661 | "type": "string", 662 | "enum": [ 663 | "verbose" 664 | ] 665 | } 666 | ] 667 | }, 668 | "sourceMap": { 669 | "description": "Source map options", 670 | "default": false, 671 | "oneOf": [ 672 | { 673 | "type": "object", 674 | "properties": { 675 | "includeSources": { 676 | "description": "Inlude source in source map.", 677 | "type": "boolean", 678 | "default": false 679 | }, 680 | "root": { 681 | "description": "", 682 | "type": "string" 683 | }, 684 | "url": { 685 | "description": "", 686 | "type": "string", 687 | "enum": [ 688 | "inline" 689 | ] 690 | } 691 | } 692 | }, 693 | { 694 | "type": "boolean" 695 | } 696 | ] 697 | 698 | } 699 | } 700 | } 701 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import * as terser from 'terser'; 2 | import * as cleancss from 'clean-css'; 3 | import * as autoprefixer from 'autoprefixer'; 4 | import * as vscode from 'vscode'; 5 | import * as path from 'path'; 6 | import { File, DataFormat } from './fs'; 7 | 8 | class Config { 9 | 10 | // General 11 | minifyOnSave: boolean | 'yes' | 'no' | 'exists'; 12 | hideButton: boolean | 'always' | 'never' | 'auto'; 13 | showLogOnWarning: boolean; 14 | showLogOnError: boolean; 15 | onSaveDelay: number; 16 | 17 | // Terser 18 | uglifyConfigFile: string; 19 | genJSmap: boolean | null; 20 | jsMapSource: string; 21 | jsMinPath: string; 22 | jsPostfix: string; 23 | js: terser.MinifyOptions; 24 | 25 | // Clean-css 26 | cleancssConfigFile: string; 27 | genCSSmap: boolean | null; 28 | cssMapSource: string; 29 | cssMinPath: string; 30 | cssPostfix: string; 31 | css: cleancss.Options; 32 | 33 | // Autoprefixer 34 | enableAutoprefixer: boolean; 35 | enableAutoprefixerSelection: boolean; 36 | autoprefixer: autoprefixer.Options; 37 | autoprefixerConfigFile: string; 38 | 39 | constructor(external = true) { 40 | 41 | const conf: Config = JSON.parse(JSON.stringify(vscode.workspace.getConfiguration('es6-css-minify'))); 42 | 43 | // General 44 | this.minifyOnSave = conf.minifyOnSave; 45 | this.hideButton = conf.hideButton; 46 | this.showLogOnWarning = conf.showLogOnWarning; 47 | this.showLogOnError = conf.showLogOnError; 48 | this.onSaveDelay = conf.onSaveDelay; 49 | 50 | // Terser 51 | this.uglifyConfigFile = conf.uglifyConfigFile; 52 | this.genJSmap = conf.genJSmap; 53 | this.jsMapSource = conf.jsMapSource; 54 | this.jsMinPath = conf.jsMinPath; 55 | this.jsPostfix = conf.jsPostfix; 56 | this.js = conf.js; 57 | 58 | // Clean-css 59 | this.cleancssConfigFile = conf.cleancssConfigFile; 60 | this.genCSSmap = conf.genCSSmap; 61 | this.cssMapSource = conf.cssMapSource; 62 | this.cssMinPath = conf.cssMinPath; 63 | this.cssPostfix = conf.cssPostfix; 64 | this.css = conf.css; 65 | 66 | // Autoprefixer 67 | this.enableAutoprefixer = conf.enableAutoprefixer; 68 | this.enableAutoprefixerSelection = conf.enableAutoprefixerSelection; 69 | this.autoprefixer = conf.autoprefixer; 70 | this.autoprefixerConfigFile = conf.autoprefixerConfigFile; 71 | 72 | if (external && vscode.workspace.workspaceFolders) { 73 | 74 | // Check if custom uglify/terser config exists and load it 75 | const jsrc = new File(path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, this.uglifyConfigFile)); 76 | if (jsrc.exists()) { 77 | let data = jsrc.parse(DataFormat.json); 78 | if (data && typeof data === 'object') { 79 | this.js = data; 80 | } else { 81 | console.error('Invalid uglifyrc file'); 82 | vscode.window.showWarningMessage('Invalid uglify/terser configuration. This is probably due to a syntax error.'); 83 | } 84 | } 85 | 86 | // Check if custom clean-css config exists and load it 87 | const cssrc = new File(path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, this.cleancssConfigFile)); 88 | if (cssrc.exists()) { 89 | let data = cssrc.parse(DataFormat.json); 90 | if (data && typeof data === 'object') { 91 | this.css = data; 92 | } else { 93 | console.error('Invalid cleancssrc file'); 94 | vscode.window.showWarningMessage('Invalid clean-css configuration. This is probably due to a syntax error.'); 95 | } 96 | } 97 | 98 | // Check if custom autoprefixer config exists and load it 99 | const aprc = new File(path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, this.autoprefixerConfigFile)); 100 | if (aprc.exists()) { 101 | let data = aprc.parse(DataFormat.json); 102 | if (data && typeof data === 'object') { 103 | this.autoprefixer = data; 104 | } else { 105 | console.error('Invalid autoprefixerrc file'); 106 | vscode.window.showWarningMessage('Invalid autoprefixer configuration. This is probably due to a syntax error.'); 107 | } 108 | } 109 | 110 | } else if (external) { 111 | 112 | vscode.window.showWarningMessage('Not loading any custom configs since no workspace is open!'); 113 | 114 | } 115 | 116 | // Overwrite css.sourceMap with genCSSmap. 117 | if (this.genCSSmap !== null) { 118 | this.css.sourceMap = this.genCSSmap; 119 | } 120 | 121 | // Overwrite js.sourceMap with genJSmap. 122 | if (this.genJSmap !== null) { 123 | this.js.sourceMap = this.genJSmap; 124 | } 125 | 126 | // RegEx 127 | // This should no longer be needed since terser accepts strings as well as RegExp. Issue #57 128 | if ( 129 | typeof this.js.mangle === 'object' && this.js.mangle.properties && 130 | typeof this.js.mangle.properties === 'object' && this.js.mangle.properties.regex 131 | ) { 132 | this.js.mangle.properties.regex = new RegExp(this.js.mangle.properties.regex); 133 | } 134 | 135 | } 136 | 137 | } 138 | 139 | export function reloadConfig(external: boolean): void { 140 | config = new Config(external); 141 | } 142 | 143 | export let config = new Config(false); 144 | -------------------------------------------------------------------------------- /src/css.ts: -------------------------------------------------------------------------------- 1 | import * as cleancss from 'clean-css'; 2 | import * as autoprefixer from 'autoprefixer'; 3 | import { efficiency } from './utils'; 4 | 5 | interface CssInputFile { 6 | file: string; 7 | data: string; 8 | } 9 | 10 | export class CssMinifier { 11 | 12 | constructor(private options: cleancss.Options, private ap: { use: boolean, options: autoprefixer.Options }) { } 13 | 14 | minify(_input: string | CssInputFile): MinifyOutput { 15 | 16 | const cssInputStr = typeof _input === 'string' ? _input : _input.data; 17 | 18 | let css: string; 19 | 20 | if (this.ap.use) { 21 | 22 | try { 23 | 24 | css = autoprefixer.process(cssInputStr, this.ap.options).toString(); 25 | 26 | } catch (e) { 27 | 28 | return { 29 | success: false, 30 | warnings: [], 31 | errors: [ 32 | // 'Autoprefixer failed to parse CSS. Probaly due to an syntax error.', 33 | e.message 34 | ] 35 | }; 36 | 37 | } 38 | 39 | } else { 40 | 41 | css = cssInputStr; 42 | 43 | } 44 | 45 | const output = new cleancss(this.options as cleancss.OptionsOutput) 46 | // .minify(css); 47 | .minify(typeof _input === 'string' ? css : { [_input.file]: { styles: css } }) // TODO: Use callback 48 | 49 | if (output.errors.length > 0) { 50 | 51 | return { 52 | success: false, 53 | warnings: output.warnings, 54 | errors: output.errors 55 | }; 56 | 57 | } else if (output.styles.trim().length === 0) { 58 | 59 | const warnings = ['Output is 0 bytes!'].concat(output.warnings); 60 | 61 | return { 62 | success: true, 63 | efficiency: efficiency(output.stats.originalSize, output.stats.minifiedSize), 64 | warnings: warnings, 65 | errors: output.errors, 66 | output: { 67 | code: output.styles, 68 | map: output.sourceMap 69 | } 70 | }; 71 | 72 | } else { 73 | 74 | return { 75 | success: true, 76 | efficiency: efficiency(output.stats.originalSize, output.stats.minifiedSize), 77 | warnings: output.warnings, 78 | errors: output.errors, 79 | output: { 80 | code: output.styles, 81 | map: output.sourceMap 82 | } 83 | }; 84 | 85 | } 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/es6-css-minify.d.ts: -------------------------------------------------------------------------------- 1 | type MinifyOutput = MinifySuccess | MinifyError; 2 | 3 | interface MinifySuccess { 4 | success: true; 5 | efficiency: number; 6 | warnings: string[]; 7 | errors: string[]; 8 | output: { 9 | code: string; 10 | map: string; 11 | }; 12 | } 13 | 14 | interface MinifyError { 15 | success: false; 16 | warnings: string[]; 17 | errors: string[]; 18 | } 19 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { config, reloadConfig } from './config'; 3 | import { statusBar } from './status-bar'; 4 | import { EXT_ID, SUPPORTED_FILES, isMinified, getOutPath, onConfigFileChange } from './utils'; 5 | import { output } from './output'; 6 | import { File } from './fs'; 7 | import { minifyDocument } from './minify-document'; 8 | import { minifySelection } from './minify-selection'; 9 | 10 | export function activate(context: vscode.ExtensionContext): void { 11 | 12 | // Load config 13 | reloadConfig(true); 14 | 15 | 16 | // Show minify button 17 | if (config.hideButton === 'never' || config.hideButton === false) { 18 | statusBar.showButton(); 19 | } 20 | 21 | 22 | // Commands 23 | context.subscriptions.push( 24 | 25 | // Reload config. 26 | vscode.commands.registerCommand(`${EXT_ID}.loadConfig`, () => { 27 | 28 | reloadConfig(true); 29 | if (config.hideButton === 'never') { 30 | statusBar.showButton(); 31 | } else if (config.hideButton === 'always') { 32 | statusBar.hideButton(); 33 | } 34 | vscode.window.showInformationMessage('Minify configuration reloaded.'); 35 | 36 | }), 37 | 38 | 39 | // Minify file. 40 | vscode.commands.registerCommand(`${EXT_ID}.minify`, () => { 41 | 42 | const editor = vscode.window.activeTextEditor; 43 | 44 | if (!editor) { 45 | vscode.window.showErrorMessage('No document open.'); 46 | return; 47 | } 48 | 49 | if (editor.document.isUntitled) { 50 | vscode.window.showErrorMessage('File must be saved before it can be minified.'); 51 | return; 52 | } 53 | 54 | minifyDocument(editor.document); 55 | 56 | }), 57 | 58 | 59 | // Minify selection. 60 | vscode.commands.registerCommand(`${EXT_ID}.minifySelection`, () => { 61 | 62 | const editor = vscode.window.activeTextEditor; 63 | 64 | if (!editor) { 65 | vscode.window.showErrorMessage('No editor open.'); 66 | return; 67 | } 68 | 69 | minifySelection(editor); 70 | 71 | }), 72 | 73 | 74 | // Minify document from explorer 75 | vscode.commands.registerCommand(`${EXT_ID}.minifyExplorer`, async (f: vscode.Uri | undefined) => { 76 | 77 | // If f is undefined, show file picker 78 | const uri: vscode.Uri | null = f instanceof vscode.Uri ? f : await (async () => { 79 | 80 | const allFiles = await vscode.workspace.findFiles('**/*'); 81 | const files = allFiles.filter(file => { 82 | 83 | return file.scheme === 'file' && (file.path.endsWith('.js') || file.path.endsWith('.css')); 84 | 85 | }); 86 | 87 | if (files.length === 0) { 88 | vscode.window.showInformationMessage('No files available to minify'); 89 | return null; 90 | } 91 | 92 | const filesRelative = files.map(file => { 93 | return vscode.workspace.asRelativePath(file.path); 94 | }); 95 | 96 | const pick = await vscode.window.showQuickPick(filesRelative); 97 | // console.log('pick', pick); 98 | if (!pick) { 99 | return null; 100 | } 101 | 102 | return files[filesRelative.indexOf(pick)]; 103 | 104 | })(); 105 | 106 | if (uri) { 107 | const doc = await vscode.workspace.openTextDocument(uri); 108 | minifyDocument(doc); 109 | } 110 | 111 | }), 112 | 113 | 114 | // Export config for easy debug. 115 | vscode.commands.registerCommand(`${EXT_ID}.exportConfig`, () => { 116 | 117 | vscode.workspace.openTextDocument({ language: 'json', content: JSON.stringify(config, null, 4)}) 118 | .then(doc => { 119 | vscode.window.showTextDocument(doc); 120 | }); 121 | 122 | }), 123 | 124 | 125 | // Minify on save. 126 | vscode.workspace.onDidSaveTextDocument(doc => { 127 | 128 | if (config.minifyOnSave === false || config.minifyOnSave === 'no' || !SUPPORTED_FILES.includes(doc.languageId)) { 129 | return; 130 | } 131 | 132 | if (config.minifyOnSave === 'exists') { 133 | if (!new File(getOutPath(doc)).exists()) { 134 | return; 135 | } 136 | } 137 | 138 | // This is a hack to get arround bad/old hardware. 139 | if (config.onSaveDelay) { 140 | setTimeout(() => { 141 | minifyDocument(doc); 142 | }, config.onSaveDelay); 143 | } else { 144 | minifyDocument(doc); 145 | } 146 | 147 | }), 148 | 149 | 150 | // Hide the minify button unless the active document is a non-minified JS/CSS file. 151 | vscode.workspace.onDidOpenTextDocument(() => { 152 | 153 | if (vscode.window.activeTextEditor && (config.hideButton === 'auto' || config.hideButton === true)) { 154 | const doc = vscode.window.activeTextEditor.document; 155 | if (SUPPORTED_FILES.includes(doc.languageId) && !isMinified(doc)) { 156 | statusBar.showButton(); 157 | } else { 158 | statusBar.hideButton(); 159 | } 160 | } 161 | 162 | }), 163 | 164 | 165 | // Reload minify config if the vscode config is modified 166 | vscode.workspace.onDidChangeConfiguration(e => { 167 | 168 | if (e.affectsConfiguration(EXT_ID)) { 169 | 170 | reloadConfig(true); 171 | if (config.hideButton === 'never') { 172 | statusBar.showButton(); 173 | } else if (config.hideButton === 'always') { 174 | statusBar.hideButton(); 175 | } 176 | vscode.window.showInformationMessage('Minify configuration reloaded.'); 177 | 178 | } 179 | 180 | }) 181 | 182 | ); 183 | 184 | 185 | const watcher = vscode.workspace.createFileSystemWatcher('**', false, false, false) 186 | watcher.onDidCreate(onConfigFileChange); 187 | watcher.onDidChange(onConfigFileChange); 188 | watcher.onDidDelete(onConfigFileChange); 189 | 190 | context.subscriptions.push(watcher); 191 | 192 | console.log('es6-css-minify 3 is now active!'); 193 | 194 | } 195 | 196 | export function deactivate(): void { 197 | output.dispose(); 198 | } 199 | -------------------------------------------------------------------------------- /src/fs.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | // import * as vscode from 'vscode'; 3 | 4 | export enum DataFormat { 5 | json = 'JSON' 6 | } 7 | 8 | export class File { 9 | 10 | constructor(private path: string) { } 11 | 12 | exists(): boolean { 13 | 14 | return fs.existsSync(this.path); 15 | 16 | } 17 | 18 | write(data: string): void { 19 | 20 | return fs.writeFileSync(this.path, data, { encoding: 'utf8' }); 21 | 22 | } 23 | 24 | read(): string { 25 | 26 | return fs.readFileSync(this.path, { 27 | encoding: 'utf8', 28 | flag: 'r' 29 | }).toString(); 30 | 31 | } 32 | 33 | parse(type: DataFormat): any { 34 | 35 | if (type === DataFormat.json) { 36 | 37 | try { 38 | 39 | return JSON.parse(this.read()); 40 | 41 | } catch (e) { 42 | 43 | console.error('fs.ts', e); 44 | return null; 45 | 46 | } 47 | 48 | } else { 49 | 50 | return null; 51 | 52 | } 53 | 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/js.ts: -------------------------------------------------------------------------------- 1 | import * as terser from 'terser'; 2 | import * as path from 'path'; 3 | import { efficiency } from './utils'; 4 | 5 | export class EsMinifier { 6 | 7 | constructor(private options: terser.MinifyOptions) { } 8 | 9 | minify(input: string, fileName: string | null, map: { outFileName: string, jsMapSource: string} | null): MinifyOutput { 10 | 11 | const local: terser.MinifyOptions = JSON.parse(JSON.stringify(this.options)); 12 | 13 | if (this.options.sourceMap && fileName !== null && map !== null) { 14 | if (this.options.sourceMap === true) { 15 | local.sourceMap = { 16 | filename: map.jsMapSource ? path.join(map.jsMapSource, fileName) : fileName, 17 | url: `${map.outFileName}.map` 18 | }; 19 | } else if (typeof local.sourceMap === 'object') { 20 | local.sourceMap.filename = map.jsMapSource ? path.join(map.jsMapSource, fileName) : fileName; 21 | local.sourceMap.url = `${map.outFileName}.map`; 22 | } 23 | } 24 | 25 | const output = terser.minify(fileName ? { [fileName]: input } : input, local); 26 | 27 | if (output.error) { 28 | 29 | return { 30 | success: false, 31 | warnings: output.warnings || [], 32 | errors: [output.error.message] 33 | }; 34 | 35 | } else if (!output.code) { 36 | 37 | const warnings = ['Output is 0 bytes!'].concat(output.warnings || []); 38 | 39 | return { 40 | success: true, 41 | efficiency: efficiency(input.length, 0), 42 | warnings: warnings, 43 | errors: [], 44 | output: { 45 | code: output.code ? output.code : '', 46 | // map: output.map ? output.map : '' 47 | map: typeof output.map === 'string' ? JSON.stringify(JSON.parse(output.map), null, 4) : typeof output.map === 'object' ? JSON.stringify(output.map, null, 4) : '' 48 | } 49 | }; 50 | 51 | } else { 52 | 53 | return { 54 | success: true, 55 | efficiency: efficiency(input.length, output.code.length), 56 | warnings: output.warnings || [], 57 | errors: [], 58 | output: { 59 | code: output.code, 60 | // map: typeof output.map === 'string' ? output.map : typeof output.map === 'object' ? JSON.stringify(output.map) : '' 61 | map: typeof output.map === 'string' ? JSON.stringify(JSON.parse(output.map), null, 4) : typeof output.map === 'object' ? JSON.stringify(output.map, null, 4) : '' 62 | } 63 | }; 64 | 65 | } 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/json.ts: -------------------------------------------------------------------------------- 1 | import { efficiency } from './utils'; 2 | 3 | export class JsonMinifier { 4 | 5 | // constructor(options: null = null) { } 6 | 7 | minify(input: string): MinifyOutput { 8 | 9 | try { 10 | 11 | const output = JSON.stringify(JSON.parse(input)); 12 | 13 | return { 14 | success: true, 15 | efficiency: efficiency(input.length, output.length), 16 | warnings: [], 17 | errors: [], 18 | output: { 19 | code: output, 20 | map: '' 21 | } 22 | }; 23 | 24 | } catch (e) { 25 | 26 | console.error(e); 27 | 28 | return { 29 | success: false, 30 | warnings: [], 31 | errors: [e.message] 32 | }; 33 | 34 | } 35 | 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/minify-document.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as path from 'path'; 3 | import { config } from './config'; 4 | import { output } from './output'; 5 | import { CssMinifier } from './css'; 6 | import { EsMinifier } from './js'; 7 | import { isMinified, getOutPath } from './utils'; 8 | import { File } from './fs'; 9 | import { statusBar } from './status-bar'; 10 | 11 | export function minifyDocument(doc: vscode.TextDocument): void { 12 | 13 | const text = doc.getText(); 14 | const baseName = path.basename(doc.fileName); 15 | 16 | if (isMinified(doc)) { 17 | // output.printMinifyResult(baseName, { 18 | // success: false, 19 | // warnings: [], 20 | // errors: ['File already minified!'] 21 | // }); 22 | vscode.window.showErrorMessage('File already minified!'); 23 | return; 24 | } 25 | 26 | // Minify 27 | switch (doc.languageId) { 28 | 29 | case 'css': { 30 | const minifier = new CssMinifier(config.css, { use: config.enableAutoprefixer, options: config.autoprefixer }); 31 | const res = minifier.minify({ 32 | file: doc.fileName, 33 | data: text 34 | }); 35 | if (res.success) { 36 | try { 37 | const outPath = getOutPath(doc); 38 | if (config.genCSSmap === true || config.genCSSmap === null) { 39 | const map = JSON.parse(res.output.map); 40 | map.sources = [config.cssMapSource ? path.join(config.cssMapSource, baseName) : baseName]; 41 | new File(`${outPath}.map`).write(JSON.stringify(map, null, 4)); 42 | res.output.code += `\n/*# sourceMappingURL=${path.basename(outPath)}.map */\n`; 43 | } 44 | new File(outPath).write(res.output.code); 45 | statusBar.showStats(res.efficiency); 46 | output.printMinifyResult(`${baseName}`, res); 47 | if (res.warnings.length && config.showLogOnWarning) { 48 | output.show(); 49 | } 50 | } catch (e) { 51 | vscode.window.showErrorMessage('Failed to write to file. Does the output path exist?'); 52 | } 53 | } else if (config.showLogOnError) { 54 | output.printMinifyResult(`${baseName}`, res); 55 | output.show(); 56 | } else { 57 | output.printMinifyResult(`${baseName}`, res); 58 | } 59 | break; 60 | } 61 | 62 | case 'javascript': { 63 | const outPath = getOutPath(doc); 64 | const minifier = new EsMinifier(config.js); 65 | const res = minifier.minify(text, baseName, { 66 | outFileName: path.basename(outPath), 67 | jsMapSource: config.jsMapSource 68 | }); 69 | if (res.success) { 70 | try { 71 | if (config.genJSmap === true || config.genJSmap === null) { 72 | new File(`${outPath}.map`).write(res.output.map); 73 | } 74 | new File(outPath).write(res.output.code); 75 | statusBar.showStats(res.efficiency); 76 | output.printMinifyResult(`${baseName}`, res); 77 | if (res.warnings.length && config.showLogOnWarning) { 78 | output.show(); 79 | } 80 | } catch (e) { 81 | vscode.window.showErrorMessage('Failed to write to file. Does the output path exist?'); 82 | } 83 | } else if (config.showLogOnError) { 84 | output.printMinifyResult(`${baseName}`, res); 85 | output.show(); 86 | } else { 87 | output.printMinifyResult(`${baseName}`, res); 88 | } 89 | break; 90 | } 91 | 92 | default: { 93 | vscode.window.showErrorMessage('Language not supported.'); 94 | break; 95 | } 96 | 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/minify-selection.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as path from 'path'; 3 | import { config } from './config'; 4 | import { output } from './output'; 5 | import { CssMinifier } from './css'; 6 | import { EsMinifier } from './js'; 7 | import { JsonMinifier } from './json'; 8 | import { statusBar } from './status-bar'; 9 | 10 | export function minifySelection(editor: vscode.TextEditor): void { 11 | 12 | const text = editor.document.getText(editor.selection); 13 | 14 | if (!text.trim()) { 15 | vscode.window.showWarningMessage('No text selected.'); 16 | return; 17 | } 18 | 19 | switch (editor.document.languageId) { 20 | 21 | case 'css': { 22 | const minifier = new CssMinifier(config.css, { use: config.enableAutoprefixerSelection, options: config.autoprefixer }); 23 | const fileName = path.basename(editor.document.fileName); 24 | const res = minifier.minify(text); 25 | output.printMinifyResult(`${fileName} (selection)`, res); 26 | if (res.success) { 27 | editor.insertSnippet(new vscode.SnippetString(res.output.code)); 28 | statusBar.showStats(res.efficiency); 29 | if (res.warnings.length && config.showLogOnWarning) { 30 | output.show(); 31 | } 32 | } else { 33 | vscode.window.showErrorMessage('Failed to minify selection. See output for more info.'); 34 | if (config.showLogOnError) { 35 | output.show(); 36 | } 37 | } 38 | break; 39 | } 40 | 41 | case 'javascript': { 42 | const minifier = new EsMinifier(config.js); 43 | const fileName = path.basename(editor.document.fileName); 44 | const res = minifier.minify(text, null, null); 45 | output.printMinifyResult(`${fileName} (selection)`, res); 46 | if (res.success) { 47 | editor.insertSnippet(new vscode.SnippetString(res.output.code)); 48 | if (res.warnings.length && config.showLogOnWarning) { 49 | output.show(); 50 | } 51 | } else { 52 | vscode.window.showErrorMessage('Failed to minify selection. See output for more info.'); 53 | if (config.showLogOnError) { 54 | output.show(); 55 | } 56 | } 57 | break; 58 | } 59 | 60 | case 'json': { 61 | const minifier = new JsonMinifier(); 62 | const fileName = path.basename(editor.document.fileName); 63 | const res = minifier.minify(text); 64 | output.printMinifyResult(`${fileName} (selection)`, res); 65 | if (res.success) { 66 | editor.insertSnippet(new vscode.SnippetString(res.output.code)); 67 | if (res.warnings.length && config.showLogOnWarning) { 68 | output.show(); 69 | } 70 | } else { 71 | vscode.window.showErrorMessage('Failed to minify selection. See output for more info.'); 72 | if (config.showLogOnError) { 73 | output.show(); 74 | } 75 | } 76 | break; 77 | } 78 | 79 | default: { 80 | vscode.window.showErrorMessage('Language not supported.'); 81 | break; 82 | } 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/output.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | class OutputChannel { 4 | 5 | private output: vscode.OutputChannel; 6 | 7 | constructor(name: string) { 8 | this.output = vscode.window.createOutputChannel(name); 9 | } 10 | 11 | write(str: string): void { 12 | this.output.append(str); 13 | } 14 | 15 | writeln(str: string): void { 16 | this.output.appendLine(str); 17 | } 18 | 19 | show(preserveFocus = true): void { 20 | this.output.show(preserveFocus); 21 | } 22 | 23 | hide(): void { 24 | this.output.hide(); 25 | } 26 | 27 | clear(): void { 28 | this.output.clear(); 29 | } 30 | 31 | name(): string { 32 | return this.output.name; 33 | } 34 | 35 | printMinifyResult(file: string, minOutput: MinifyOutput): void { 36 | 37 | this.write(`[${file}]:`); 38 | 39 | if (minOutput.success && minOutput.errors.length === 0) { 40 | this.write(` OK - ${Math.abs(minOutput.efficiency)}% ${minOutput.efficiency < 0 ? 'bigger' : 'smaller' }\n`); 41 | } else { 42 | this.write('\n'); 43 | } 44 | 45 | if (minOutput.warnings.length) { 46 | 47 | this.writeln(`\t[Warnings]: ${minOutput.warnings.length ? minOutput.warnings.length : 'None' }`); 48 | minOutput.warnings.forEach(w => { 49 | this.writeln(`\t\t- ${w}`); 50 | }); 51 | 52 | } 53 | 54 | if (minOutput.errors.length) { 55 | 56 | this.writeln(`\t[Errors]: ${minOutput.errors.length ? minOutput.errors.length : 'None' }`); 57 | minOutput.errors.forEach(w => { 58 | this.writeln(`\t\t- ${w}`); 59 | }); 60 | 61 | } 62 | 63 | if (!minOutput.success && minOutput.errors.length === 0) { 64 | this.writeln('\t[Errors]:'); 65 | this.writeln('\t\t- No errors were reported but the minification failed! Open a ticket at https://github.com/olback/es6-css-minify and describe your issue.'); 66 | } 67 | 68 | } 69 | 70 | dispose(): void { 71 | this.output.dispose(); 72 | } 73 | 74 | } 75 | 76 | export const output = new OutputChannel('JS & CSS Minifier'); 77 | -------------------------------------------------------------------------------- /src/status-bar.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { EXT_ID } from './utils'; 3 | 4 | class StatusBar { 5 | 6 | private _button: vscode.StatusBarItem; 7 | 8 | constructor() { 9 | this._button = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 1); 10 | this._button.text = '$(fold) Minify'; 11 | this._button.command = `${EXT_ID}.minify`; 12 | this._button.tooltip = 'Minify current file.'; 13 | } 14 | 15 | showButton(): void { 16 | 17 | this._button.show(); 18 | 19 | } 20 | 21 | hideButton(): void { 22 | 23 | this._button.hide(); 24 | 25 | } 26 | 27 | showStats(eff: number, timeout = 5000): void { 28 | vscode.window.setStatusBarMessage(`$(graph) Output is ${Math.abs(eff)}% ${eff < 0 ? 'bigger' : 'smaller' }.`, timeout); 29 | } 30 | 31 | showMessage(str: string, timeout = 5000): void { 32 | vscode.window.setStatusBarMessage(str, timeout); 33 | } 34 | 35 | } 36 | 37 | export const statusBar = new StatusBar(); 38 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main(): Promise { 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 | const launchArgs = [ 16 | 'src/test/workspace' 17 | ]; 18 | 19 | // Download VS Code, unzip it and run the integration test 20 | await runTests({ extensionDevelopmentPath, extensionTestsPath, launchArgs }); 21 | } catch (err) { 22 | console.error('Failed to run tests'); 23 | process.exit(1); 24 | } 25 | } 26 | 27 | main(); 28 | -------------------------------------------------------------------------------- /src/test/suite/config.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import * as path from 'path'; 4 | import { EXT_ID } from '../../utils'; 5 | import { config, reloadConfig } from '../../config'; 6 | import { File, DataFormat } from '../../fs'; 7 | import { WORKSPACE_PATH } from './test_utils'; 8 | 9 | interface IndexSignature { 10 | [key: string]: any; 11 | } 12 | 13 | suite('Conifg class', () => { 14 | 15 | test('Config matches package.json', () => { 16 | 17 | const ext = vscode.extensions.getExtension(`olback.${EXT_ID}`) as vscode.Extension; 18 | 19 | const packageConfigStructure: IndexSignature = {}; 20 | 21 | for (const p in ext.packageJSON.contributes.configuration.properties) { 22 | const property = p.replace(`${EXT_ID}.`, ''); 23 | packageConfigStructure[property] = ext.packageJSON.contributes.configuration.properties[p].type; 24 | } 25 | 26 | // Make sure all settings in package.json are included in the class. 27 | for (const p in packageConfigStructure) { 28 | 29 | const actual = typeof (config as IndexSignature)[p]; 30 | const expected = packageConfigStructure[p]; 31 | const enumArr: any[] | undefined = ext.packageJSON.contributes.configuration.properties[`es6-css-minify.${p}`].enum; 32 | // const defaultValue = ext.packageJSON.contributes.configuration.properties[`es6-css-minify.${p}`].default; 33 | 34 | console.log(`${p}: enum:${Array.isArray(enumArr)} actual:${actual} expected:${expected} typeof-expected:${typeof expected}`); 35 | 36 | if (expected === undefined && Array.isArray(enumArr)) { 37 | 38 | assert.strictEqual(enumArr.includes((config as IndexSignature)[p]), true, `${actual} not found in enum`); 39 | 40 | } else { 41 | 42 | assert.strictEqual( 43 | actual, 44 | expected, 45 | `Found property "${p}" with type ${expected} in package.json but it does not exist in class` 46 | ); 47 | 48 | } 49 | } 50 | 51 | // Make sure there are no extra properties in the class. 52 | for (const p in (config as IndexSignature)) { 53 | 54 | const actual = typeof (config as IndexSignature)[p]; 55 | const expected = packageConfigStructure[p]; 56 | const enumArr: any[] | undefined = ext.packageJSON.contributes.configuration.properties[`es6-css-minify.${p}`].enum; 57 | 58 | if (expected !== undefined && !Array.isArray(enumArr)) { 59 | 60 | assert.strictEqual( 61 | actual, 62 | expected, 63 | `Found property "${p}" with type ${expected} in class but it does not exist in package.json` 64 | ); 65 | 66 | } 67 | 68 | } 69 | 70 | }); 71 | 72 | test('Parse .uglifyrc', () => { 73 | 74 | const uglifyrc = new File(path.join(WORKSPACE_PATH, config.uglifyConfigFile)).parse(DataFormat.json); 75 | reloadConfig(true); 76 | 77 | // Since we modify the js object after its been parsed, delete it from both the parsed file and the config. 78 | delete uglifyrc.sourceMap; 79 | delete config.js.sourceMap; 80 | 81 | assert.deepStrictEqual(uglifyrc, config.js); 82 | 83 | }); 84 | 85 | 86 | test('Parse .cleancssrc', () => { 87 | 88 | const cleancssrc = new File(path.join(WORKSPACE_PATH, config.cleancssConfigFile)).parse(DataFormat.json); 89 | reloadConfig(true); 90 | 91 | // Since we modify the css object after its been parsed, delete it from both the parsed file and the config. 92 | delete cleancssrc.sourceMap; 93 | delete config.css.sourceMap; 94 | 95 | assert.deepStrictEqual(cleancssrc, config.css); 96 | 97 | }); 98 | 99 | test('config.js defaults is correct', () => { 100 | 101 | reloadConfig(false); 102 | 103 | const defaultJs = { 104 | mangle: false, 105 | compress: { 106 | unused: false 107 | }, 108 | output: { 109 | quote_style: 0 110 | }, 111 | sourceMap: true, 112 | warnings: true 113 | }; 114 | 115 | assert.deepStrictEqual(config.js, defaultJs); 116 | 117 | }); 118 | 119 | test('config.css defaults is correct', () => { 120 | 121 | reloadConfig(false); 122 | 123 | const defaultCss = { 124 | rebase: false, 125 | sourceMap: true 126 | }; 127 | 128 | assert.deepStrictEqual(config.css, defaultCss); 129 | 130 | }); 131 | 132 | }); 133 | 134 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import { EXT_ID } from '../../utils'; 4 | 5 | suite('Extension', () => { 6 | 7 | test('Extension loaded by VS Code', () => { 8 | 9 | assert.ok(vscode.extensions.getExtension(`olback.${EXT_ID}`)); 10 | 11 | }); 12 | 13 | test('All commands registerd', async () => { 14 | 15 | const allRegisterdCommands = await vscode.commands.getCommands(true); 16 | const foundRegisterdExtCommands = allRegisterdCommands.filter(v => v.includes(EXT_ID)); 17 | const commandsFromPackageJson = (vscode.extensions.getExtension(`olback.${EXT_ID}`) as vscode.Extension).packageJSON.contributes.commands.map((v: any) => v.command); 18 | 19 | assert.deepStrictEqual( 20 | foundRegisterdExtCommands, 21 | commandsFromPackageJson, 22 | 'Registerd commands does not match package.json' 23 | ); 24 | 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /src/test/suite/fs.test.ts: -------------------------------------------------------------------------------- 1 | import { File, DataFormat } from '../../fs'; 2 | import * as assert from 'assert'; 3 | import * as fs from 'fs'; 4 | import * as path from 'path'; 5 | import { EXT_ID } from '../../utils'; 6 | import { EXT_ROOT } from './test_utils'; 7 | 8 | suite('File class', () => { 9 | 10 | test('Open file', () => { 11 | 12 | assert.doesNotThrow(() => { 13 | 14 | const packagePath = path.join(EXT_ROOT, 'package.json'); 15 | // tslint:disable-next-line:no-unused-expression 16 | new File(packagePath).read(); 17 | 18 | }); 19 | 20 | }); 21 | 22 | test('Read file', () => { 23 | 24 | const packagePath = path.join(EXT_ROOT, 'package.json'); 25 | const data = new File(packagePath).read(); 26 | 27 | assert.strictEqual(typeof data, 'string'); 28 | assert.ok(data.length > 0); 29 | 30 | }); 31 | 32 | test('Parse file', () => { 33 | 34 | const packagePath = path.join(EXT_ROOT, 'package.json'); 35 | const data = new File(packagePath).parse(DataFormat.json); 36 | 37 | assert.ok(data); 38 | assert.strictEqual(typeof data, 'object'); 39 | assert.strictEqual(data.name, EXT_ID); 40 | 41 | }); 42 | 43 | test('File exists', () => { 44 | 45 | const packagePath = path.join(EXT_ROOT, 'package.json'); 46 | const exists = new File(packagePath).exists(); 47 | 48 | assert.equal(exists, true); 49 | 50 | }); 51 | 52 | test('File does not exists', () => { 53 | 54 | const exists = new File('this_file_does_not_exist').exists(); 55 | 56 | assert.equal(exists, false); 57 | 58 | }); 59 | 60 | test('Write file', () => { 61 | 62 | const filePath = path.join(EXT_ROOT, '.ignoreme'); 63 | const data ='this is a test'; 64 | const file = new File(filePath); 65 | file.write(data); 66 | 67 | assert.strictEqual(fs.existsSync(filePath), true); 68 | assert.strictEqual(fs.readFileSync(filePath, 'utf8'), data); 69 | fs.unlinkSync(filePath); 70 | 71 | }); 72 | 73 | test('Throw is file does not exist', () => { 74 | 75 | assert.throws(() => { 76 | 77 | // tslint:disable-next-line:no-unused-expression 78 | new File('path/to/file/that/does/not/exist').read(); 79 | 80 | }); 81 | 82 | }); 83 | 84 | }); 85 | -------------------------------------------------------------------------------- /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 | }); 10 | mocha.useColors(true); 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 | e(err); 34 | } 35 | }); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /src/test/suite/minify.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import * as fs from 'fs'; 4 | import * as path from 'path'; 5 | import { EXT_ID } from '../../utils'; 6 | import { WORKSPACE_PATH } from './test_utils'; 7 | 8 | suite('Minfy Tests', () => { 9 | 10 | test('Minify Javascript (default settings)', async () => { 11 | 12 | const uri = vscode.Uri.file(path.join(WORKSPACE_PATH, 'js', 'aaa.main.js')); 13 | const doc = await vscode.workspace.openTextDocument(uri); 14 | await vscode.window.showTextDocument(doc); 15 | await vscode.commands.executeCommand(`${EXT_ID}.minify`); 16 | 17 | const minjsp = path.join(WORKSPACE_PATH, 'js', 'aaa.main.min.js'); 18 | setTimeout(() => { 19 | assert.equal(fs.existsSync(minjsp), true, 'Minified file does not exist'); 20 | }, 50); 21 | 22 | }); 23 | 24 | test('Minify Javascript (default settings, syntax errors)', async () => { 25 | 26 | const uri = vscode.Uri.file(path.join(WORKSPACE_PATH, 'js', 'syntax.error.js')); 27 | const doc = await vscode.workspace.openTextDocument(uri); 28 | await vscode.window.showTextDocument(doc); 29 | await vscode.commands.executeCommand(`${EXT_ID}.minify`); 30 | 31 | const minjsp = path.join(WORKSPACE_PATH, 'js', 'syntax.error.min.js'); 32 | setTimeout(() => { 33 | assert.notEqual(fs.existsSync(minjsp), true, 'Minified file exists, it sould not'); 34 | }, 50); 35 | 36 | }); 37 | 38 | test('Minify CSS (new path, new postfix)', async () => { 39 | 40 | const uri = vscode.Uri.file(path.join(WORKSPACE_PATH, 'css', 'main.css')); 41 | const doc = await vscode.workspace.openTextDocument(uri); 42 | await vscode.window.showTextDocument(doc); 43 | await vscode.commands.executeCommand(`${EXT_ID}.minify`); 44 | 45 | const mincssp = path.join(WORKSPACE_PATH, 'dist', 'css', 'main.minified.css'); 46 | setTimeout(() => { 47 | assert.equal(fs.existsSync(mincssp), true, 'Minified file does not exist'); 48 | }, 50); 49 | 50 | }); 51 | 52 | }); 53 | -------------------------------------------------------------------------------- /src/test/suite/test_utils.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | export const WORKSPACE_PATH = path.join(__dirname, '..', '..', '..', 'src', 'test', 'workspace'); 4 | export const EXT_ROOT = path.join(__dirname, '..', '..', '..'); 5 | -------------------------------------------------------------------------------- /src/test/workspace/.autoprefixerrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /src/test/workspace/.cleancssrc: -------------------------------------------------------------------------------- 1 | { 2 | "rebase": false, 3 | "inline": [ 4 | "all" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/test/workspace/.uglifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "mangle": false, 3 | "compress": { 4 | "unused": false 5 | }, 6 | "output": { 7 | "quote_style": 0 8 | }, 9 | "warnings": true 10 | } 11 | -------------------------------------------------------------------------------- /src/test/workspace/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "es6-css-minify.cssMinPath": "dist/css", 3 | "es6-css-minify.cssPostfix": "minified", 4 | "es6-css-minify.enableAutoprefixer": true, 5 | "es6-css-minify.enableAutoprefixerSelection": true, 6 | // "es6-css-minify.hideButton": "never", 7 | "es6-css-minify.minifyOnSave": "exists", 8 | "es6-css-minify.genCSSmap": true, 9 | "es6-css-minify.genJSmap": true, 10 | "es6-css-minify.cssMapSource": "../../css" 11 | } -------------------------------------------------------------------------------- /src/test/workspace/css/footer.css: -------------------------------------------------------------------------------- 1 | footer { 2 | background-color: black; 3 | color: #f0f; 4 | border-top-left-radius: 50%; 5 | border-top-right-radius: 30%; 6 | border-bottom-right-radius: 90%; 7 | border-bottom-left-radius: 10%; 8 | } 9 | -------------------------------------------------------------------------------- /src/test/workspace/css/main.css: -------------------------------------------------------------------------------- 1 | /* Regular comment */ 2 | /*! Important stuff! */ 3 | 4 | @import url('https://fonts.googleapis.com/css?family=Roboto&display=swap'); 5 | @import 'footer.css'; 6 | 7 | .example { 8 | display: grid; 9 | transition: all .5s; 10 | user-select: none; 11 | background: linear-gradient(to bottom, white, black); 12 | } 13 | 14 | @media (min-resolution: 2dppx) { 15 | .image { 16 | background-image: url(../img/image@2x.png); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/workspace/dist/css/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olback/es6-css-minify/51ef98605b238218d8e2e28a6185dd691d5ca109/src/test/workspace/dist/css/.gitkeep -------------------------------------------------------------------------------- /src/test/workspace/js/aaa.main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Issue #1 'unused code' 3 | * https://github.com/olback/es6-css-minify/issues/1 4 | */ 5 | 6 | (function($) { 7 | class showDivWithText { 8 | constructor(param) { 9 | this.text = param; 10 | this.init(); 11 | } 12 | 13 | init() { 14 | $("
") 15 | .text(this.text) 16 | .appendTo("body"); 17 | } 18 | } 19 | })(jQuery); 20 | 21 | /** 22 | * ES6 features 23 | */ 24 | let a = { 25 | bs: "fghfghfg", 26 | cs: "khfgjhkjfghkljfgjhfghfggfhgf", 27 | ds: "gfdgdjghdfjghdfjghdfjlghfd", 28 | es: "aaaaaaaaaaaaaaaaaaaaaaaaa" 29 | }; 30 | const b = 43; 31 | 32 | const c = (a, b) => { 33 | return a * b; 34 | }; 35 | 36 | console.log(c(a, b)); 37 | 38 | async function foo(url) { 39 | return await fetch(url); 40 | } 41 | -------------------------------------------------------------------------------- /src/test/workspace/js/syntax.error.js: -------------------------------------------------------------------------------- 1 | const a = 'aaaa'; 2 | let b = 'bbbbb; 3 | var c = 'ccccccccc"; 4 | 5 | for (let i = 0; i < 100; i++) { 6 | console.log(i); 7 | } 8 | -------------------------------------------------------------------------------- /src/test/workspace/json/data.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "userId": 1, 3 | "id": 1, 4 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 5 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 6 | }, 7 | { 8 | "userId": 1, 9 | "id": 2, 10 | "title": "qui est esse", 11 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 12 | }, 13 | { 14 | "userId": 1, 15 | "id": 3, 16 | "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", 17 | "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut" 18 | }, 19 | { 20 | "userId": 1, 21 | "id": 4, 22 | "title": "eum et est occaecati", 23 | "body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit" 24 | }, 25 | { 26 | "userId": 1, 27 | "id": 5, 28 | "title": "nesciunt quas odio", 29 | "body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque" 30 | }, 31 | { 32 | "userId": 1, 33 | "id": 6, 34 | "title": "dolorem eum magni eos aperiam quia", 35 | "body": "ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae" 36 | }, 37 | { 38 | "userId": 1, 39 | "id": 7, 40 | "title": "magnam facilis autem", 41 | "body": "dolore placeat quibusdam ea quo vitae\nmagni quis enim qui quis quo nemo aut saepe\nquidem repellat excepturi ut quia\nsunt ut sequi eos ea sed quas" 42 | }, 43 | { 44 | "userId": 1, 45 | "id": 8, 46 | "title": "dolorem dolore est ipsam", 47 | "body": "dignissimos aperiam dolorem qui eum\nfacilis quibusdam animi sint suscipit qui sint possimus cum\nquaerat magni maiores excepturi\nipsam ut commodi dolor voluptatum modi aut vitae" 48 | }, 49 | { 50 | "userId": 1, 51 | "id": 9, 52 | "title": "nesciunt iure omnis dolorem tempora et accusantium", 53 | "body": "consectetur animi nesciunt iure dolore\nenim quia ad\nveniam autem ut quam aut nobis\net est aut quod aut provident voluptas autem voluptas" 54 | }, 55 | { 56 | "userId": 1, 57 | "id": 10, 58 | "title": "optio molestias id quia eum", 59 | "body": "quo et expedita modi cum officia vel magni\ndoloribus qui repudiandae\nvero nisi sit\nquos veniam quod sed accusamus veritatis error" 60 | }, 61 | { 62 | "userId": 2, 63 | "id": 11, 64 | "title": "et ea vero quia laudantium autem", 65 | "body": "delectus reiciendis molestiae occaecati non minima eveniet qui voluptatibus\naccusamus in eum beatae sit\nvel qui neque voluptates ut commodi qui incidunt\nut animi commodi" 66 | }, 67 | { 68 | "userId": 2, 69 | "id": 12, 70 | "title": "in quibusdam tempore odit est dolorem", 71 | "body": "itaque id aut magnam\npraesentium quia et ea odit et ea voluptas et\nsapiente quia nihil amet occaecati quia id voluptatem\nincidunt ea est distinctio odio" 72 | }, 73 | { 74 | "userId": 2, 75 | "id": 13, 76 | "title": "dolorum ut in voluptas mollitia et saepe quo animi", 77 | "body": "aut dicta possimus sint mollitia voluptas commodi quo doloremque\niste corrupti reiciendis voluptatem eius rerum\nsit cumque quod eligendi laborum minima\nperferendis recusandae assumenda consectetur porro architecto ipsum ipsam" 78 | }, 79 | { 80 | "userId": 2, 81 | "id": 14, 82 | "title": "voluptatem eligendi optio", 83 | "body": "fuga et accusamus dolorum perferendis illo voluptas\nnon doloremque neque facere\nad qui dolorum molestiae beatae\nsed aut voluptas totam sit illum" 84 | }, 85 | { 86 | "userId": 2, 87 | "id": 15, 88 | "title": "eveniet quod temporibus", 89 | "body": "reprehenderit quos placeat\nvelit minima officia dolores impedit repudiandae molestiae nam\nvoluptas recusandae quis delectus\nofficiis harum fugiat vitae" 90 | }, 91 | { 92 | "userId": 2, 93 | "id": 16, 94 | "title": "sint suscipit perspiciatis velit dolorum rerum ipsa laboriosam odio", 95 | "body": "suscipit nam nisi quo aperiam aut\nasperiores eos fugit maiores voluptatibus quia\nvoluptatem quis ullam qui in alias quia est\nconsequatur magni mollitia accusamus ea nisi voluptate dicta" 96 | }, 97 | { 98 | "userId": 2, 99 | "id": 17, 100 | "title": "fugit voluptas sed molestias voluptatem provident", 101 | "body": "eos voluptas et aut odit natus earum\naspernatur fuga molestiae ullam\ndeserunt ratione qui eos\nqui nihil ratione nemo velit ut aut id quo" 102 | }, 103 | { 104 | "userId": 2, 105 | "id": 18, 106 | "title": "voluptate et itaque vero tempora molestiae", 107 | "body": "eveniet quo quis\nlaborum totam consequatur non dolor\nut et est repudiandae\nest voluptatem vel debitis et magnam" 108 | }, 109 | { 110 | "userId": 2, 111 | "id": 19, 112 | "title": "adipisci placeat illum aut reiciendis qui", 113 | "body": "illum quis cupiditate provident sit magnam\nea sed aut omnis\nveniam maiores ullam consequatur atque\nadipisci quo iste expedita sit quos voluptas" 114 | }, 115 | { 116 | "userId": 2, 117 | "id": 20, 118 | "title": "doloribus ad provident suscipit at", 119 | "body": "qui consequuntur ducimus possimus quisquam amet similique\nsuscipit porro ipsam amet\neos veritatis officiis exercitationem vel fugit aut necessitatibus totam\nomnis rerum consequatur expedita quidem cumque explicabo" 120 | }, 121 | { 122 | "userId": 3, 123 | "id": 21, 124 | "title": "asperiores ea ipsam voluptatibus modi minima quia sint", 125 | "body": "repellat aliquid praesentium dolorem quo\nsed totam minus non itaque\nnihil labore molestiae sunt dolor eveniet hic recusandae veniam\ntempora et tenetur expedita sunt" 126 | }, 127 | { 128 | "userId": 3, 129 | "id": 22, 130 | "title": "dolor sint quo a velit explicabo quia nam", 131 | "body": "eos qui et ipsum ipsam suscipit aut\nsed omnis non odio\nexpedita earum mollitia molestiae aut atque rem suscipit\nnam impedit esse" 132 | }, 133 | { 134 | "userId": 3, 135 | "id": 23, 136 | "title": "maxime id vitae nihil numquam", 137 | "body": "veritatis unde neque eligendi\nquae quod architecto quo neque vitae\nest illo sit tempora doloremque fugit quod\net et vel beatae sequi ullam sed tenetur perspiciatis" 138 | }, 139 | { 140 | "userId": 3, 141 | "id": 24, 142 | "title": "autem hic labore sunt dolores incidunt", 143 | "body": "enim et ex nulla\nomnis voluptas quia qui\nvoluptatem consequatur numquam aliquam sunt\ntotam recusandae id dignissimos aut sed asperiores deserunt" 144 | }, 145 | { 146 | "userId": 3, 147 | "id": 25, 148 | "title": "rem alias distinctio quo quis", 149 | "body": "ullam consequatur ut\nomnis quis sit vel consequuntur\nipsa eligendi ipsum molestiae et omnis error nostrum\nmolestiae illo tempore quia et distinctio" 150 | }, 151 | { 152 | "userId": 3, 153 | "id": 26, 154 | "title": "est et quae odit qui non", 155 | "body": "similique esse doloribus nihil accusamus\nomnis dolorem fuga consequuntur reprehenderit fugit recusandae temporibus\nperspiciatis cum ut laudantium\nomnis aut molestiae vel vero" 156 | }, 157 | { 158 | "userId": 3, 159 | "id": 27, 160 | "title": "quasi id et eos tenetur aut quo autem", 161 | "body": "eum sed dolores ipsam sint possimus debitis occaecati\ndebitis qui qui et\nut placeat enim earum aut odit facilis\nconsequatur suscipit necessitatibus rerum sed inventore temporibus consequatur" 162 | }, 163 | { 164 | "userId": 3, 165 | "id": 28, 166 | "title": "delectus ullam et corporis nulla voluptas sequi", 167 | "body": "non et quaerat ex quae ad maiores\nmaiores recusandae totam aut blanditiis mollitia quas illo\nut voluptatibus voluptatem\nsimilique nostrum eum" 168 | }, 169 | { 170 | "userId": 3, 171 | "id": 29, 172 | "title": "iusto eius quod necessitatibus culpa ea", 173 | "body": "odit magnam ut saepe sed non qui\ntempora atque nihil\naccusamus illum doloribus illo dolor\neligendi repudiandae odit magni similique sed cum maiores" 174 | }, 175 | { 176 | "userId": 3, 177 | "id": 30, 178 | "title": "a quo magni similique perferendis", 179 | "body": "alias dolor cumque\nimpedit blanditiis non eveniet odio maxime\nblanditiis amet eius quis tempora quia autem rem\na provident perspiciatis quia" 180 | }, 181 | { 182 | "userId": 4, 183 | "id": 31, 184 | "title": "ullam ut quidem id aut vel consequuntur", 185 | "body": "debitis eius sed quibusdam non quis consectetur vitae\nimpedit ut qui consequatur sed aut in\nquidem sit nostrum et maiores adipisci atque\nquaerat voluptatem adipisci repudiandae" 186 | }, 187 | { 188 | "userId": 4, 189 | "id": 32, 190 | "title": "doloremque illum aliquid sunt", 191 | "body": "deserunt eos nobis asperiores et hic\nest debitis repellat molestiae optio\nnihil ratione ut eos beatae quibusdam distinctio maiores\nearum voluptates et aut adipisci ea maiores voluptas maxime" 192 | }, 193 | { 194 | "userId": 4, 195 | "id": 33, 196 | "title": "qui explicabo molestiae dolorem", 197 | "body": "rerum ut et numquam laborum odit est sit\nid qui sint in\nquasi tenetur tempore aperiam et quaerat qui in\nrerum officiis sequi cumque quod" 198 | }, 199 | { 200 | "userId": 4, 201 | "id": 34, 202 | "title": "magnam ut rerum iure", 203 | "body": "ea velit perferendis earum ut voluptatem voluptate itaque iusto\ntotam pariatur in\nnemo voluptatem voluptatem autem magni tempora minima in\nest distinctio qui assumenda accusamus dignissimos officia nesciunt nobis" 204 | }, 205 | { 206 | "userId": 4, 207 | "id": 35, 208 | "title": "id nihil consequatur molestias animi provident", 209 | "body": "nisi error delectus possimus ut eligendi vitae\nplaceat eos harum cupiditate facilis reprehenderit voluptatem beatae\nmodi ducimus quo illum voluptas eligendi\net nobis quia fugit" 210 | }, 211 | { 212 | "userId": 4, 213 | "id": 36, 214 | "title": "fuga nam accusamus voluptas reiciendis itaque", 215 | "body": "ad mollitia et omnis minus architecto odit\nvoluptas doloremque maxime aut non ipsa qui alias veniam\nblanditiis culpa aut quia nihil cumque facere et occaecati\nqui aspernatur quia eaque ut aperiam inventore" 216 | }, 217 | { 218 | "userId": 4, 219 | "id": 37, 220 | "title": "provident vel ut sit ratione est", 221 | "body": "debitis et eaque non officia sed nesciunt pariatur vel\nvoluptatem iste vero et ea\nnumquam aut expedita ipsum nulla in\nvoluptates omnis consequatur aut enim officiis in quam qui" 222 | }, 223 | { 224 | "userId": 4, 225 | "id": 38, 226 | "title": "explicabo et eos deleniti nostrum ab id repellendus", 227 | "body": "animi esse sit aut sit nesciunt assumenda eum voluptas\nquia voluptatibus provident quia necessitatibus ea\nrerum repudiandae quia voluptatem delectus fugit aut id quia\nratione optio eos iusto veniam iure" 228 | }, 229 | { 230 | "userId": 4, 231 | "id": 39, 232 | "title": "eos dolorem iste accusantium est eaque quam", 233 | "body": "corporis rerum ducimus vel eum accusantium\nmaxime aspernatur a porro possimus iste omnis\nest in deleniti asperiores fuga aut\nvoluptas sapiente vel dolore minus voluptatem incidunt ex" 234 | }, 235 | { 236 | "userId": 4, 237 | "id": 40, 238 | "title": "enim quo cumque", 239 | "body": "ut voluptatum aliquid illo tenetur nemo sequi quo facilis\nipsum rem optio mollitia quas\nvoluptatem eum voluptas qui\nunde omnis voluptatem iure quasi maxime voluptas nam" 240 | }, 241 | { 242 | "userId": 5, 243 | "id": 41, 244 | "title": "non est facere", 245 | "body": "molestias id nostrum\nexcepturi molestiae dolore omnis repellendus quaerat saepe\nconsectetur iste quaerat tenetur asperiores accusamus ex ut\nnam quidem est ducimus sunt debitis saepe" 246 | }, 247 | { 248 | "userId": 5, 249 | "id": 42, 250 | "title": "commodi ullam sint et excepturi error explicabo praesentium voluptas", 251 | "body": "odio fugit voluptatum ducimus earum autem est incidunt voluptatem\nodit reiciendis aliquam sunt sequi nulla dolorem\nnon facere repellendus voluptates quia\nratione harum vitae ut" 252 | }, 253 | { 254 | "userId": 5, 255 | "id": 43, 256 | "title": "eligendi iste nostrum consequuntur adipisci praesentium sit beatae perferendis", 257 | "body": "similique fugit est\nillum et dolorum harum et voluptate eaque quidem\nexercitationem quos nam commodi possimus cum odio nihil nulla\ndolorum exercitationem magnam ex et a et distinctio debitis" 258 | }, 259 | { 260 | "userId": 5, 261 | "id": 44, 262 | "title": "optio dolor molestias sit", 263 | "body": "temporibus est consectetur dolore\net libero debitis vel velit laboriosam quia\nipsum quibusdam qui itaque fuga rem aut\nea et iure quam sed maxime ut distinctio quae" 264 | }, 265 | { 266 | "userId": 5, 267 | "id": 45, 268 | "title": "ut numquam possimus omnis eius suscipit laudantium iure", 269 | "body": "est natus reiciendis nihil possimus aut provident\nex et dolor\nrepellat pariatur est\nnobis rerum repellendus dolorem autem" 270 | }, 271 | { 272 | "userId": 5, 273 | "id": 46, 274 | "title": "aut quo modi neque nostrum ducimus", 275 | "body": "voluptatem quisquam iste\nvoluptatibus natus officiis facilis dolorem\nquis quas ipsam\nvel et voluptatum in aliquid" 276 | }, 277 | { 278 | "userId": 5, 279 | "id": 47, 280 | "title": "quibusdam cumque rem aut deserunt", 281 | "body": "voluptatem assumenda ut qui ut cupiditate aut impedit veniam\noccaecati nemo illum voluptatem laudantium\nmolestiae beatae rerum ea iure soluta nostrum\neligendi et voluptate" 282 | }, 283 | { 284 | "userId": 5, 285 | "id": 48, 286 | "title": "ut voluptatem illum ea doloribus itaque eos", 287 | "body": "voluptates quo voluptatem facilis iure occaecati\nvel assumenda rerum officia et\nillum perspiciatis ab deleniti\nlaudantium repellat ad ut et autem reprehenderit" 288 | }, 289 | { 290 | "userId": 5, 291 | "id": 49, 292 | "title": "laborum non sunt aut ut assumenda perspiciatis voluptas", 293 | "body": "inventore ab sint\nnatus fugit id nulla sequi architecto nihil quaerat\neos tenetur in in eum veritatis non\nquibusdam officiis aspernatur cumque aut commodi aut" 294 | }, 295 | { 296 | "userId": 5, 297 | "id": 50, 298 | "title": "repellendus qui recusandae incidunt voluptates tenetur qui omnis exercitationem", 299 | "body": "error suscipit maxime adipisci consequuntur recusandae\nvoluptas eligendi et est et voluptates\nquia distinctio ab amet quaerat molestiae et vitae\nadipisci impedit sequi nesciunt quis consectetur" 300 | }, 301 | { 302 | "userId": 6, 303 | "id": 51, 304 | "title": "soluta aliquam aperiam consequatur illo quis voluptas", 305 | "body": "sunt dolores aut doloribus\ndolore doloribus voluptates tempora et\ndoloremque et quo\ncum asperiores sit consectetur dolorem" 306 | }, 307 | { 308 | "userId": 6, 309 | "id": 52, 310 | "title": "qui enim et consequuntur quia animi quis voluptate quibusdam", 311 | "body": "iusto est quibusdam fuga quas quaerat molestias\na enim ut sit accusamus enim\ntemporibus iusto accusantium provident architecto\nsoluta esse reprehenderit qui laborum" 312 | }, 313 | { 314 | "userId": 6, 315 | "id": 53, 316 | "title": "ut quo aut ducimus alias", 317 | "body": "minima harum praesentium eum rerum illo dolore\nquasi exercitationem rerum nam\nporro quis neque quo\nconsequatur minus dolor quidem veritatis sunt non explicabo similique" 318 | }, 319 | { 320 | "userId": 6, 321 | "id": 54, 322 | "title": "sit asperiores ipsam eveniet odio non quia", 323 | "body": "totam corporis dignissimos\nvitae dolorem ut occaecati accusamus\nex velit deserunt\net exercitationem vero incidunt corrupti mollitia" 324 | }, 325 | { 326 | "userId": 6, 327 | "id": 55, 328 | "title": "sit vel voluptatem et non libero", 329 | "body": "debitis excepturi ea perferendis harum libero optio\neos accusamus cum fuga ut sapiente repudiandae\net ut incidunt omnis molestiae\nnihil ut eum odit" 330 | }, 331 | { 332 | "userId": 6, 333 | "id": 56, 334 | "title": "qui et at rerum necessitatibus", 335 | "body": "aut est omnis dolores\nneque rerum quod ea rerum velit pariatur beatae excepturi\net provident voluptas corrupti\ncorporis harum reprehenderit dolores eligendi" 336 | }, 337 | { 338 | "userId": 6, 339 | "id": 57, 340 | "title": "sed ab est est", 341 | "body": "at pariatur consequuntur earum quidem\nquo est laudantium soluta voluptatem\nqui ullam et est\net cum voluptas voluptatum repellat est" 342 | }, 343 | { 344 | "userId": 6, 345 | "id": 58, 346 | "title": "voluptatum itaque dolores nisi et quasi", 347 | "body": "veniam voluptatum quae adipisci id\net id quia eos ad et dolorem\naliquam quo nisi sunt eos impedit error\nad similique veniam" 348 | }, 349 | { 350 | "userId": 6, 351 | "id": 59, 352 | "title": "qui commodi dolor at maiores et quis id accusantium", 353 | "body": "perspiciatis et quam ea autem temporibus non voluptatibus qui\nbeatae a earum officia nesciunt dolores suscipit voluptas et\nanimi doloribus cum rerum quas et magni\net hic ut ut commodi expedita sunt" 354 | }, 355 | { 356 | "userId": 6, 357 | "id": 60, 358 | "title": "consequatur placeat omnis quisquam quia reprehenderit fugit veritatis facere", 359 | "body": "asperiores sunt ab assumenda cumque modi velit\nqui esse omnis\nvoluptate et fuga perferendis voluptas\nillo ratione amet aut et omnis" 360 | }, 361 | { 362 | "userId": 7, 363 | "id": 61, 364 | "title": "voluptatem doloribus consectetur est ut ducimus", 365 | "body": "ab nemo optio odio\ndelectus tenetur corporis similique nobis repellendus rerum omnis facilis\nvero blanditiis debitis in nesciunt doloribus dicta dolores\nmagnam minus velit" 366 | }, 367 | { 368 | "userId": 7, 369 | "id": 62, 370 | "title": "beatae enim quia vel", 371 | "body": "enim aspernatur illo distinctio quae praesentium\nbeatae alias amet delectus qui voluptate distinctio\nodit sint accusantium autem omnis\nquo molestiae omnis ea eveniet optio" 372 | }, 373 | { 374 | "userId": 7, 375 | "id": 63, 376 | "title": "voluptas blanditiis repellendus animi ducimus error sapiente et suscipit", 377 | "body": "enim adipisci aspernatur nemo\nnumquam omnis facere dolorem dolor ex quis temporibus incidunt\nab delectus culpa quo reprehenderit blanditiis asperiores\naccusantium ut quam in voluptatibus voluptas ipsam dicta" 378 | }, 379 | { 380 | "userId": 7, 381 | "id": 64, 382 | "title": "et fugit quas eum in in aperiam quod", 383 | "body": "id velit blanditiis\neum ea voluptatem\nmolestiae sint occaecati est eos perspiciatis\nincidunt a error provident eaque aut aut qui" 384 | }, 385 | { 386 | "userId": 7, 387 | "id": 65, 388 | "title": "consequatur id enim sunt et et", 389 | "body": "voluptatibus ex esse\nsint explicabo est aliquid cumque adipisci fuga repellat labore\nmolestiae corrupti ex saepe at asperiores et perferendis\nnatus id esse incidunt pariatur" 390 | }, 391 | { 392 | "userId": 7, 393 | "id": 66, 394 | "title": "repudiandae ea animi iusto", 395 | "body": "officia veritatis tenetur vero qui itaque\nsint non ratione\nsed et ut asperiores iusto eos molestiae nostrum\nveritatis quibusdam et nemo iusto saepe" 396 | }, 397 | { 398 | "userId": 7, 399 | "id": 67, 400 | "title": "aliquid eos sed fuga est maxime repellendus", 401 | "body": "reprehenderit id nostrum\nvoluptas doloremque pariatur sint et accusantium quia quod aspernatur\net fugiat amet\nnon sapiente et consequatur necessitatibus molestiae" 402 | }, 403 | { 404 | "userId": 7, 405 | "id": 68, 406 | "title": "odio quis facere architecto reiciendis optio", 407 | "body": "magnam molestiae perferendis quisquam\nqui cum reiciendis\nquaerat animi amet hic inventore\nea quia deleniti quidem saepe porro velit" 408 | }, 409 | { 410 | "userId": 7, 411 | "id": 69, 412 | "title": "fugiat quod pariatur odit minima", 413 | "body": "officiis error culpa consequatur modi asperiores et\ndolorum assumenda voluptas et vel qui aut vel rerum\nvoluptatum quisquam perspiciatis quia rerum consequatur totam quas\nsequi commodi repudiandae asperiores et saepe a" 414 | }, 415 | { 416 | "userId": 7, 417 | "id": 70, 418 | "title": "voluptatem laborum magni", 419 | "body": "sunt repellendus quae\nest asperiores aut deleniti esse accusamus repellendus quia aut\nquia dolorem unde\neum tempora esse dolore" 420 | }, 421 | { 422 | "userId": 8, 423 | "id": 71, 424 | "title": "et iusto veniam et illum aut fuga", 425 | "body": "occaecati a doloribus\niste saepe consectetur placeat eum voluptate dolorem et\nqui quo quia voluptas\nrerum ut id enim velit est perferendis" 426 | }, 427 | { 428 | "userId": 8, 429 | "id": 72, 430 | "title": "sint hic doloribus consequatur eos non id", 431 | "body": "quam occaecati qui deleniti consectetur\nconsequatur aut facere quas exercitationem aliquam hic voluptas\nneque id sunt ut aut accusamus\nsunt consectetur expedita inventore velit" 432 | }, 433 | { 434 | "userId": 8, 435 | "id": 73, 436 | "title": "consequuntur deleniti eos quia temporibus ab aliquid at", 437 | "body": "voluptatem cumque tenetur consequatur expedita ipsum nemo quia explicabo\naut eum minima consequatur\ntempore cumque quae est et\net in consequuntur voluptatem voluptates aut" 438 | }, 439 | { 440 | "userId": 8, 441 | "id": 74, 442 | "title": "enim unde ratione doloribus quas enim ut sit sapiente", 443 | "body": "odit qui et et necessitatibus sint veniam\nmollitia amet doloremque molestiae commodi similique magnam et quam\nblanditiis est itaque\nquo et tenetur ratione occaecati molestiae tempora" 444 | }, 445 | { 446 | "userId": 8, 447 | "id": 75, 448 | "title": "dignissimos eum dolor ut enim et delectus in", 449 | "body": "commodi non non omnis et voluptas sit\nautem aut nobis magnam et sapiente voluptatem\net laborum repellat qui delectus facilis temporibus\nrerum amet et nemo voluptate expedita adipisci error dolorem" 450 | }, 451 | { 452 | "userId": 8, 453 | "id": 76, 454 | "title": "doloremque officiis ad et non perferendis", 455 | "body": "ut animi facere\ntotam iusto tempore\nmolestiae eum aut et dolorem aperiam\nquaerat recusandae totam odio" 456 | }, 457 | { 458 | "userId": 8, 459 | "id": 77, 460 | "title": "necessitatibus quasi exercitationem odio", 461 | "body": "modi ut in nulla repudiandae dolorum nostrum eos\naut consequatur omnis\nut incidunt est omnis iste et quam\nvoluptates sapiente aliquam asperiores nobis amet corrupti repudiandae provident" 462 | }, 463 | { 464 | "userId": 8, 465 | "id": 78, 466 | "title": "quam voluptatibus rerum veritatis", 467 | "body": "nobis facilis odit tempore cupiditate quia\nassumenda doloribus rerum qui ea\nillum et qui totam\naut veniam repellendus" 468 | }, 469 | { 470 | "userId": 8, 471 | "id": 79, 472 | "title": "pariatur consequatur quia magnam autem omnis non amet", 473 | "body": "libero accusantium et et facere incidunt sit dolorem\nnon excepturi qui quia sed laudantium\nquisquam molestiae ducimus est\nofficiis esse molestiae iste et quos" 474 | }, 475 | { 476 | "userId": 8, 477 | "id": 80, 478 | "title": "labore in ex et explicabo corporis aut quas", 479 | "body": "ex quod dolorem ea eum iure qui provident amet\nquia qui facere excepturi et repudiandae\nasperiores molestias provident\nminus incidunt vero fugit rerum sint sunt excepturi provident" 480 | }, 481 | { 482 | "userId": 9, 483 | "id": 81, 484 | "title": "tempora rem veritatis voluptas quo dolores vero", 485 | "body": "facere qui nesciunt est voluptatum voluptatem nisi\nsequi eligendi necessitatibus ea at rerum itaque\nharum non ratione velit laboriosam quis consequuntur\nex officiis minima doloremque voluptas ut aut" 486 | }, 487 | { 488 | "userId": 9, 489 | "id": 82, 490 | "title": "laudantium voluptate suscipit sunt enim enim", 491 | "body": "ut libero sit aut totam inventore sunt\nporro sint qui sunt molestiae\nconsequatur cupiditate qui iste ducimus adipisci\ndolor enim assumenda soluta laboriosam amet iste delectus hic" 492 | }, 493 | { 494 | "userId": 9, 495 | "id": 83, 496 | "title": "odit et voluptates doloribus alias odio et", 497 | "body": "est molestiae facilis quis tempora numquam nihil qui\nvoluptate sapiente consequatur est qui\nnecessitatibus autem aut ipsa aperiam modi dolore numquam\nreprehenderit eius rem quibusdam" 498 | }, 499 | { 500 | "userId": 9, 501 | "id": 84, 502 | "title": "optio ipsam molestias necessitatibus occaecati facilis veritatis dolores aut", 503 | "body": "sint molestiae magni a et quos\neaque et quasi\nut rerum debitis similique veniam\nrecusandae dignissimos dolor incidunt consequatur odio" 504 | }, 505 | { 506 | "userId": 9, 507 | "id": 85, 508 | "title": "dolore veritatis porro provident adipisci blanditiis et sunt", 509 | "body": "similique sed nisi voluptas iusto omnis\nmollitia et quo\nassumenda suscipit officia magnam sint sed tempora\nenim provident pariatur praesentium atque animi amet ratione" 510 | }, 511 | { 512 | "userId": 9, 513 | "id": 86, 514 | "title": "placeat quia et porro iste", 515 | "body": "quasi excepturi consequatur iste autem temporibus sed molestiae beatae\net quaerat et esse ut\nvoluptatem occaecati et vel explicabo autem\nasperiores pariatur deserunt optio" 516 | }, 517 | { 518 | "userId": 9, 519 | "id": 87, 520 | "title": "nostrum quis quasi placeat", 521 | "body": "eos et molestiae\nnesciunt ut a\ndolores perspiciatis repellendus repellat aliquid\nmagnam sint rem ipsum est" 522 | }, 523 | { 524 | "userId": 9, 525 | "id": 88, 526 | "title": "sapiente omnis fugit eos", 527 | "body": "consequatur omnis est praesentium\nducimus non iste\nneque hic deserunt\nvoluptatibus veniam cum et rerum sed" 528 | }, 529 | { 530 | "userId": 9, 531 | "id": 89, 532 | "title": "sint soluta et vel magnam aut ut sed qui", 533 | "body": "repellat aut aperiam totam temporibus autem et\narchitecto magnam ut\nconsequatur qui cupiditate rerum quia soluta dignissimos nihil iure\ntempore quas est" 534 | }, 535 | { 536 | "userId": 9, 537 | "id": 90, 538 | "title": "ad iusto omnis odit dolor voluptatibus", 539 | "body": "minus omnis soluta quia\nqui sed adipisci voluptates illum ipsam voluptatem\neligendi officia ut in\neos soluta similique molestias praesentium blanditiis" 540 | }, 541 | { 542 | "userId": 10, 543 | "id": 91, 544 | "title": "aut amet sed", 545 | "body": "libero voluptate eveniet aperiam sed\nsunt placeat suscipit molestias\nsimilique fugit nam natus\nexpedita consequatur consequatur dolores quia eos et placeat" 546 | }, 547 | { 548 | "userId": 10, 549 | "id": 92, 550 | "title": "ratione ex tenetur perferendis", 551 | "body": "aut et excepturi dicta laudantium sint rerum nihil\nlaudantium et at\na neque minima officia et similique libero et\ncommodi voluptate qui" 552 | }, 553 | { 554 | "userId": 10, 555 | "id": 93, 556 | "title": "beatae soluta recusandae", 557 | "body": "dolorem quibusdam ducimus consequuntur dicta aut quo laboriosam\nvoluptatem quis enim recusandae ut sed sunt\nnostrum est odit totam\nsit error sed sunt eveniet provident qui nulla" 558 | }, 559 | { 560 | "userId": 10, 561 | "id": 94, 562 | "title": "qui qui voluptates illo iste minima", 563 | "body": "aspernatur expedita soluta quo ab ut similique\nexpedita dolores amet\nsed temporibus distinctio magnam saepe deleniti\nomnis facilis nam ipsum natus sint similique omnis" 564 | }, 565 | { 566 | "userId": 10, 567 | "id": 95, 568 | "title": "id minus libero illum nam ad officiis", 569 | "body": "earum voluptatem facere provident blanditiis velit laboriosam\npariatur accusamus odio saepe\ncumque dolor qui a dicta ab doloribus consequatur omnis\ncorporis cupiditate eaque assumenda ad nesciunt" 570 | }, 571 | { 572 | "userId": 10, 573 | "id": 96, 574 | "title": "quaerat velit veniam amet cupiditate aut numquam ut sequi", 575 | "body": "in non odio excepturi sint eum\nlabore voluptates vitae quia qui et\ninventore itaque rerum\nveniam non exercitationem delectus aut" 576 | }, 577 | { 578 | "userId": 10, 579 | "id": 97, 580 | "title": "quas fugiat ut perspiciatis vero provident", 581 | "body": "eum non blanditiis soluta porro quibusdam voluptas\nvel voluptatem qui placeat dolores qui velit aut\nvel inventore aut cumque culpa explicabo aliquid at\nperspiciatis est et voluptatem dignissimos dolor itaque sit nam" 582 | }, 583 | { 584 | "userId": 10, 585 | "id": 98, 586 | "title": "laboriosam dolor voluptates", 587 | "body": "doloremque ex facilis sit sint culpa\nsoluta assumenda eligendi non ut eius\nsequi ducimus vel quasi\nveritatis est dolores" 588 | }, 589 | { 590 | "userId": 10, 591 | "id": 99, 592 | "title": "temporibus sit alias delectus eligendi possimus magni", 593 | "body": "quo deleniti praesentium dicta non quod\naut est molestias\nmolestias et officia quis nihil\nitaque dolorem quia" 594 | }, 595 | { 596 | "userId": 10, 597 | "id": 100, 598 | "title": "at nam consequatur ea labore ea harum", 599 | "body": "cupiditate quo est a modi nesciunt soluta\nipsa voluptas error itaque dicta in\nautem qui minus magnam et distinctio eum\naccusamus ratione error aut" 600 | } 601 | ] 602 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { config, reloadConfig } from './config'; 3 | import * as path from 'path'; 4 | 5 | export const EXT_ID = 'es6-css-minify'; 6 | export const SUPPORTED_FILES = [ 7 | 'javascript', 8 | 'css' 9 | ]; 10 | 11 | export function isMinified(doc: vscode.TextDocument): boolean { 12 | const baseName = path.basename(doc.fileName); 13 | const postfix = baseName.split('.')[baseName.split('.').length - 2]; 14 | return (doc.languageId === 'javascript' && postfix === config.jsPostfix) || (doc.languageId === 'css' && postfix === config.cssPostfix); 15 | } 16 | 17 | export function efficiency(original: number, minified: number): number { 18 | return original === 0 ? 0 : Number((100 - ((minified / original) * 100)).toFixed(2)); 19 | } 20 | 21 | export function getOutPath(doc: vscode.TextDocument): string { 22 | 23 | const file = { 24 | basename: path.basename(doc.uri.fsPath), 25 | extname: path.extname(doc.uri.fsPath), 26 | dirname: path.dirname(doc.uri.fsPath), 27 | languageId: doc.languageId 28 | }; 29 | 30 | let outNameParts = file.basename.split('.'); 31 | 32 | outNameParts.pop(); 33 | 34 | if (config.jsPostfix && file.languageId === 'javascript') { 35 | 36 | outNameParts.push(config.jsPostfix); 37 | 38 | } else if (config.cssPostfix && file.languageId === 'css') { 39 | 40 | outNameParts.push(config.cssPostfix); 41 | 42 | } 43 | 44 | outNameParts.push(file.extname.replace('.', '')); 45 | const baseOut = outNameParts.join('.'); 46 | 47 | let outPath: string; 48 | 49 | if (file.languageId === 'javascript') { 50 | 51 | if (config.jsMinPath && vscode.workspace.workspaceFolders) { 52 | outPath = path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, config.jsMinPath, baseOut); 53 | } else { 54 | outPath = path.join(file.dirname, baseOut); 55 | } 56 | 57 | } else if (file.languageId === 'css') { 58 | 59 | if (config.cssMinPath && vscode.workspace.workspaceFolders) { 60 | outPath = path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, config.cssMinPath, baseOut); 61 | } else { 62 | outPath = path.join(file.dirname, baseOut); 63 | } 64 | 65 | } else { 66 | 67 | outPath = ''; 68 | 69 | } 70 | 71 | return outPath; 72 | 73 | } 74 | 75 | function isConfigFile(path: string): boolean { 76 | 77 | return path.endsWith(config.uglifyConfigFile) || path.endsWith(config.cleancssConfigFile) || path.endsWith(config.autoprefixerConfigFile); 78 | 79 | } 80 | 81 | export function onConfigFileChange(uri: vscode.Uri) { 82 | 83 | if (isConfigFile(uri.path)) { 84 | 85 | reloadConfig(true); 86 | vscode.window.showInformationMessage('Minify configuration reloaded.'); 87 | 88 | } 89 | 90 | } 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true, /* enable all strict type-checking options */ 12 | "noImplicitAny": true, 13 | "noUnusedLocals": true, /* Report errors on unused locals. */ 14 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 15 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 16 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 17 | "noImplicitThis": true 18 | }, 19 | "include": [ 20 | "src/**/*.ts", 21 | "node_modules/vscode/vscode.d.ts", 22 | "node_modules/vscode/lib/*" 23 | ], 24 | "exclude": [ 25 | "node_modules", 26 | ".vscode-test" 27 | ] 28 | } -------------------------------------------------------------------------------- /tsconfig.webpack.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "node_modules", 5 | ".vscode-test", 6 | "./src/test" 7 | ] 8 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-string-throw": true, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": [ 9 | true, 10 | "always" 11 | ], 12 | "triple-equals": true, 13 | "typedef": [ 14 | true, 15 | "call-signature", 16 | "arrow-call-signature", 17 | // "parameter", 18 | // "arrow-parameter", 19 | "property-declaration", 20 | // "variable-declaration", 21 | "member-variable-declaration", 22 | "object-destructuring", 23 | "array-destructuring" 24 | ] 25 | }, 26 | "defaultSeverity": "warning" 27 | } 28 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | //@ts-check 7 | 8 | 'use strict'; 9 | 10 | const path = require('path'); 11 | 12 | const tsconfig = 'tsconfig.webpack.json'; 13 | 14 | /**@type {import('webpack').Configuration}*/ 15 | const config = { 16 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 17 | 18 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 19 | output: { // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 20 | path: path.resolve(__dirname, 'dist'), 21 | filename: 'extension.js', 22 | libraryTarget: "commonjs2", 23 | devtoolModuleFilenameTemplate: "../[resource-path]", 24 | }, 25 | devtool: 'source-map', 26 | externals: { 27 | 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/ 28 | }, 29 | resolve: { // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 30 | extensions: ['.ts', '.js'] 31 | }, 32 | plugins: [ 33 | new (require('fork-ts-checker-webpack-plugin'))({ 34 | async: false, 35 | useTypescriptIncrementalApi: true, 36 | memoryLimit: 768, 37 | checkSyntacticErrors: true, 38 | tsconfig: tsconfig 39 | }) 40 | ], 41 | module: { 42 | rules: [{ 43 | test: /\.ts$/, 44 | exclude: /node_modules/, 45 | use: [{ 46 | loader: 'ts-loader', 47 | options: { 48 | transpileOnly: true, 49 | configFile: tsconfig, 50 | compilerOptions: { 51 | "module": "es6" // override `tsconfig.json` so that TypeScript emits native JavaScript modules. 52 | } 53 | } 54 | }] 55 | }] 56 | }, 57 | } 58 | 59 | module.exports = config; 60 | --------------------------------------------------------------------------------