Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

View File

@ -0,0 +1,88 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var util = require('util'),
path = require('path'),
fs = require('fs'),
abbrev = require('abbrev');
function Factory(kind, dir, allowAbbreviations) {
this.kind = kind;
this.dir = dir;
this.allowAbbreviations = allowAbbreviations;
this.classMap = {};
this.abbreviations = null;
}
Factory.prototype = {
knownTypes: function () {
var keys = Object.keys(this.classMap);
keys.sort();
return keys;
},
resolve: function (abbreviatedType) {
if (!this.abbreviations) {
this.abbreviations = abbrev(this.knownTypes());
}
return this.abbreviations[abbreviatedType];
},
register: function (constructor) {
var type = constructor.TYPE;
if (!type) { throw new Error('Could not register ' + this.kind + ' constructor [no TYPE property]: ' + util.inspect(constructor)); }
this.classMap[type] = constructor;
this.abbreviations = null;
},
create: function (type, opts) {
var allowAbbrev = this.allowAbbreviations,
realType = allowAbbrev ? this.resolve(type) : type,
Cons;
Cons = realType ? this.classMap[realType] : null;
if (!Cons) { throw new Error('Invalid ' + this.kind + ' [' + type + '], allowed values are ' + this.knownTypes().join(', ')); }
return new Cons(opts);
},
loadStandard: function (dir) {
var that = this;
fs.readdirSync(dir).forEach(function (file) {
if (file !== 'index.js' && file.indexOf('.js') === file.length - 3) {
try {
that.register(require(path.resolve(dir, file)));
} catch (ex) {
console.error(ex.message);
console.error(ex.stack);
throw new Error('Could not register ' + that.kind + ' from file ' + file);
}
}
});
},
bindClassMethods: function (Cons) {
var tmpKind = this.kind.charAt(0).toUpperCase() + this.kind.substring(1), //ucfirst
allowAbbrev = this.allowAbbreviations;
Cons.mix = Factory.mix;
Cons.register = this.register.bind(this);
Cons.create = this.create.bind(this);
Cons.loadAll = this.loadStandard.bind(this, this.dir);
Cons['get' + tmpKind + 'List'] = this.knownTypes.bind(this);
if (allowAbbrev) {
Cons['resolve' + tmpKind + 'Name'] = this.resolve.bind(this);
}
}
};
Factory.mix = function (cons, proto) {
Object.keys(proto).forEach(function (key) {
cons.prototype[key] = proto[key];
});
};
module.exports = Factory;

View File

@ -0,0 +1,76 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var async = require('async'),
glob = require('glob'),
fs = require('fs'),
path = require('path'),
seq = 0;
function filesFor(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = null;
}
options = options || {};
var root = options.root,
includes = options.includes,
excludes = options.excludes,
realpath = options.realpath,
relative = options.relative,
opts;
root = root || process.cwd();
includes = includes && Array.isArray(includes) ? includes : [ '**/*.js' ];
excludes = excludes && Array.isArray(excludes) ? excludes : [ '**/node_modules/**' ];
opts = { cwd: root, nodir: true, ignore: excludes };
seq += 1;
opts['x' + seq + new Date().getTime()] = true; //cache buster for minimatch cache bug
glob(includes.join(' '), opts, function (err, files) {
if (err) { return callback(err); }
if (relative) { return callback(err, files); }
if (!realpath) {
files = files.map(function (file) { return path.resolve(root, file); });
return callback(err, files);
}
var realPathCache = module.constructor._realpathCache || {};
async.map(files, function (file, done) {
fs.realpath(path.resolve(root, file), realPathCache, done);
}, callback);
});
}
function matcherFor(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = null;
}
options = options || {};
options.relative = false; //force absolute paths
options.realpath = true; //force real paths (to match Node.js module paths)
filesFor(options, function (err, files) {
var fileMap = {},
matchFn;
if (err) { return callback(err); }
files.forEach(function (file) { fileMap[file] = true; });
matchFn = function (file) { return fileMap[file]; };
matchFn.files = Object.keys(fileMap);
return callback(null, matchFn);
});
}
module.exports = {
filesFor: filesFor,
matcherFor: matcherFor
};

