Skip to content

Commit

Permalink
Merge a64152f into ffde936
Browse files Browse the repository at this point in the history
  • Loading branch information
popomore committed Aug 13, 2014
2 parents ffde936 + a64152f commit 4303a7e
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 100 deletions.
106 changes: 72 additions & 34 deletions lib/file.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
'use strict';

var fs = require('fs');
var path = require('path');
var join = path.join;
var dirname = path.dirname;
var extname = path.extname;
var util = require('./util');
var isRelative = util.isRelative;
var winPath = util.winPath;
var debug = require('debug')('father:file');

module.exports = File;

File.cache = {};

File.require = function requireFile(src, pkg) {
src = tryFile(src, pkg.dest);
var fullpath = join(pkg.dest, src);
if (fullpath in File.cache) {
debug('found %s in File.cache', fullpath);
return File.cache[fullpath];
}
var file = new File(src, pkg);
debug('save %s in File.cache', file.fullpath);
return File.cache[file.fullpath] = file;
};

File.ignore = function ignoreFile(name) {
var pkg = {
name: name,
dest: ''
};
var file = new File('', pkg);
file.ignore = true;
file._dependencies = [];
return file;
};

function File(filepath, pkg) {
this.filepath = filepath;
this.pkg = pkg;
this.path = filepath;
this.extension = extname(filepath).substring(1);
this.fullpath = join(pkg.dest, filepath);
}

