Skip to content

Commit

Permalink
Refactor path resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
TrySound committed Dec 21, 2015
1 parent fd2b1dd commit d26b4fa
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 153 deletions.
128 changes: 40 additions & 88 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ var fs = require("fs")
var path = require("path")

var assign = require("object-assign")
var resolve = require("resolve")
var postcss = require("postcss")
var helpers = require("postcss-message-helpers")
var glob = require("glob")
var parseImports = require("./lib/parse-imports")
var resolveMedia = require("./lib/resolve-media")
var resolveId = require("./lib/resolve-id")

/**
* Constants
Expand Down Expand Up @@ -257,41 +257,50 @@ function readAtImport(
}

addInputToPath(options)
var resolvedFilename = resolveFilename(
parsedAtImport.uri,
options.root,
options.path,
atRule.source,
options.resolve
)
var base = atRule.source && atRule.source.input && atRule.source.input.file
? path.dirname(path.resolve(options.root, atRule.source.input.file))
: options.root

if (options.skipDuplicates) {
// skip files already imported at the same scope
if (
state.importedFiles[resolvedFilename] &&
state.importedFiles[resolvedFilename][media]
) {
atRule.remove()
return Promise.resolve()
return Promise.resolve().then(function() {
if (options.resolve) {
return options.resolve(parsedAtImport.uri, base, options)
}
return resolveId(
parsedAtImport.uri,
base,
options.path
)
}).then(function(resolvedFilename) {
if (options.skipDuplicates) {
// skip files already imported at the same scope
if (
state.importedFiles[resolvedFilename] &&
state.importedFiles[resolvedFilename][media]
) {
atRule.remove()
return Promise.resolve()
}

// save imported files to skip them next time
if (!state.importedFiles[resolvedFilename]) {
state.importedFiles[resolvedFilename] = {}
// save imported files to skip them next time
if (!state.importedFiles[resolvedFilename]) {
state.importedFiles[resolvedFilename] = {}
}
state.importedFiles[resolvedFilename][media] = true
}
state.importedFiles[resolvedFilename][media] = true
}

return readImportedContent(
result,
atRule,
parsedAtImport,
assign({}, options),
resolvedFilename,
state,
media,
processor
)
return readImportedContent(
result,
atRule,
parsedAtImport,
assign({}, options),
resolvedFilename,
state,
media,
processor
)
}).catch(function(err) {
result.warn(err.message, { node: atRule })
})
}

/**
Expand Down Expand Up @@ -414,63 +423,6 @@ function insertRules(atRule, parsedAtImport, newStyles) {
atRule.replaceWith(newNodes)
}

/**
* Check if a file exists
*
* @param {String} name
*/
function resolveFilename(name, root, paths, source, resolver) {
var dir = source && source.input && source.input.file
? path.dirname(path.resolve(root, source.input.file))
: root

try {
var resolveOpts = {
basedir: dir,
moduleDirectory: moduleDirectories.concat(paths),
paths: paths,
extensions: [ ".css" ],
packageFilter: function processPackage(pkg) {
pkg.main = pkg.style || "index.css"
return pkg
},
}
var file
resolver = resolver || resolve.sync
try {
file = resolver(name, resolveOpts)
}
catch (e) {
// fix to try relative files on windows with "./"
// if it's look like it doesn't start with a relative path already
// if (name.match(/^\.\.?/)) {throw e}
try {
file = resolver("./" + name, resolveOpts)
}
catch (err) {
// LAST HOPE
if (!paths.some(function(dir2) {
file = path.join(dir2, name)
return fs.existsSync(file)
})) {
throw err
}
}
}

return path.normalize(file)
}
catch (e) {
throw new Error(
"Failed to find '" + name + "' from " + root +
"\n in [ " +
"\n " + paths.join(",\n ") +
"\n ]",
source
)
}
}