View File

@ -0,0 +1,154 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var path = require('path'),
util = require('util'),
fs = require('fs'),
async = require('async'),
mkdirp = require('mkdirp'),
writer = require('./writer'),
Writer = writer.Writer,
ContentWriter = writer.ContentWriter;
function extend(cons, proto) {
Object.keys(proto).forEach(function (k) {
cons.prototype[k] = proto[k];
});
}
function BufferedContentWriter() {
ContentWriter.call(this);
this.content = '';
}
util.inherits(BufferedContentWriter, ContentWriter);
extend(BufferedContentWriter, {
write: function (str) {
this.content += str;
},
getContent: function () {
return this.content;
}
});
function StreamContentWriter(stream) {
ContentWriter.call(this);
this.stream = stream;
}
util.inherits(StreamContentWriter, ContentWriter);
extend(StreamContentWriter, {
write: function (str) {
this.stream.write(str);
}
});
function SyncFileWriter() {
Writer.call(this);
}
util.inherits(SyncFileWriter, Writer);
extend(SyncFileWriter, {
writeFile: function (file, callback) {
mkdirp.sync(path.dirname(file));
var cw = new BufferedContentWriter();
callback(cw);
fs.writeFileSync(file, cw.getContent(), 'utf8');
},
done: function () {
this.emit('done'); //everything already done
}
});
function AsyncFileWriter() {
this.queue = async.queue(this.processFile.bind(this), 20);
this.openFileMap = {};
}
util.inherits(AsyncFileWriter, Writer);
extend(AsyncFileWriter, {
writeFile: function (file, callback) {
this.openFileMap[file] = true;
this.queue.push({ file: file, callback: callback });
},
processFile: function (task, cb) {
var file = task.file,
userCallback = task.callback,
that = this,
stream,
contentWriter;
mkdirp.sync(path.dirname(file));
stream = fs.createWriteStream(file);
stream.on('close', function () {
delete that.openFileMap[file];
cb();
that.checkDone();
});
stream.on('error', function (err) { that.emit('error', err); });
contentWriter = new StreamContentWriter(stream);
userCallback(contentWriter);
stream.end();
},
done: function () {
this.doneCalled = true;
this.checkDone();
},
checkDone: function () {
if (!this.doneCalled) { return; }
if (Object.keys(this.openFileMap).length === 0) {
this.emit('done');
}
}
});
/**
* a concrete writer implementation that can write files synchronously or
* asynchronously based on the constructor argument passed to it.
*
* Usage
* -----
*
* var sync = true,
* fileWriter = new require('istanbul').FileWriter(sync);
*
* fileWriter.on('done', function () { console.log('done'); });
* fileWriter.copyFile('/foo/bar.jpg', '/baz/bar.jpg');
* fileWriter.writeFile('/foo/index.html', function (contentWriter) {
* contentWriter.println('<html>');
* contentWriter.println('</html>');
* });
* fileWriter.done(); // will emit the `done` event when all files are written
*
* @class FileWriter
* @extends Writer
* @module io
* @param sync
* @constructor
*/
function FileWriter(sync) {
Writer.call(this);
var that = this;
this.delegate = sync ? new SyncFileWriter() : new AsyncFileWriter();
this.delegate.on('error', function (err) { that.emit('error', err); });
this.delegate.on('done', function () { that.emit('done'); });
}
util.inherits(FileWriter, Writer);
extend(FileWriter, {
copyFile: function (source, dest) {
mkdirp.sync(path.dirname(dest));
fs.writeFileSync(dest, fs.readFileSync(source));
},
writeFile: function (file, callback) {
this.delegate.writeFile(file, callback);
},
done: function () {
this.delegate.done();
}
});
module.exports = FileWriter;

View File

