From 88674f17b9da33015f773256620f171c1cb3a77b Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 11 Jan 2016 17:42:54 +0300 Subject: [PATCH 01/40] demo --- demo/browser.js | 0 demo/components/Button/index.js | 5 +++++ demo/components/Page.js | 12 ++++++++++++ demo/package.json | 16 ++++++++++++++++ demo/readme.md | 2 ++ demo/webpack.config.js | 28 ++++++++++++++++++++++++++++ demo/worker.js | 14 ++++++++++++++ 7 files changed, 77 insertions(+) create mode 100644 demo/browser.js create mode 100644 demo/components/Button/index.js create mode 100644 demo/components/Page.js create mode 100644 demo/package.json create mode 100644 demo/readme.md create mode 100644 demo/webpack.config.js create mode 100644 demo/worker.js diff --git a/demo/browser.js b/demo/browser.js new file mode 100644 index 0000000..e69de29 diff --git a/demo/components/Button/index.js b/demo/components/Button/index.js new file mode 100644 index 0000000..9569618 --- /dev/null +++ b/demo/components/Button/index.js @@ -0,0 +1,5 @@ +import React from 'react'; + +export default _ => ( + + ); diff --git a/demo/package.json b/demo/package.json index 8ddd8f0..62171af 100644 --- a/demo/package.json +++ b/demo/package.json @@ -5,12 +5,39 @@ "main": "worker.js", "scripts": { "compile": "webpack", - "start": "node worker", + "start": "node app/worker", "test": "echo \"Error: no test specified\" && exit 1" }, + "config": { + "css": "[name]_[local]__[hash:base64:5]", + "port": 3000 + }, "keywords": [ "css-modules" ], "author": "Alexey Litvinov", - "license": "MIT" + "license": "MIT", + "devDependencies": { + "babel-loader": "^6.2.1", + "css-loader": "^0.23.1", + "extract-text-webpack-plugin": "^1.0.1", + "style-loader": "^0.13.0", + "webpack": "^1.12.10" + }, + "dependencies": { + "babel-core": "^6.4.0", + "babel-preset-es2015": "^6.3.13", + "babel-preset-react": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "css-modules-require-hook": "^2.1.0", + "express": "^4.13.3", + "lodash": "^3.10.1", + "postcss": "^5.0.14", + "postcss-modules-extract-imports": "^1.0.0", + "postcss-modules-local-by-default": "^1.0.1", + "postcss-modules-scope": "^1.0.0", + "postcss-modules-values": "^1.1.1", + "react": "^0.14.6", + "react-dom": "^0.14.6" + } } diff --git a/demo/readme.md b/demo/readme.md index 6207029..69cda3c 100644 --- a/demo/readme.md +++ b/demo/readme.md @@ -1,2 +1,10 @@ Universal usage example ======================= + +## Usage + +```bash +npm i +npm run compile +npm run start +``` diff --git a/demo/webpack.config.js b/demo/webpack.config.js index 282b51b..8acf37c 100644 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -3,8 +3,10 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin'); const path = require('path'); +const config = require('./package').config; + module.exports = { - entry: path.resolve('browser.js'), + entry: path.resolve('app/browser.js'), output: { filename: 'browser.js', @@ -13,15 +15,21 @@ module.exports = { module: { loaders: [ + { + test: /\.js$/i, + exclude: /node_modules/, + loader: 'babel?presets[]=es2015,presets[]=react,presets[]=stage-0', + }, { test: /\.css$/i, - loader: ExtractTextPlugin.extract('style', 'css?modules'), + loader: ExtractTextPlugin.extract('style', + `css?modules&localIdentName=${config.css}`), }, ], }, plugins: [ - new ExtractTextPlugin('result.css', { + new ExtractTextPlugin('common.css', { allChunks: true }), ], diff --git a/demo/worker.js b/demo/worker.js deleted file mode 100644 index 8f8154a..0000000 --- a/demo/worker.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const express = require('express'); -const hook = require('css-modules-require-hook'); -const path = require('path'); - -const config = require('./package').config; -const app = express(); - -app.use(express.static(path.join(__dirname, 'static'))); - -app.get('/', (req, res) => res.render('page')); - -app.listen(config.port, _ => console.log(`listening ${config.port}`)); From 1df2a3192bf43ab2d9d8ba8391ef18d4b0f249fd Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 12 Feb 2016 22:33:29 +0300 Subject: [PATCH 03/40] common setup for the editor --- .editorconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c270cfa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +# cheat sheet: http://EditorConfig.org From 0a5c7bdef2a07285008f3edf57c4d5a1e1d37b8d Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 12 Feb 2016 22:34:07 +0300 Subject: [PATCH 04/40] the new tests --- lib/attachHook.js | 10 + lib/index.js | 89 ++++++ test/api/extensions.js | 20 ++ test/api/fixture/oceanic.css | 4 + test/api/processCss.js | 16 ++ test/cache.js | 101 ------- test/cases/webpack/.gitignore | 1 - test/cases/webpack/source.css | 4 - test/cases/webpack/source.js | 1 - test/common-test-cases.js | 272 ------------------ test/cssi/interchange-format/colors.css | 7 - test/cssi/interchange-format/expected.css | 6 - test/cssi/interchange-format/expected.json | 3 - test/cssi/interchange-format/source.css | 11 - test/cssi/pseudo-variables/colors.css | 4 - test/cssi/pseudo-variables/expected.css | 5 - test/cssi/pseudo-variables/expected.json | 3 - test/cssi/pseudo-variables/source.css | 13 - test/demo.css | 4 + test/extractor.js | 21 -- test/fixture/dynamic.css | 4 - test/plugins.js | 36 --- test/public-api.js | 137 --------- test/setup.js | 2 + test/sugar.js | 18 ++ .../compose-node-module/expected.css | 5 - .../compose-node-module/expected.json | 3 - .../test-cases/compose-node-module/source.css | 3 - test/test-cases/extra-extension/expected.json | 3 - test/test-cases/extra-extension/source.scss | 5 - test/test-cases/localise-export/expected.css | 9 - test/test-cases/localise-export/expected.json | 5 - test/test-cases/localise-export/source.css | 9 - test/test-cases/multiple-dependencies/b.css | 8 - test/test-cases/multiple-dependencies/c.css | 3 - test/test-cases/multiple-dependencies/d.css | 6 - .../multiple-dependencies/expected.css | 20 -- .../multiple-dependencies/expected.json | 3 - .../multiple-dependencies/source.css | 7 - test/test-cases/multiple-sources/b.css | 4 - test/test-cases/multiple-sources/c.css | 3 - test/test-cases/multiple-sources/d.css | 3 - test/test-cases/multiple-sources/expected.css | 15 - .../test-cases/multiple-sources/expected.json | 4 - test/test-cases/multiple-sources/source1.css | 5 - test/test-cases/multiple-sources/source2.css | 4 - test/test-cases/simple-export/expected.css | 7 - test/test-cases/simple-export/expected.json | 3 - test/test-cases/simple-export/source.css | 7 - .../single-import-export/colors.css | 7 - .../single-import-export/expected.css | 10 - .../single-import-export/expected.json | 3 - .../single-import-export/source.css | 4 - test/test-cases/values/borders.css | 3 - test/test-cases/values/breakpoints.css | 3 - test/test-cases/values/colors.css | 16 -- test/test-cases/values/expected.css | 35 --- test/test-cases/values/expected.json | 9 - test/test-cases/values/source.css | 24 -- test/utility.js | 18 -- 60 files changed, 163 insertions(+), 905 deletions(-) create mode 100644 lib/attachHook.js create mode 100644 lib/index.js create mode 100644 test/api/extensions.js create mode 100644 test/api/fixture/oceanic.css create mode 100644 test/api/processCss.js delete mode 100644 test/cache.js delete mode 100644 test/cases/webpack/.gitignore delete mode 100644 test/cases/webpack/source.css delete mode 100644 test/cases/webpack/source.js delete mode 100644 test/common-test-cases.js delete mode 100644 test/cssi/interchange-format/colors.css delete mode 100644 test/cssi/interchange-format/expected.css delete mode 100644 test/cssi/interchange-format/expected.json delete mode 100644 test/cssi/interchange-format/source.css delete mode 100644 test/cssi/pseudo-variables/colors.css delete mode 100644 test/cssi/pseudo-variables/expected.css delete mode 100644 test/cssi/pseudo-variables/expected.json delete mode 100644 test/cssi/pseudo-variables/source.css create mode 100644 test/demo.css delete mode 100644 test/extractor.js delete mode 100644 test/fixture/dynamic.css delete mode 100644 test/plugins.js delete mode 100644 test/public-api.js create mode 100644 test/setup.js create mode 100644 test/sugar.js delete mode 100644 test/test-cases/compose-node-module/expected.css delete mode 100644 test/test-cases/compose-node-module/expected.json delete mode 100644 test/test-cases/compose-node-module/source.css delete mode 100644 test/test-cases/extra-extension/expected.json delete mode 100644 test/test-cases/extra-extension/source.scss delete mode 100644 test/test-cases/localise-export/expected.css delete mode 100644 test/test-cases/localise-export/expected.json delete mode 100644 test/test-cases/localise-export/source.css delete mode 100644 test/test-cases/multiple-dependencies/b.css delete mode 100644 test/test-cases/multiple-dependencies/c.css delete mode 100644 test/test-cases/multiple-dependencies/d.css delete mode 100644 test/test-cases/multiple-dependencies/expected.css delete mode 100644 test/test-cases/multiple-dependencies/expected.json delete mode 100644 test/test-cases/multiple-dependencies/source.css delete mode 100644 test/test-cases/multiple-sources/b.css delete mode 100644 test/test-cases/multiple-sources/c.css delete mode 100644 test/test-cases/multiple-sources/d.css delete mode 100644 test/test-cases/multiple-sources/expected.css delete mode 100644 test/test-cases/multiple-sources/expected.json delete mode 100644 test/test-cases/multiple-sources/source1.css delete mode 100644 test/test-cases/multiple-sources/source2.css delete mode 100644 test/test-cases/simple-export/expected.css delete mode 100644 test/test-cases/simple-export/expected.json delete mode 100644 test/test-cases/simple-export/source.css delete mode 100644 test/test-cases/single-import-export/colors.css delete mode 100644 test/test-cases/single-import-export/expected.css delete mode 100644 test/test-cases/single-import-export/expected.json delete mode 100644 test/test-cases/single-import-export/source.css delete mode 100644 test/test-cases/values/borders.css delete mode 100644 test/test-cases/values/breakpoints.css delete mode 100644 test/test-cases/values/colors.css delete mode 100644 test/test-cases/values/expected.css delete mode 100644 test/test-cases/values/expected.json delete mode 100644 test/test-cases/values/source.css delete mode 100644 test/utility.js diff --git a/lib/attachHook.js b/lib/attachHook.js new file mode 100644 index 0000000..58e2043 --- /dev/null +++ b/lib/attachHook.js @@ -0,0 +1,10 @@ +/** + * @param {function} compile + * @param {string} extension + */ +module.exports = function attachHook(compile, extension) { + require.extensions[extension] = function cssModulesHook(m, filename) { + const tokens = compile(filename); + return m._compile(`module.exports = ${JSON.stringify(tokens)}`, filename); + }; +}; diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..e4ae107 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,89 @@ +const assign = require('lodash').assign; +const attachHook = require('./attachHook'); +const dirname = require('path').dirname; +const genericNames = require('generic-names'); +const identity = require('lodash').identity; +const readFileSync = require('fs').readFileSync; +const relative = require('path').relative; +const resolve = require('path').resolve; + +const postcss = require('postcss'); +const Values = require('postcss-modules-values'); +const LocalByDefault = require('postcss-modules-local-by-default'); +const ExtractImports = require('postcss-modules-extract-imports'); +const Scope = require('postcss-modules-scope'); +const Parser = require('postcss-modules-parser'); + +module.exports = function setupHook({ + extensions = '.css', + preprocessCss = identity, + processCss, + to, + append = [], + prepend = [], + createImportedName, + generateScopedName, + mode, + use, + rootDir: context = process.cwd(), +}) { + const tokensByFile = {}; + + let scopedName = function () {}; + if (generateScopedName) { + scopedName = typeof generateScopedName !== 'function' + ? genericNames(generateScopedName || '[name]__[local]___[hash:base64:5]', {context}) + : generateScopedName; + } else { + // small fallback + scopedName = (local, filename) => Scope.generateScopedName(local, relative(context, filename)); + } + + const plugins = [ + ...prepend, + Values, + mode + ? new LocalByDefault({mode}) + : LocalByDefault, + createImportedName + ? new ExtractImports({createImportedName}) + : ExtractImports, + new Scope({generateScopedName: scopedName}), + ...append, + ].concat(new Parser({fetch})); // no pushing in order to avoid the possible mutations; + + // https://github.com/postcss/postcss#options + const runner = postcss(plugins); + + // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts + + function fetch(_to, from) { + // getting absolute path to the processing file + const filename = /\w/i.test(_to[0]) + ? require.resolve(_to) + : resolve(dirname(from), _to); + + // checking cache + let tokens = tokensByFile[filename]; + if (tokens) { + return tokens; + } + + const source = preprocessCss(readFileSync(filename, 'utf8'), filename); + // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts + const lazyResult = runner.process(source, assign({}, {from: filename})); + + // https://github.com/postcss/postcss/blob/master/docs/api.md#lazywarnings + lazyResult.warnings().forEach(message => console.warn(message.text)); + + tokens = lazyResult.root.tokens; + + if (processCss) { + processCss(lazyResult.css, filename); + } + + return tokens; + }; + + attachHook(filename => fetch(filename, filename), '.css'); +}; diff --git a/test/api/extensions.js b/test/api/extensions.js new file mode 100644 index 0000000..cb44e31 --- /dev/null +++ b/test/api/extensions.js @@ -0,0 +1,20 @@ +const dropCache = require('../sugar').dropCache; +const dropHook = require('../sugar').dropHook; +const identity = require('lodash').identity; +const spy = require('sinon').spy; + +suite('api/extensions', () => { + suite('uses .css by default', () => { + test('should provide tokens', () => { + const tokens = require('./fixture/oceanic.css'); + assert(tokens); + }); + + setup(() => hook({})); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + dropHook('.css'); + }); + }); +}); diff --git a/test/api/fixture/oceanic.css b/test/api/fixture/oceanic.css new file mode 100644 index 0000000..7e4881c --- /dev/null +++ b/test/api/fixture/oceanic.css @@ -0,0 +1,4 @@ +.color +{ + background: #1e2a35; +} diff --git a/test/api/processCss.js b/test/api/processCss.js new file mode 100644 index 0000000..30dcca3 --- /dev/null +++ b/test/api/processCss.js @@ -0,0 +1,16 @@ +const dropCache = require('../sugar').dropCache; +const identity = require('lodash').identity; +const spy = require('sinon').spy; + +suite('api/processCss()', () => { + const processCss = spy(identity); + + test('should be called', () => assert(processCss.called)); + + setup(() => { + hook({processCss: processCss}); + require('./fixture/oceanic.css'); + }); + + teardown(() => dropCache('./api/fixture/oceanic.css')); +}); diff --git a/test/cache.js b/test/cache.js deleted file mode 100644 index 5329e8e..0000000 --- a/test/cache.js +++ /dev/null @@ -1,101 +0,0 @@ -import { equal } from 'assert'; -import { writeFileSync } from 'fs'; -import { join } from 'path'; -import { dropCache } from '../utils/sugar'; -import hook from '../src'; - -const fixture = join(__dirname, 'fixture/dynamic.css'); - -function updateFile(content) { - writeFileSync(fixture, content, 'utf8'); -} - -describe('development mode', () => { - describe('shouldn`t calls cache in development mode', () => { - describe('devMode:false options should override NODE_ENV="development"', () => { - before(() => { - hook({ devMode: false }); - updateFile('.block\n{\n display: block;\n}'); - process.env.NODE_ENV = 'development'; - require(fixture); - updateFile('.inline-block\n{\n display: inline-block;\n}'); - }); - - after(() => { - process.env.NODE_ENV = ''; - dropCache(fixture); - }); - - it('should retrive data from cache', () => { - const tokens = require(fixture); - const keys = Object.keys(tokens); - equal(keys.length, 1); - equal(keys.join(''), 'block'); - }); - }); - - describe('should cache calls without any options', () => { - before(() => { - hook(); - updateFile('.block\n{\n display: block;\n}'); - require(fixture); - updateFile('.inline-block\n{\n display: inline-block;\n}'); - }); - - after(() => { - dropCache(fixture); - }); - - it('should retrive data from cache', () => { - const tokens = require(fixture); - const keys = Object.keys(tokens); - equal(keys.length, 1); - equal(keys.join(''), 'block'); - }); - }); - }); - - describe('should clear cache in development mode', () => { - describe('devMode:true option should works without NODE_ENV="development"', () => { - before(() => { - hook({ devMode: true }); - updateFile('.block\n{\n display: block;\n}'); - require(fixture); - updateFile('.inline-block\n{\n display: inline-block;\n}'); - }); - - after(() => { - dropCache(fixture); - }); - - it('should retrive data from fs', () => { - const tokens = require(fixture); - const keys = Object.keys(tokens); - equal(keys.length, 1); - equal(keys.join(''), 'inline-block'); - }); - }); - - describe('NODE_ENV="development" should works without debug:true option', () => { - before(() => { - hook(); - updateFile('.block\n{\n display: block;\n}'); - process.env.NODE_ENV = 'development'; - require(fixture); - updateFile('.inline-block\n{\n display: inline-block;\n}'); - }); - - after(() => { - process.env.NODE_ENV = ''; - dropCache(fixture); - }); - - it('should retrive data from fs', () => { - const tokens = require(fixture); - const keys = Object.keys(tokens); - equal(keys.length, 1); - equal(keys.join(''), 'inline-block'); - }); - }); - }); -}); diff --git a/test/cases/webpack/.gitignore b/test/cases/webpack/.gitignore deleted file mode 100644 index fcfc4a1..0000000 --- a/test/cases/webpack/.gitignore +++ /dev/null @@ -1 +0,0 @@ -result* diff --git a/test/cases/webpack/source.css b/test/cases/webpack/source.css deleted file mode 100644 index c8481a9..0000000 --- a/test/cases/webpack/source.css +++ /dev/null @@ -1,4 +0,0 @@ -.local -{ - color: white; -} diff --git a/test/cases/webpack/source.js b/test/cases/webpack/source.js deleted file mode 100644 index ae1bf86..0000000 --- a/test/cases/webpack/source.js +++ /dev/null @@ -1 +0,0 @@ -var css = require('./source.css'); diff --git a/test/common-test-cases.js b/test/common-test-cases.js deleted file mode 100644 index c0774c6..0000000 --- a/test/common-test-cases.js +++ /dev/null @@ -1,272 +0,0 @@ -import { dropCache } from '../utils/sugar'; -import { equal } from 'assert'; -import { readFileSync } from 'fs'; -import { resolve } from 'path'; -import { extend } from 'lodash'; -import FileSystemLoader from 'css-modules-loader-core/lib/file-system-loader'; -import hook from '../src'; - -const normalize = str => str.replace(/\r\n?/g, '\n'); -const pipelines = { - 'test-cases': undefined, - 'cssi': [], -}; - -let expectedCSS; -let expectedTokens; - -describe('common-test-cases', () => { - - describe('test-cases', () => { - - describe('compose node module', () => { - before(() => { - dropCache(resolve('test/test-cases/compose-node-module/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/compose-node-module/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/compose-node-module/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it.skip('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('compose-node-module/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/compose-node-module/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('extra extension', () => { - before(() => { - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/extra-extension/expected.json'), 'utf8')); - hook({extensions: ['.scss']}); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/extra-extension/source.scss')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - - }); - - describe('localise export', () => { - before(() => { - dropCache(resolve('test/test-cases/localise-export/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/localise-export/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/localise-export/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('localise-export/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/localise-export/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('multiple dependencies', () => { - before(() => { - dropCache(resolve('test/test-cases/multiple-dependencies/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/multiple-dependencies/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/multiple-dependencies/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('multiple-dependencies/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/multiple-dependencies/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('multiple sources', () => { - before(() => { - dropCache(resolve('test/test-cases/multiple-sources/source1.css')); - dropCache(resolve('test/test-cases/multiple-sources/source2.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/multiple-sources/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/multiple-sources/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('multiple-sources/source1.css', '/').then(tokens1 => { - loader.fetch('multiple-sources/source2.css', '/').then(tokens2 => { - equal(loader.finalSource, expectedCSS); - const tokens = extend({}, tokens1, tokens2); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }).then(done, done); - }).catch(done); - }); - - it('require-hook', () => { - const tokens = extend({}, - require(resolve('test/test-cases/multiple-sources/source1.css')), - require(resolve('test/test-cases/multiple-sources/source2.css')) - ); - - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('simple export', () => { - before(() => { - dropCache(resolve('test/test-cases/simple-export/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/simple-export/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/simple-export/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('simple-export/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/simple-export/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('single import export', () => { - before(() => { - dropCache(resolve('test/test-cases/single-import-export/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/single-import-export/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/single-import-export/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('single-import-export/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/single-import-export/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('values', () => { - before(() => { - dropCache(resolve('test/test-cases/values/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/test-cases/values/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/test-cases/values/expected.json'), 'utf8')); - hook({rootDir: resolve('test/test-cases'), use: pipelines['test-cases']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/test-cases'), pipelines['test-cases']); - - loader.fetch('values/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/test-cases/values/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - }); - - describe('cssi', () => { - - describe('interchange format', () => { - before(() => { - dropCache(resolve('test/cssi/interchange-format/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/cssi/interchange-format/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/cssi/interchange-format/expected.json'), 'utf8')); - hook({rootDir: resolve('test/cssi'), use: pipelines['cssi']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/cssi'), pipelines['cssi']); - - loader.fetch('interchange-format/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/cssi/interchange-format/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - describe('pseudo variables', () => { - before(() => { - dropCache(resolve('test/cssi/pseudo-variables/source.css')); - expectedCSS = normalize(readFileSync(resolve('test/cssi/pseudo-variables/expected.css'), 'utf8')); - expectedTokens = JSON.parse(readFileSync(resolve('test/cssi/pseudo-variables/expected.json'), 'utf8')); - hook({rootDir: resolve('test/cssi'), use: pipelines['cssi']}); - }); - - it('loader-core', done => { - const loader = new FileSystemLoader(resolve('test/cssi'), pipelines['cssi']); - - loader.fetch('pseudo-variables/source.css', '/') - .then(tokens => { - equal(loader.finalSource, expectedCSS); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }) - .then(done, done); - }); - - it('require-hook', () => { - const tokens = require(resolve('test/cssi/pseudo-variables/source.css')); - equal(JSON.stringify(tokens), JSON.stringify(expectedTokens)); - }); - }); - - }); - -}); diff --git a/test/cssi/interchange-format/colors.css b/test/cssi/interchange-format/colors.css deleted file mode 100644 index 4057aae..0000000 --- a/test/cssi/interchange-format/colors.css +++ /dev/null @@ -1,7 +0,0 @@ -:export { - blackShadow: x__single_import_export_colors__blackShadow; -} - -.x__single_import_export_colors__blackShadow { - box-shadow: 0 0 10px -2px black; -} diff --git a/test/cssi/interchange-format/expected.css b/test/cssi/interchange-format/expected.css deleted file mode 100644 index 36f1092..0000000 --- a/test/cssi/interchange-format/expected.css +++ /dev/null @@ -1,6 +0,0 @@ -.x__single_import_export_colors__blackShadow { - box-shadow: 0 0 10px -2px black; -} -.x__single_import_export_source__localName { - color: red; -} diff --git a/test/cssi/interchange-format/expected.json b/test/cssi/interchange-format/expected.json deleted file mode 100644 index 43311c7..0000000 --- a/test/cssi/interchange-format/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "localName": "x__single_import_export_source__localName x__single_import_export_colors__blackShadow" -} diff --git a/test/cssi/interchange-format/source.css b/test/cssi/interchange-format/source.css deleted file mode 100644 index d7125a0..0000000 --- a/test/cssi/interchange-format/source.css +++ /dev/null @@ -1,11 +0,0 @@ -:import("./colors.css") { - i__tmp_import_djhgdsag: blackShadow; -} - -:export { - localName: x__single_import_export_source__localName i__tmp_import_djhgdsag; -} - -.x__single_import_export_source__localName { - color: red; -} diff --git a/test/cssi/pseudo-variables/colors.css b/test/cssi/pseudo-variables/colors.css deleted file mode 100644 index 3ac72d9..0000000 --- a/test/cssi/pseudo-variables/colors.css +++ /dev/null @@ -1,4 +0,0 @@ -:export { - black: #222; - white: #ddd; -} diff --git a/test/cssi/pseudo-variables/expected.css b/test/cssi/pseudo-variables/expected.css deleted file mode 100644 index 371497c..0000000 --- a/test/cssi/pseudo-variables/expected.css +++ /dev/null @@ -1,5 +0,0 @@ - -.x__lol { - color: #222; - background: #ddd; -} diff --git a/test/cssi/pseudo-variables/expected.json b/test/cssi/pseudo-variables/expected.json deleted file mode 100644 index b8c3c23..0000000 --- a/test/cssi/pseudo-variables/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lol": "x__lol" -} diff --git a/test/cssi/pseudo-variables/source.css b/test/cssi/pseudo-variables/source.css deleted file mode 100644 index cc4b95a..0000000 --- a/test/cssi/pseudo-variables/source.css +++ /dev/null @@ -1,13 +0,0 @@ -:import("./colors.css") { - i__black: black; - i__white: white; -} - -:export { - lol: x__lol; -} - -.x__lol { - color: i__black; - background: i__white; -} diff --git a/test/demo.css b/test/demo.css new file mode 100644 index 0000000..15aa57d --- /dev/null +++ b/test/demo.css @@ -0,0 +1,4 @@ +.app +{ + background: white; +} \ No newline at end of file diff --git a/test/extractor.js b/test/extractor.js deleted file mode 100644 index 8dcb64a..0000000 --- a/test/extractor.js +++ /dev/null @@ -1,21 +0,0 @@ -import { equal } from 'assert'; -import { execSync } from 'child_process'; -import { readFileSync } from 'fs'; -import { resolve } from 'path'; -import hook from '../src'; - -describe('extractor', () => { - let selector; - - before(() => { - hook({generateScopedName: '[name]__[local]___[hash:base64:5]'}); - execSync('npm run fixture', {cwd: process.cwd()}); - selector = readFileSync(resolve('test/cases/webpack/result.css'), 'utf8') - .split('\n').shift().replace(/^\./, ''); - }); - - it('should generate the same selectors as the webpack does', () => { - const tokens = require('./cases/webpack/source.css'); - equal(selector, tokens.local); - }); -}); diff --git a/test/fixture/dynamic.css b/test/fixture/dynamic.css deleted file mode 100644 index d34188e..0000000 --- a/test/fixture/dynamic.css +++ /dev/null @@ -1,4 +0,0 @@ -.inline-block -{ - display: inline-block; -} \ No newline at end of file diff --git a/test/plugins.js b/test/plugins.js deleted file mode 100644 index 5e804cb..0000000 --- a/test/plugins.js +++ /dev/null @@ -1,36 +0,0 @@ -import { equal } from 'assert'; -import { identity } from 'lodash'; -import { dropCache } from '../utils/sugar'; -import hook from '../src'; - -import ExtractImports from 'postcss-modules-extract-imports'; -import LocalByDefault from 'postcss-modules-local-by-default'; -import Scope from 'postcss-modules-scope'; - -describe('plugins', () => { - afterEach(() => dropCache('awesome-theme/oceanic.css')); - - describe('custom generateScopedName() function', () => { - before(() => hook({generateScopedName: identity})); - - it('tokens should have the same generated names', () => { - const tokens = require('awesome-theme/oceanic.css'); - equal(tokens.color, 'color'); - }); - }); - - describe('explicit way to set generateScopedName() function', () => { - before(() => hook({ - use: [ - ExtractImports, - LocalByDefault, - new Scope({generateScopedName: identity}), - ], - })); - - it('tokens should have the same generated names', () => { - const tokens = require('awesome-theme/oceanic.css'); - equal(tokens.color, 'color'); - }); - }); -}); diff --git a/test/public-api.js b/test/public-api.js deleted file mode 100644 index d29beee..0000000 --- a/test/public-api.js +++ /dev/null @@ -1,137 +0,0 @@ -import { noop } from 'lodash'; -import { equal, ok } from 'assert'; -import { dropCache, spy, Through } from '../utils/sugar'; -import hook from '../src'; - -describe('public api', () => { - afterEach(() => dropCache('awesome-theme/oceanic.css')); - - describe('extending list of plugins', () => { - describe('"prepend" should add plugins in the beginning of the pipeline', () => { - let processor; - - beforeEach(() => { - processor = spy(noop); - - hook({ - prepend: [ - new Through({processor: processor}), - ], - }); - - require('awesome-theme/oceanic.css'); - }); - - it('processor should be called', () => - ok(processor.called)); - }); - - describe('"append" should add plugins to the pipeline', () => { - let processor; - - beforeEach(() => { - processor = spy(noop); - - hook({ - append: [ - new Through({processor: processor}), - ], - }); - - require('awesome-theme/oceanic.css'); - }); - - it('processor should be called', () => - ok(processor.called)); - }); - - describe('"use" should set the new list of plugins', () => { - let appendProcessor; - let prependProcessor; - let useProcessor; - - beforeEach(() => { - appendProcessor = spy(noop); - prependProcessor = spy(noop); - useProcessor = spy(noop); - - hook({ - append: [ - new Through({processor: appendProcessor}), - ], - prepend: [ - new Through({processor: prependProcessor}), - ], - use: [ - new Through({processor: useProcessor}), - ], - }); - - require('awesome-theme/oceanic.css'); - }); - - it('plugin added by append option should not be called', () => - ok(!appendProcessor.called)); - - it('plugin added by prepend option should not be called', () => - ok(!prependProcessor.called)); - - it('plugin added by use option should be called', () => - ok(useProcessor.called)); - }); - }); - - describe('setting custom processors for the CSS', () => { - describe('"preprocessCss()" should transform CSS before the PostCSS', () => { - let processor; - let providedFilename; - let providedContent; - - beforeEach(() => { - processor = spy((content, filename) => { - providedFilename = filename; - providedContent = content; - return ''; - }); - - hook({preprocessCss: processor}); - require('awesome-theme/oceanic.css'); - }); - - it('processor should be called', () => - ok(processor.called)); - - it('filename should be provided', () => - equal(providedFilename, require.resolve('awesome-theme/oceanic.css'))); - - it('content of the file should be provided', () => - ok(providedContent.length)); - }); - - describe('"processCss()" should transform CSS after the PostCSS', () => { - let processor; - let providedFilename; - let providedContent; - - beforeEach(() => { - processor = spy((content, filename) => { - providedFilename = filename; - providedContent = content; - return ''; - }); - - hook({processCss: processor}); - require('awesome-theme/oceanic.css'); - }); - - it('processor should be called', () => - ok(processor.called)); - - it('filename should be provided', () => - equal(providedFilename, require.resolve('awesome-theme/oceanic.css'))); - - it('content of the file should be provided', () => - ok(providedContent.length)); - }); - }); -}); diff --git a/test/setup.js b/test/setup.js new file mode 100644 index 0000000..c3b614f --- /dev/null +++ b/test/setup.js @@ -0,0 +1,2 @@ +global.assert = require('assert'); +global.hook = require('../'); diff --git a/test/sugar.js b/test/sugar.js new file mode 100644 index 0000000..6cfb37b --- /dev/null +++ b/test/sugar.js @@ -0,0 +1,18 @@ +/** + * Drops require cache for the certain module + * + * @param {string} modulePath + */ +function dropCache(modulePath) { + delete require.cache[require.resolve(modulePath)]; +}; + +/** + * @param {string} extension + */ +function dropHook(extension) { + delete require.extensions[extension]; +} + +exports.dropCache = dropCache; +exports.dropHook = dropHook; diff --git a/test/test-cases/compose-node-module/expected.css b/test/test-cases/compose-node-module/expected.css deleted file mode 100644 index 0667b94..0000000 --- a/test/test-cases/compose-node-module/expected.css +++ /dev/null @@ -1,5 +0,0 @@ -._compose_node_module_cool_styles_foo__example { - color: #F00; -} -._compose_node_module_source__foo { -} diff --git a/test/test-cases/compose-node-module/expected.json b/test/test-cases/compose-node-module/expected.json deleted file mode 100644 index c4555ba..0000000 --- a/test/test-cases/compose-node-module/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "foo": "_compose_node_module_source__foo _node_modules_awesome_theme_common__paragraph _node_modules_awesome_theme_oceanic__color" -} diff --git a/test/test-cases/compose-node-module/source.css b/test/test-cases/compose-node-module/source.css deleted file mode 100644 index 4d73aec..0000000 --- a/test/test-cases/compose-node-module/source.css +++ /dev/null @@ -1,3 +0,0 @@ -.foo { - composes: paragraph from "awesome-theme/common.css"; -} diff --git a/test/test-cases/extra-extension/expected.json b/test/test-cases/extra-extension/expected.json deleted file mode 100644 index 9c3b35c..0000000 --- a/test/test-cases/extra-extension/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "localName": "_test_test_cases_extra_extension_source__localName" -} diff --git a/test/test-cases/extra-extension/source.scss b/test/test-cases/extra-extension/source.scss deleted file mode 100644 index cc61ab6..0000000 --- a/test/test-cases/extra-extension/source.scss +++ /dev/null @@ -1,5 +0,0 @@ -$color: #c0ffee; - -.localName { - color: $color; -} diff --git a/test/test-cases/localise-export/expected.css b/test/test-cases/localise-export/expected.css deleted file mode 100644 index c4be0d9..0000000 --- a/test/test-cases/localise-export/expected.css +++ /dev/null @@ -1,9 +0,0 @@ -._localise_export_source__one { - color: red; -} -._localise_export_source__two { - color: green; -} -._localise_export_source__three { - color: blue; -} diff --git a/test/test-cases/localise-export/expected.json b/test/test-cases/localise-export/expected.json deleted file mode 100644 index 85eb15c..0000000 --- a/test/test-cases/localise-export/expected.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "one": "_localise_export_source__one", - "two": "_localise_export_source__two", - "three": "_localise_export_source__three" -} diff --git a/test/test-cases/localise-export/source.css b/test/test-cases/localise-export/source.css deleted file mode 100644 index 8fdc200..0000000 --- a/test/test-cases/localise-export/source.css +++ /dev/null @@ -1,9 +0,0 @@ -:local(.one) { - color: red; -} -:local(.two) { - color: green; -} -:local(.three) { - color: blue; -} diff --git a/test/test-cases/multiple-dependencies/b.css b/test/test-cases/multiple-dependencies/b.css deleted file mode 100644 index e29560a..0000000 --- a/test/test-cases/multiple-dependencies/b.css +++ /dev/null @@ -1,8 +0,0 @@ -.b1 { - composes: d1 d2 from "./d.css"; - color: #b1b1b1; -} - -.b2 { - color: #b2b2b2; -} diff --git a/test/test-cases/multiple-dependencies/c.css b/test/test-cases/multiple-dependencies/c.css deleted file mode 100644 index e5a7b52..0000000 --- a/test/test-cases/multiple-dependencies/c.css +++ /dev/null @@ -1,3 +0,0 @@ -.c { - color: #ccc; -} diff --git a/test/test-cases/multiple-dependencies/d.css b/test/test-cases/multiple-dependencies/d.css deleted file mode 100644 index 4e7ec24..0000000 --- a/test/test-cases/multiple-dependencies/d.css +++ /dev/null @@ -1,6 +0,0 @@ -.d1 { - color: #d1d1d1; -} -.d2 { - color: #d2d2d2; -} diff --git a/test/test-cases/multiple-dependencies/expected.css b/test/test-cases/multiple-dependencies/expected.css deleted file mode 100644 index 01b0d9f..0000000 --- a/test/test-cases/multiple-dependencies/expected.css +++ /dev/null @@ -1,20 +0,0 @@ -._multiple_dependencies_d__d1 { - color: #d1d1d1; -} -._multiple_dependencies_d__d2 { - color: #d2d2d2; -} -._multiple_dependencies_b__b1 { - color: #b1b1b1; -} - -._multiple_dependencies_b__b2 { - color: #b2b2b2; -} -._multiple_dependencies_c__c { - color: #ccc; -} -._multiple_dependencies_source__a { - color: #aaa; -} - diff --git a/test/test-cases/multiple-dependencies/expected.json b/test/test-cases/multiple-dependencies/expected.json deleted file mode 100644 index 7327ebb..0000000 --- a/test/test-cases/multiple-dependencies/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "a": "_multiple_dependencies_source__a _multiple_dependencies_b__b1 _multiple_dependencies_d__d1 _multiple_dependencies_d__d2 _multiple_dependencies_b__b2 _multiple_dependencies_c__c something-global" -} diff --git a/test/test-cases/multiple-dependencies/source.css b/test/test-cases/multiple-dependencies/source.css deleted file mode 100644 index 0824a26..0000000 --- a/test/test-cases/multiple-dependencies/source.css +++ /dev/null @@ -1,7 +0,0 @@ -.a { - composes: b1 b2 from "./b.css"; - composes: c from "./c.css"; - composes: something-global from global; - color: #aaa; -} - diff --git a/test/test-cases/multiple-sources/b.css b/test/test-cases/multiple-sources/b.css deleted file mode 100644 index c4dcd92..0000000 --- a/test/test-cases/multiple-sources/b.css +++ /dev/null @@ -1,4 +0,0 @@ -.b { - composes: d from "./d.css"; - color: #bbb; -} diff --git a/test/test-cases/multiple-sources/c.css b/test/test-cases/multiple-sources/c.css deleted file mode 100644 index e5a7b52..0000000 --- a/test/test-cases/multiple-sources/c.css +++ /dev/null @@ -1,3 +0,0 @@ -.c { - color: #ccc; -} diff --git a/test/test-cases/multiple-sources/d.css b/test/test-cases/multiple-sources/d.css deleted file mode 100644 index 4638a27..0000000 --- a/test/test-cases/multiple-sources/d.css +++ /dev/null @@ -1,3 +0,0 @@ -.d { - color: #ddd; -} diff --git a/test/test-cases/multiple-sources/expected.css b/test/test-cases/multiple-sources/expected.css deleted file mode 100644 index da64401..0000000 --- a/test/test-cases/multiple-sources/expected.css +++ /dev/null @@ -1,15 +0,0 @@ -._multiple_sources_d__d { - color: #ddd; -} -._multiple_sources_b__b { - color: #bbb; -} -._multiple_sources_c__c { - color: #ccc; -} -._multiple_sources_source1__a { - color: #aaa; -} -._multiple_sources_source2__foo { - color: #f00; -} diff --git a/test/test-cases/multiple-sources/expected.json b/test/test-cases/multiple-sources/expected.json deleted file mode 100644 index 074abf9..0000000 --- a/test/test-cases/multiple-sources/expected.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "a": "_multiple_sources_source1__a _multiple_sources_b__b _multiple_sources_d__d _multiple_sources_c__c", - "foo": "_multiple_sources_source2__foo _multiple_sources_b__b _multiple_sources_d__d" -} diff --git a/test/test-cases/multiple-sources/source1.css b/test/test-cases/multiple-sources/source1.css deleted file mode 100644 index 983c7fd..0000000 --- a/test/test-cases/multiple-sources/source1.css +++ /dev/null @@ -1,5 +0,0 @@ -.a { - composes: b from "./b.css"; - composes: c from "./c.css"; - color: #aaa; -} diff --git a/test/test-cases/multiple-sources/source2.css b/test/test-cases/multiple-sources/source2.css deleted file mode 100644 index 151a720..0000000 --- a/test/test-cases/multiple-sources/source2.css +++ /dev/null @@ -1,4 +0,0 @@ -.foo { - composes: b from "./b.css"; - color: #f00; -} diff --git a/test/test-cases/simple-export/expected.css b/test/test-cases/simple-export/expected.css deleted file mode 100644 index 2f8e4da..0000000 --- a/test/test-cases/simple-export/expected.css +++ /dev/null @@ -1,7 +0,0 @@ -._simple_export_source__localName { - color: red; -} - -._simple_export_source__localName:hover { - color: blue; -} diff --git a/test/test-cases/simple-export/expected.json b/test/test-cases/simple-export/expected.json deleted file mode 100644 index c8ee742..0000000 --- a/test/test-cases/simple-export/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "localName": "_simple_export_source__localName" -} diff --git a/test/test-cases/simple-export/source.css b/test/test-cases/simple-export/source.css deleted file mode 100644 index fbb8713..0000000 --- a/test/test-cases/simple-export/source.css +++ /dev/null @@ -1,7 +0,0 @@ -.localName { - color: red; -} - -.localName:hover { - color: blue; -} diff --git a/test/test-cases/single-import-export/colors.css b/test/test-cases/single-import-export/colors.css deleted file mode 100644 index a7c1ce1..0000000 --- a/test/test-cases/single-import-export/colors.css +++ /dev/null @@ -1,7 +0,0 @@ -.blackShadow { - box-shadow: 0 0 10px -2px black; -} - -.redBorder { - border: 1px solid red; -} diff --git a/test/test-cases/single-import-export/expected.css b/test/test-cases/single-import-export/expected.css deleted file mode 100644 index 74398b2..0000000 --- a/test/test-cases/single-import-export/expected.css +++ /dev/null @@ -1,10 +0,0 @@ -._single_import_export_colors__blackShadow { - box-shadow: 0 0 10px -2px black; -} - -._single_import_export_colors__redBorder { - border: 1px solid red; -} -._single_import_export_source__localName { - color: red; -} diff --git a/test/test-cases/single-import-export/expected.json b/test/test-cases/single-import-export/expected.json deleted file mode 100644 index 802cd4e..0000000 --- a/test/test-cases/single-import-export/expected.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "localName": "_single_import_export_source__localName _single_import_export_colors__blackShadow _single_import_export_colors__redBorder" -} diff --git a/test/test-cases/single-import-export/source.css b/test/test-cases/single-import-export/source.css deleted file mode 100644 index 57dbc17..0000000 --- a/test/test-cases/single-import-export/source.css +++ /dev/null @@ -1,4 +0,0 @@ -.localName { - composes: blackShadow redBorder from "./colors.css"; - color: red; -} diff --git a/test/test-cases/values/borders.css b/test/test-cases/values/borders.css deleted file mode 100644 index f3670f7..0000000 --- a/test/test-cases/values/borders.css +++ /dev/null @@ -1,3 +0,0 @@ -.dashed { - border: 4px dashed; -} diff --git a/test/test-cases/values/breakpoints.css b/test/test-cases/values/breakpoints.css deleted file mode 100644 index 0b80b8b..0000000 --- a/test/test-cases/values/breakpoints.css +++ /dev/null @@ -1,3 +0,0 @@ -@value small (max-width: 599px); -@value medium (min-width: 600px) and (max-width: 959px); -@value large (min-width: 960px); diff --git a/test/test-cases/values/colors.css b/test/test-cases/values/colors.css deleted file mode 100644 index ff83776..0000000 --- a/test/test-cases/values/colors.css +++ /dev/null @@ -1,16 +0,0 @@ -@value primary: #f01; -@value secondary: #2f2; - -.text-primary { - color: primary; -} -.bg-primary { - background-color: primary; -} - -.text-secondary { - color: secondary; -} -.bg-secondary { - background-color: secondary; -} diff --git a/test/test-cases/values/expected.css b/test/test-cases/values/expected.css deleted file mode 100644 index 0562fb8..0000000 --- a/test/test-cases/values/expected.css +++ /dev/null @@ -1,35 +0,0 @@ -._values_borders__dashed { - border: 4px dashed; -} - -._values_colors__text-primary { - color: #f01; -} -._values_colors__bg-primary { - background-color: #f01; -} - -._values_colors__text-secondary { - color: #2f2; -} -._values_colors__bg-secondary { - background-color: #2f2; -} -/* Imports without a "from" are just passed through */ -@import url('./old-skool.css'); - -._values_source__foo { - box-shadow: 0 0 10px #f01; - border-color: #2f2; -} - -@media (max-width: 599px) { - ._values_source__foo { - background: white; - } -} -@media (min-width: 600px) and (max-width: 959px) { - ._values_source__foo { - background: peru; - } -} diff --git a/test/test-cases/values/expected.json b/test/test-cases/values/expected.json deleted file mode 100644 index ee98683..0000000 --- a/test/test-cases/values/expected.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "borders": "\"./borders.css\"", - "breakpoints": "\"./breakpoints.css\"", - "small": "(max-width: 599px)", - "medium": "(min-width: 600px) and (max-width: 959px)", - "secondary": "#2f2", - "blue": "#f01", - "foo": "_values_source__foo _values_borders__dashed _values_colors__text-secondary" -} diff --git a/test/test-cases/values/source.css b/test/test-cases/values/source.css deleted file mode 100644 index 2c63c32..0000000 --- a/test/test-cases/values/source.css +++ /dev/null @@ -1,24 +0,0 @@ -@value borders: "./borders.css", breakpoints: "./breakpoints.css"; -@value small, medium from breakpoints; -@value secondary, primary as blue from "./colors.css"; - -/* Imports without a "from" are just passed through */ -@import url('./old-skool.css'); - -.foo { - composes: dashed from borders; - composes: text-secondary from "./colors.css"; - box-shadow: 0 0 10px blue; - border-color: secondary; -} - -@media small { - .foo { - background: white; - } -} -@media medium { - .foo { - background: peru; - } -} diff --git a/test/utility.js b/test/utility.js deleted file mode 100644 index 8e4c7cf..0000000 --- a/test/utility.js +++ /dev/null @@ -1,18 +0,0 @@ -import { ok } from 'assert'; -import { is } from '../src/utility'; - -describe('utility', () => { - describe('is()', () => { - it('should return true for an array', () => ok(is('array', []))); - - it('should return false for not an array', () => ok(!is('array', null))); - - it('should return true for a function', () => ok(is('function', () => {}))); - - it('should return false for not a function', () => ok(!is('function', null))); - - it('should return true for a string', () => ok(is('string', ''))); - - it('should return false for not a string', () => ok(!is('string', null))); - }); -}); From 9d34fd3cfaa9fa72a49fa8b661c3bd87bae2e887 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 12 Feb 2016 23:07:24 +0300 Subject: [PATCH 05/40] raw preset implementation --- preset.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 preset.js diff --git a/preset.js b/preset.js new file mode 100644 index 0000000..fb9dddd --- /dev/null +++ b/preset.js @@ -0,0 +1,10 @@ +const hook = require('.'); +const lookup = require('lookup-fs'); + +lookup('css-modules-file.js', (err, cssModulesFilePath) => { + if (err) { + throw new Error('Unable to find css-modules-file.js'); + } + + hook(require(cssModulesFilePath)); +}); From 18e9c9b673380ca2ae23d3382852490c082e256d Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 12 Feb 2016 23:07:43 +0300 Subject: [PATCH 06/40] package update --- package.json | 79 +++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index 546f7c8..0e95b1e 100644 --- a/package.json +++ b/package.json @@ -1,63 +1,15 @@ { "name": "css-modules-require-hook", - "version": "2.1.1", + "version": "3.0.0", "description": "A require hook to compile CSS Modules on the fly", - "main": "index.js", + "main": "lib/index.js", "engines": { "node": ">=0.12" }, - "dependencies": { - "debug": "^2.2.0", - "generic-names": "^1.0.1", - "icss-replace-symbols": "^1.0.2", - "lodash.assign": "^3.2.0", - "lodash.foreach": "^3.0.3", - "lodash.identity": "^3.0.0", - "lodash.isarray": "^3.0.4", - "lodash.isfunction": "^3.0.6", - "lodash.isstring": "^3.0.1", - "postcss-modules-parser": "^1.1.0" - }, - "devDependencies": { - "babel": "^5.8.20", - "babel-eslint": "^4.0.5", - "css-loader": "^0.21.0", - "css-modules-loader-core": "^1.0.0", - "eslint": "^1.0.0", - "eslint-config-airbnb": "0.0.7", - "eslint-config-airbnb-lite": "^1.0.3", - "eslint-watch": "^1.2.4", - "extract-text-webpack-plugin": "^0.8.2", - "in-publish": "^2.0.0", - "isparta": "^3.0.3", - "lodash": "^3.10.1", - "mocha": "^2.2.5", - "postcss": "^5.0.10", - "postcss-loader": "^0.7.0", - "postcss-modules-extract-imports": "^1.0.0", - "postcss-modules-local-by-default": "^1.0.0", - "postcss-modules-scope": "^1.0.0", - "postcss-modules-values": "^1.1.0", - "precommit-hook": "^3.0.0", - "style-loader": "^0.13.0", - "webpack": "^1.12.2" - }, - "peerDependencies": { - "postcss": "^5.x", - "postcss-modules-extract-imports": "^1.0.0", - "postcss-modules-local-by-default": "^1.0.0", - "postcss-modules-scope": "^1.0.0", - "postcss-modules-values": "^1.1.0" - }, "scripts": { - "fixture": "webpack", - "start": "esw -w .", - "lint": "eslint .", - "test": "mocha --compilers js:babel/register --timeout 5000", - "test:cov": "`npm bin`/babel-node `npm bin`/isparta cover --report text --report html `npm bin`/_mocha", - "test:gen": "babel-node generate-tests", - "build": "babel src --out-dir dist", - "prepublish": "in-publish && npm run -s build || in-install" + "prepublish": "in-publish && npm run -s build || in-install", + "test": "mocha --require test/setup.js --ui tdd test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict", + "test:w": "mocha --require test/setup.js --ui tdd --watch test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict" }, "repository": { "type": "git", @@ -77,8 +29,21 @@ "url": "https://github.com/css-modules/css-modules-require-hook/issues" }, "homepage": "https://github.com/css-modules/css-modules-require-hook", - "pre-commit": [ - "lint", - "test" - ] + "pre-commit": [], + "dependencies": { + "debug": "^2.2.0", + "generic-names": "^1.0.1", + "icss-replace-symbols": "^1.0.2", + "lodash": "^4.3.0", + "postcss": "^5.0.15", + "postcss-modules-extract-imports": "^1.0.0", + "postcss-modules-local-by-default": "^1.0.1", + "postcss-modules-parser": "^1.1.0", + "postcss-modules-scope": "^1.0.0", + "postcss-modules-values": "^1.1.1" + }, + "devDependencies": { + "mocha": "^2.4.5", + "sinon": "^1.17.3" + } } From 72ee0a0522d2adfc927f3a56ae148e5ae2996653 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Thu, 18 Feb 2016 01:20:59 +0300 Subject: [PATCH 07/40] more tests for the public api --- test/api/append.js | 22 ++++++++++++++++++++++ test/api/extensions.js | 5 ++--- test/api/prepend.js | 22 ++++++++++++++++++++++ test/api/preprocessCss.js | 19 +++++++++++++++++++ test/api/processCss.js | 9 ++++++--- test/api/rootDir.js | 26 ++++++++++++++++++++++++++ test/api/use.js | 26 ++++++++++++++++++++++++++ test/setup.js | 1 + test/sugar.js | 13 ++++++++++--- 9 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 test/api/append.js create mode 100644 test/api/prepend.js create mode 100644 test/api/preprocessCss.js create mode 100644 test/api/rootDir.js create mode 100644 test/api/use.js diff --git a/test/api/append.js b/test/api/append.js new file mode 100644 index 0000000..7e718dd --- /dev/null +++ b/test/api/append.js @@ -0,0 +1,22 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const identity = require('lodash').lodash; +const Through = require('../sugar').Through; + +suite('api/append', () => { + suite('should add plugins to the pipeline', () => { + const processor = spy(identity); + + test('plugin should be called', () => assert(processor.called)); + + setup(() => { + hook({append: [new Through(processor)]}); + require('./fixture/oceanic.css'); + }); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); + }); +}); diff --git a/test/api/extensions.js b/test/api/extensions.js index cb44e31..05a31db 100644 --- a/test/api/extensions.js +++ b/test/api/extensions.js @@ -1,7 +1,6 @@ +const detachHook = require('../sugar').detachHook; const dropCache = require('../sugar').dropCache; -const dropHook = require('../sugar').dropHook; const identity = require('lodash').identity; -const spy = require('sinon').spy; suite('api/extensions', () => { suite('uses .css by default', () => { @@ -14,7 +13,7 @@ suite('api/extensions', () => { teardown(() => { dropCache('./api/fixture/oceanic.css'); - dropHook('.css'); + detachHook('.css'); }); }); }); diff --git a/test/api/prepend.js b/test/api/prepend.js new file mode 100644 index 0000000..a88b3c6 --- /dev/null +++ b/test/api/prepend.js @@ -0,0 +1,22 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const identity = require('lodash').lodash; +const Through = require('../sugar').Through; + +suite('api/prepend', () => { + suite('should add plugins to the pipeline', () => { + const processor = spy(identity); + + test('plugin should be called', () => assert(processor.called)); + + setup(() => { + hook({prepend: [new Through(processor)]}); + require('./fixture/oceanic.css'); + }); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); + }); +}); diff --git a/test/api/preprocessCss.js b/test/api/preprocessCss.js new file mode 100644 index 0000000..7134e6f --- /dev/null +++ b/test/api/preprocessCss.js @@ -0,0 +1,19 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const identity = require('lodash').identity; + +suite('api/preprocessCss', () => { + const preprocessCss = spy(identity); + + test('should be called', () => assert(preprocessCss.called)); + + setup(() => { + hook({preprocessCss}); + require('./fixture/oceanic.css'); + }); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); +}); diff --git a/test/api/processCss.js b/test/api/processCss.js index 30dcca3..1854e70 100644 --- a/test/api/processCss.js +++ b/test/api/processCss.js @@ -1,6 +1,6 @@ +const detachHook = require('../sugar').detachHook; const dropCache = require('../sugar').dropCache; const identity = require('lodash').identity; -const spy = require('sinon').spy; suite('api/processCss()', () => { const processCss = spy(identity); @@ -8,9 +8,12 @@ suite('api/processCss()', () => { test('should be called', () => assert(processCss.called)); setup(() => { - hook({processCss: processCss}); + hook({processCss}); require('./fixture/oceanic.css'); }); - teardown(() => dropCache('./api/fixture/oceanic.css')); + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); }); diff --git a/test/api/rootDir.js b/test/api/rootDir.js new file mode 100644 index 0000000..d4959c0 --- /dev/null +++ b/test/api/rootDir.js @@ -0,0 +1,26 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const path = require('path'); + +suite('api/rootDir', () => { + suite('should change the way in which tokens are generated', () => { + let tokens1; + let tokens2; + + test('should return different tokens', () => assert.notDeepEqual(tokens1, tokens2)); + + setup(() => { + hook({rootDir: path.join(__dirname, '../../')}); + tokens1 = require('./fixture/oceanic.css'); + dropCache('./api/fixture/oceanic.css'); + + hook({rootDir: __dirname}); + tokens2 = require('./fixture/oceanic.css'); + }); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); + }); +}); diff --git a/test/api/use.js b/test/api/use.js new file mode 100644 index 0000000..e063b91 --- /dev/null +++ b/test/api/use.js @@ -0,0 +1,26 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const identity = require('lodash').lodash; +const Through = require('../sugar').Through; + +suite('api/use', () => { + suite('should replace plugins in the pipeline', () => { + const processor = spy(identity); + let tokens; + + test('plugin should be called', () => { + assert(processor.called); + assert.deepEqual(tokens, {}); + }); + + setup(() => { + hook({use: [new Through(processor)]}); + tokens = require('./fixture/oceanic.css'); + }); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); + }); +}); diff --git a/test/setup.js b/test/setup.js index c3b614f..762f142 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,2 +1,3 @@ global.assert = require('assert'); global.hook = require('../'); +global.spy = require('sinon').spy; diff --git a/test/sugar.js b/test/sugar.js index 6cfb37b..ae8f9ff 100644 --- a/test/sugar.js +++ b/test/sugar.js @@ -1,3 +1,5 @@ +const plugin = require('postcss').plugin; + /** * Drops require cache for the certain module * @@ -8,11 +10,16 @@ function dropCache(modulePath) { }; /** - * @param {string} extension + * @param {string} extension */ -function dropHook(extension) { +function detachHook(extension) { delete require.extensions[extension]; } +const Through = plugin('through', function postcssThrough(processor) { + return css => processor(css); +}); + exports.dropCache = dropCache; -exports.dropHook = dropHook; +exports.detachHook = detachHook; +exports.Through = Through; From 7a54d1fc68ca21aec0709f290384f411500ac02a Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Thu, 18 Feb 2016 02:28:19 +0300 Subject: [PATCH 08/40] test for generateScopedName option --- test/api/generateScopedName.js | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 test/api/generateScopedName.js diff --git a/test/api/generateScopedName.js b/test/api/generateScopedName.js new file mode 100644 index 0000000..276db64 --- /dev/null +++ b/test/api/generateScopedName.js @@ -0,0 +1,56 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const identity = require('lodash').lodash; + +suite('api/generateScopedName', () => { + suite('using function', () => { + let args; + let tokens; + + const processor = spy(function (selector, filepath, source) { + args = [selector, filepath, source]; + return selector; + }); + + test('processor should be called', () => { + assert(processor.called); + }); + + test('should provide selector, filepath and source to the function', () => { + assert.deepEqual(args, [ + 'color', + '/Users/sullenor/Documents/repos/css-modules-require-hook/test/api/fixture/oceanic.css', + '.color\n{\n background: #1e2a35;\n}\n', + ]); + }); + + test('should return tokens with same keys', () => { + assert.deepEqual(tokens, { + color: 'color', + }); + }); + + setup(() => { + hook({generateScopedName: processor}); + tokens = require('./fixture/oceanic.css'); + }); + }); + + suite('using string pattern', () => { + let tokens; + + test('should return tokens with id', () => assert.deepEqual(tokens, { + color: 'oceanic__color___1GAeQ', + })); + + setup(() => { + hook({generateScopedName: '[name]__[local]___[hash:base64:5]'}); + tokens = require('./fixture/oceanic.css'); + }); + }); + + teardown(() => { + dropCache('./api/fixture/oceanic.css'); + detachHook('.css'); + }); +}); From 3292d258b1cd07661bc37929cf904426509d1cbf Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Thu, 18 Feb 2016 11:50:33 +0300 Subject: [PATCH 09/40] validation draft --- lib/index.js | 13 +++++++++---- lib/validate.js | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 lib/validate.js diff --git a/lib/index.js b/lib/index.js index e4ae107..58191a8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,6 +6,7 @@ const identity = require('lodash').identity; const readFileSync = require('fs').readFileSync; const relative = require('path').relative; const resolve = require('path').resolve; +const validate = require('./validate'); const postcss = require('postcss'); const Values = require('postcss-modules-values'); @@ -27,19 +28,23 @@ module.exports = function setupHook({ use, rootDir: context = process.cwd(), }) { + validate(arguments[0]); + const tokensByFile = {}; - let scopedName = function () {}; + let scopedName; if (generateScopedName) { scopedName = typeof generateScopedName !== 'function' ? genericNames(generateScopedName || '[name]__[local]___[hash:base64:5]', {context}) : generateScopedName; } else { // small fallback - scopedName = (local, filename) => Scope.generateScopedName(local, relative(context, filename)); + scopedName = (local, filename) => { + return Scope.generateScopedName(local, relative(context, filename)); + }; } - const plugins = [ + const plugins = (use || [ ...prepend, Values, mode @@ -50,7 +55,7 @@ module.exports = function setupHook({ : ExtractImports, new Scope({generateScopedName: scopedName}), ...append, - ].concat(new Parser({fetch})); // no pushing in order to avoid the possible mutations; + ]).concat(new Parser({fetch})); // no pushing in order to avoid the possible mutations; // https://github.com/postcss/postcss#options const runner = postcss(plugins); diff --git a/lib/validate.js b/lib/validate.js new file mode 100644 index 0000000..a945ea8 --- /dev/null +++ b/lib/validate.js @@ -0,0 +1,17 @@ +const rules = { + // hook + extensions: 'array|string', + preprocessCss: 'function', + processCss: 'function', + to: 'string', + // plugins + append: 'array', + prepend: 'array', + use: 'array', + createImportedName: 'function', + generateScopedName: 'function|string', + mode: 'string', + rootDir: 'string', +}; + +module.exports = function validate(options) {} From 0a4abde1b1430a12b7dd874b8cf536041fd0c495 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 00:57:06 +0300 Subject: [PATCH 10/40] implemented validation --- lib/validate.js | 27 ++++++++++++++++++++++++++- test/lib/validate.js | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/lib/validate.js diff --git a/lib/validate.js b/lib/validate.js index a945ea8..df9ee70 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -1,3 +1,7 @@ +const difference = require('lodash').difference; +const forEach = require('lodash').forEach; +const keys = require('lodash').keys; + const rules = { // hook extensions: 'array|string', @@ -14,4 +18,25 @@ const rules = { rootDir: 'string', }; -module.exports = function validate(options) {} +const tests = { + array: require('lodash').isArray, + function: require('lodash').isFunction, + string: require('lodash').isString, +}; + +module.exports = function validate(options) { + const unknownOptions = difference(keys(options), keys(rules)); + if (unknownOptions.length) { + throw new Error(`unknown arguments: ${unknownOptions.join(', ')}.`); + } + + forEach(rules, (types, rule) => { + if (typeof options[rule] === 'undefined') { + return; + } + + if (!types.split('|').some(type => tests[type](options[rule]))) { + throw new TypeError(`should specify ${types} as ${rule}`); + } + }); +} diff --git a/test/lib/validate.js b/test/lib/validate.js new file mode 100644 index 0000000..b0e7ef7 --- /dev/null +++ b/test/lib/validate.js @@ -0,0 +1,19 @@ +const validate = require('../../lib/validate'); + +suite('lib/validate', () => { + test('should thrown an error for the option with multiple types if wrong type specified', () => { + assert.throws(() => validate({extensions: null}, TypeError)); + }); + + test('should thrown an error for the option with single type if wrong type specified', () => { + assert.throws(() => validate({preprocessCss: ''}, TypeError)); + }); + + test('should NOT throw an error for the valid type', () => { + assert.doesNotThrow(() => validate({preprocessCss: function () {}})); + }); + + test('should throw an error if unknown options are specified', () => { + assert.throws(() => validate({a: '', b: ''}), Error); + }); +}); From ded44307443af273a327a4e8777d749cb98aa339 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 01:24:32 +0300 Subject: [PATCH 11/40] ignore option draft --- lib/attachHook.js | 13 ++++++++++--- lib/index.js | 8 +++++++- lib/validate.js | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/attachHook.js b/lib/attachHook.js index 58e2043..37e4821 100644 --- a/lib/attachHook.js +++ b/lib/attachHook.js @@ -1,10 +1,17 @@ /** * @param {function} compile * @param {string} extension + * @param {function} isException */ -module.exports = function attachHook(compile, extension) { +module.exports = function attachHook(compile, extension, isException) { + const existingHook = require.extensions[extension]; + require.extensions[extension] = function cssModulesHook(m, filename) { - const tokens = compile(filename); - return m._compile(`module.exports = ${JSON.stringify(tokens)}`, filename); + if (isException(filename)) { + existingHook(m, filename); + } else { + const tokens = compile(filename); + return m._compile(`module.exports = ${JSON.stringify(tokens)}`, filename); + } }; }; diff --git a/lib/index.js b/lib/index.js index 58191a8..0da34b1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -62,6 +62,12 @@ module.exports = function setupHook({ // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts + /** + * @todo think about replacing sequential fetch function calls with requires calls + * @param {string} _to + * @param {string} from + * @return {object} + */ function fetch(_to, from) { // getting absolute path to the processing file const filename = /\w/i.test(_to[0]) @@ -90,5 +96,5 @@ module.exports = function setupHook({ return tokens; }; - attachHook(filename => fetch(filename, filename), '.css'); + attachHook(filename => fetch(filename, filename), '.css', () => false); }; diff --git a/lib/validate.js b/lib/validate.js index df9ee70..249c0a4 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -5,6 +5,7 @@ const keys = require('lodash').keys; const rules = { // hook extensions: 'array|string', + ignore: 'function|regex', preprocessCss: 'function', processCss: 'function', to: 'string', From b76dd646473f7404b29824abb9389f91354d91f2 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 02:39:26 +0300 Subject: [PATCH 12/40] simple css test cases --- .gitignore | 3 -- test/demo.css | 4 -- .../cases/compose-node-module/expected.json | 3 ++ .../cases/compose-node-module/source.css | 4 ++ .../cases/multiple-dependencies/colors.css | 4 ++ .../cases/multiple-dependencies/expected.json | 3 ++ .../cases/multiple-dependencies/fonts.css | 5 +++ .../cases/multiple-dependencies/margins.css | 9 ++++ .../cases/multiple-dependencies/source.css | 6 +++ test/tokens/index.js | 45 +++++++++++++++++++ .../node_modules}/awesome-theme/common.css | 0 .../node_modules}/awesome-theme/oceanic.css | 0 12 files changed, 79 insertions(+), 7 deletions(-) delete mode 100644 test/demo.css create mode 100644 test/tokens/cases/compose-node-module/expected.json create mode 100644 test/tokens/cases/compose-node-module/source.css create mode 100644 test/tokens/cases/multiple-dependencies/colors.css create mode 100644 test/tokens/cases/multiple-dependencies/expected.json create mode 100644 test/tokens/cases/multiple-dependencies/fonts.css create mode 100644 test/tokens/cases/multiple-dependencies/margins.css create mode 100644 test/tokens/cases/multiple-dependencies/source.css create mode 100644 test/tokens/index.js rename {node_modules => test/tokens/node_modules}/awesome-theme/common.css (100%) rename {node_modules => test/tokens/node_modules}/awesome-theme/oceanic.css (100%) diff --git a/.gitignore b/.gitignore index 7b2bf1d..905f8e6 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,3 @@ node_modules/* # added automatically by precommit-hook as defaults .jshint* - -dist/ -!node_modules/awesome-theme diff --git a/test/demo.css b/test/demo.css deleted file mode 100644 index 15aa57d..0000000 --- a/test/demo.css +++ /dev/null @@ -1,4 +0,0 @@ -.app -{ - background: white; -} \ No newline at end of file diff --git a/test/tokens/cases/compose-node-module/expected.json b/test/tokens/cases/compose-node-module/expected.json new file mode 100644 index 0000000..337a00f --- /dev/null +++ b/test/tokens/cases/compose-node-module/expected.json @@ -0,0 +1,3 @@ +{ + "foo": "_test_tokens_cases_compose_node_module_source__foo _node_modules_awesome_theme_common__paragraph _node_modules_awesome_theme_oceanic__color" +} diff --git a/test/tokens/cases/compose-node-module/source.css b/test/tokens/cases/compose-node-module/source.css new file mode 100644 index 0000000..996bf71 --- /dev/null +++ b/test/tokens/cases/compose-node-module/source.css @@ -0,0 +1,4 @@ +.foo +{ + composes: paragraph from 'awesome-theme/common.css'; +} diff --git a/test/tokens/cases/multiple-dependencies/colors.css b/test/tokens/cases/multiple-dependencies/colors.css new file mode 100644 index 0000000..b0469a7 --- /dev/null +++ b/test/tokens/cases/multiple-dependencies/colors.css @@ -0,0 +1,4 @@ +.text +{ + color: #333; +} diff --git a/test/tokens/cases/multiple-dependencies/expected.json b/test/tokens/cases/multiple-dependencies/expected.json new file mode 100644 index 0000000..9b02481 --- /dev/null +++ b/test/tokens/cases/multiple-dependencies/expected.json @@ -0,0 +1,3 @@ +{ + "article": "_test_tokens_cases_multiple_dependencies_source__article _test_tokens_cases_multiple_dependencies_colors__text _test_tokens_cases_multiple_dependencies_fonts__medium _test_tokens_cases_multiple_dependencies_margins__mediumBottom _test_tokens_cases_multiple_dependencies_margins__mediumTop" +} diff --git a/test/tokens/cases/multiple-dependencies/fonts.css b/test/tokens/cases/multiple-dependencies/fonts.css new file mode 100644 index 0000000..7420611 --- /dev/null +++ b/test/tokens/cases/multiple-dependencies/fonts.css @@ -0,0 +1,5 @@ +.medium +{ + font-family: helvetica; + font-size: 13px; +} diff --git a/test/tokens/cases/multiple-dependencies/margins.css b/test/tokens/cases/multiple-dependencies/margins.css new file mode 100644 index 0000000..8f8c3e6 --- /dev/null +++ b/test/tokens/cases/multiple-dependencies/margins.css @@ -0,0 +1,9 @@ +.mediumBottom +{ + margin-bottom: 20px; +} + +.mediumTop +{ + margin-top: 20px; +} diff --git a/test/tokens/cases/multiple-dependencies/source.css b/test/tokens/cases/multiple-dependencies/source.css new file mode 100644 index 0000000..38bcf2f --- /dev/null +++ b/test/tokens/cases/multiple-dependencies/source.css @@ -0,0 +1,6 @@ +.article +{ + composes: text from './colors.css'; + composes: medium from './fonts.css'; + composes: mediumBottom mediumTop from './margins.css'; +} diff --git a/test/tokens/index.js b/test/tokens/index.js new file mode 100644 index 0000000..298b7a6 --- /dev/null +++ b/test/tokens/index.js @@ -0,0 +1,45 @@ +const basename = require('path').basename; +const readdirSync = require('fs').readdirSync; +const readFileSync = require('fs').readFileSync; +const resolve = require('path').resolve; + +/** + * @param {string} testCase + */ +function describeTest(testCase) { + const source = readfile(testCase, 'source.css'); + if (source === null) { + return; + } + + test(basename(testCase), () => { + const expected = JSON.parse(readfile(testCase, 'expected.json')); + assert.deepEqual(require(resolve(testCase, 'source.css')), expected); + }); +} + +/** + * @param {string} dir + * @return {string[]} + */ +function readdir(dir) { + return readdirSync(resolve(__dirname, dir)) + .map(nesteddir => resolve(__dirname, dir, nesteddir)); +} + +/** + * @param {...string} file + * @return {string|null} + */ +function readfile(file) { + try { + return readFileSync(resolve.apply(null, arguments), 'utf8'); + } catch(e) { + return null; + } +} + +suite('tokens', () => { + setup(() => hook({})); + readdir('./cases').forEach(describeTest); +}); diff --git a/node_modules/awesome-theme/common.css b/test/tokens/node_modules/awesome-theme/common.css similarity index 100% rename from node_modules/awesome-theme/common.css rename to test/tokens/node_modules/awesome-theme/common.css diff --git a/node_modules/awesome-theme/oceanic.css b/test/tokens/node_modules/awesome-theme/oceanic.css similarity index 100% rename from node_modules/awesome-theme/oceanic.css rename to test/tokens/node_modules/awesome-theme/oceanic.css From 0cb6adc5cbab98477cf1084eac7e0b3a7b3543f8 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 02:44:29 +0300 Subject: [PATCH 13/40] small fallback for the modern versions --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b71507b..ca8e5dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ language: node_js node_js: - - "4.1" - - "0.12" + - "4.3" From f642f8afafa48a8039963e12eee4d2d87365fcc2 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 02:45:37 +0300 Subject: [PATCH 14/40] todo --- test/tokens/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tokens/index.js b/test/tokens/index.js index 298b7a6..697aa33 100644 --- a/test/tokens/index.js +++ b/test/tokens/index.js @@ -12,6 +12,7 @@ function describeTest(testCase) { return; } + // @todo add a small shortcut to choose certain tests test(basename(testCase), () => { const expected = JSON.parse(readfile(testCase, 'expected.json')); assert.deepEqual(require(resolve(testCase, 'source.css')), expected); From 42f5488109e6a97e843b029bd5aad5158c154896 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 02:46:46 +0300 Subject: [PATCH 15/40] cleanup --- .eslintignore | 8 ---- .eslintrc | 11 ----- .npmignore | 10 ---- generate-tests.js | 119 ---------------------------------------------- index.js | 1 - package.json | 1 + preset.js | 2 +- src/extractor.js | 55 --------------------- src/guard.js | 5 -- src/hook.js | 10 ---- src/index.js | 93 ------------------------------------ src/utility.js | 18 ------- src/validate.js | 31 ------------ utils/sugar.js | 36 -------------- webpack.config.js | 29 ----------- 15 files changed, 2 insertions(+), 427 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc delete mode 100644 .npmignore delete mode 100644 generate-tests.js delete mode 100644 index.js delete mode 100644 src/extractor.js delete mode 100644 src/guard.js delete mode 100644 src/hook.js delete mode 100644 src/index.js delete mode 100644 src/utility.js delete mode 100644 src/validate.js delete mode 100644 utils/sugar.js delete mode 100644 webpack.config.js diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 925e6af..0000000 --- a/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -dist -coverage -node_modules - -generate-tests.js -test/cases/webpack/* -test/common-test-cases.js -webpack.config.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 515956c..0000000 --- a/.eslintrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "eslint-config-airbnb-lite", - "env": { - "es6": true, - "mocha": true - }, - "rules": { - "key-spacing": [2, {"align": "value"}], - "no-use-before-define": [2, "nofunc"] - } -} diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 8e053ed..0000000 --- a/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by dmn (https://github.com/inikulin/dmn) - -.git* -.npmignore -.travis.yml -generate-tests.js -src/ -test/ -utils/ -webpack.config.js diff --git a/generate-tests.js b/generate-tests.js deleted file mode 100644 index 734593d..0000000 --- a/generate-tests.js +++ /dev/null @@ -1,119 +0,0 @@ -import { existsSync, readdirSync, writeFile } from 'fs'; -import { join, resolve, sep } from 'path'; -import { toArray } from 'lodash'; - -const destination = resolve('test/common-test-cases.js'); -const cases = ['test-cases', 'cssi']; - -function resolveTo() { - const args = toArray(arguments); - return resolve(join.apply(null, ['test'].concat(args))); -} - -let content = -`import { dropCache } from '../utils/sugar';\n`+ -`import { equal } from 'assert';\n`+ -`import { readFileSync } from 'fs';\n`+ -`import { resolve } from 'path';\n`+ -`import { extend } from 'lodash';\n`+ -`import FileSystemLoader from 'css-modules-loader-core/lib/file-system-loader';\n`+ -`import hook from '../src';\n`+ -`\n`+ -`const normalize = str => str.replace(/\\r\\n?/g, '\\n');\n`+ -`const pipelines = {\n`+ -` 'test-cases': undefined,\n`+ -` 'cssi': [],\n`+ -`};\n`+ -`\n`+ -`let expectedCSS;\n`+ -`let expectedTokens;\n`+ -`\n`+ -`describe('common-test-cases', () => {\n`; - -cases.forEach(dirname => { - content += - `\n`+ - ` describe('${dirname}', () => {\n`; - - readdirSync(resolveTo(dirname)).forEach(testCase => { - if (existsSync(resolveTo(dirname, testCase, 'source.css'))) { - - content += - `\n`+ - ` describe('${testCase.replace(/-/g, ' ')}', () => {\n`+ - ` before(() => {\n`+ - ` dropCache(resolve('test${sep + dirname + sep + testCase + sep}source.css'));\n`+ - ` expectedCSS = normalize(readFileSync(resolve('test${sep + dirname + sep + testCase + sep}expected.css'), 'utf8'));\n`+ - ` expectedTokens = JSON.parse(readFileSync(resolve('test${sep + dirname + sep + testCase + sep}expected.json'), 'utf8'));\n`+ - ` hook({rootDir: resolve('test${sep + dirname}'), use: pipelines['${dirname}']});\n`+ - ` });\n`+ - `\n`+ - ` it.skip('loader-core', done => {\n`+ - ` const loader = new FileSystemLoader(resolve('test${sep + dirname}'), pipelines['${dirname}']);\n`+ - `\n`+ - ` loader.fetch('${testCase + sep}source.css', '/')\n`+ - ` .then(tokens => {\n`+ - ` equal(loader.finalSource, expectedCSS);\n`+ - ` equal(JSON.stringify(tokens), JSON.stringify(expectedTokens));\n`+ - ` })\n`+ - ` .then(done, done);\n`+ - ` });\n`+ - `\n`+ - ` it('require-hook', () => {\n`+ - ` const tokens = require(resolve('test${sep + dirname + sep + testCase + sep}source.css'));\n`+ - ` equal(JSON.stringify(tokens), JSON.stringify(expectedTokens));\n`+ - ` });\n`+ - ` });\n`; - - } else { - - content += - `\n`+ - ` describe('${testCase.replace(/-/g, ' ')}', () => {\n`+ - ` before(() => {\n`+ - ` dropCache(resolve('test${sep + dirname + sep + testCase + sep}source1.css'));\n`+ - ` dropCache(resolve('test${sep + dirname + sep + testCase + sep}source2.css'));\n`+ - ` expectedCSS = normalize(readFileSync(resolve('test${sep + dirname + sep + testCase + sep}expected.css'), 'utf8'));\n`+ - ` expectedTokens = JSON.parse(readFileSync(resolve('test${sep + dirname + sep + testCase + sep}expected.json'), 'utf8'));\n`+ - ` hook({rootDir: resolve('test${sep + dirname}'), use: pipelines['${dirname}']});\n`+ - ` });\n`+ - `\n`+ - ` it.skip('loader-core', done => {\n`+ - ` const loader = new FileSystemLoader(resolve('test${sep + dirname}'), pipelines['${dirname}']);\n`+ - `\n`+ - ` loader.fetch('${testCase + sep}source1.css', '/').then(tokens1 => {\n`+ - ` loader.fetch('${testCase + sep}source2.css', '/').then(tokens2 => {\n`+ - ` equal(loader.finalSource, expectedCSS);\n`+ - ` const tokens = extend({}, tokens1, tokens2);\n`+ - ` equal(JSON.stringify(tokens), JSON.stringify(expectedTokens));\n`+ - ` }).then(done, done);\n`+ - ` }).catch(done);\n`+ - ` });\n`+ - `\n`+ - ` it('require-hook', () => {\n`+ - ` const tokens = extend({},\n`+ - ` require(resolve('test${sep + dirname + sep + testCase + sep}source1.css')),\n`+ - ` require(resolve('test${sep + dirname + sep + testCase + sep}source2.css'))\n`+ - ` );\n`+ - `\n`+ - ` equal(JSON.stringify(tokens), JSON.stringify(expectedTokens));\n`+ - ` });\n`+ - ` });\n`; - - } - }); - - content += - `\n`+ - ` });\n`; -}); - -content += -`\n`+ -`});\n`; - -writeFile(destination, content, 'utf8', err => { - if (err) { - throw err; - } -}); diff --git a/index.js b/index.js deleted file mode 100644 index cce6933..0000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./dist'); diff --git a/package.json b/package.json index 0e95b1e..deb8afe 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "generic-names": "^1.0.1", "icss-replace-symbols": "^1.0.2", "lodash": "^4.3.0", + "lookup-fs": "^1.0.0", "postcss": "^5.0.15", "postcss-modules-extract-imports": "^1.0.0", "postcss-modules-local-by-default": "^1.0.1", diff --git a/preset.js b/preset.js index fb9dddd..346fd7d 100644 --- a/preset.js +++ b/preset.js @@ -1,7 +1,7 @@ const hook = require('.'); const lookup = require('lookup-fs'); -lookup('css-modules-file.js', (err, cssModulesFilePath) => { +lookup('cmrh.conf.js', (err, cssModulesFilePath) => { if (err) { throw new Error('Unable to find css-modules-file.js'); } diff --git a/src/extractor.js b/src/extractor.js deleted file mode 100644 index c7bcb07..0000000 --- a/src/extractor.js +++ /dev/null @@ -1,55 +0,0 @@ -import postcss from 'postcss'; -import genericNames from 'generic-names'; -import { relative } from 'path'; - -import Values from 'postcss-modules-values'; -import LocalByDefault from 'postcss-modules-local-by-default'; -import ExtractImports from 'postcss-modules-extract-imports'; -import Scope from 'postcss-modules-scope'; -import Parser from 'postcss-modules-parser'; - -/** - * @param {array} options.append - * @param {array} options.prepend - * @param {array} options.use - * @param {function} options.createImportedName - * @param {function|string} options.generateScopedName - * @param {string} options.mode - * @param {string} options.rootDir - * @param {function} fetch - * @return {object} - */ -export default function extractor({ - append = [], - prepend = [], - createImportedName, - generateScopedName, - mode, - use, - rootDir: context = process.cwd(), -} = {}, fetch) { - let scopedName; - if (generateScopedName) { - scopedName = typeof generateScopedName !== 'function' - ? genericNames(generateScopedName || '[name]__[local]___[hash:base64:5]', {context}) - : generateScopedName; - } else { - // small fallback - scopedName = (local, filename) => Scope.generateScopedName(local, relative(context, filename)); - } - - const plugins = (use || [ - ...prepend, - Values, - mode - ? new LocalByDefault({mode}) - : LocalByDefault, - createImportedName - ? new ExtractImports({createImportedName}) - : ExtractImports, - new Scope({generateScopedName: scopedName}), - ...append, - ]).concat(new Parser({fetch})); // no pushing in order to avoid the possible mutations - - return postcss(plugins); -} diff --git a/src/guard.js b/src/guard.js deleted file mode 100644 index 95aae22..0000000 --- a/src/guard.js +++ /dev/null @@ -1,5 +0,0 @@ -if (global._cssModulesPolyfill) { - throw new Error('only one instance of css-modules-require-hook is allowed'); -} - -global._cssModulesPolyfill = true; diff --git a/src/hook.js b/src/hook.js deleted file mode 100644 index 755b0c7..0000000 --- a/src/hook.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @param {function} compile - * @param {string} extension - */ -export default function attachHook(compile, extension) { - require.extensions[extension] = function hook(m, filename) { - const tokens = compile(filename); - return m._compile('module.exports = ' + JSON.stringify(tokens), filename); - }; -} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 3cb5a18..0000000 --- a/src/index.js +++ /dev/null @@ -1,93 +0,0 @@ -import assign from 'lodash.assign'; -import debug from 'debug'; -import hook from './hook'; -import identity from 'lodash.identity'; -import extractor from './extractor'; -import { readFileSync } from 'fs'; -import { dirname, resolve } from 'path'; -import validate from './validate'; -import './guard'; - -// cache -let tokensByFile = {}; -// globals; -let debugMode = process.env.NODE_ENV !== 'development'; -let instance = extractor({}, fetch); -let processorOptions = {}; -let preProcess = identity; -let postProcess; - -const debugFetch = debug('css-modules:fetch'); -const debugSetup = debug('css-modules:setup'); - -/** - * @param {array} options.extensions - * @param {function} options.preprocessCss - * @param {function} options.processCss - * @param {string} options.to - * @param {object} options.rest - */ -export default function setup({ extensions: extraExtensions, preprocessCss, processCss, to, devMode, ...rest } = {}) { - debugSetup(arguments[0]); - validate(arguments[0]); - instance = extractor(rest, fetch); - processorOptions = {to}; - preProcess = preprocessCss || identity; - postProcess = processCss || null; - // clearing cache - tokensByFile = {}; - - // debug option is preferred NODE_ENV === 'development' - if (typeof devMode !== 'undefined') { - debugMode = devMode; - } - - if (extraExtensions) { - extraExtensions.forEach((extension) => hook(filename => fetch(filename, filename), extension)); - } -} - -/** - * @param {string} to Absolute or relative path. Also can be path to the Node.JS module. - * @param {string} from Absolute path. - * @return {object} - */ -function fetch(to, from) { - // getting absolute path to the processing file - const filename = /\w/i.test(to[0]) - ? require.resolve(to) - : resolve(dirname(from), to); - - // checking cache - let tokens = tokensByFile[filename]; - if (tokens) { - debugFetch({cache: true, filename}); - return tokens; - } - - debugFetch({cache: false, filename}); - const CSSSource = preProcess(readFileSync(filename, 'utf8'), filename); - // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts - const lazyResult = instance.process(CSSSource, assign(processorOptions, {from: filename})); - - // https://github.com/postcss/postcss/blob/master/docs/api.md#lazywarnings - lazyResult.warnings().forEach(message => console.warn(message.text)); - - tokens = lazyResult.root.tokens; - - if (!debugMode) { - // updating cache - tokensByFile[filename] = tokens; - } else { - // clearing cache in development mode - delete require.cache[filename]; - } - - if (postProcess) { - postProcess(lazyResult.css, filename); - } - - return tokens; -} - -hook(filename => fetch(filename, filename), '.css'); diff --git a/src/utility.js b/src/utility.js deleted file mode 100644 index bf38088..0000000 --- a/src/utility.js +++ /dev/null @@ -1,18 +0,0 @@ -import isArray from 'lodash.isarray'; -import isFunction from 'lodash.isfunction'; -import isString from 'lodash.isstring'; - -const check = { - 'array': isArray, - 'function': isFunction, - 'string': isString, -}; - -/** - * @param {string} type - * @param {*} value - * @return {boolean} - */ -export function is(type, value) { - return check[type](value); -} diff --git a/src/validate.js b/src/validate.js deleted file mode 100644 index a985046..0000000 --- a/src/validate.js +++ /dev/null @@ -1,31 +0,0 @@ -import forEach from 'lodash.foreach'; -import { is } from './utility'; -import { format } from 'util'; - -const rules = { - // hook - extensions: 'array', - preprocessCss: 'function', - processCss: 'function', - to: 'string', - // plugins - append: 'array', - prepend: 'array', - use: 'array', - createImportedName: 'function', - generateScopedName: 'function|string', - mode: 'string', - rootDir: 'string', -}; - -export default function validate(options = {}) { - forEach(rules, (types, rule) => { - if (!options[rule]) { - return; - } - - if (!types.split('|').some(type => is(type, options[rule]))) { - throw new Error(format('should specify %s for the %s', types, rule)); - } - }); -} diff --git a/utils/sugar.js b/utils/sugar.js deleted file mode 100644 index bec8e00..0000000 --- a/utils/sugar.js +++ /dev/null @@ -1,36 +0,0 @@ -import { identity } from 'lodash'; -import { plugin } from 'postcss'; - -/** - * @param {string} moduleName - */ -export function dropCache(moduleName) { - delete require.cache[require.resolve(moduleName)]; -} - -/** - * @param {function} fn - * @return {function} - */ -export function spy(fn) { - const wrapper = function wrapper() { - wrapper.called = true; - wrapper.times++; - return fn.apply(this, arguments); - }; - - wrapper.called = false; - wrapper.times = 0; - - return wrapper; -} - -/** - * Simple PostCSS plugin for the test purpose - * @param {object} opts - * @return {Function} - */ -export const Through = plugin('through', function through(opts = {}) { - const processor = opts.processor || identity; - return css => processor(css); -}); diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index f8b28da..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var ExtractTextPlugin = require('extract-text-webpack-plugin'); -var path = require('path'); - -module.exports = { - entry: path.resolve('test/cases/webpack/source.js'), - - output: { - filename: 'result.js', - path: path.resolve('test/cases/webpack') - }, - - module: { - loaders: [ - { - test: /\.css$/, - loader: ExtractTextPlugin.extract('style-loader', - 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') - } - ] - }, - - plugins: [ - new ExtractTextPlugin('result.css', { - allChunks: true - }) - ] -}; From d9ceb6831cd0a5513edca332a67251daca754955 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Fri, 19 Feb 2016 23:28:10 +0300 Subject: [PATCH 16/40] fix for the compose-node-module test custom path provided to the node_modules folder --- package.json | 5 ++--- test/tokens/cases/compose-node-module/expected.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index deb8afe..5758485 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,8 @@ "node": ">=0.12" }, "scripts": { - "prepublish": "in-publish && npm run -s build || in-install", - "test": "mocha --require test/setup.js --ui tdd test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict", - "test:w": "mocha --require test/setup.js --ui tdd --watch test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict" + "test": "NODE_PATH=$(pwd)/test/tokens/node_modules mocha --require test/setup.js --ui tdd test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict", + "test:w": "NODE_PATH=$(pwd)/test/tokens/node_modules mocha --require test/setup.js --ui tdd --watch test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict" }, "repository": { "type": "git", diff --git a/test/tokens/cases/compose-node-module/expected.json b/test/tokens/cases/compose-node-module/expected.json index 337a00f..9b0d086 100644 --- a/test/tokens/cases/compose-node-module/expected.json +++ b/test/tokens/cases/compose-node-module/expected.json @@ -1,3 +1,3 @@ { - "foo": "_test_tokens_cases_compose_node_module_source__foo _node_modules_awesome_theme_common__paragraph _node_modules_awesome_theme_oceanic__color" + "foo": "_test_tokens_cases_compose_node_module_source__foo _test_tokens_node_modules_awesome_theme_common__paragraph _test_tokens_node_modules_awesome_theme_oceanic__color" } From 57caf730976ad101133ae8cdf4b7a832822a72ff Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sat, 20 Feb 2016 00:16:31 +0300 Subject: [PATCH 17/40] scripts update --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5758485..7485135 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ "node": ">=0.12" }, "scripts": { - "test": "NODE_PATH=$(pwd)/test/tokens/node_modules mocha --require test/setup.js --ui tdd test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict", - "test:w": "NODE_PATH=$(pwd)/test/tokens/node_modules mocha --require test/setup.js --ui tdd --watch test/*/*.js --harmony_destructuring --harmony_spread_arrays --use_strict" + "test": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --harmony_destructuring --harmony_spread_arrays --use_strict", + "test:w": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --harmony_destructuring --harmony_spread_arrays --use_strict", + "test:unit": "mocha --require test/setup.js --ui tdd test/*/*.js" }, "repository": { "type": "git", From 1e16d5908625597ffffecab0563897eee3e9e20b Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sat, 20 Feb 2016 01:04:18 +0300 Subject: [PATCH 18/40] ignore option implementation --- lib/index.js | 23 +++++++++++++- lib/validate.js | 3 +- package.json | 1 + test/api/append.js | 2 +- test/api/extensions.js | 2 +- test/api/fixture/typography.css | 6 ++++ test/api/generateScopedName.js | 2 +- test/api/ignore.js | 53 +++++++++++++++++++++++++++++++++ test/api/prepend.js | 2 +- test/api/preprocessCss.js | 2 +- test/api/processCss.js | 2 +- test/api/rootDir.js | 2 +- test/api/use.js | 2 +- test/tokens/index.js | 2 ++ 14 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 test/api/fixture/typography.css create mode 100644 test/api/ignore.js diff --git a/lib/index.js b/lib/index.js index 0da34b1..90db93a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,9 @@ const assign = require('lodash').assign; const attachHook = require('./attachHook'); const dirname = require('path').dirname; const genericNames = require('generic-names'); +const globToRegex = require('glob-to-regexp'); const identity = require('lodash').identity; +const negate = require('lodash').negate; const readFileSync = require('fs').readFileSync; const relative = require('path').relative; const resolve = require('path').resolve; @@ -15,8 +17,25 @@ const ExtractImports = require('postcss-modules-extract-imports'); const Scope = require('postcss-modules-scope'); const Parser = require('postcss-modules-parser'); +/** + * @param {function|regex|string} ignore glob, regex or function + * @return {function} + */ +function buildExceptionChecker(ignore) { + if (ignore instanceof RegExp) { + return filepath => ignore.test(filepath); + } + + if (typeof ignore === 'string') { + return filepath => globToRegex(ignore).test(filepath); + } + + return ignore || negate(identity); +} + module.exports = function setupHook({ extensions = '.css', + ignore, preprocessCss = identity, processCss, to, @@ -96,5 +115,7 @@ module.exports = function setupHook({ return tokens; }; - attachHook(filename => fetch(filename, filename), '.css', () => false); + const isException = buildExceptionChecker(ignore); + + attachHook(filename => fetch(filename, filename), '.css', isException); }; diff --git a/lib/validate.js b/lib/validate.js index 249c0a4..2310191 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -5,7 +5,7 @@ const keys = require('lodash').keys; const rules = { // hook extensions: 'array|string', - ignore: 'function|regex', + ignore: 'function|regex|string', preprocessCss: 'function', processCss: 'function', to: 'string', @@ -22,6 +22,7 @@ const rules = { const tests = { array: require('lodash').isArray, function: require('lodash').isFunction, + regex: require('lodash').isRegExp, string: require('lodash').isString, }; diff --git a/package.json b/package.json index 7485135..3d120db 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "dependencies": { "debug": "^2.2.0", "generic-names": "^1.0.1", + "glob-to-regexp": "^0.1.0", "icss-replace-symbols": "^1.0.2", "lodash": "^4.3.0", "lookup-fs": "^1.0.0", diff --git a/test/api/append.js b/test/api/append.js index 7e718dd..0a4ddd3 100644 --- a/test/api/append.js +++ b/test/api/append.js @@ -15,8 +15,8 @@ suite('api/append', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); }); diff --git a/test/api/extensions.js b/test/api/extensions.js index 05a31db..405c19a 100644 --- a/test/api/extensions.js +++ b/test/api/extensions.js @@ -12,8 +12,8 @@ suite('api/extensions', () => { setup(() => hook({})); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); }); diff --git a/test/api/fixture/typography.css b/test/api/fixture/typography.css new file mode 100644 index 0000000..f41b71d --- /dev/null +++ b/test/api/fixture/typography.css @@ -0,0 +1,6 @@ +@import url(http://fonts.googleapis.com/css?family=Vollkorn:400,400italic,700,700italic&subset=latin); + +.common +{ + font: 1.3em 'Vollkorn', Palatino, Times; +} diff --git a/test/api/generateScopedName.js b/test/api/generateScopedName.js index 276db64..065f5f2 100644 --- a/test/api/generateScopedName.js +++ b/test/api/generateScopedName.js @@ -50,7 +50,7 @@ suite('api/generateScopedName', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); diff --git a/test/api/ignore.js b/test/api/ignore.js new file mode 100644 index 0000000..e3645fa --- /dev/null +++ b/test/api/ignore.js @@ -0,0 +1,53 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; + +suite('api/ignore', () => { + suite('glob', () => { + setup(() => hook({ + ignore: '*oceanic*', + })); + + test('should return tokens', () => { + assert.deepEqual(require('./fixture/typography.css'), { + common: '_test_api_fixture_typography__common', + }); + }); + + test('should throw an exception', () => { + assert.throws(() => require('./fixture/oceanic.css')); + }); + }); + + suite('function', () => { + setup(() => hook({ + ignore: filename => /typography/.test(filename), + })); + + test('should return tokens', () => { + assert.throws(() => require('./fixture/typography.css')); + }); + + test('should throw an exception', () => { + assert.deepEqual(require('./fixture/oceanic.css'), { + color: '_test_api_fixture_oceanic__color', + }); + }); + }); + + suite('regex', () => { + setup(() => hook({ + ignore: /\.css$/, + })); + + test('should throw an exception', () => { + assert.throws(() => require('./fixture/typography.css')); + assert.throws(() => require('./fixture/oceanic.css')); + }); + }); + + teardown(() => { + detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); + dropCache('./api/fixture/typography.css'); + }); +}); diff --git a/test/api/prepend.js b/test/api/prepend.js index a88b3c6..c9b6e7b 100644 --- a/test/api/prepend.js +++ b/test/api/prepend.js @@ -15,8 +15,8 @@ suite('api/prepend', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); }); diff --git a/test/api/preprocessCss.js b/test/api/preprocessCss.js index 7134e6f..f5364d2 100644 --- a/test/api/preprocessCss.js +++ b/test/api/preprocessCss.js @@ -13,7 +13,7 @@ suite('api/preprocessCss', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); diff --git a/test/api/processCss.js b/test/api/processCss.js index 1854e70..11a4aa9 100644 --- a/test/api/processCss.js +++ b/test/api/processCss.js @@ -13,7 +13,7 @@ suite('api/processCss()', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); diff --git a/test/api/rootDir.js b/test/api/rootDir.js index d4959c0..1e5f05a 100644 --- a/test/api/rootDir.js +++ b/test/api/rootDir.js @@ -19,8 +19,8 @@ suite('api/rootDir', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); }); diff --git a/test/api/use.js b/test/api/use.js index e063b91..a78c487 100644 --- a/test/api/use.js +++ b/test/api/use.js @@ -19,8 +19,8 @@ suite('api/use', () => { }); teardown(() => { - dropCache('./api/fixture/oceanic.css'); detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); }); }); }); diff --git a/test/tokens/index.js b/test/tokens/index.js index 697aa33..e63f9f7 100644 --- a/test/tokens/index.js +++ b/test/tokens/index.js @@ -1,4 +1,5 @@ const basename = require('path').basename; +const detachHook = require('../sugar').detachHook; const readdirSync = require('fs').readdirSync; const readFileSync = require('fs').readFileSync; const resolve = require('path').resolve; @@ -42,5 +43,6 @@ function readfile(file) { suite('tokens', () => { setup(() => hook({})); + teardown(() => detachHook('.css')); readdir('./cases').forEach(describeTest); }); From 2ddce599bbac25c51345fa11221598df0599d64b Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sat, 20 Feb 2016 01:19:13 +0300 Subject: [PATCH 19/40] extra test --- test/tokens/cases/multiple-sources/colors.css | 4 ++++ test/tokens/cases/multiple-sources/expected.json | 4 ++++ test/tokens/cases/multiple-sources/source.css | 9 +++++++++ test/tokens/cases/multiple-sources/typography.css | 5 +++++ 4 files changed, 22 insertions(+) create mode 100644 test/tokens/cases/multiple-sources/colors.css create mode 100644 test/tokens/cases/multiple-sources/expected.json create mode 100644 test/tokens/cases/multiple-sources/source.css create mode 100644 test/tokens/cases/multiple-sources/typography.css diff --git a/test/tokens/cases/multiple-sources/colors.css b/test/tokens/cases/multiple-sources/colors.css new file mode 100644 index 0000000..179b73a --- /dev/null +++ b/test/tokens/cases/multiple-sources/colors.css @@ -0,0 +1,4 @@ +.oceanic +{ + background: #1e2a35; +} diff --git a/test/tokens/cases/multiple-sources/expected.json b/test/tokens/cases/multiple-sources/expected.json new file mode 100644 index 0000000..bf9d7e3 --- /dev/null +++ b/test/tokens/cases/multiple-sources/expected.json @@ -0,0 +1,4 @@ +{ + "article": "_test_tokens_cases_multiple_sources_source__article _test_tokens_cases_multiple_sources_colors__oceanic", + "text": "_test_tokens_cases_multiple_sources_source__text _test_tokens_cases_multiple_sources_typography__text _test_tokens_cases_multiple_sources_colors__oceanic" +} diff --git a/test/tokens/cases/multiple-sources/source.css b/test/tokens/cases/multiple-sources/source.css new file mode 100644 index 0000000..e9cb318 --- /dev/null +++ b/test/tokens/cases/multiple-sources/source.css @@ -0,0 +1,9 @@ +.article +{ + composes: oceanic from './colors.css'; +} + +.text +{ + composes: text from './typography.css'; +} diff --git a/test/tokens/cases/multiple-sources/typography.css b/test/tokens/cases/multiple-sources/typography.css new file mode 100644 index 0000000..560bcfc --- /dev/null +++ b/test/tokens/cases/multiple-sources/typography.css @@ -0,0 +1,5 @@ +.text +{ + composes: oceanic from './colors.css'; + font-family: helvetica; +} From a985863232d4afb067d77a3b3d5c441ef3d7870a Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sat, 20 Feb 2016 01:40:23 +0300 Subject: [PATCH 20/40] falling test for preset --- preset.js | 10 ++++++---- test/preset/cmrh.conf.js | 3 +++ test/preset/fixture/oceanic.css | 4 ++++ test/preset/index.js | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 test/preset/cmrh.conf.js create mode 100644 test/preset/fixture/oceanic.css create mode 100644 test/preset/index.js diff --git a/preset.js b/preset.js index 346fd7d..7402e71 100644 --- a/preset.js +++ b/preset.js @@ -1,10 +1,12 @@ const hook = require('.'); const lookup = require('lookup-fs'); -lookup('cmrh.conf.js', (err, cssModulesFilePath) => { - if (err) { - throw new Error('Unable to find css-modules-file.js'); +// should it be a sync call? +lookup('cmrh.conf.js', module.parent.filename, (er, cssModulesFilePath) => { + if (er) { + throw new Error('Unable to find cmrh.conf.js'); } - hook(require(cssModulesFilePath)); + const preset = require(cssModulesFilePath); + hook(preset); }); diff --git a/test/preset/cmrh.conf.js b/test/preset/cmrh.conf.js new file mode 100644 index 0000000..0fc52b8 --- /dev/null +++ b/test/preset/cmrh.conf.js @@ -0,0 +1,3 @@ +module.exports = { + generateScopedName: '[name]__[local]___[hash:base64:5]', +}; diff --git a/test/preset/fixture/oceanic.css b/test/preset/fixture/oceanic.css new file mode 100644 index 0000000..7e4881c --- /dev/null +++ b/test/preset/fixture/oceanic.css @@ -0,0 +1,4 @@ +.color +{ + background: #1e2a35; +} diff --git a/test/preset/index.js b/test/preset/index.js new file mode 100644 index 0000000..03ae444 --- /dev/null +++ b/test/preset/index.js @@ -0,0 +1,16 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; + +suite('css-modules-require-hook/preset', () => { + setup(() => require('../../preset')); + + test('should return tokens', () => { + const tokens = require('./fixture/oceanic.css'); + assert.deepEqual(tokens, {}); + }); + + teardown(() => { + detachHook('.css'); + dropCache('./preset/fixture/oceanic.css'); + }); +}); From 13732756bb919f404cddf12856327675798ced65 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sun, 21 Feb 2016 01:21:23 +0300 Subject: [PATCH 21/40] presets implementation --- package.json | 4 ++-- preset.js | 16 +++++++--------- test/preset/index.js | 4 +++- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 3d120db..42d5b96 100644 --- a/package.json +++ b/package.json @@ -36,13 +36,13 @@ "glob-to-regexp": "^0.1.0", "icss-replace-symbols": "^1.0.2", "lodash": "^4.3.0", - "lookup-fs": "^1.0.0", "postcss": "^5.0.15", "postcss-modules-extract-imports": "^1.0.0", "postcss-modules-local-by-default": "^1.0.1", "postcss-modules-parser": "^1.1.0", "postcss-modules-scope": "^1.0.0", - "postcss-modules-values": "^1.1.1" + "postcss-modules-values": "^1.1.1", + "seekout": "^1.0.1" }, "devDependencies": { "mocha": "^2.4.5", diff --git a/preset.js b/preset.js index 7402e71..e5bc68b 100644 --- a/preset.js +++ b/preset.js @@ -1,12 +1,10 @@ +const dirname = require('path').dirname; const hook = require('.'); -const lookup = require('lookup-fs'); +const seekout = require('seekout'); -// should it be a sync call? -lookup('cmrh.conf.js', module.parent.filename, (er, cssModulesFilePath) => { - if (er) { - throw new Error('Unable to find cmrh.conf.js'); - } +const preset = seekout('cmrh.conf.js', dirname(module.parent.filename)); +if (!preset) { + throw new Error('Unable to find cmrh.conf.js'); +} - const preset = require(cssModulesFilePath); - hook(preset); -}); +hook(require(preset)); diff --git a/test/preset/index.js b/test/preset/index.js index 03ae444..286c002 100644 --- a/test/preset/index.js +++ b/test/preset/index.js @@ -6,7 +6,9 @@ suite('css-modules-require-hook/preset', () => { test('should return tokens', () => { const tokens = require('./fixture/oceanic.css'); - assert.deepEqual(tokens, {}); + assert.deepEqual(tokens, { + color: 'oceanic__color___1sqWL', + }); }); teardown(() => { From 903c058ef6509f36dc4cc820da060646184dfc0c Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sun, 21 Feb 2016 14:25:19 +0300 Subject: [PATCH 22/40] added babel compiler to tests --- .babelrc | 5 +++++ package.json | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 .babelrc diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..3c078e9 --- /dev/null +++ b/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "es2015" + ] +} diff --git a/package.json b/package.json index 42d5b96..9bcae9b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "test": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --harmony_destructuring --harmony_spread_arrays --use_strict", "test:w": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --harmony_destructuring --harmony_spread_arrays --use_strict", + "test:babel": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --compilers js:babel-register", "test:unit": "mocha --require test/setup.js --ui tdd test/*/*.js" }, "repository": { @@ -45,6 +46,8 @@ "seekout": "^1.0.1" }, "devDependencies": { + "babel-preset-es2015": "^6.5.0", + "babel-register": "^6.5.2", "mocha": "^2.4.5", "sinon": "^1.17.3" } From 45bc7eecca5f0c300ecd1604b4dbcb750c051e13 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sun, 21 Feb 2016 14:46:11 +0300 Subject: [PATCH 23/40] npmignore --- .npmignore | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..891c86d --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +.babelrc +.editorconfig +.gitignore +.npmignore +.travis.yml +demo From 60460ad03e307d6ae8960ab3b4ad57d563c86369 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sun, 21 Feb 2016 15:16:42 +0300 Subject: [PATCH 24/40] build script --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 9bcae9b..e9282ff 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "node": ">=0.12" }, "scripts": { + "build": "babel lib --out-dir lib && babel preset.js --out-file preset.js", "test": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --harmony_destructuring --harmony_spread_arrays --use_strict", "test:w": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --harmony_destructuring --harmony_spread_arrays --use_strict", "test:babel": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --compilers js:babel-register", @@ -46,6 +47,7 @@ "seekout": "^1.0.1" }, "devDependencies": { + "babel-cli": "^6.5.1", "babel-preset-es2015": "^6.5.0", "babel-register": "^6.5.2", "mocha": "^2.4.5", From 57249c785b37bb75a0797a17c8ab11244ca7314d Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Sun, 21 Feb 2016 15:33:45 +0300 Subject: [PATCH 25/40] test command updated for babel --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e9282ff..4fde707 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,10 @@ }, "scripts": { "build": "babel lib --out-dir lib && babel preset.js --out-file preset.js", - "test": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --harmony_destructuring --harmony_spread_arrays --use_strict", - "test:w": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --harmony_destructuring --harmony_spread_arrays --use_strict", + "test": "npm run test:babel", "test:babel": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --compilers js:babel-register", + "test:node": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --harmony_destructuring --harmony_spread_arrays --use_strict", + "test:watch": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --harmony_destructuring --harmony_spread_arrays --use_strict", "test:unit": "mocha --require test/setup.js --ui tdd test/*/*.js" }, "repository": { From 13a2da82790ecbe56efd6379aa7bbbe54ceb505a Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 12:55:22 +0300 Subject: [PATCH 26/40] test for environment --- lib/index.js | 8 +++++ test/env/fixture/oceanic.css | 4 +++ test/env/node_env.js | 62 ++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 test/env/fixture/oceanic.css create mode 100644 test/env/node_env.js diff --git a/lib/index.js b/lib/index.js index 90db93a..3c0380c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -108,6 +108,14 @@ module.exports = function setupHook({ tokens = lazyResult.root.tokens; + if (process.env.NODE_ENV !== 'development') { + // updating cache + tokensByFile[filename] = tokens; + } else { + // clearing cache in development mode + delete require.cache[filename]; + } + if (processCss) { processCss(lazyResult.css, filename); } diff --git a/test/env/fixture/oceanic.css b/test/env/fixture/oceanic.css new file mode 100644 index 0000000..7e4881c --- /dev/null +++ b/test/env/fixture/oceanic.css @@ -0,0 +1,4 @@ +.color +{ + background: #1e2a35; +} diff --git a/test/env/node_env.js b/test/env/node_env.js new file mode 100644 index 0000000..5a6c4f5 --- /dev/null +++ b/test/env/node_env.js @@ -0,0 +1,62 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const resolve = require('path').resolve; +const writeFileSync = require('fs').writeFileSync; + +const destination = resolve(__dirname, './fixture/oceanic.css'); +const source1 = `.color\n{\n background: #1e2a35;\n}\n`; +const source2 = `.awesome-color\n{\n background: #1e2a35;\n}\n`; + +suite('env.NODE_ENV', () => { + suite('in the development mode', () => { + test('should get tokens from fs, not from cache', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + 'awesome-color': '_test_env_fixture_oceanic__awesome-color', + }); + }); + + setup(() => { + process.env.NODE_ENV = 'development'; + hook({}); + writeFile(source1); + require('./fixture/oceanic.css'); + writeFile(source2); + }); + + teardown(() => { + process.env.NODE_ENV = ''; + writeFile(source1); + detachHook('.css'); + dropCache('./env/fixture/oceanic.css'); + }); + }); + + suite('not in the development mode', () => { + test('should get tokens from cache', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + 'color': '_test_env_fixture_oceanic__color', + }); + }); + + setup(() => { + hook({}); + require('./fixture/oceanic.css'); + }); + + teardown(() => { + detachHook('.css'); + dropCache('./env/fixture/oceanic.css'); + }); + }); +}); + +/** + * @param {string} data + */ +function writeFile(data) { + writeFileSync(destination, data, 'utf8'); +} From 1afd7affa539a76ac27d53641e53e4c0c861c42a Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 13:04:51 +0300 Subject: [PATCH 27/40] small update --- test/api/rootDir.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/rootDir.js b/test/api/rootDir.js index 1e5f05a..2028fd8 100644 --- a/test/api/rootDir.js +++ b/test/api/rootDir.js @@ -1,6 +1,6 @@ const detachHook = require('../sugar').detachHook; const dropCache = require('../sugar').dropCache; -const path = require('path'); +const join = require('path').join; suite('api/rootDir', () => { suite('should change the way in which tokens are generated', () => { @@ -10,7 +10,7 @@ suite('api/rootDir', () => { test('should return different tokens', () => assert.notDeepEqual(tokens1, tokens2)); setup(() => { - hook({rootDir: path.join(__dirname, '../../')}); + hook({rootDir: join(__dirname, '../../')}); tokens1 = require('./fixture/oceanic.css'); dropCache('./api/fixture/oceanic.css'); From 86a0a0833fc63ab7ac654a63e55f02212cc4b05e Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 13:37:15 +0300 Subject: [PATCH 28/40] readme update --- README.md | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d2cf103..47a98c6 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,7 @@ Compiling in runtime, [universal](https://medium.com/@mjackson/universal-javascr ## Requirements -To use this tool we require [Node.js v0.12.x](https://github.com/nodejs/node) (or higher) and several modules to be installed. - -- [postcss](https://github.com/postcss/postcss) version 5 or higher -- [postcss-modules-values](https://github.com/css-modules/postcss-modules-values) -- [postcss-modules-extract-imports](https://github.com/css-modules/postcss-modules-extract-imports) -- [postcss-modules-local-by-default](https://github.com/css-modules/postcss-modules-local-by-default) -- [postcss-modules-scope](https://github.com/css-modules/postcss-modules-scope) +To use this tool we require [Node.js v0.12.x](https://github.com/nodejs/node) (or higher). ## Installation @@ -30,28 +24,45 @@ $ npm i css-modules-require-hook ## Usage -In this section I've tried to cover the common cases of usage. +Now, there are two ways to attach hook: manually or using preset file. -### Development mode +The first one allows you to pass options manually after module was required, to make it work. Example: -Usually, Node.js caches all the `require` calls by default. In order to invalidate cache for the purpose of development you should set the environment variable `NODE_ENV` to `development`. For example: +```javascript +const hook = require('css-modules-require-hook'); -```bash -$ NODE_ENV=development node server.js -``` +hook({ + generateScopedName: '[name]__[local]___[hash:base64:5]', +}); -Still you can use `devMode` option (see below) to override behavior which is imposed by environment variable. +// const styles = require('./icon.css'); +``` -### Basic example +The second one allows you to move options to separated file `cmrh.conf.js`, which should be located in your working directory (`process.cwd()`) or in its ancestors. Example: -Basically to attach the require hook you need to require this module. If you need to adjust it see the tuning section below. +```javascript +// cmrh.conf.js +module.exports = { + generateScopedName: '[name]__[local]___[hash:base64:5]', +}; +``` ```javascript -require('css-modules-require-hook'); +require('css-modules-require-hook/preset'); + +// const styles = require('./icon.css'); +``` + +### Development mode -// var styles = require('./icon.css'); +Usually, Node.js caches all the `require` calls by default. In order to invalidate cache for the purpose of development you should set the environment variable `NODE_ENV` to `development`. For example: + +```bash +$ NODE_ENV=development node server.js ``` +Still you can use `devMode` option (see below) to override behavior which is imposed by environment variable. + ### Adding custom PostCSS plugins ```javascript From 164873bb9ef323be2619bfbcd09b121bf5c23154 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 13:41:41 +0300 Subject: [PATCH 29/40] added description about ignore option --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 47a98c6..ef6899a 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,10 @@ hook({ Attach the require hook to additional file extensions (for example `['.scss']`). +### `ignore` function|regex|string + +Provides possibility to exclude particular files from processing. Supports glob and regular expressions syntax. Also you may provide custom function. + ### `rootDir` string Provides absolute path to the project directory. Providing this will result in better generated class names. It can be obligatory, if you run require hook and build tools (like [css-modulesify](https://github.com/css-modules/css-modulesify)) from different working directories. From 6f57c7f7570122f09035533238f67efee99a7a4d Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 13:43:39 +0300 Subject: [PATCH 30/40] test fix --- test/api/generateScopedName.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/api/generateScopedName.js b/test/api/generateScopedName.js index 065f5f2..a6d092e 100644 --- a/test/api/generateScopedName.js +++ b/test/api/generateScopedName.js @@ -1,6 +1,7 @@ const detachHook = require('../sugar').detachHook; const dropCache = require('../sugar').dropCache; const identity = require('lodash').lodash; +const resolve = require('path').resolve; suite('api/generateScopedName', () => { suite('using function', () => { @@ -19,7 +20,7 @@ suite('api/generateScopedName', () => { test('should provide selector, filepath and source to the function', () => { assert.deepEqual(args, [ 'color', - '/Users/sullenor/Documents/repos/css-modules-require-hook/test/api/fixture/oceanic.css', + resolve('test/api/fixture/oceanic.css'), '.color\n{\n background: #1e2a35;\n}\n', ]); }); From 02008fd8badc41cce2124d22d7f2ad5ecc702664 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 15:29:23 +0300 Subject: [PATCH 31/40] debugability --- README.md | 1 + lib/index.js | 40 +++++++++++++++++++++++++--------------- preset.js | 7 ++++++- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ef6899a..d3ef1d4 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ Short alias for the [postcss-modules-local-by-default](https://github.com/css-mo [debug](https://www.npmjs.com/package/debug) package is used for debugging. So to turn it on simply specify the **DEBUG** environment variable: - `DEBUG=css-modules:fetch` — to see resolved paths to the files. +- `DEBUG=css-modules:preset` — to see whether config was found or not. - `DEBUG=css-modules:setup` — to see the new options list. - `DEBUG=css-modules:*` — to see everything. diff --git a/lib/index.js b/lib/index.js index 3c0380c..391a5eb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -17,21 +17,8 @@ const ExtractImports = require('postcss-modules-extract-imports'); const Scope = require('postcss-modules-scope'); const Parser = require('postcss-modules-parser'); -/** - * @param {function|regex|string} ignore glob, regex or function - * @return {function} - */ -function buildExceptionChecker(ignore) { - if (ignore instanceof RegExp) { - return filepath => ignore.test(filepath); - } - - if (typeof ignore === 'string') { - return filepath => globToRegex(ignore).test(filepath); - } - - return ignore || negate(identity); -} +const debugFetch = require('debug')('css-modules:fetch'); +const debugSetup = require('debug')('css-modules:setup'); module.exports = function setupHook({ extensions = '.css', @@ -47,6 +34,7 @@ module.exports = function setupHook({ use, rootDir: context = process.cwd(), }) { + debugSetup(arguments[0]); validate(arguments[0]); const tokensByFile = {}; @@ -93,9 +81,12 @@ module.exports = function setupHook({ ? require.resolve(_to) : resolve(dirname(from), _to); + // checking cache let tokens = tokensByFile[filename]; if (tokens) { + debugFetch(`${filename} → cache`); + debugFetch(tokens); return tokens; } @@ -120,6 +111,9 @@ module.exports = function setupHook({ processCss(lazyResult.css, filename); } + debugFetch(`${filename} → fs`); + debugFetch(tokens); + return tokens; }; @@ -127,3 +121,19 @@ module.exports = function setupHook({ attachHook(filename => fetch(filename, filename), '.css', isException); }; + +/** + * @param {function|regex|string} ignore glob, regex or function + * @return {function} + */ +function buildExceptionChecker(ignore) { + if (ignore instanceof RegExp) { + return filepath => ignore.test(filepath); + } + + if (typeof ignore === 'string') { + return filepath => globToRegex(ignore).test(filepath); + } + + return ignore || negate(identity); +} diff --git a/preset.js b/preset.js index e5bc68b..f8ae63d 100644 --- a/preset.js +++ b/preset.js @@ -1,10 +1,15 @@ +const debug = require('debug')('css-modules:preset'); const dirname = require('path').dirname; const hook = require('.'); const seekout = require('seekout'); +debug('→ cmrh.conf.js'); const preset = seekout('cmrh.conf.js', dirname(module.parent.filename)); + if (!preset) { - throw new Error('Unable to find cmrh.conf.js'); + debug('failure'); + return void hook({}); } +debug('success'); hook(require(preset)); From bddbf22f4a9aa1d2064a935a7329eb21bf22b0ba Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 16:38:33 +0300 Subject: [PATCH 32/40] preset fix --- preset.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/preset.js b/preset.js index f8ae63d..29f1446 100644 --- a/preset.js +++ b/preset.js @@ -8,8 +8,8 @@ const preset = seekout('cmrh.conf.js', dirname(module.parent.filename)); if (!preset) { debug('failure'); - return void hook({}); + hook({}); +} else { + debug('success'); + hook(require(preset)); } - -debug('success'); -hook(require(preset)); From 3dfdca97718580a05bd024b353a8a68b997a1ea4 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 17:15:19 +0300 Subject: [PATCH 33/40] devMode --- lib/index.js | 10 +++++++--- lib/validate.js | 2 ++ test/api/devMode.js | 0 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 test/api/devMode.js diff --git a/lib/index.js b/lib/index.js index 391a5eb..0e7e6ec 100644 --- a/lib/index.js +++ b/lib/index.js @@ -21,6 +21,7 @@ const debugFetch = require('debug')('css-modules:fetch'); const debugSetup = require('debug')('css-modules:setup'); module.exports = function setupHook({ + devMode, extensions = '.css', ignore, preprocessCss = identity, @@ -39,6 +40,11 @@ module.exports = function setupHook({ const tokensByFile = {}; + // debug option is preferred NODE_ENV === 'development' + const debugMode = typeof devMode !== 'undefined' + ? devMode + : process.env.NODE_ENV === 'development'; + let scopedName; if (generateScopedName) { scopedName = typeof generateScopedName !== 'function' @@ -67,8 +73,6 @@ module.exports = function setupHook({ // https://github.com/postcss/postcss#options const runner = postcss(plugins); - // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts - /** * @todo think about replacing sequential fetch function calls with requires calls * @param {string} _to @@ -99,7 +103,7 @@ module.exports = function setupHook({ tokens = lazyResult.root.tokens; - if (process.env.NODE_ENV !== 'development') { + if (!debugMode) { // updating cache tokensByFile[filename] = tokens; } else { diff --git a/lib/validate.js b/lib/validate.js index 2310191..b12cd6f 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -4,6 +4,7 @@ const keys = require('lodash').keys; const rules = { // hook + devMode: 'boolean', extensions: 'array|string', ignore: 'function|regex|string', preprocessCss: 'function', @@ -21,6 +22,7 @@ const rules = { const tests = { array: require('lodash').isArray, + boolean: require('lodash').isBoolean, function: require('lodash').isFunction, regex: require('lodash').isRegExp, string: require('lodash').isString, diff --git a/test/api/devMode.js b/test/api/devMode.js new file mode 100644 index 0000000..e69de29 From 470a33ac6e404451cac92dbe186e8f629e4eae75 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 17:27:44 +0300 Subject: [PATCH 34/40] coverage report --- .npmignore | 1 + package.json | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.npmignore b/.npmignore index 891c86d..8daaae1 100644 --- a/.npmignore +++ b/.npmignore @@ -3,4 +3,5 @@ .gitignore .npmignore .travis.yml +coverage demo diff --git a/package.json b/package.json index 4fde707..a0df845 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "build": "babel lib --out-dir lib && babel preset.js --out-file preset.js", "test": "npm run test:babel", "test:babel": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --compilers js:babel-register", + "test:coverage": "NODE_PATH=$(pwd)/test/tokens/node_modules babel-node --presets es2015 `npm bin`/isparta cover --report text --report html `npm bin`/_mocha -- --require test/setup.js --ui tdd test/*/*.js", "test:node": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --harmony_destructuring --harmony_spread_arrays --use_strict", "test:watch": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --harmony_destructuring --harmony_spread_arrays --use_strict", "test:unit": "mocha --require test/setup.js --ui tdd test/*/*.js" @@ -51,6 +52,7 @@ "babel-cli": "^6.5.1", "babel-preset-es2015": "^6.5.0", "babel-register": "^6.5.2", + "isparta": "^4.0.0", "mocha": "^2.4.5", "sinon": "^1.17.3" } From 5b08828b1bc25206ce2eecd579d51aaec3ceb633 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 18:59:43 +0300 Subject: [PATCH 35/40] multiple extensions --- lib/index.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 0e7e6ec..5746a95 100644 --- a/lib/index.js +++ b/lib/index.js @@ -121,11 +121,23 @@ module.exports = function setupHook({ return tokens; }; + const exts = toArray(extensions); const isException = buildExceptionChecker(ignore); - attachHook(filename => fetch(filename, filename), '.css', isException); + // @todo add possibility to specify particular config for each extension + exts.forEach(extension => attachHook(filename => fetch(filename, filename), '.css', isException)); }; +/** + * @param {*} option + * @return {array} + */ +function toArray(option) { + return Array.isArray(option) + ? option + : [option]; +} + /** * @param {function|regex|string} ignore glob, regex or function * @return {function} From 3816896480d0ce18778602ed517ebe23129cd56f Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Mon, 22 Feb 2016 23:10:42 +0300 Subject: [PATCH 36/40] devMode test --- test/api/devMode.js | 105 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/test/api/devMode.js b/test/api/devMode.js index e69de29..3ba88e3 100644 --- a/test/api/devMode.js +++ b/test/api/devMode.js @@ -0,0 +1,105 @@ +const detachHook = require('../sugar').detachHook; +const dropCache = require('../sugar').dropCache; +const resolve = require('path').resolve; +const writeFileSync = require('fs').writeFileSync; + +const destination = resolve(__dirname, './fixture/oceanic.css'); +const source1 = `.color\n{\n background: #1e2a35;\n}\n`; +const source2 = `.awesome-color\n{\n background: #1e2a35;\n}\n`; + +suite('api/devMode', () => { + suite('shouldn`t calls cache in development mode', () => { + suite('devMode:false options should override NODE_ENV="development"', () => { + test('should retrive data from cache', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + color: '_test_api_fixture_oceanic__color', + }); + }); + + setup(() => { + process.env.NODE_ENV = 'development'; + hook({devMode: false}); + writeFile(source1); + require('./fixture/oceanic.css'); + writeFile(source2); + }); + + teardown(() => { + process.env.NODE_ENV = ''; + }); + }); + + suite('should cache calls without any options', () => { + test('should retrive data from cache', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + color: '_test_api_fixture_oceanic__color', + }); + }); + + setup(() => { + hook({}); + writeFile(source1); + require('./fixture/oceanic.css'); + writeFile(source2); + }); + }); + }); + + suite('should clear cache in development mode', () => { + suite('devMode:true option should works without NODE_ENV="development"', () => { + test('should retrive data from fs', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + 'awesome-color': '_test_api_fixture_oceanic__awesome-color', + }); + }); + + setup(() => { + hook({devMode: true}); + writeFile(source1); + require('./fixture/oceanic.css'); + writeFile(source2); + }); + }); + + suite('NODE_ENV="development" should works without debug:true option', () => { + test('should retrive data from fs', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + 'awesome-color': '_test_api_fixture_oceanic__awesome-color', + }); + }); + + setup(() => { + process.env.NODE_ENV = 'development'; + hook({}); + writeFile(source1); + require('./fixture/oceanic.css'); + writeFile(source2); + }); + + teardown(() => { + process.env.NODE_ENV = ''; + }); + }); + }); + + teardown(() => { + writeFile(source1); + detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); + }); +}); + +/** + * @param {string} data + */ +function writeFile(data) { + writeFileSync(destination, data, 'utf8'); +} From 13f1f01183c131e6355c3cf1bcac4cefbd1eadd3 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Tue, 23 Feb 2016 00:22:15 +0300 Subject: [PATCH 37/40] preset update --- preset.js | 14 +++++++------- test/preset/index.js | 26 +++++++++++++++++++++----- test/preset/{ => js}/cmrh.conf.js | 0 test/preset/js/preset.js | 2 ++ 4 files changed, 30 insertions(+), 12 deletions(-) rename test/preset/{ => js}/cmrh.conf.js (100%) create mode 100644 test/preset/js/preset.js diff --git a/preset.js b/preset.js index 29f1446..b20216c 100644 --- a/preset.js +++ b/preset.js @@ -1,15 +1,15 @@ +const basename = require('path').basename; const debug = require('debug')('css-modules:preset'); const dirname = require('path').dirname; -const hook = require('.'); +const hook = require('./lib/index'); const seekout = require('seekout'); -debug('→ cmrh.conf.js'); const preset = seekout('cmrh.conf.js', dirname(module.parent.filename)); -if (!preset) { - debug('failure'); - hook({}); -} else { - debug('success'); +if (preset) { + debug(`→ ${basename(preset)}`); hook(require(preset)); +} else { + debug(`→ defaults`); + hook({}); } diff --git a/test/preset/index.js b/test/preset/index.js index 286c002..90f7b64 100644 --- a/test/preset/index.js +++ b/test/preset/index.js @@ -2,17 +2,33 @@ const detachHook = require('../sugar').detachHook; const dropCache = require('../sugar').dropCache; suite('css-modules-require-hook/preset', () => { - setup(() => require('../../preset')); + suite('using cmrh.conf.js file', () => { + test('should return tokens', () => { + const tokens = require('./fixture/oceanic.css'); - test('should return tokens', () => { - const tokens = require('./fixture/oceanic.css'); - assert.deepEqual(tokens, { - color: 'oceanic__color___1sqWL', + assert.deepEqual(tokens, { + color: 'oceanic__color___1sqWL', + }); }); + + setup(() => require('./js/preset')); + }); + + suite('using defaults', () => { + test('should return tokens', () => { + const tokens = require('./fixture/oceanic.css'); + + assert.deepEqual(tokens, { + color: '_test_preset_fixture_oceanic__color', + }); + }); + + setup(() => require('../../preset')); }); teardown(() => { detachHook('.css'); + dropCache('../preset'); dropCache('./preset/fixture/oceanic.css'); }); }); diff --git a/test/preset/cmrh.conf.js b/test/preset/js/cmrh.conf.js similarity index 100% rename from test/preset/cmrh.conf.js rename to test/preset/js/cmrh.conf.js diff --git a/test/preset/js/preset.js b/test/preset/js/preset.js new file mode 100644 index 0000000..6e12428 --- /dev/null +++ b/test/preset/js/preset.js @@ -0,0 +1,2 @@ +// using cmrh.conf.js in the local directory +require('../../../preset'); From 1b1f4405c416128b50c2af6bf310b00f92d6972d Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Tue, 23 Feb 2016 00:25:59 +0300 Subject: [PATCH 38/40] small fix --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 5746a95..d58235e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -48,7 +48,7 @@ module.exports = function setupHook({ let scopedName; if (generateScopedName) { scopedName = typeof generateScopedName !== 'function' - ? genericNames(generateScopedName || '[name]__[local]___[hash:base64:5]', {context}) + ? genericNames(generateScopedName, {context}) // for example '[name]__[local]___[hash:base64:5]' : generateScopedName; } else { // small fallback From aa1bee5a9d17afaea91e230491b096450370ee6b Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Tue, 23 Feb 2016 00:36:43 +0300 Subject: [PATCH 39/40] extra extensions test --- lib/index.js | 2 +- test/api/extensions.js | 34 ++++++++++++++++++++++++++++++++++ test/api/fixture/oceanic.scss | 4 ++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/api/fixture/oceanic.scss diff --git a/lib/index.js b/lib/index.js index d58235e..70fccc3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -125,7 +125,7 @@ module.exports = function setupHook({ const isException = buildExceptionChecker(ignore); // @todo add possibility to specify particular config for each extension - exts.forEach(extension => attachHook(filename => fetch(filename, filename), '.css', isException)); + exts.forEach(extension => attachHook(filename => fetch(filename, filename), extension, isException)); }; /** diff --git a/test/api/extensions.js b/test/api/extensions.js index 405c19a..775aba5 100644 --- a/test/api/extensions.js +++ b/test/api/extensions.js @@ -16,4 +16,38 @@ suite('api/extensions', () => { dropCache('./api/fixture/oceanic.css'); }); }); + + suite('uses provided extension', () => { + test('should provide tokens', () => { + const tokens = require('./fixture/oceanic.css'); + assert(tokens); + }); + + setup(() => hook({extensions: '.css'})); + + teardown(() => { + detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); + }); + }); + + suite('uses multiple extensions', () => { + test('should provide tokens', () => { + const tokens = require('./fixture/oceanic.css'); + assert(tokens); + }); + + test('should provide tokens', () => { + const tokens = require('./fixture/oceanic.scss'); + assert(tokens); + }); + + setup(() => hook({extensions: ['.css', '.scss']})); + + teardown(() => { + detachHook('.css'); + dropCache('./api/fixture/oceanic.css'); + dropCache('./api/fixture/oceanic.scss'); + }); + }); }); diff --git a/test/api/fixture/oceanic.scss b/test/api/fixture/oceanic.scss new file mode 100644 index 0000000..7e4881c --- /dev/null +++ b/test/api/fixture/oceanic.scss @@ -0,0 +1,4 @@ +.color +{ + background: #1e2a35; +} From ac0edf3bd55eb6e2fb1b34ed5a8c1d93504b4e10 Mon Sep 17 00:00:00 2001 From: Alexey Litvinov Date: Tue, 23 Feb 2016 00:52:40 +0300 Subject: [PATCH 40/40] readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3ef1d4..d3047dd 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ $ npm i css-modules-require-hook Now, there are two ways to attach hook: manually or using preset file. -The first one allows you to pass options manually after module was required, to make it work. Example: +The first one allows you to pass options manually after module was required. Example: ```javascript const hook = require('css-modules-require-hook'); @@ -38,7 +38,7 @@ hook({ // const styles = require('./icon.css'); ``` -The second one allows you to move options to separated file `cmrh.conf.js`, which should be located in your working directory (`process.cwd()`) or in its ancestors. Example: +The second one allows you to move options to the separate file `cmrh.conf.js`. Config file should be located in the same directory where executor is or in its ancestor directories. In that case hook will be attached right after the `css-modules-require-hook/preset` module will be required. Example: ```javascript // cmrh.conf.js