diff --git a/test/GLOSSARY.md b/test/GLOSSARY.md new file mode 100644 index 0000000..623a0fd --- /dev/null +++ b/test/GLOSSARY.md @@ -0,0 +1,7 @@ +# GLOSSARY + +- `canonical package name`: is the combination of a `package name` with an `endpoint` (example: `github:components/jquery`). +- `endpoint`: is platform where packets are hosted (`npm` or `github`). +- `override` or `override file`: is a `package.json` override file. +- `package name`: is the name of a package at some endpoint (example: `components/jquery` from `github` endpoint or `d3` from `npm` endpoint). +- `registry entry`: is just the mapping represented in the `registry.json` (example: `"jquery": "github:components/jquery"`). \ No newline at end of file diff --git a/test/index.js b/test/index.js index 288aa6f..ec06fd2 100644 --- a/test/index.js +++ b/test/index.js @@ -1,69 +1,160 @@ -"use strict"; +'use strict'; + +var util = require('util'); +var mout = require('mout'); +var colors = require('colors/safe'); +var endpoints = { + github: require('jspm-github'), + npm: require('jspm-npm') +}; + +var forOwn = mout.object.forOwn; +var gray = colors.gray; var log = require('./lib/log'); -var RegistryFile = require('./lib/RegistryFile'); +var JsonFile = require('./lib/JsonFile'); var OverrideFile = require('./lib/OverrideFile'); -var summary = []; +var OverridesList = require('./lib/OverridesList'); -/** - * Commander - */ +// +// COMMANDER CONFIGURATION +// var program = require('commander'); program .version('0.0.1') .usage('[options] ') - .option('-e, --only-errors', 'Show only summary', 0) + .option('-e, --only-errors', 'Show only errors', 0) .parse(process.argv); + +// +// LOG HELPERS +// + +/** + * @function error - log errors messages + * @param {String|Array} msg + * @return {Function} error + */ +var error = function(msg){ + + if(!program.onlyErrors) + log.error(msg); + + if(Array.isArray(msg)) { + error.summary.concat(msg); + + } else { + error.summary.push(msg); + + } + + return error; +}; + +/** + * @type {Array} list all errors + */ +error.summary = []; + +/** + * function ok - log validation passed messages + * @param {String|Array} msg + * @return {Function} ok + */ +var ok = function(msg){ + + if(!program.onlyErrors) + log.ok(msg); + + return ok; +}; + +// +// VALIDATION PROCESS +// + /** * registry.json */ -var registry = RegistryFile(); -if(registry.errors().length) -{ - summary = summary.concat(registry.errors()); - log.error(registry.errors()); - process.exit(1); +var overrideFile = new OverrideFile(); + +if(overrideFile.errors().length) { + // json format errors + error(overrideFile.errors()); + +} else { + ok('registry.json is valid json'); + + overrideFile.forEachRegistryEntry(function(pkg, registryEntryName){ + + // validate specific packages + if(program.args.length) { + + var pos = program.args.indexOf(registryEntryName); + + if(pos === -1) + return; + + // replace for test the package-override + program.args[pos] = pkg.canonical; + } + + if(!pkg.endpoint || !pkg.name) + return error( util.format('%s not respects the format {ENDPOINT}:{PACKAGE_NAME}', gray(pkg.canonical)) ); + + if(!endpoints[pkg.endpoint]) + return error( util.format('%s is not valid enpoint', gray(pkg.endpoint)) ); + + if(!endpoints[pkg.endpoint].packageFormat.test( pkg.name )) + return error( util.format('%s is not valid package name from %s endpoint', gray(pkg.name), gray(pkg.endpoint)) ); + + ok( util.format('%s => %s', registryEntryName, pkg.canonical) ); + }); + } -// log ok -if(!program.onlyErrors) - log.ok('registry.json'); - - /** - * Packages + * package overrides files */ -registry.forEach(function(endpoint, name){ +forOwn(endpoints, function(Endpoint, endpointName){ - if(program.args.length && program.args.indexOf(name) === -1) - return; + var overridesList = new OverridesList(endpointName); - var override = new OverrideFile(endpoint); + overridesList.forEachOverrideFile(function(fileinfo){ - if(override.errors().length) { + if(fileinfo.ext !== 'json') + return error( util.format('%s is not json file', gray(fileinfo.path)) ); + + if(!fileinfo.packageName || !fileinfo.packageVersion) + return error( util.format('%s not respects the file name format {PACKAGE_NAME}@{PACKAGE_VERSION}.json', gray(fileinfo.path)) ); - var errorDescription = name + ' => ' + endpoint + '\n\t' + override.errors().join('\n\t'); - summary.push(errorDescription); + if(!Endpoint.packageFormat.test( fileinfo.packageName )) + return error( util.format('%s is not valid package name from %s endpoint', gray(fileinfo.packageName), gray(fileinfo.endpoint)) ); - } else if(!program.onlyErrors) { - log.ok(name + ' => ' + endpoint); + // validate specific packages + if(program.args.length && program.args.indexOf(fileinfo.canonicalPackageName) === -1 ) + return; - if(!override.isFile()) - log.info(' not override file from ' + name); - } + var overrideFile = new JsonFile(fileinfo.path); + if(overrideFile.errors().length) + return error( util.format('%s is not valid json file \n - %s', gray(fileinfo.path), overrideFile.errors().join('\n -')) ); + + ok( fileinfo.canonicalPackageName + '@' + fileinfo.packageVersion ); + }); }); -/** - * Summary - */ -if(summary.length) { +// +// SUMMARY LOG +// + +if(error.summary.length) { log.n() ('Error summary ................') - .error(summary) + .error(error.summary) .n(); process.exit(1); diff --git a/test/lib/JsonFile.js b/test/lib/JsonFile.js index 708f565..165d563 100644 --- a/test/lib/JsonFile.js +++ b/test/lib/JsonFile.js @@ -1,5 +1,5 @@ -"use strict;" -var fs = require('fs'); +'use strict'; + var mout = require('mout'); var extend = mout.object.deepMixIn; var forOwn = mout.object.forOwn; @@ -14,19 +14,18 @@ var JsonFile = module.exports = function JsonFile(file){ return new JsonFile(file); this._file = String(file); - this._errors = this._errors || []; - this._json = this._json || {}; + this._errors = []; + this._json = {}; if( !(/\.json$/.test(file)) ){ this.error(this._file + ' is not json file'); } else { - try{ + try { extend(this._json, require(this._file)); } catch(e) { - this.error(e.message); } @@ -38,18 +37,18 @@ JsonFile.prototype.error = function(msg){ this._errors.push(msg); return this; -} +}; JsonFile.prototype.errors = function(){ return this._errors; -} +}; JsonFile.prototype.forEach = function(fn){ forOwn(this._json, fn, this); - return this; + return this; }; diff --git a/test/lib/OverrideFile.js b/test/lib/OverrideFile.js index 16de9fc..adf8215 100644 --- a/test/lib/OverrideFile.js +++ b/test/lib/OverrideFile.js @@ -1,88 +1,46 @@ -"use strict;" +'use strict'; -var fs = require('fs'); var util = require('util'); var path = require('path'); -var glob = require('glob'); -var mout = require('mout'); -var colors = require('colors/safe'); var JsonFile = require('./JsonFile'); - -var registries = { - github: require('jspm-github'), - npm: require('jspm-npm') -}; +var CANONICAL_NAME_EXPECTATION = /^([^:\s]*):([^\s]*)$/; /** * @constructor OverrideFile - */ -var OverrideFile = module.exports = function OverrideFile(endpoint){ + */ +var OverrideFile = module.exports = function OverrideFile(){ if( !(this instanceof OverrideFile) ) - return new OverrideFile(endpoint); - - this._endpoint = endpoint; - this._files = []; - this._errors = this._errors || []; - this._registry; - this._package; - - var match = /^([^:\s]*):([^\s]*)$/.exec(endpoint); - - if(!match) - { - this.error('invalid enpoint package'); - } - else - { - this._registry = match[1]; - this._package = match[2]; - - if(!registries[this._registry]) - { - this.error('invalid registry'); - } - else if(!registries[this._registry].packageFormat.test(this._package)) - { - this.error('invalid pacakge name'); - } - - this._glob = path.resolve('./package-overrides', this._registry) + '/' + this._package + '@*.json'; - - - this._files = glob.sync(this._glob); - this.forEach(function(file){ - - var err = JsonFile(file).errors(); - - if(err.length > 0) - this.error(JsonFile(file).errors().join('\n')); - - }); - } + return new OverrideFile(); + JsonFile.call(this, path.resolve('./registry.json')); }; util.inherits(OverrideFile, JsonFile); -OverrideFile.prototype.error = function(msg){ +OverrideFile.prototype.forEachRegistryEntry = function(fn){ - var result = ''; - result += this._endpoint ? colors.gray(this._endpoint) + ' ' : ''; - result += msg; + return this.forEach(function(canonicalPackageName, registryEntryName){ - return JsonFile.prototype.error.call(this, result); -}; + var pkg = {}; + var match = CANONICAL_NAME_EXPECTATION.exec(canonicalPackageName); -OverrideFile.prototype.forEach = function(fn){ + if (!match) { + pkg = { + canonical: canonicalPackageName, + endpoint: undefined, + name: undefined, + }; + + } else { + pkg = { + canonical: match[0], + endpoint: match[1], + name: match[2], + }; + } - mout.array.forEach(this._files, fn, this); - - return this; -}; - -OverrideFile.prototype.isFile = function(){ - - return this._files.length > 0; -}; + fn.call(this, pkg, registryEntryName); + }); +}; \ No newline at end of file diff --git a/test/lib/OverridesList.js b/test/lib/OverridesList.js new file mode 100644 index 0000000..2bea171 --- /dev/null +++ b/test/lib/OverridesList.js @@ -0,0 +1,53 @@ +'use strict'; + +var path = require('path'); +var glob = require('glob'); +var mout = require('mout'); +var forOwn = mout.object.forOwn; +var FILE_EXTENSION = /[^.]*$/i; +var PACKAGE_EXPECTATION = /(.*)@(.*).json$/; + +/** + * @constructor OverridesList + */ + +var OverridesList = module.exports = function OverridesList(endpoint){ + + this._endpoint = endpoint; + this._basePath = path.resolve('./package-overrides', this._endpoint); + this._files = glob.sync('**/*', {cwd: this._basePath, nodir: true}); + +}; + +OverridesList.prototype.forEachOverrideFile = function(fn){ + + forOwn(this._files, function(file, index){ + + var pathfile = path.resolve(this._basePath, file); + var extfile = FILE_EXTENSION.exec(pathfile)[0]; + + var fileinfo = { + packageName: undefined, + packageVersion: undefined, + canonicalPackageName: undefined, + + file: file, + endpoint: this._endpoint, + path: pathfile, + ext: extfile + }; + + var match = PACKAGE_EXPECTATION.exec(file); + + if (match) { + fileinfo.packageName = match[1]; + fileinfo.packageVersion = match[2]; + fileinfo.canonicalPackageName = fileinfo.endpoint + ':' + fileinfo.packageName; + } + + fn.call(this, fileinfo, index); + + }, this); + + return this; +} diff --git a/test/lib/RegistryFile.js b/test/lib/RegistryFile.js deleted file mode 100644 index ad26846..0000000 --- a/test/lib/RegistryFile.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict;" -var util = require('util'); -var path = require('path'); -var JsonFile = require('./JsonFile'); - -/** - * @constructor RegistryFile - */ - -var RegistryFile = module.exports = function RegistryFile(){ - - if( !(this instanceof RegistryFile) ) - return new RegistryFile(); - - JsonFile.call(this, path.resolve('./registry.json')); -}; - - -util.inherits(RegistryFile, JsonFile); \ No newline at end of file