@ -0,0 +1,30 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var OPT_PREFIX = " ",
OPT_START = OPT_PREFIX.length,
TEXT_START = 14,
STOP = 80,
wrap = require('wordwrap')(TEXT_START, STOP),
paraWrap = require('wordwrap')(1, STOP);
function formatPara(text) {
return paraWrap(text);
}
function formatOption(option, helpText) {
var formattedText = wrap(helpText);
if (option.length > TEXT_START - OPT_START - 2) {
return OPT_PREFIX + option + '\n' + formattedText;
} else {
return OPT_PREFIX + option + formattedText.substring((OPT_PREFIX + option).length);
}
}
module.exports = {
formatPara: formatPara,
formatOption: formatOption
};

View File

@ -0,0 +1,12 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
module.exports.create = function (message) {
var err = new Error(message);
err.inputError = true;
return err;
};

View File

@ -0,0 +1,109 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
function InsertionText(text, consumeBlanks) {
this.text = text;
this.origLength = text.length;
this.offsets = [];
this.consumeBlanks = consumeBlanks;
this.startPos = this.findFirstNonBlank();
this.endPos = this.findLastNonBlank();
}
var WHITE_RE = /[ \f\n\r\t\v\u00A0\u2028\u2029]/;
InsertionText.prototype = {
findFirstNonBlank: function () {
var pos = -1,
text = this.text,
len = text.length,
i;
for (i = 0; i < len; i += 1) {
if (!text.charAt(i).match(WHITE_RE)) {
pos = i;
break;
}
}
return pos;
},
findLastNonBlank: function () {
var text = this.text,
len = text.length,
pos = text.length + 1,
i;
for (i = len - 1; i >= 0; i -= 1) {
if (!text.charAt(i).match(WHITE_RE)) {
pos = i;
break;
}
}
return pos;
},
originalLength: function () {
return this.origLength;
},
insertAt: function (col, str, insertBefore, consumeBlanks) {
consumeBlanks = typeof consumeBlanks === 'undefined' ? this.consumeBlanks : consumeBlanks;
col = col > this.originalLength() ? this.originalLength() : col;
col = col < 0 ? 0 : col;
if (consumeBlanks) {
if (col <= this.startPos) {
col = 0;
}
if (col > this.endPos) {
col = this.origLength;
}
}
var len = str.length,
offset = this.findOffset(col, len, insertBefore),
realPos = col + offset,
text = this.text;
this.text = text.substring(0, realPos) + str + text.substring(realPos);
return this;
},
findOffset: function (pos, len, insertBefore) {
var offsets = this.offsets,
offsetObj,
cumulativeOffset = 0,
i;
for (i = 0; i < offsets.length; i += 1) {
offsetObj = offsets[i];
if (offsetObj.pos < pos || (offsetObj.pos === pos && !insertBefore)) {
cumulativeOffset += offsetObj.len;
}
if (offsetObj.pos >= pos) {
break;
}
}
if (offsetObj && offsetObj.pos === pos) {
offsetObj.len += len;
} else {
offsets.splice(i, 0, { pos: pos, len: len });
}
return cumulativeOffset;
},
wrap: function (startPos, startText, endPos, endText, consumeBlanks) {
this.insertAt(startPos, startText, true, consumeBlanks);
this.insertAt(endPos, endText, false, consumeBlanks);
return this;
},
wrapLine: function (startText, endText) {
this.wrap(0, startText, this.originalLength(), endText);
},
toString: function () {
return this.text;
}
};
module.exports = InsertionText;

View File

@ -0,0 +1,13 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var path = require('path'),
fs = require('fs'),
pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', '..', 'package.json'), 'utf8'));
module.exports = {
NAME: pkg.name,
VERSION: pkg.version
};

View File

