diff --git a/.gitignore b/.gitignore index 491fc35..017354f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -node_modules +node_modules/* +!node_modules/cool-styles lib diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d669492 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 4 + - 6 diff --git a/README.md b/README.md index 8bc5622..8a666de 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ # CSS Module Loader Core > A loader-agnostic CSS Modules implementation, based on PostCSS +[![Build Status](https://travis-ci.org/css-modules/css-modules-loader-core.svg?branch=master)](https://travis-ci.org/css-modules/css-modules-loader-core) + ## API +```js +import Core from 'css-modules-loader-core' +let core = new Core() +``` + ### core.load( sourceString , sourcePath , pathFetcher ) =>
  Promise({ injectableSource, exportTokens }) Processes the input CSS `sourceString`, looking for dependencies such as `@import` or `:import`. Any localisation will happen by prefixing a sanitised version of `sourcePath` When dependencies are found, it will ask the `pathFetcher` for each dependency, resolve & inline any imports, and return the following object: @@ -12,22 +19,21 @@ Processes the input CSS `sourceString`, looking for dependencies such as `@impor These should map nicely to what your build-tool-specific loader needs to do its job. -### core.plugins = pluginArray +### new Core([plugins]) The default set of plugins is [[postcss-modules-local-by-default](https://github.com/css-modules/postcss-modules-local-by-default), [postcss-modules-extract-imports](https://github.com/css-modules/postcss-modules-extract-imports), [postcss-modules-scope](https://github.com/css-modules/postcss-modules-scope)] (i.e. the CSS Modules specification). This can override which PostCSS plugins you wish to execute, e.g. ```js -import core from 'css-loader-core' +import Core from 'css-loader-core' import autoprefixer from 'autoprefixer' import colorFunctions from 'postcss-color-function' // Don't run local-by-default, but use colorFunctions // beforehand and autoprefixer afterwards: -core.plugins = [ +let core = new Core([ colorFunctions, core.plugins.extractImports, core.plugins.scope, autoprefixer("Last 2 Versions") -] +]) ``` - diff --git a/node_modules/cool-styles/foo.css b/node_modules/cool-styles/foo.css new file mode 100644 index 0000000..65f95db --- /dev/null +++ b/node_modules/cool-styles/foo.css @@ -0,0 +1,3 @@ +.example { + color: #F00; +} diff --git a/package.json b/package.json index 3d240e3..01f795d 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,33 @@ { "name": "css-modules-loader-core", - "version": "0.0.3", + "version": "1.1.0", "description": "A loader-agnostic CSS Modules implementation, based on PostCSS", "main": "lib/index.js", "directories": { "test": "test" }, "dependencies": { - "postcss": "^4.1.11", - "postcss-modules-extract-imports": "0.0.2", - "postcss-modules-local-by-default": "0.0.7", - "postcss-modules-scope": "0.0.3" + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.1", + "postcss-modules-extract-imports": "1.1.0", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0" }, "devDependencies": { - "babel": "^5.4.7", - "babel-eslint": "^3.1.9", - "babelify": "^6.1.2", - "chokidar-cli": "^0.2.1", - "eslint": "^0.22.1", - "mocha": "^2.2.5" + "babel": "5.8.29", + "babel-eslint": "7.1.0", + "babelify": "7.3.0", + "chokidar-cli": "1.1.0", + "eslint": "3.10.1", + "mocha": "3.1.2" }, "scripts": { "lint": "eslint src", "build": "babel --out-dir lib src", "autotest": "chokidar src test -c 'npm test'", "test": "mocha --compilers js:babel/register", - "prepublish": "npm run build" + "prepublish": "rm -rf lib/* && npm run build" }, "repository": { "type": "git", diff --git a/src/file-system-loader.js b/src/file-system-loader.js index 24bdc72..e26c2c0 100644 --- a/src/file-system-loader.js +++ b/src/file-system-loader.js @@ -20,25 +20,41 @@ const traceKeySorter = ( a, b ) => { }; export default class FileSystemLoader { - constructor( root ) { + constructor( root, plugins ) { this.root = root this.sources = {} - this.seenPaths = new Set() + this.traces = {} this.importNr = 0 + this.core = new Core(plugins) + this.tokensByFile = {}; } fetch( _newPath, relativeTo, _trace ) { let newPath = _newPath.replace( /^["']|["']$/g, "" ), trace = _trace || String.fromCharCode( this.importNr++ ) return new Promise( ( resolve, reject ) => { - let rootRelativePath = path.resolve( path.dirname( relativeTo ), newPath ), - fileRelativePath = this.root + rootRelativePath + let relativeDir = path.dirname( relativeTo ), + rootRelativePath = path.resolve( relativeDir, newPath ), + fileRelativePath = path.resolve( path.join( this.root, relativeDir ), newPath ) + + // if the path is not relative or absolute, try to resolve it in node_modules + if (newPath[0] !== '.' && newPath[0] !== '/') { + try { + fileRelativePath = require.resolve(newPath); + } + catch (e) {} + } + + const tokens = this.tokensByFile[fileRelativePath] + if (tokens) { return resolve(tokens) } fs.readFile( fileRelativePath, "utf-8", ( err, source ) => { if ( err ) reject( err ) - Core.load( source, rootRelativePath, trace, this.fetch.bind( this ) ) + this.core.load( source, rootRelativePath, trace, this.fetch.bind( this ) ) .then( ( { injectableSource, exportTokens } ) => { - this.sources[trace] = injectableSource + this.sources[fileRelativePath] = injectableSource + this.traces[trace] = fileRelativePath + this.tokensByFile[fileRelativePath] = exportTokens resolve( exportTokens ) }, reject ) } ) @@ -46,7 +62,16 @@ export default class FileSystemLoader { } get finalSource() { - return Object.keys( this.sources ).sort( traceKeySorter ).map( s => this.sources[s] ) - .join( "" ) + const traces = this.traces + const sources = this.sources + let written = new Set() + + return Object.keys( traces ).sort( traceKeySorter ).map(key => { + const filename = traces[key] + if (written.has(filename)) { return null } + written.add(filename) + + return sources[filename]; + }).join( "" ) } } diff --git a/src/index.js b/src/index.js index a0dc57b..92795bd 100644 --- a/src/index.js +++ b/src/index.js @@ -2,21 +2,14 @@ import postcss from 'postcss' import localByDefault from 'postcss-modules-local-by-default' import extractImports from 'postcss-modules-extract-imports' import scope from 'postcss-modules-scope' +import values from 'postcss-modules-values' import Parser from './parser' -export default { - // These three plugins are aliased under this package for simplicity. - localByDefault, - extractImports, - scope, - - // The default set of plugins - plugins: [ - localByDefault, - extractImports, - scope - ], +export default class Core { + constructor( plugins ) { + this.plugins = plugins || Core.defaultPlugins + } load( sourceString, sourcePath, trace, pathFetcher ) { let parser = new Parser( pathFetcher, trace ) @@ -28,3 +21,11 @@ export default { } ) } } + +// These four plugins are aliased under this package for simplicity. +Core.values = values +Core.localByDefault = localByDefault +Core.extractImports = extractImports +Core.scope = scope + +Core.defaultPlugins = [values, localByDefault, extractImports, scope] diff --git a/src/parser.js b/src/parser.js index e28f199..8dfb1dc 100644 --- a/src/parser.js +++ b/src/parser.js @@ -1,4 +1,5 @@ const importRegexp = /^:import\((.+)\)$/ +import replaceSymbols from 'icss-replace-symbols' export default class Parser { constructor( pathFetcher, trace ) { @@ -11,6 +12,7 @@ export default class Parser { plugin( css, result ) { return Promise.all( this.fetchAllImports( css ) ) + .then( _ => this.linkImportedSymbols( css ) ) .then( _ => this.extractExports( css ) ) } @@ -24,6 +26,10 @@ export default class Parser { return imports } + linkImportedSymbols( css ) { + replaceSymbols(css, this.translations) + } + extractExports( css ) { css.each( node => { if ( node.type == "rule" && node.selector == ":export" ) this.handleExport( node ) @@ -39,7 +45,7 @@ export default class Parser { this.exportTokens[decl.prop] = decl.value } } ) - exportNode.removeSelf() + exportNode.remove() } fetchImport( importNode, relativeTo, depNr ) { @@ -48,10 +54,10 @@ export default class Parser { return this.pathFetcher( file, relativeTo, depTrace ).then( exports => { importNode.each( decl => { if ( decl.type == 'decl' ) { - this.translations[decl.value] = exports[decl.prop] + this.translations[decl.prop] = exports[decl.value] } } ) - importNode.removeSelf() + importNode.remove() }, err => console.log( err ) ) } } diff --git a/test/cssi/interchange-format/colors.css b/test/cssi/interchange-format/colors.css new file mode 100644 index 0000000..4057aae --- /dev/null +++ b/test/cssi/interchange-format/colors.css @@ -0,0 +1,7 @@ +: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 new file mode 100644 index 0000000..36f1092 --- /dev/null +++ b/test/cssi/interchange-format/expected.css @@ -0,0 +1,6 @@ +.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 new file mode 100644 index 0000000..43311c7 --- /dev/null +++ b/test/cssi/interchange-format/expected.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 0000000..d7125a0 --- /dev/null +++ b/test/cssi/interchange-format/source.css @@ -0,0 +1,11 @@ +: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 new file mode 100644 index 0000000..3ac72d9 --- /dev/null +++ b/test/cssi/pseudo-variables/colors.css @@ -0,0 +1,4 @@ +:export { + black: #222; + white: #ddd; +} diff --git a/test/cssi/pseudo-variables/expected.css b/test/cssi/pseudo-variables/expected.css new file mode 100644 index 0000000..371497c --- /dev/null +++ b/test/cssi/pseudo-variables/expected.css @@ -0,0 +1,5 @@ + +.x__lol { + color: #222; + background: #ddd; +} diff --git a/test/cssi/pseudo-variables/expected.json b/test/cssi/pseudo-variables/expected.json new file mode 100644 index 0000000..b8c3c23 --- /dev/null +++ b/test/cssi/pseudo-variables/expected.json @@ -0,0 +1,3 @@ +{ + "lol": "x__lol" +} diff --git a/test/cssi/pseudo-variables/source.css b/test/cssi/pseudo-variables/source.css new file mode 100644 index 0000000..cc4b95a --- /dev/null +++ b/test/cssi/pseudo-variables/source.css @@ -0,0 +1,13 @@ +: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/test-cases.js b/test/test-cases.js index 616c01b..c6adcff 100644 --- a/test/test-cases.js +++ b/test/test-cases.js @@ -9,19 +9,47 @@ let normalize = ( str ) => { return str.replace( /\r\n?/g, "\n" ); } -describe( "test-cases", () => { - let testDir = path.join( __dirname, "test-cases" ) - fs.readdirSync( testDir ).forEach( testCase => { - if ( fs.existsSync( path.join( testDir, testCase, "source.css" ) ) ) { - it( "should " + testCase.replace( /-/g, " " ), done => { - let expected = normalize( fs.readFileSync( path.join( testDir, testCase, "expected.css" ), "utf-8" ) ) - let loader = new FileSystemLoader( testDir ) - let expectedTokens = JSON.parse( fs.readFileSync( path.join( testDir, testCase, "expected.json" ), "utf-8" ) ) - loader.fetch( `${testCase}/source.css`, "/" ).then( tokens => { +const pipelines = { + "test-cases": undefined, + "cssi": [] +} + +Object.keys( pipelines ).forEach( dirname => { + describe( dirname, () => { + let testDir = path.join( __dirname, dirname ) + fs.readdirSync( testDir ).forEach( testCase => { + if ( fs.existsSync( path.join( testDir, testCase, "source.css" ) ) ) { + it( "should " + testCase.replace( /-/g, " " ), done => { + let expected = normalize( fs.readFileSync( path.join( testDir, testCase, "expected.css" ), "utf-8" ) ) + let loader = new FileSystemLoader( testDir, pipelines[dirname] ) + let expectedTokens = JSON.parse( fs.readFileSync( path.join( testDir, testCase, "expected.json" ), "utf-8" ) ) + loader.fetch( `${testCase}/source.css`, "/" ).then( tokens => { + assert.equal( loader.finalSource, expected ) + assert.equal( JSON.stringify( tokens ), JSON.stringify( expectedTokens ) ) + } ).then( done, done ) + } ); + } + } ); + } ); +} ) + +// special case for testing multiple sources +describe( 'multiple sources', () => { + let testDir = path.join( __dirname, 'test-cases' ) + let testCase = 'multiple-sources'; + let dirname = 'test-cases'; + if ( fs.existsSync( path.join( testDir, testCase, "source1.css" ) ) ) { + it( "should " + testCase.replace( /-/g, " " ), done => { + let expected = normalize( fs.readFileSync( path.join( testDir, testCase, "expected.css" ), "utf-8" ) ) + let loader = new FileSystemLoader( testDir, pipelines[dirname] ) + let expectedTokens = JSON.parse( fs.readFileSync( path.join( testDir, testCase, "expected.json" ), "utf-8" ) ) + loader.fetch( `${testCase}/source1.css`, "/" ).then( tokens1 => { + loader.fetch( `${testCase}/source2.css`, "/" ).then( tokens2 => { assert.equal( loader.finalSource, expected ) + const tokens = Object.assign({}, tokens1, tokens2); assert.equal( JSON.stringify( tokens ), JSON.stringify( expectedTokens ) ) } ).then( done, done ) - } ); - } - } ); + }) + } ); + } } ); diff --git a/test/test-cases/compose-node-module/expected.css b/test/test-cases/compose-node-module/expected.css new file mode 100644 index 0000000..0667b94 --- /dev/null +++ b/test/test-cases/compose-node-module/expected.css @@ -0,0 +1,5 @@ +._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 new file mode 100644 index 0000000..a57448c --- /dev/null +++ b/test/test-cases/compose-node-module/expected.json @@ -0,0 +1,3 @@ +{ + "foo": "_compose_node_module_source__foo _compose_node_module_cool_styles_foo__example" +} diff --git a/test/test-cases/compose-node-module/source.css b/test/test-cases/compose-node-module/source.css new file mode 100644 index 0000000..6477b1d --- /dev/null +++ b/test/test-cases/compose-node-module/source.css @@ -0,0 +1,3 @@ +.foo { + composes: example from "cool-styles/foo.css"; +} diff --git a/test/test-cases/localise-export/expected.css b/test/test-cases/localise-export/expected.css index f09dca6..c4be0d9 100644 --- a/test/test-cases/localise-export/expected.css +++ b/test/test-cases/localise-export/expected.css @@ -1,4 +1,3 @@ - ._localise_export_source__one { color: red; } diff --git a/test/test-cases/multiple-dependencies/b.css b/test/test-cases/multiple-dependencies/b.css index 859eda9..e29560a 100644 --- a/test/test-cases/multiple-dependencies/b.css +++ b/test/test-cases/multiple-dependencies/b.css @@ -1,4 +1,8 @@ -.b { - extends: d from "./d.css"; - color: #bbb; +.b1 { + composes: d1 d2 from "./d.css"; + color: #b1b1b1; +} + +.b2 { + color: #b2b2b2; } diff --git a/test/test-cases/multiple-dependencies/d.css b/test/test-cases/multiple-dependencies/d.css index 4638a27..4e7ec24 100644 --- a/test/test-cases/multiple-dependencies/d.css +++ b/test/test-cases/multiple-dependencies/d.css @@ -1,3 +1,6 @@ -.d { - color: #ddd; +.d1 { + color: #d1d1d1; +} +.d2 { + color: #d2d2d2; } diff --git a/test/test-cases/multiple-dependencies/expected.css b/test/test-cases/multiple-dependencies/expected.css index 7b81d2a..01b0d9f 100644 --- a/test/test-cases/multiple-dependencies/expected.css +++ b/test/test-cases/multiple-dependencies/expected.css @@ -1,16 +1,19 @@ - -._multiple_dependencies_d__d { - color: #ddd; +._multiple_dependencies_d__d1 { + color: #d1d1d1; } - -._multiple_dependencies_b__b { - color: #bbb; +._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 index c457552..7327ebb 100644 --- a/test/test-cases/multiple-dependencies/expected.json +++ b/test/test-cases/multiple-dependencies/expected.json @@ -1,3 +1,3 @@ { - "a": "_multiple_dependencies_source__a _multiple_dependencies_b__b _multiple_dependencies_d__d _multiple_dependencies_c__c" + "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 index 72e7221..0824a26 100644 --- a/test/test-cases/multiple-dependencies/source.css +++ b/test/test-cases/multiple-dependencies/source.css @@ -1,6 +1,7 @@ .a { - extends: b from "./b.css"; - extends: c from "./c.css"; + 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 new file mode 100644 index 0000000..c4dcd92 --- /dev/null +++ b/test/test-cases/multiple-sources/b.css @@ -0,0 +1,4 @@ +.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 new file mode 100644 index 0000000..e5a7b52 --- /dev/null +++ b/test/test-cases/multiple-sources/c.css @@ -0,0 +1,3 @@ +.c { + color: #ccc; +} diff --git a/test/test-cases/multiple-sources/d.css b/test/test-cases/multiple-sources/d.css new file mode 100644 index 0000000..4638a27 --- /dev/null +++ b/test/test-cases/multiple-sources/d.css @@ -0,0 +1,3 @@ +.d { + color: #ddd; +} diff --git a/test/test-cases/multiple-sources/expected.css b/test/test-cases/multiple-sources/expected.css new file mode 100644 index 0000000..da64401 --- /dev/null +++ b/test/test-cases/multiple-sources/expected.css @@ -0,0 +1,15 @@ +._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 new file mode 100644 index 0000000..074abf9 --- /dev/null +++ b/test/test-cases/multiple-sources/expected.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 0000000..983c7fd --- /dev/null +++ b/test/test-cases/multiple-sources/source1.css @@ -0,0 +1,5 @@ +.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 new file mode 100644 index 0000000..151a720 --- /dev/null +++ b/test/test-cases/multiple-sources/source2.css @@ -0,0 +1,4 @@ +.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 index 471585d..2f8e4da 100644 --- a/test/test-cases/simple-export/expected.css +++ b/test/test-cases/simple-export/expected.css @@ -1,4 +1,3 @@ - ._simple_export_source__localName { color: red; } diff --git a/test/test-cases/single-import-export/colors.css b/test/test-cases/single-import-export/colors.css index 334426e..a7c1ce1 100644 --- a/test/test-cases/single-import-export/colors.css +++ b/test/test-cases/single-import-export/colors.css @@ -1,3 +1,7 @@ .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 index 81b058d..74398b2 100644 --- a/test/test-cases/single-import-export/expected.css +++ b/test/test-cases/single-import-export/expected.css @@ -1,8 +1,10 @@ - ._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 index 35b62eb..802cd4e 100644 --- a/test/test-cases/single-import-export/expected.json +++ b/test/test-cases/single-import-export/expected.json @@ -1,3 +1,3 @@ { - "localName": "_single_import_export_source__localName _single_import_export_colors__blackShadow" + "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 index 2b196fb..57dbc17 100644 --- a/test/test-cases/single-import-export/source.css +++ b/test/test-cases/single-import-export/source.css @@ -1,4 +1,4 @@ .localName { - extends: blackShadow from "./colors.css"; + composes: blackShadow redBorder from "./colors.css"; color: red; } diff --git a/test/test-cases/values/borders.css b/test/test-cases/values/borders.css new file mode 100644 index 0000000..f3670f7 --- /dev/null +++ b/test/test-cases/values/borders.css @@ -0,0 +1,3 @@ +.dashed { + border: 4px dashed; +} diff --git a/test/test-cases/values/breakpoints.css b/test/test-cases/values/breakpoints.css new file mode 100644 index 0000000..0b80b8b --- /dev/null +++ b/test/test-cases/values/breakpoints.css @@ -0,0 +1,3 @@ +@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 new file mode 100644 index 0000000..ff83776 --- /dev/null +++ b/test/test-cases/values/colors.css @@ -0,0 +1,16 @@ +@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 new file mode 100644 index 0000000..0562fb8 --- /dev/null +++ b/test/test-cases/values/expected.css @@ -0,0 +1,35 @@ +._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 new file mode 100644 index 0000000..ee98683 --- /dev/null +++ b/test/test-cases/values/expected.json @@ -0,0 +1,9 @@ +{ + "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 new file mode 100644 index 0000000..3953a8d --- /dev/null +++ b/test/test-cases/values/source.css @@ -0,0 +1,25 @@ +@value borders: "./borders.css"; +@value 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; + } +}