Skip to content

Commit

Permalink
feat(package-analyzer): support packages without package.json files
Browse files Browse the repository at this point in the history
closes #575
  • Loading branch information
JeroenVinke committed Apr 8, 2017
1 parent 324f3e1 commit c225bb7
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 11 deletions.
36 changes: 25 additions & 11 deletions lib/build/package-analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ exports.PackageAnalyzer = class {

function loadPackageMetadata(project, description) {
return setLocation(project, description)
.then(() => fs.readFile(description.metadataLocation))
.then(data => {
description.metadata = JSON.parse(data.toString());
.then(() => {
if (description.metadataLocation) {
return fs.readFile(description.metadataLocation)
.then(data => {
description.metadata = JSON.parse(data.toString());
});
}
})
.catch(e => {
console.log(`Unable to load package metadata (package.json) of ${description.name}:`);
Expand All @@ -49,16 +53,20 @@ function determineLoaderConfig(project, description) {
let location = path.resolve(description.location);
let sourcePath;

if (metadata.jspm) {
let jspm = metadata.jspm;
if (metadata) {
if (metadata.jspm) {
let jspm = metadata.jspm;

if (jspm.directories && jspm.directories.dist) {
sourcePath = path.join(location, jspm.directories.dist, jspm.main);
if (jspm.directories && jspm.directories.dist) {
sourcePath = path.join(location, jspm.directories.dist, jspm.main);
} else {
sourcePath = path.join(location, metadata.main);
}
} else {
sourcePath = path.join(location, metadata.main);
}
} else {
sourcePath = path.join(location, metadata.main);
sourcePath = path.join(location, 'index');
}

sourcePath = path.relative(path.resolve(project.paths.root), sourcePath);
Expand All @@ -75,7 +83,8 @@ function setLocation(project, description) {
return getPackageFolder(project, description)
.then(packageFolder => {
description.location = packageFolder;
description.metadataLocation = path.join(description.location, 'package.json');

return tryFindMetadata(project, description);
});
case 'custom':
if (!description.loaderConfig || !description.loaderConfig.packageRoot) {
Expand All @@ -85,14 +94,19 @@ function setLocation(project, description) {
}

description.location = path.resolve(project.paths.root, description.loaderConfig.packageRoot);
description.metadataLocation = path.join(description.location, 'package.json');

return Promise.resolve();
return tryFindMetadata(project, description);
default:
return Promise.reject(`The package source "${description.source}" is not supported.`);
}
}

function tryFindMetadata(project, description) {
return fs.stat(path.join(description.location, 'package.json'))
.then(() => description.metadataLocation = path.join(description.location, 'package.json'))
.catch(() => {});
}

function getPackageFolder(project, description) {
if (!description.loaderConfig || !description.loaderConfig.path) {
return lookupPackageFolderDefaultStrategy(project.paths.root)
Expand Down
174 changes: 174 additions & 0 deletions spec/lib/build/package-analyzer.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
'use strict';

const path = require('path');
const PackageAnalyzer = require('../../../lib/build/package-analyzer').PackageAnalyzer;

describe('The PackageAnalyzer', () => {
let mockfs;
let project;
let sut;

beforeEach(() => {
mockfs = require('mock-fs');

project = {
paths: {
root: './src/'
}
};

sut = new PackageAnalyzer(project);

const fsConfig = {};
mockfs(fsConfig);
});

afterEach(() => {
mockfs.restore();
});

it('sets source to npm when node_modules is found in the path', done => {
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('node_modules/my-package', 'package.json')] = '{ }';
mockfs(fsConfig);

let loaderConfig = {
name: 'my-package',
path: '../node_modules/my-package'
};

sut.reverseEngineer(loaderConfig)
.then(description => {
expect(description.source).toBe('npm');
expect(description.loaderConfig).toBe(loaderConfig);
done();
})
.catch(e => done.fail(e));
});

it('sets source to custom when node_modules is not found in the path', done => {
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('some-folder/my-package', 'package.json')] = '{ }';
mockfs(fsConfig);

let loaderConfig = {
name: 'my-package',
path: '../some-folder/my-package',
packageRoot: '../some-folder/my-package'
};

sut.reverseEngineer(loaderConfig)
.then(description => {
expect(description.source).toBe('custom');
expect(description.loaderConfig).toBe(loaderConfig);
done();
})
.catch(e => done.fail(e));
});

it('creates description when there is no package.json', done => {
const fsConfig = {};
mockfs(fsConfig);

let loaderConfig = {
name: 'my-package',
path: '../some-folder/my-package',
packageRoot: '../some-folder/my-package'
};

sut.reverseEngineer(loaderConfig)
.then(description => {
expect(description.source).toBe('custom');
expect(description.loaderConfig).toBe(loaderConfig);
done();
})
.catch(e => done.fail(e));
});

it('reads package.json as package metadata', done => {
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('some-folder/my-package', 'package.json')] = '{ "name": "my-package" }';
mockfs(fsConfig);

let loaderConfig = {
name: 'my-package',
path: '../some-folder/my-package',
packageRoot: '../some-folder/my-package'
};

sut.reverseEngineer(loaderConfig)
.then(description => {
expect(description.metadata.name).toBe('my-package');
done();
})
.catch(e => done.fail(e));
});

it('analyze() reads package.json as package metadata', done => {
// setup mock package.json
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('node_modules/my-package', 'package.json')] = '{ "name": "my-package", "main": "index.js" }';
fsConfig[project.paths.root] = {};
mockfs(fsConfig);

sut.analyze('my-package')
.then(description => {
expect(description.metadata.name).toBe('my-package');
done();
})
.catch(e => done.fail(e));
});

it('analyze() determines loaderConfig', done => {
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('node_modules/my-package', 'package.json')] = '{ "name": "my-package", "main": "index.js" }';
fsConfig[project.paths.root] = {};
mockfs(fsConfig);

sut.analyze('my-package')
.then(description => {
expect(description.loaderConfig.name).toBe('my-package');
expect(description.loaderConfig.path).toBe('..\\node_modules\\my-package\\index');
done();
})
.catch(e => done.fail(e));
});

it('analyze() uses jspm.directories.dist and jspm.main path if available', done => {
// setup mock package.json
const fsConfig = {};
let json = '{ "name": "my-package", "main": "index.js", "jspm": { "directories": { "dist": "foobar" }, "main": "my-main.js" } }';
fsConfig[path.join('node_modules/my-package', 'package.json')] = json;
fsConfig[project.paths.root] = {};
mockfs(fsConfig);

sut.analyze('my-package')
.then(description => {
expect(description.loaderConfig.name).toBe('my-package');
expect(description.loaderConfig.path).toBe('..\\node_modules\\my-package\\foobar\\my-main');
done();
})
.catch(e => done.fail(e));
});

it('analyze() works when there is no package.json. Uses index.js as the main file', done => {
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('node_modules/my-package')] = {};
fsConfig[project.paths.root] = {};
mockfs(fsConfig);

sut.analyze('my-package')
.then(description => {
expect(description.loaderConfig.name).toBe('my-package');
expect(description.loaderConfig.path).toBe('..\\node_modules\\my-package\\index');
done();
})
.catch(e => done.fail(e));
});
});

0 comments on commit c225bb7

Please sign in to comment.