@ -0,0 +1,213 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var path = require('path'),
SEP = path.sep || '/',
utils = require('../object-utils');
function commonArrayPrefix(first, second) {
var len = first.length < second.length ? first.length : second.length,
i,
ret = [];
for (i = 0; i < len; i += 1) {
if (first[i] === second[i]) {
ret.push(first[i]);
} else {
break;
}
}
return ret;
}
function findCommonArrayPrefix(args) {
if (args.length === 0) {
return [];
}
var separated = args.map(function (arg) { return arg.split(SEP); }),
ret = separated.pop();
if (separated.length === 0) {
return ret.slice(0, ret.length - 1);
} else {
return separated.reduce(commonArrayPrefix, ret);
}
}
function Node(fullName, kind, metrics) {
this.name = fullName;
this.fullName = fullName;
this.kind = kind;
this.metrics = metrics || null;
this.parent = null;
this.children = [];
}
Node.prototype = {
displayShortName: function () {
return this.relativeName;
},
fullPath: function () {
return this.fullName;
},
addChild: function (child) {
this.children.push(child);
child.parent = this;
},
toJSON: function () {
return {
name: this.name,
relativeName: this.relativeName,
fullName: this.fullName,
kind: this.kind,
metrics: this.metrics,
parent: this.parent === null ? null : this.parent.name,
children: this.children.map(function (node) { return node.toJSON(); })
};
}
};
function TreeSummary(summaryMap, commonPrefix) {
this.prefix = commonPrefix;
this.convertToTree(summaryMap, commonPrefix);
}
TreeSummary.prototype = {
getNode: function (shortName) {
return this.map[shortName];
},
convertToTree: function (summaryMap, arrayPrefix) {
var nodes = [],
rootPath = arrayPrefix.join(SEP) + SEP,
root = new Node(rootPath, 'dir'),
tmp,
tmpChildren,
seen = {},
filesUnderRoot = false;
seen[rootPath] = root;
Object.keys(summaryMap).forEach(function (key) {
var metrics = summaryMap[key],
node,
parentPath,
parent;
node = new Node(key, 'file', metrics);
seen[key] = node;
nodes.push(node);
parentPath = path.dirname(key) + SEP;
if (parentPath === SEP + SEP || parentPath === '.' + SEP) {
parentPath = SEP + '__root__' + SEP;
}
parent = seen[parentPath];
if (!parent) {
parent = new Node(parentPath, 'dir');
root.addChild(parent);
seen[parentPath] = parent;
}
parent.addChild(node);
if (parent === root) { filesUnderRoot = true; }
});
if (filesUnderRoot && arrayPrefix.length > 0) {
arrayPrefix.pop(); //start at one level above
tmp = root;
tmpChildren = tmp.children;
tmp.children = [];
root = new Node(arrayPrefix.join(SEP) + SEP, 'dir');
root.addChild(tmp);
tmpChildren.forEach(function (child) {
if (child.kind === 'dir') {
root.addChild(child);
} else {
tmp.addChild(child);
}
});
}
this.fixupNodes(root, arrayPrefix.join(SEP) + SEP);
this.calculateMetrics(root);
this.root = root;
this.map = {};
this.indexAndSortTree(root, this.map);
},
fixupNodes: function (node, prefix, parent) {
var that = this;
if (node.name.indexOf(prefix) === 0) {
node.name = node.name.substring(prefix.length);
}
if (node.name.charAt(0) === SEP) {
node.name = node.name.substring(1);
}
if (parent) {
if (parent.name !== '__root__' + SEP) {
node.relativeName = node.name.substring(parent.name.length);
} else {
node.relativeName = node.name;
}
} else {
node.relativeName = node.name.substring(prefix.length);
}
node.children.forEach(function (child) {
that.fixupNodes(child, prefix, node);
});
},
calculateMetrics: function (entry) {
var that = this,
fileChildren;
if (entry.kind !== 'dir') {return; }
entry.children.forEach(function (child) {
that.calculateMetrics(child);
});
entry.metrics = utils.mergeSummaryObjects.apply(
null,
entry.children.map(function (child) { return child.metrics; })
);
// calclulate "java-style" package metrics where there is no hierarchy
// across packages
fileChildren = entry.children.filter(function (n) { return n.kind !== 'dir'; });
if (fileChildren.length > 0) {
entry.packageMetrics = utils.mergeSummaryObjects.apply(
null,
fileChildren.map(function (child) { return child.metrics; })
);
} else {
entry.packageMetrics = null;
}
},
indexAndSortTree: function (node, map) {
var that = this;
map[node.name] = node;
node.children.sort(function (a, b) {
a = a.relativeName;
b = b.relativeName;
return a < b ? -1 : a > b ? 1 : 0;
});
node.children.forEach(function (child) {
that.indexAndSortTree(child, map);
});
},
toJSON: function () {
return {
prefix: this.prefix,
root: this.root.toJSON()
};
}
};
function TreeSummarizer() {
this.summaryMap = {};
}
TreeSummarizer.prototype = {
addFileCoverageSummary: function (filePath, metrics) {
this.summaryMap[filePath] = metrics;
},
getTreeSummary: function () {
var commonArrayPrefix = findCommonArrayPrefix(Object.keys(this.summaryMap));
return new TreeSummary(this.summaryMap, commonArrayPrefix);
}
};
module.exports = TreeSummarizer;

