Skip to content

Breaking API changes & CSSI tests #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@

## API

```js
import Core from 'css-modules-loader-core'
let core = new Core()
```

### core.load( sourceString , sourcePath , pathFetcher ) =><br>&nbsp;&nbsp;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:
Expand All @@ -12,22 +17,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")
]
])
```

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
},
"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.4"
"postcss-modules-extract-imports": "0.0.3",
"postcss-modules-local-by-default": "^0.0.7",
"postcss-modules-scope": "^0.0.5"
},
"devDependencies": {
"babel": "^5.4.7",
"babel-eslint": "^3.1.11",
"babel": "^5.5.4",
"babel-eslint": "^3.1.14",
"babelify": "^6.1.2",
"chokidar-cli": "^0.2.1",
"eslint": "^0.22.1",
Expand Down
5 changes: 3 additions & 2 deletions src/file-system-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ const traceKeySorter = ( a, b ) => {
};

export default class FileSystemLoader {
constructor( root ) {
constructor( root, plugins ) {
this.root = root
this.sources = {}
this.importNr = 0
this.core = new Core(plugins)
}

fetch( _newPath, relativeTo, _trace ) {
Expand All @@ -35,7 +36,7 @@ export default class FileSystemLoader {

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
resolve( exportTokens )
Expand Down
23 changes: 11 additions & 12 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,10 @@ import scope from 'postcss-modules-scope'

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 )
Expand All @@ -28,3 +20,10 @@ export default {
} )
}
}


// These three plugins are aliased under this package for simplicity.
Core.localByDefault = localByDefault
Core.extractImports = extractImports
Core.scope = scope
Core.defaultPlugins = [localByDefault, extractImports, scope]
11 changes: 10 additions & 1 deletion src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default class Parser {

plugin( css, result ) {
return Promise.all( this.fetchAllImports( css ) )
.then( _ => this.linkImportedSymbols( css ) )
.then( _ => this.extractExports( css ) )
}

Expand All @@ -24,6 +25,14 @@ export default class Parser {
return imports
}

linkImportedSymbols( css ) {
css.eachDecl( decl => {
Object.keys(this.translations).forEach( translation => {
decl.value = decl.value.replace(translation, this.translations[translation])
} )
})
}

extractExports( css ) {
css.each( node => {
if ( node.type == "rule" && node.selector == ":export" ) this.handleExport( node )
Expand All @@ -48,7 +57,7 @@ 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()
Expand Down
7 changes: 7 additions & 0 deletions test/cssi/interchange-format/colors.css
Original file line number Diff line number Diff line change
@@ -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;
}
6 changes: 6 additions & 0 deletions test/cssi/interchange-format/expected.css
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions test/cssi/interchange-format/expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"localName": "x__single_import_export_source__localName x__single_import_export_colors__blackShadow"
}
11 changes: 11 additions & 0 deletions test/cssi/interchange-format/source.css
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 4 additions & 0 deletions test/cssi/pseudo-variables/colors.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:export {
black: #222;
white: #ddd;
}
5 changes: 5 additions & 0 deletions test/cssi/pseudo-variables/expected.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

.x__lol {
color: #222;
background: #ddd;
}
3 changes: 3 additions & 0 deletions test/cssi/pseudo-variables/expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"lol": "x__lol"
}
13 changes: 13 additions & 0 deletions test/cssi/pseudo-variables/source.css
Original file line number Diff line number Diff line change
@@ -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;
}
37 changes: 22 additions & 15 deletions test/test-cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,26 @@ 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 => {
assert.equal( loader.finalSource, expected )
assert.equal( JSON.stringify( tokens ), JSON.stringify( expectedTokens ) )
} ).then( done, done )
} );
}
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 )
} );
}
} );
} );
} );
} )
2 changes: 1 addition & 1 deletion test/test-cases/multiple-dependencies/b.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.b {
extends: d from "./d.css";
composes: d from "./d.css";
color: #bbb;
}
4 changes: 2 additions & 2 deletions test/test-cases/multiple-dependencies/source.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.a {
extends: b from "./b.css";
extends: c from "./c.css";
composes: b from "./b.css";
composes: c from "./c.css";
color: #aaa;
}

2 changes: 1 addition & 1 deletion test/test-cases/single-import-export/source.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.localName {
extends: blackShadow from "./colors.css";
composes: blackShadow from "./colors.css";
color: red;
}