@geoapps/sass2css
Advanced tools
| image: node:lts-alpine | ||
| stages: | ||
| - test | ||
| before_script: | ||
| - yarn | ||
| lint: | ||
| stage: test | ||
| script: | ||
| - yarn lint |
+19
-7
@@ -20,2 +20,6 @@ #!/usr/bin/env node | ||
| }) | ||
| .option('input-img-dir-name', { | ||
| describe: 'Relative path to directory with source images', | ||
| type: 'string' | ||
| }) | ||
| .option('output-dir-name', { | ||
@@ -25,15 +29,23 @@ describe: 'Relative path to output directory', | ||
| }) | ||
| .option('compress', { | ||
| describe: 'Whether to compress output CSS file', | ||
| type: 'boolean' | ||
| .option('output-img-dir-name', { | ||
| describe: 'Relative path to output directory for images', | ||
| type: 'string' | ||
| }) | ||
| .option('modes', { | ||
| describe: 'Output modes', | ||
| type: 'array' | ||
| }) | ||
| .default('base-path', '.') | ||
| .default('input-dir-name', 'src/sass') | ||
| .default('input-file-name', 'index.sass') | ||
| .default('input-img-dir-name', 'src/img') | ||
| .default('output-dir-name', 'dist/css') | ||
| .default('compress', false); | ||
| .default('output-img-dir-name', 'dist/img') | ||
| .default('modes', ['development', 'production']); | ||
| }, options => { | ||
| const mode = process.env.NODE_ENV || 'development'; | ||
| const compress = mode === 'production'; | ||
| sass2Css({ ...options, compress }); | ||
| const modes = process.env.NODE_ENV ? [process.env.NODE_ENV] : options.modes; | ||
| sass2Css({ ...options, modes }).catch(error => { | ||
| console.error(error); | ||
| process.exit(-1); | ||
| }); | ||
| }) | ||
@@ -40,0 +52,0 @@ .wrap(null) |
+7
-1
| ## Changelog | ||
| ### 0.1.0 | ||
| ### 0.2.0 (2019-02-07) | ||
| - `compress` option is replaced by `modes`. | ||
| - Copying image files is supported. | ||
| - Gitlab CI support is added. | ||
| ### 0.1.0 (2019-02-06) | ||
| - First release. |
+88
-24
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const sass = require('node-sass'); | ||
| const jsonfile = require('jsonfile'); | ||
| const copyFiles = require('copyfiles'); | ||
| const mkdirp = require('mkdirp'); | ||
| const chalk = require('chalk'); | ||
| const nodeModulesImportRegExp = /^~(.+)$/; | ||
| const availableModes = ['development', 'production']; | ||
| /** | ||
@@ -15,6 +21,8 @@ * Convert SASS to CSS | ||
| * @param {String} [options.inputFileName=index.sass] Name of input SASS file | ||
| * @param {String} [options.inputImgDirName=src/img] Relative path to directory with source images | ||
| * @param {String} [options.outputDirName=dist/css] Relative path to output directory | ||
| * @param {Boolean} [options.compress=false] Whether to compress output CSS file | ||
| * @param {String} [options.outputImgDirName=dist/img] Relative path to output directory for images | ||
| * @param {Array} [options.modes=['development', 'production']] Output modes | ||
| */ | ||
| function sass2Css(options = {}) { | ||
| async function sass2Css(options = {}) { | ||
| const { | ||
@@ -24,4 +32,6 @@ basePath = '.', | ||
| inputFileName = 'index.sass', | ||
| inputImgDirName = 'src/img', | ||
| outputDirName = 'dist/css', | ||
| compress = false | ||
| outputImgDirName = 'dist/img', | ||
| modes = ['development', 'production'] | ||
| } = options; | ||
@@ -34,3 +44,3 @@ | ||
| try { | ||
| const packageJson = require(packageJsonPath); | ||
| const packageJson = await jsonfile.readFile(packageJsonPath); | ||
| packageName = packageJson.name; | ||
@@ -42,31 +52,72 @@ } | ||
| const { outputFileName = `${packageName}${compress ? '.min' : ''}.css` } = options; | ||
| const inputDirPath = path.resolve(baseDirPath, inputDirName); | ||
| const inputFilePath = path.resolve(inputDirPath, inputFileName); | ||
| const inputImgDirPath = path.resolve(baseDirPath, inputImgDirName); | ||
| const outputDirPath = path.resolve(baseDirPath, outputDirName); | ||
| const outputFilePath = path.resolve(outputDirPath, outputFileName); | ||
| const outputImgDirPath = path.resolve(baseDirPath, outputImgDirName); | ||
| const nodeModulesPath = path.resolve(baseDirPath, 'node_modules'); | ||
| sass.render({ | ||
| file: inputFilePath, | ||
| outFile: outputFilePath, | ||
| outputStyle: compress ? 'compressed' : 'nested', | ||
| importer: (url, prev, done) => { | ||
| const file = url.replace(nodeModulesImportRegExp, `${nodeModulesPath}/$1`); | ||
| done({ file }); | ||
| if (await directoryExists(inputImgDirPath)) { | ||
| await copyDir(inputImgDirPath, outputImgDirPath); | ||
| console.log(chalk.green.bold('Image files are copied.')); | ||
| } | ||
| const renderSass = options => { | ||
| const { outputFilePath, outputStyle } = options; | ||
| return new Promise((resolve, reject) => { | ||
| sass.render({ | ||
| file: inputFilePath, | ||
| outFile: outputFilePath, | ||
| outputStyle, | ||
| importer: (url, prev, done) => { | ||
| const file = url.replace(nodeModulesImportRegExp, `${nodeModulesPath}/$1`); | ||
| done({ file }); | ||
| } | ||
| }, (error, result) => { | ||
| if (error) { | ||
| reject(error); | ||
| return; | ||
| } | ||
| mkdirp.sync(outputDirPath); | ||
| fs.writeFile(outputFilePath, result.css, error => { | ||
| if (error) { | ||
| reject(error); | ||
| } | ||
| else { | ||
| resolve(); | ||
| } | ||
| }); | ||
| }); | ||
| }); | ||
| }; | ||
| for (let i = 0; i < modes.length; i++) { | ||
| const mode = modes[i]; | ||
| if (!availableModes.includes(mode)) { | ||
| return Promise.reject(`Mode "${mode}" is not supported.`); | ||
| } | ||
| }, (error, result) => { | ||
| if (error) { | ||
| console.error('Unable to transform SASS to CSS.'); | ||
| console.error(error); | ||
| return; | ||
| const { outputFileName = `${packageName}${mode === 'production' ? '.min' : ''}.css` } = options; | ||
| const outputFilePath = path.resolve(outputDirPath, outputFileName); | ||
| const outputStyle = mode === 'production' ? 'compressed' : 'nested'; | ||
| try { | ||
| await renderSass({ outputFilePath, outputStyle }); | ||
| console.log(chalk.yellow.bold(`Output CSS file "${outputFilePath}" is written.`)); | ||
| } | ||
| mkdirp.sync(outputDirPath); | ||
| fs.writeFile(outputFilePath, result.css, error => { | ||
| catch (e) { | ||
| console.error(chalk.red.bold(`Unable to write output CSS file "${outputFilePath}".`)); | ||
| } | ||
| } | ||
| } | ||
| function copyDir(inputDir, outputDir) { | ||
| return new Promise((resolve, reject) => { | ||
| copyFiles([`${inputDir}/**/*`, outputDir], { up: inputDir.split(path.sep).length }, error => { | ||
| if (error) { | ||
| console.error(`Unable to write output CSS file "${outputFilePath}".`); | ||
| return; | ||
| reject(error); | ||
| } | ||
| console.log(`Output CSS file "${outputFilePath}" is written.`); | ||
| else { | ||
| resolve(); | ||
| } | ||
| }); | ||
@@ -76,2 +127,15 @@ }); | ||
| function getFileItemStats(fileItemPath) { | ||
| return new Promise(resolve => fs.stat(fileItemPath, (error, stats) => resolve(error ? false : stats))); | ||
| } | ||
| async function directoryExists(dirPath) { | ||
| try { | ||
| return (await getFileItemStats(dirPath)).isDirectory(); | ||
| } | ||
| catch (e) { | ||
| return false; | ||
| } | ||
| } | ||
| module.exports = sass2Css; |
+4
-1
| { | ||
| "name": "@geoapps/sass2css", | ||
| "version": "0.1.0", | ||
| "version": "0.2.0", | ||
| "description": "Converting library SASS to CSS", | ||
@@ -21,2 +21,5 @@ "main": "index.js", | ||
| "dependencies": { | ||
| "chalk": "^2.4.2", | ||
| "copyfiles": "^2.1.0", | ||
| "jsonfile": "^5.0.0", | ||
| "mkdirp": "^0.5.1", | ||
@@ -23,0 +26,0 @@ "node-sass": "^4.11.0", |
+3
-1
@@ -41,4 +41,6 @@ # @geoapps/sass2css | ||
| - `--input-file-name` (`inputFileName`) Name of input SASS file (default is `index.sass`). | ||
| - `--input-img-dir-name` (`inputImgDirName`) Relative path to directory with source images (default is `src/img`). | ||
| - `--output-dir-name` (`outputDirName`) Relative path to output directory (default is `dist/css`). | ||
| - `--compress` (`compress`) Whether to compress output CSS file (default is `false`). | ||
| - `--output-img-dir-name` (`outputImgDirName`) Relative path to output directory for images (default is `dist/img`). | ||
| - `--modes` (`modes`) Output modes (default is `['development', 'production']`). | ||
@@ -45,0 +47,0 @@ ## Changelog |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
8571
52.54%6
20%180
60.71%49
4.26%6
100%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added