/**
* Read the contents of a file
*
Expand Down
82 changes: 82 additions & 0 deletions lib/resolve-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
var fs = require("fs")
var path = require("path")
var resolveModule = require("resolve")

var moduleDirectories = [
"web_modules",
"node_modules",
]

function isFile(path) {
return new Promise(function(resolve, reject) {
fs.stat(path, function(err, stat) {
if (err) {
if (err.code === "ENOENT") {
return resolve(false)
}
return reject(err)
}
resolve(stat.isFile() || stat.isFIFO())
})
})
}

function getFirstExistingFile(files) {
return files.reduce(function(promise, file) {
return promise.then(function(resolvedFile) {
if (resolvedFile) {
return resolvedFile
}
return isFile(file).then(function(is) {
if (is) {
return file
}
})
})
}, Promise.resolve())
}

module.exports = function(id, base, paths) {
var files = [ base ].concat(paths).reduce(function(files, p) {
files.push(path.resolve(p, id))
files.push(path.resolve(p, id + ".css"))
files.push(path.resolve(p, id, "index.css"))
return files
}, [])

return getFirstExistingFile(files).then(function(existing) {
if (existing) {
return existing
}
var opts = {
basedir: path.resolve(base),
moduleDirectory: moduleDirectories,
extensions: [ ".css" ],
packageFilter: function(pkg) {
if (!/\.css$/.test(pkg.main)) {
pkg.main = pkg.style || "index.css"
}
return pkg
},
}

return new Promise(function(resolve) {
resolveModule(id, opts, function(err, existing) {
if (err) {
return resolve()
}
resolve(existing)
})
})
}).then(function(existing) {
if (existing) {
return existing
}
throw new Error([
"Failed to find '" + id + "'",
"in [ ",
" " + paths.join(",\n "),
"]",
].join("\n "))
})
}
7 changes: 4 additions & 3 deletions test/fixtures/ignore.expected.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
@import "http://css" (min-width: 25em);

@import "http://css-screen" (min-width: 25em) and screen;

@import "http://css";

Expand Down Expand Up @@ -28,6 +25,10 @@

@import url(//css);

@import "http://css" (min-width: 25em);

@import "http://css-screen" (min-width: 25em) and screen;

@media (min-width: 25em){
ignore{}
}
Expand Down
1 change: 0 additions & 1 deletion test/fixtures/imports/local-module/main.css

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/imports/local-module/package.json

This file was deleted.

19 changes: 0 additions & 19 deletions test/fixtures/modules.css

This file was deleted.

21 changes: 0 additions & 21 deletions test/fixtures/modules.expected.css

This file was deleted.

35 changes: 15 additions & 20 deletions test/import.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import test from "ava"
import path from "path"
import { readFileSync } from "fs"
import postcss from "postcss"
import atImport from ".."
Expand Down Expand Up @@ -54,12 +55,6 @@ test("should not need `path` option if `source` option has been passed", t => {
})
})

test("should be able to consume npm package or local modules", t => {
return compareFixtures(t, "modules", {
root: ".",
})
})

test("should not fail with only one absolute import", t => {
var base = "@import url(http://)"
return postcss()
Expand All @@ -85,13 +80,11 @@ test("should output readable trace", t => {
return postcss()
.use(atImport())
.process(readFileSync(file), { from: file })
.catch(error => {
t.throws(
() => {
throw error
},
.then(result => {
t.is(
result.warnings()[0].text,
/* eslint-disable max-len */
/import-missing.css:2:5: Failed to find 'missing-file.css' from .*\n\s+in \[/gm
"Failed to find 'missing-file.css'\n in [ \n " + path.resolve("fixtures/imports") + "\n ]"
/* eslint-enabme max-len */
)
})
Expand Down Expand Up @@ -155,14 +148,16 @@ test("should work with no styles without throwing an error", t => {

test("should be able to consume modules in the custom-resolve way", t => {
const resolve = require("resolve")
const sassResolve = (file, opts) => {
opts = opts || {}
opts.extensions = [ ".scss", ".css" ]
opts.packageFilter = pkg => {
pkg.main = pkg.sass || pkg.style || "index"
return pkg
}
return resolve.sync(file, opts)
const sassResolve = (id, base, importOptions) => {
return resolve.sync(id, {
basedir: base,
extensions: [ ".scss", ".css" ],
paths: importOptions.path,
packageFilter: pkg => {
pkg.main = pkg.sass || pkg.style || "index"
return pkg
},
})
}
return compareFixtures(t, "custom-resolve-modules", {
root: ".",
Expand Down

0 comments on commit d26b4fa

Please sign in to comment.