File.prototype.lookup = function(cb, extra) {
Expand All @@ -39,44 +63,58 @@ File.prototype._run = function() {
if (this.cache) return this.cache;

var that = this, cache = [];
var fileDeps = this.dependencies;
var pkg = this.pkg;
var basepath = this.filepath;

var filepath, pkg_, file;
fileDeps.forEach(function(id) {
if (isRelative(id)) {
pkg_ = pkg;
filepath = resolvePath(id, basepath);
} else {
pkg_ = pkg.dependencies[id];
if (!pkg_) {
return cache.push({
ignore: true,
pkg: {name: id},
isRelative: false
});
}
filepath = pkg_.main;
}

var fileDeps = this._dependencies;
fileDeps.forEach(function(file) {
cache.push({
ignore: false,
filepath: filepath,
pkg: pkg_,
isRelative: isRelative(id),
ignore: file.ignore === true,
path: file.path,
pkg: file.pkg,
isRelative: that.pkg.name === file.pkg.name,
dependent: that,
extension: extname(filepath).substring(1)
extension: file.extension
});

file = pkg_.files[filepath];
var deps = file._run();
cache = cache.concat(deps);
});

return this.cache = cache;
};

function resolvePath(relative, base) {
return winPath(join(dirname(base), relative));
Object.defineProperty(File.prototype, 'dependencies', {
get: function() {
return this._dependencies.map(function(file) {
if (file.ignore) {
return file.pkg.name;
}
if (this.pkg.name !== file.pkg.name) {
return file.pkg.name + (file.pkg.main !== file.path ? '/' + file.path : '');
}
file = path.relative(path.dirname(this.path), file.path);
return file.charAt(0) === '.' ? file : './' + file;
}, this);
}
});

function tryFile(src, cwd) {
var fileArray = [src];
if (!/\.js$/.test(src)) {
fileArray.push(src + '.js');
}
if (!extname(src)) {
fileArray.push(src + '/index.js');
}

for (var i in fileArray) {
var file = join(cwd, fileArray[i]);
try {
var stat = fs.statSync(file);
if (stat.isFile()) {
return fileArray[i];
}
} catch(e) {}
}

debug('%s not found', src);
throw new Error(join(cwd, src) + ' not found');
}
91 changes: 35 additions & 56 deletions lib/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
var fs = require('fs');
var path = require('path');
var join = path.join;
var dirname = path.dirname;
var extname = path.extname;
var glob = require('glob');
var requires = require('searequire');
var imports = require('css-imports');
Expand Down Expand Up @@ -108,7 +106,7 @@ var Package = Class.create({
});
}
},
configurable: true
enumerable: true
};

Object.defineProperty(that, key, prop);
Expand All @@ -120,6 +118,7 @@ var Package = Class.create({
debug('*start parse %s', this.dest);
this._parsing = true;
this._pkg = this.readPackage();
this._pkg.files = {};
this.id = this._pkg.id;

// parsing
Expand Down Expand Up @@ -162,61 +161,63 @@ var Package = Class.create({
},

_parseFiles: function() {
var dest = this.dest, options = this.options;
var pkg = this._pkg, files = pkg.files = {};
var that = this;
var options = this.options;

getEntry(this, options).forEach(lookupFiles);
getEntry(this, options).forEach(function(src) {
lookupFiles(src, this);
}, this);

function lookupFiles(src) {
src = tryFile(src, dest);
var ext = extname(src).substring(1);
src = winPath(src);
function lookupFiles(src, pkg) {
var files = pkg._pkg.files;
var file = File.require(src, pkg);
src = winPath(file.path);

// parsing or parsed
if (files[src]) {
if (!files[src].dependencies) {
if (!files[src]._dependencies) {
throw new Error('found ' + src + ' has recursive dependency');
}
// dependencies exist if file has been parsed,
return files[src].dependencies;
return files[src]._dependencies;
} else {
files[src] = new File(src, that);
files[src] = file;
}

// file dependencies
var data = fs.readFileSync(join(dest, src)).toString();
var deps = getFileDeps(data, ext, options)
var deps = getFileDeps(file.fullpath, file.extension, options)
.filter(function(item) {
// skip file or package
return options.skip.indexOf(item) === -1;
})
.map(function(name) {
var file;
// packages of dependency
if (!isRelative(name)) {
var pkg_ = pkg.dependencies[name];
if (!pkg_ && options.ignore.indexOf(name) === -1) {
throw new Error(name + ' not found but required');
if (options.ignore.indexOf(name) !== -1) {
debug('ignore id(%s)', name);
return File.ignore(name);
}

debug('transport package id(%s)', name);
var finfo = util.getFileInfo(name, pkg);
file = File.require(finfo.path, finfo.pkg);
if (!finfo.pkg.files[file]) {
lookupFiles(finfo.path, finfo.pkg);
}
return name;
return file;
}

// relative
var dir = dirname(join(dest, src));
name = tryFile(name, dir);
return winPath(name);
debug('transport relative id(%s) of basepath(%s)', name, src);
var path = resolvePath(name, src);
file = File.require(path, pkg);
lookupFiles(path, pkg);
return file;
});

// just parse relative files
deps.filter(function(name) {
return isRelative(name);
}).forEach(function(name) {
lookupFiles(resolvePath(name, src));
});
files[src]._dependencies = deps;

files[src].dependencies = deps;

debug('_parseFiles of pkg(%s): file %s, deps [%s]', pkg.id, src, deps);
debug('_parseFiles of pkg(%s): file %s, deps [%s]', pkg.id, src, files[src].dependencies);
return deps;
}
},
Expand All @@ -232,7 +233,8 @@ var Package = Class.create({
module.exports = Package;


function getFileDeps(code, ext) {
function getFileDeps(fullpath, ext) {
var code = fs.readFileSync(fullpath).toString();
switch(ext) {
case 'js':
return requires(code, true).filter(filterAsync).map(transform);
Expand Down Expand Up @@ -299,29 +301,6 @@ function getEntry(pkg, options) {
}
}

function tryFile(src, cwd) {
var fileArray = [src];
if (!/\.js$/.test(src)) {
fileArray.push(src + '.js');
}
if (!extname(src)) {
fileArray.push(src + '/index.js');
}

for (var i in fileArray) {
var file = join(cwd, fileArray[i]);
try {
var stat = fs.statSync(file);
if (stat.isFile()) {
return fileArray[i];
}
} catch(e) {}
}

debug('%s not found', src);
throw new Error(join(cwd, src) + ' not found');
}

function extend(target) {
var args = [].slice.call(arguments, 1);
args.forEach(function(obj) {
Expand Down
17 changes: 16 additions & 1 deletion lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ exports.getBase = getBase;
exports.resolvePath = resolvePath;
exports.isRelative = isRelative;
exports.winPath = winPath;
exports.getFileInfo = getFileInfo;

function getVersion(version, dest) {
var dirs = fs.readdirSync(dest);
Expand Down Expand Up @@ -45,7 +46,6 @@ function getBase(pkg) {

function resolvePath(relative, base) {
if (!isRelative(relative) || !base) return relative;
debug('transport relative id(%s) of basepath(%s)', relative, base);
relative = join(dirname(base), relative);
if (isRelative(relative)) throw new Error(winPath(relative) + ' is out of bound');
return relative;
Expand All @@ -62,3 +62,18 @@ function isRelative(filepath) {
function winPath(path) {
return path.replace(/\\/g, '/');
}

function getFileInfo(filepath, pkg) {
var m = filepath.match(/^([a-z0-9-_]+)(?:\/(.+))*$/i);
if (!m) {
throw new Error('unknown name ' + filepath);
}
pkg = pkg.dependencies[m[1]];
if (!pkg) {
throw new Error(m[1] + ' not found but required');
}
return {
path: m[2] || pkg.main,
pkg: pkg
};
}
16 changes: 8 additions & 8 deletions test/file.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('Father.File', function() {
it('lookup all deps', function() {
var ret = pkg.files['a.js'].lookup(function(fileInfo) {
var pkg = fileInfo.pkg;
return [pkg.name, pkg.version, fileInfo.filepath].join('/');
return [pkg.name, pkg.version, fileInfo.path].join('/');
});
ret.should.eql([
'b/1.1.0/src/b.js',
Expand All @@ -30,7 +30,7 @@ describe('Father.File', function() {
var ret = pkg.files['a.js'].lookup(function(fileInfo) {
var pkg_ = fileInfo.pkg;
return pkg.name === pkg_.name ?
[pkg_.name, pkg_.version, fileInfo.filepath].join('/') :
[pkg_.name, pkg_.version, fileInfo.path].join('/') :
[pkg_.name, pkg_.version, pkg_.main].join('/');
});
ret.should.eql([
Expand All @@ -48,7 +48,7 @@ describe('Father.File', function() {
var ret = pkg.files['a.js'].lookup(function(fileInfo) {
if (fileInfo.isRelative) return false;
var pkg = fileInfo.pkg;
return [pkg.name, pkg.version, fileInfo.filepath].join('/');
return [pkg.name, pkg.version, fileInfo.path].join('/');
});
ret.should.eql([
'b/1.1.0/src/b.js',
Expand All @@ -61,9 +61,9 @@ describe('Father.File', function() {
it('file dependent', function() {
var ret = pkg.files['a.js'].lookup(function(fileInfo) {
var pkg = fileInfo.pkg, dependent = fileInfo.dependent;
return [dependent.pkg.name, dependent.pkg.version, dependent.filepath].join('/') +
return [dependent.pkg.name, dependent.pkg.version, dependent.path].join('/') +
' -> ' +
[pkg.name, pkg.version, fileInfo.filepath].join('/');
[pkg.name, pkg.version, fileInfo.path].join('/');
});
ret.should.eql([
'a/1.0.0/a.js -> b/1.1.0/src/b.js',
Expand All @@ -90,7 +90,7 @@ describe('Father.File', function() {
case 'd':
return '';
default:
return [pkg.name, pkg.version, fileInfo.filepath].join('/');
return [pkg.name, pkg.version, fileInfo.path].join('/');
}
});
ret.should.eql([
Expand All @@ -102,15 +102,15 @@ describe('Father.File', function() {

it('lookup extra', function() {
var extra = [{
filepath: 'index.js',
path: 'index.js',
pkg: {
name: 'extra',
version: '1.0.0'
}
}];
var ret = pkg.files['a.js'].lookup(function(fileInfo) {
var pkg = fileInfo.pkg;
return [pkg.name, pkg.version, fileInfo.filepath].join('/');
return [pkg.name, pkg.version, fileInfo.path].join('/');
}, extra);
ret.should.eql([
'b/1.1.0/src/b.js',
Expand Down

0 comments on commit 4303a7e

Please sign in to comment.