View File

@ -0,0 +1,92 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var util = require('util'),
EventEmitter = require('events').EventEmitter;
function extend(cons, proto) {
Object.keys(proto).forEach(function (k) {
cons.prototype[k] = proto[k];
});
}
/**
* abstract interfaces for writing content
* @class ContentWriter
* @module io
* @main io
* @constructor
*/
//abstract interface for writing content
function ContentWriter() {
}
ContentWriter.prototype = {
/**
* writes the specified string as-is
* @method write
* @param {String} str the string to write
*/
write: /* istanbul ignore next: abstract method */ function (/* str */) {
throw new Error('write: must be overridden');
},
/**
* writes the specified string with a newline at the end
* @method println
* @param {String} str the string to write
*/
println: function (str) { this.write(str + '\n'); }
};
/**
* abstract interface for writing files and assets. The caller is expected to
* call `done` on the writer after it has finished writing all the required
* files. The writer is an event-emitter that emits a `done` event when `done`
* is called on it *and* all files have successfully been written.
*
* @class Writer
* @constructor
*/
function Writer() {
EventEmitter.call(this);
}
util.inherits(Writer, EventEmitter);
extend(Writer, {
/**
* allows writing content to a file using a callback that is passed a content writer
* @method writeFile
* @param {String} file the name of the file to write
* @param {Function} callback the callback that is called as `callback(contentWriter)`
*/
writeFile: /* istanbul ignore next: abstract method */ function (/* file, callback */) {
throw new Error('writeFile: must be overridden');
},
/**
* copies a file from source to destination
* @method copyFile
* @param {String} source the file to copy, found on the file system
* @param {String} dest the destination path
*/
copyFile: /* istanbul ignore next: abstract method */ function (/* source, dest */) {
throw new Error('copyFile: must be overridden');
},
/**
* marker method to indicate that the caller is done with this writer object
* The writer is expected to emit a `done` event only after this method is called
* and it is truly done.
* @method done
*/
done: /* istanbul ignore next: abstract method */ function () {
throw new Error('done: must be overridden');
}
});
module.exports = {
Writer: Writer,
ContentWriter: ContentWriter
};

View File

@ -0,0 +1,49 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
//EXPERIMENTAL code: do not rely on this in anyway until the docs say it is allowed
var path = require('path'),
yuiRegexp = /yui-nodejs\.js$/;
module.exports = function (matchFn, transformFn, verbose) {
return function (file) {
if (!file.match(yuiRegexp)) {
return;
}
var YMain = require(file),
YUI,
loaderFn,
origGet;
if (YMain.YUI) {
YUI = YMain.YUI;
loaderFn = YUI.Env && YUI.Env.mods && YUI.Env.mods['loader-base'] ? YUI.Env.mods['loader-base'].fn : null;
if (!loaderFn) { return; }
if (verbose) { console.log('Applying YUI load post-hook'); }
YUI.Env.mods['loader-base'].fn = function (Y) {
loaderFn.call(null, Y);
origGet = Y.Get._exec;
Y.Get._exec = function (data, url, cb) {
if (matchFn(url) || matchFn(path.resolve(url))) { //allow for relative paths as well
if (verbose) {
console.log('Transforming [' + url + ']');
}
try {
data = transformFn(data, url);
} catch (ex) {
console.error('Error transforming: ' + url + ' return original code');
console.error(ex.message || ex);
if (ex.stack) { console.error(ex.stack); }
}
}
return origGet.call(Y, data, url, cb);
};
return Y;
};
}
};
};