Skip to content

Commit 1e15f28

Browse files
committed
YES, cracked it. Maintaining a dep ID trace and a sorting algorithm and we're laughing
1 parent 0a8218c commit 1e15f28

File tree

6 files changed

+43
-14
lines changed

6 files changed

+43
-14
lines changed

src/file-system-loader.js

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,51 @@ import Core from './index.js'
22
import fs from 'fs'
33
import path from 'path'
44

5+
// Sorts dependencies in the following way:
6+
// AAA comes before AA and A
7+
// AB comes after AA and before A
8+
// All Bs come after all As
9+
// This ensures that the files are always returned in the following order:
10+
// - In the order they were required, except
11+
// - After all their dependencies
12+
const traceKeySorter = ( a, b ) => {
13+
if ( a.length < b.length ) {
14+
return a < b.substring( 0, a.length ) ? -1 : 1
15+
} else if ( a.length > b.length ) {
16+
return a.substring( 0, b.length ) <= b ? -1 : 1
17+
} else {
18+
return a < b ? -1 : 1
19+
}
20+
};
21+
522
export default class FileSystemLoader {
623
constructor( root ) {
724
this.root = root
8-
this.sources = []
25+
this.sources = {}
926
this.seenPaths = new Set()
27+
this.importNr = 0
1028
}
1129

12-
fetch( _newPath, relativeTo ) {
13-
let newPath = _newPath.replace( /^["']|["']$/g, "" )
30+
fetch( _newPath, relativeTo, _trace ) {
31+
let newPath = _newPath.replace( /^["']|["']$/g, "" ),
32+
trace = _trace || String.fromCharCode( this.importNr++ )
1433
return new Promise( ( resolve, reject ) => {
1534
let rootRelativePath = path.resolve( path.dirname( relativeTo ), newPath ),
1635
fileRelativePath = this.root + rootRelativePath
1736

1837
fs.readFile( fileRelativePath, "utf-8", ( err, source ) => {
1938
if ( err ) reject( err )
20-
Core.load( source, rootRelativePath, this.fetch.bind( this ) )
39+
Core.load( source, rootRelativePath, trace, this.fetch.bind( this ) )
2140
.then( ( { injectableSource, exportTokens } ) => {
22-
this.sources.push( injectableSource )
41+
this.sources[trace] = injectableSource
2342
resolve( exportTokens )
2443
}, reject )
2544
} )
2645
} )
2746
}
47+
48+
get finalSource() {
49+
return Object.keys( this.sources ).sort( traceKeySorter ).map( s => this.sources[s] )
50+
.join( "" )
51+
}
2852
}

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export default {
1818
scope
1919
],
2020

21-
load( sourceString, sourcePath, pathFetcher ) {
22-
let parser = new Parser( pathFetcher )
21+
load( sourceString, sourcePath, trace, pathFetcher ) {
22+
let parser = new Parser( pathFetcher, trace )
2323

2424
return postcss( this.plugins.concat( [parser.plugin] ) )
2525
.process( sourceString, { from: "/" + sourcePath } )

src/parser.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const importRegexp = /^:import\((.+)\)$/
22

33
export default class Parser {
4-
constructor( pathFetcher ) {
4+
constructor( pathFetcher, trace ) {
55
this.pathFetcher = pathFetcher
66
this.plugin = this.plugin.bind( this )
77
this.exportTokens = {}
88
this.translations = {}
9+
this.trace = trace
910
}
1011

1112
plugin( css, result ) {
@@ -17,7 +18,7 @@ export default class Parser {
1718
let imports = []
1819
css.each( node => {
1920
if ( node.type == "rule" && node.selector.match( importRegexp ) ) {
20-
imports.push( this.fetchImport( node, css.source.input.from ) )
21+
imports.push( this.fetchImport( node, css.source.input.from, imports.length ) )
2122
}
2223
} )
2324
return imports
@@ -41,9 +42,10 @@ export default class Parser {
4142
exportNode.removeSelf()
4243
}
4344

44-
fetchImport( importNode, relativeTo ) {
45-
let file = importNode.selector.match( importRegexp )[1]
46-
return this.pathFetcher( file, relativeTo ).then( exports => {
45+
fetchImport( importNode, relativeTo, depNr ) {
46+
let file = importNode.selector.match( importRegexp )[1],
47+
depTrace = this.trace + String.fromCharCode(depNr)
48+
return this.pathFetcher( file, relativeTo, depTrace ).then( exports => {
4749
importNode.each( decl => {
4850
if ( decl.type == 'decl' ) {
4951
this.translations[decl.value] = exports[decl.prop]

test/test-cases.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe( "test-cases", () => {
1818
let loader = new FileSystemLoader( testDir )
1919
let expectedTokens = JSON.parse( fs.readFileSync( path.join( testDir, testCase, "expected.json" ), "utf-8" ) )
2020
loader.fetch( `${testCase}/source.css`, "/" ).then( tokens => {
21-
assert.equal( loader.sources.join( "" ), expected )
21+
assert.equal( loader.finalSource, expected )
2222
assert.equal( JSON.stringify( tokens ), JSON.stringify( expectedTokens ) )
2323
} ).then( done, done )
2424
} );

test/test-cases/multiple-dependencies/expected.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
._multiple_dependencies_source__a {
1515
color: #aaa;
1616
}
17+
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
{}
1+
{
2+
"a": "_multiple_dependencies_source__a _multiple_dependencies_b__b _multiple_dependencies_d__d _multiple_dependencies_c__c"
3+
}

0 commit comments

Comments
 (0)