From 76295676a1c073f6d2cd15f5c54b0edcbbbc14c6 Mon Sep 17 00:00:00 2001
From: XhmikosR <xhmikosr@gmail.com>
Date: Mon, 27 Nov 2017 19:41:48 +0200
Subject: [PATCH] Replace lint-vars.sh with a Node.js script. (#24860)

Also, include it in the `css` npm script since it's instant.
---
 build/lint-vars.js | 83 ++++++++++++++++++++++++++++++++++++++++++++++
 build/lint-vars.sh | 28 ----------------
 package-lock.json  | 18 +++++-----
 package.json       |  2 ++
 4 files changed, 94 insertions(+), 37 deletions(-)
 create mode 100644 build/lint-vars.js
 delete mode 100755 build/lint-vars.sh

diff --git a/build/lint-vars.js b/build/lint-vars.js
new file mode 100644
index 0000000000..909f5293d7
--- /dev/null
+++ b/build/lint-vars.js
@@ -0,0 +1,83 @@
+#!/usr/bin/env node
+
+/*!
+ * Script to find unused Sass variables.
+ *
+ * Copyright 2017 The Bootstrap Authors
+ * Copyright 2017 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const fs = require('fs')
+const path = require('path')
+const glob = require('glob')
+
+// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
+function regExpQuote(str) {
+  return str.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
+}
+
+let globalSuccess = true
+
+function findUnusedVars(dir) {
+  if (!(fs.existsSync(dir) && fs.statSync(dir).isDirectory())) {
+    console.log(`"${dir}": Not a valid directory!`)
+    process.exit(1)
+  }
+
+  console.log(`Finding unused variables in "${dir}"...`)
+
+  // A variable to handle success/failure message in this function
+  let unusedVarsFound = false
+
+  // Array of all Sass files' content
+  const sassFiles = glob.sync(path.join(dir, '**/*.scss'))
+  // String of all Sass files' content
+  let sassFilesString = ''
+
+  sassFiles.forEach((file) => {
+    sassFilesString += fs.readFileSync(file, 'utf8')
+  })
+
+  // Array of all Sass variables
+  const variables = sassFilesString.match(/(^\$[a-zA-Z0-9_-]+[^:])/gm)
+
+  console.log(`There's a total of ${variables.length} variables.`)
+
+  // Loop through each variable
+  variables.forEach((variable) => {
+    const re = new RegExp(regExpQuote(variable), 'g')
+    const count = (sassFilesString.match(re) || []).length
+
+    if (count === 1) {
+      console.log(`Variable "${variable}" is only used once!`)
+      unusedVarsFound = true
+      globalSuccess = false
+    }
+  })
+
+  if (unusedVarsFound === false) {
+    console.log(`No unused variables found in "${dir}".`)
+  }
+}
+
+function main(args) {
+  if (args.length < 1) {
+    console.log('Wrong arguments!')
+    console.log('Usage: lint-vars.js folder [, folder2...]')
+    process.exit(1)
+  }
+
+  args.forEach((arg) => {
+    findUnusedVars(arg)
+  })
+
+  if (globalSuccess === false) {
+    process.exit(1)
+  }
+}
+
+// The first and second args are: path/to/node script.js
+main(process.argv.slice(2))
diff --git a/build/lint-vars.sh b/build/lint-vars.sh
deleted file mode 100755
index ae7f716c1f..0000000000
--- a/build/lint-vars.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-#
-# Approach:
-# 1. Find variable declaration in the form of "$my-var: anyvalue"
-# 2. Loop through found variables and find occurrences of each variable in all sass files
-# 3. Filter out vars that occurred only once
-#
-# Run from command line with `build/lint-vars.sh scss`.
-#
-# Source: https://gist.github.com/badsyntax/6193491
-
-if [ -z "$1" ]; then
-	echo "Please specify a directory as the first argument."
-	exit 1
-fi
-if [ ! -d "$1" ]; then
-	echo "Not a valid directory."
-	exit 1
-fi
-
-echo "Finding unused variables. This might take some time..."
-
-vars=$(find "$1" -type f -name "*.scss" -exec grep --color=never -h '^$[a-zA-Z0-9_-][^:]*' {} \; | sed 's/$\([a-zA-Z0-9_-][^:]*\).*/\1/')
-
-for var in $vars; do
-	echo -n "Occurrences of \"\$$var\":"
-	find "$1" -type f -name "*.scss" -exec grep --color=never -h "$var" "{}" \; | wc -l
-done | grep ' 1$'
diff --git a/package-lock.json b/package-lock.json
index 1e36304d14..28dbe1de48 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6934,15 +6934,6 @@
         "duplexer": "0.1.1"
       }
     },
-    "string_decoder": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
-      "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "5.1.1"
-      }
-    },
     "string-width": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
@@ -6981,6 +6972,15 @@
         "function-bind": "1.1.1"
       }
     },
+    "string_decoder": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+      "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
     "stringstream": {
       "version": "0.0.5",
       "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
diff --git a/package.json b/package.json
index 101fed0a27..ae787dd86f 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
     "css-compile-docs": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 assets/scss/docs.scss assets/css/docs.min.css",
     "css-lint": "stylelint --config build/.stylelintrc --syntax scss \"scss/**/*.scss\"",
     "css-lint-docs": "stylelint --config build/.stylelintrc --syntax scss \"assets/scss/*.scss\" && stylelint --config docs/4.0/examples/.stylelintrc \"docs/**/*.css\"",
+    "css-lint-vars": "node build/lint-vars.js scss/ assets/scss/",
     "css-prefix": "postcss --config build/postcss.config.js --replace \"dist/css/*.css\" \"!dist/css/*.min.css\"",
     "css-prefix-docs": "postcss --config build/postcss.config.js --replace \"assets/css/docs.min.css\" \"docs/**/*.css\"",
     "css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css",
@@ -94,6 +95,7 @@
     "cross-env": "^5.1.1",
     "eslint": "^4.11.0",
     "eslint-plugin-compat": "^2.1.0",
+    "glob": "^7.1.2",
     "htmllint-cli": "^0.0.6",
     "jsunitsaucelabs": "^1.3.0",
     "karma": "^1.7.1",
-- 
GitLab