I'm using Sublime Text 3, and CSS Linter.
In my settings I've put the ignore rule, and currently there is only the "outline-none" rule, I'd like to include all the rules which refer to IE6 and IE7 based errors.
Is there a list what are the IE6 and IE7 rules so that I can put them in the ignore array?
My CSSLint.sublime-settings look like this:
// CSSLint rules you wish to ignore. Must be an array. Leave blank to include all default rules.
{
"ignore": ["outline-none"]
}
To answer my own question, in the end I figured how to do what I need:
{
"user": {
"debug": false,
"delay": 0.25,
"error_color": "D02000",
"gutter_theme": "Packages/SublimeLinter/gutter-themes/Danish Royalty/Danish Royalty.gutter-theme",
"gutter_theme_excludes": [],
"lint_mode": "background",
"linters": {
"csslint": {
"#disable": false,
"args": [],
"box-sizing": false,
"errors": "",
"excludes": [],
"ignore": [
"outline-none",
"box-sizing",
"ids",
"adjoining-classes",
"floats",
"qualified-headings",
"unique-headings",
"important",
"universal-selector",
"box-model",
"font-faces",
"font-sizes"
],
"warnings": ""
},
"eslint": {
"#disable": true,
"args": [],
"excludes": []
},
"jscs": {
"#disable": true,
"args": [],
"excludes": []
},
"jshint": {
"#disable": false,
"args": [],
"excludes": [],
"ignore": [
"newcap"
],
"newcap": false,
"tab_size": 4
},
"jslint": {
"#disable": true,
"args": [],
"excludes": [],
"ignore": [
"newcap"
],
"newcap": false
},
"php": {
"#disable": false,
"args": [],
"excludes": []
}
},
"mark_style": "outline",
"no_column_highlights_line": false,
"passive_warnings": false,
"paths": {
"linux": [],
"osx": [],
"windows": []
},
"python_paths": {
"linux": [],
"osx": [],
"windows": []
},
"rc_search_limit": 3,
"shell_timeout": 10,
"show_errors_on_save": false,
"show_marks_in_minimap": true,
"syntax_map": {
"html (django)": "html",
"html (rails)": "html",
"html 5": "html",
"php": "html",
"python django": "python"
},
"warning_color": "D02000",
"wrap_find": true
}
}
Just go to Preferences > Package Settings > SublimeLinter > Settings - User and paste the above in the opened file.
These are the options that I found not to be of practical importance, so I just ignored them.
Hope it helps :)
Related
Upgrading from babel to SWC. I deleted the .babelrc file but now the path aliases are no longer recognized in my project. Tried to restore this with a .swrc
.swrc
{
"jsc": {
"target": "ES2017",
"baseUrl": ".",
"paths": {
"#components/*": ["./components/*"]
}
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2017",
"lib": ["es6", "dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "ESNEXT",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"baseUrl": ".",
"paths": {
"#components/*": ["./components/*"],
}
},
"exclude": ["node_modules", "**/*.stories.tsx"],
"include": ["**/*.ts", "**/*.tsx", "next-env.d.ts", "next.config.js"]
}
14:24 Error: Unable to resolve path to module '#components/NavBar'
.eslintrc.json
{
"root": true,
"parser": "#typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:#typescript-eslint/eslint-recommended",
"plugin:#typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended"
],
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"#typescript-eslint", "react", "prettier"
],
"rules": {
"prefer-const": "off",
"import/extensions": "off",
"jsx-a11y/anchor-is-valid": "off",
"import/no-cycle": [0, { "ignoreExternal": true }],
"prettier/prettier": ["error", { "endOfLine": "auto" }],
"react/prop-types": "off",
"react-hooks/exhaustive-deps": "off",
"react/no-unescaped-entities": "off",
"react/jsx-filename-extension": [1, { "extensions": [".ts", ".tsx"] }],
"react/jsx-props-no-spreading": ["error", { "html": "ignore", "custom": "ignore", "exceptions": [""] }],
// needed because of https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md#how-to-use & https://stackoverflow.com/questions/63818415/react-was-used-before-it-was-defined
"no-use-before-define": "off",
"#typescript-eslint/no-use-before-define": [
"error",
{ "functions": false, "classes": false, "variables": true }
],
"#typescript-eslint/ban-ts-comment": "off",
"#typescript-eslint/no-explicit-any": "off"
},
"settings": {
"import/resolver": {
"babel-module": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
}
}
old .babelrc
{
"presets": ["next/babel"],
"plugins": [
[
"module-resolver",
{
"root": ["./"],
"alias": {
"#components": "./components",
"#api": "./api",
"#models": "./models",
"#screens": "./screens",
"#hooks": "./hooks",
"#services": "./services",
"#constants": "./constants",
"#context": "./context",
"#queries": "./queries",
"#data": "./data",
"#typeDefs": "./types",
"#generated": "./generated",
"#utils": "./utils",
"#pages": "./pages",
"#public": "./public"
}
}
]
]
}
Was able to solve this with a few tweaks.
Remove the import/resolver section of .eslintrc.json
Extend next in eslint.
I two projects, one with React (v17.0.2) and the other with Next.js (v11.1.0) In both I
have implemented ESlint with Prettier and Stylelint.
My problem is that in React project everything is working smoothly and fine, however in Next.js project, stylelint is not linting component.modules.scss files (but other.css files are).
In React, scss files are in ./src/assets/scss/*
in Next.js scss files are in ./styles/*
These are the config files content:
.eslintrc.json
{
"settings": {
"react": {
"version": "detect"
}
},
"plugins": [
"react",
"react-hooks",
"jsx-a11y",
"only-warn",
"prettier"
],
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2021,
"ecmaFeature": {
"jsx": true,
"modules": true
}
},
"env": {
"browser": true,
"jest": true,
"es2021": true,
"node": true
},
"parser": "babel-eslint",
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:prettier/recommended",
"next"
],
"rules": {
"camelcase": "off",
"react/prop-types": "off",
"react/jsx-curly-newline": ["off", "consistent"],
"react/jsx-handler-names": "off",
"react/display-name": ["off"],
"prettier/prettier": "error",
"arrow-body-style": "off",
"prefer-arrow-callback": "off"
}
}
.prettierrc
{
"singleQuote": true,
"trailingComma": "all",
"parser": "flow",
"semi": false,
"useTabs": false,
"editor.formatOnSave": true,
"stylelintIntegration": true
}
.stylelintrc.json
{
"extends": "stylelint-config-sass-guidelines",
"plugins": [
"stylelint-scss"
],
"rules": {
"at-rule-no-unknown": null,
"scss/at-rule-no-unknown": true,
"indentation": 2,
"number-leading-zero": null,
"max-nesting-depth": 10
}
}
Any help please? Thanks
I found what was wrong;
Need to add this in .vscode/settings.json
"stylelint.validate": ["css", "scss", ".module.scss"]
.module.scss was not considered as .scss, so adding it to the config made everything works
I have added an application to my WordPress site with a plug in that am using to automatically add posts with a python scripts. My API is working just fine even after testing on postman.
However the post Meta Desc and Key Phrase columns don't show anything as in a post added manually. (See screenshot; the first post is the one added via an api). I will appreciate any idea as to why this is.
post = {
'title': question_title,
'status': 'publish',
"content": question,
"type": "post",
"categories": [2],
"focus_keyphrase": question_title,
}
gradeboosts_url = "https://gradeboosts.com/wp-json/wp/v2"
user = 'aloy'
password = '****************'
creds = user + ':' + password
token = base64.b64encode(creds.encode())
headers = {'Authorization': 'Basic ' + token.decode('utf-8')}
r = requests.post(gradeboosts_url + '/posts', json=post, headers=headers)
A full postman get request that is displaying all columns on wordpress:
response = {
"id": 1692997,
"date": "2021-08-13T12:43:38",
"date_gmt": "2021-08-13T12:43:38",
"guid": {
"rendered": "https://gradeboosts.com/health-sciences-homework-help-3/"
},
"modified": "2021-08-13T12:43:38",
"modified_gmt": "2021-08-13T12:43:38",
"slug": "health-sciences-homework-help-3",
"status": "publish",
"type": "post",
"link": "https://gradeboosts.com/health-sciences-homework-help-3/",
"title": {
"rendered": "Health Sciences homework help"
},
"content": {
"rendered": "<p>Health Sciences homework help. An ion is an atom that has gained or lost one or more electrons.</p>\n<p> I don’t think that this is maths, but more chemistry.<br />\nAn ion is an atom that has a charge due to a lost or gain of electrons. Usually, ions occur when the atom tries to get a full outershell, either by losing electrons (and thus gaining a positive charge) or by gaining electrons (and thus getting a negative charge).</p>\n<p>Health Sciences homework help</p>\n",
"protected": false
},
"excerpt": {
"rendered": "<p>What’s an ion?</p>\n",
"protected": false
},
"author": 2,
"featured_media": 0,
"comment_status": "open",
"ping_status": "open",
"sticky": false,
"template": "",
"format": "standard",
"meta": {
"spay_email": ""
},
"categories": [],
"tags": [],
"yst_prominent_words": [],
"jetpack_featured_media_url": "",
"_links": {
"self": [
{
"href": "https://gradeboosts.com/wp-json/wp/v2/posts/1692997"
}
],
"collection": [
{
"href": "https://gradeboosts.com/wp-json/wp/v2/posts"
}
],
"about": [
{
"href": "https://gradeboosts.com/wp-json/wp/v2/types/post"
}
],
"author": [
{
"embeddable": true,
"href": "https://gradeboosts.com/wp-json/wp/v2/users/2"
}
],
"replies": [
{
"embeddable": true,
"href": "https://gradeboosts.com/wp-json/wp/v2/comments?post=1692997"
}
],
"version-history": [
{
"count": 190,
"href": "https://gradeboosts.com/wp-json/wp/v2/posts/1692997/revisions"
}
],
"predecessor-version": [
{
"id": 1698135,
"href": "https://gradeboosts.com/wp-json/wp/v2/posts/1692997/revisions/1698135"
}
],
"wp:attachment": [
{
"href": "https://gradeboosts.com/wp-json/wp/v2/media?parent=1692997"
}
],
"wp:term": [
{
"taxonomy": "category",
"embeddable": true,
"href": "https://gradeboosts.com/wp-json/wp/v2/categories?post=1692997"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "https://gradeboosts.com/wp-json/wp/v2/tags?post=1692997"
},
{
"taxonomy": "yst_prominent_words",
"embeddable": true,
"href": "https://gradeboosts.com/wp-json/wp/v2/yst_prominent_words?post=1692997"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
I'm trying to get a dist folder populated with the standard files + the .gz version of them. I did ng eject to get the webpack.config.js file so I could add the compression plugin https://github.com/webpack-contrib/compression-webpack-plugin. I added the new CompressPlugin({}) as the last plugin and marked the ejected: false in the .angular-cli.json file.
When I then run ng build I don't get any .gzip/.gz files generated which I would expect have.
Is there something I am missing or doing wrong? The full webpack file (mostly generated by ng new is:
const fs = require('fs');
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');
const postcssUrl = require('postcss-url');
const cssnano = require('cssnano');
const CompressionPlugin = require("compression-webpack-plugin");
const { NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NamedModulesPlugin } = require('webpack');
const { NamedLazyChunksWebpackPlugin, BaseHrefWebpackPlugin } = require('#angular/cli/plugins/webpack');
const { CommonsChunkPlugin } = require('webpack').optimize;
const { AotPlugin } = require('#ngtools/webpack');
const nodeModules = path.join(process.cwd(), 'node_modules');
const realNodeModules = fs.realpathSync(nodeModules);
const genDirNodeModules = path.join(process.cwd(), 'src', '$$_gendir', 'node_modules');
const entryPoints = ["inline","polyfills","sw-register","styles","vendor","main"];
const minimizeCss = false;
const baseHref = "";
const deployUrl = "";
const postcssPlugins = function () {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /#preserve|#license|[##]\s*source(?:Mapping)?URL|^!/i;
const minimizeOptions = {
autoprefixer: false,
safe: true,
mergeLonghand: false,
discardComments: { remove: (comment) => !importantCommentRe.test(comment) }
};
return [
postcssUrl({
url: (URL) => {
// Only convert root relative URLs, which CSS-Loader won't process into require().
if (!URL.startsWith('/') || URL.startsWith('//')) {
return URL;
}
if (deployUrl.match(/:\/\//)) {
// If deployUrl contains a scheme, ignore baseHref use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${URL}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
}
else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
}
}
}),
autoprefixer(),
].concat(minimizeCss ? [cssnano(minimizeOptions)] : []);
};
module.exports = {
"resolve": {
"extensions": [
".ts",
".js"
],
"modules": [
"./node_modules",
"./node_modules"
],
"symlinks": true
},
"resolveLoader": {
"modules": [
"./node_modules",
"./node_modules"
]
},
"entry": {
"main": [
"./src\\main.ts"
],
"polyfills": [
"./src\\polyfills.ts"
],
"styles": [
"./src\\styles.css"
]
},
"output": {
"path": path.join(process.cwd(), "dist"),
"filename": "[name].bundle.js",
"chunkFilename": "[id].chunk.js"
},
"module": {
"rules": [
{
"enforce": "pre",
"test": /\.js$/,
"loader": "source-map-loader",
"exclude": [
/(\\|\/)node_modules(\\|\/)/
]
},
{
"test": /\.html$/,
"loader": "raw-loader"
},
{
"test": /\.(eot|svg|cur)$/,
"loader": "file-loader?name=[name].[hash:20].[ext]"
},
{
"test": /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
"loader": "url-loader?name=[name].[hash:20].[ext]&limit=10000"
},
{
"exclude": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.css$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.scss$|\.sass$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": false,
"precision": 8,
"includePaths": []
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.less$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "less-loader",
"options": {
"sourceMap": false
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.styl$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "stylus-loader",
"options": {
"sourceMap": false,
"paths": []
}
}
]
},
{
"include": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.css$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
}
]
},
{
"include": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.scss$|\.sass$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": false,
"precision": 8,
"includePaths": []
}
}
]
},
{
"include": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.less$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "less-loader",
"options": {
"sourceMap": false
}
}
]
},
{
"include": [
path.join(process.cwd(), "src\\styles.css")
],
"test": /\.styl$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "stylus-loader",
"options": {
"sourceMap": false,
"paths": []
}
}
]
},
{
"test": /\.ts$/,
"loader": "#ngtools/webpack"
}
]
},
"plugins": [
new NoEmitOnErrorsPlugin(),
new CopyWebpackPlugin([
{
"context": "src",
"to": "",
"from": {
"glob": "assets/**/*",
"dot": true
}
},
{
"context": "src",
"to": "",
"from": {
"glob": "favicon.ico",
"dot": true
}
}
], {
"ignore": [
".gitkeep"
],
"debug": "warning"
}),
new ProgressPlugin(),
new CircularDependencyPlugin({
"exclude": /(\\|\/)node_modules(\\|\/)/,
"failOnError": false
}),
new NamedLazyChunksWebpackPlugin(),
new HtmlWebpackPlugin({
"template": "./src\\index.html",
"filename": "./index.html",
"hash": false,
"inject": true,
"compile": true,
"favicon": false,
"minify": false,
"cache": true,
"showErrors": true,
"chunks": "all",
"excludeChunks": [],
"title": "Webpack App",
"xhtml": true,
"chunksSortMode": function sort(left, right) {
let leftIndex = entryPoints.indexOf(left.names[0]);
let rightindex = entryPoints.indexOf(right.names[0]);
if (leftIndex > rightindex) {
return 1;
}
else if (leftIndex < rightindex) {
return -1;
}
else {
return 0;
}
}
}),
new BaseHrefWebpackPlugin({}),
new CommonsChunkPlugin({
"name": [
"inline"
],
"minChunks": null
}),
new CommonsChunkPlugin({
"name": [
"vendor"
],
"minChunks": (module) => {
return module.resource
&& (module.resource.startsWith(nodeModules)
|| module.resource.startsWith(genDirNodeModules)
|| module.resource.startsWith(realNodeModules));
},
"chunks": [
"main"
]
}),
new SourceMapDevToolPlugin({
"filename": "[file].map[query]",
"moduleFilenameTemplate": "[resource-path]",
"fallbackModuleFilenameTemplate": "[resource-path]?[hash]",
"sourceRoot": "webpack:///"
}),
new CommonsChunkPlugin({
"name": [
"main"
],
"minChunks": 2,
"async": "common"
}),
new NamedModulesPlugin({}),
new AotPlugin({
"mainPath": "main.ts",
"replaceExport": false,
"hostReplacementPaths": {
"environments\\environment.ts": "environments\\environment.ts"
},
"exclude": [],
"tsConfigPath": "src\\tsconfig.app.json",
"skipCodeGeneration": true
}),
new CompressionPlugin({})
],
"node": {
"fs": "empty",
"global": true,
"crypto": "empty",
"tls": "empty",
"net": "empty",
"process": true,
"module": false,
"clearImmediate": false,
"setImmediate": false
},
"devServer": {
"historyApiFallback": true
}
};
I'm using #angular/cli 1.4.4.
Note the main reason why I'm doing that is to improve some SEO recommendations because apparently my vendor.css is 600Kb big and being pointed out in the PageSpeed Ingishts: Your page has 1 blocking CSS resources. This causes a delay in rendering your page. It contains 3rd party css only - actually only bootstrap + font-awesome. Unless there is something else to prevent this I thought of compression. I also thought that the web server would auto compress and serve .gz files but I don't know whether that test would apply.
Any help is much appreciated! Thanks
Only ejected application's build is processed by exposed on the root webpack.config.js file. Application which is not ejected (or set to ejected: false) will completely ignore this webpack.config.js file.
So in order to use gzipped files you will need to work with ejected app and use new npm scripts automatically added to package.json.
Instead of 'ng build', now you should run:
npm run build
my related answers that may help:
Angular4 build - gzip missing
How to undo Angular 2 Cli ng-eject
Here is an example of what is happening now:
.class {
}
So when I'm typing .class { SublimeText automatically inserts } (which is correct).
Then I press Enter and get this:
.class {
#CURSOR_POSITION#
}
But what I really want is (attention to the closing bracket):
.class {
#CURSOR_POSITION#
}
I've even seen (ok, it was only once) in some editor special setting for this. Now I start using SublimeText (which is cool!) and I feel that it can be customized in a such way but I'm not quite sure how.
Ok! It's not really hard to do it but it was not simple to know how to do it =)
So my approach is:
Write a simple macro (I've edited the default Enter macro called Add Line in Braces.sublime-macro which lives in ~Data/Packages/Default) and save it with a new name.
I've called it CSS.Add Line in Braces.sublime-macro and put in ~Data/Packages/User.
[
{"command": "insert", "args": {"characters": "\n\n"} },
{"command": "move_to", "args": {"to": "hardbol", "extend": false} },
{"command": "insert", "args": {"characters": "\t"} },
{"command": "move", "args": {"by": "lines", "forward": false} },
{"command": "move_to", "args": {"to": "hardeol", "extend": false} },
{"command": "reindent", "args": {"single_line": true} }
]
Apply it for Enter key in CSS files. For that we need to fo to Preferences > Key Bindings - User (it will open ~Data/Packages/User/Default (YOUR_OPERATING_SYSTEM).sublime-keymap) and paste there the following code:
[
{ "keys": ["enter"], "command": "run_macro_file", "args": {"file": "Packages/User/CSS.Add Line in Braces.sublime-macro"}, "context":
[
{ "key": "selector", "operator": "equal", "operand": "source.css" },
{ "key": "setting.auto_indent", "operator": "equal", "operand": true },
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\{$", "match_all": true },
{ "key": "following_text", "operator": "regex_contains", "operand": "^\\}", "match_all": true }
]
}
]
It is copy-pasted from the defult keybinding file with one context addition:
{ "key": "selector", "operator": "equal", "operand": "source.css" }
which tells Sublime to apply it only for CSS ext.
Profit!