jscpd
Version:
Copy/paste detector for programming code, support JavaScript, CoffeeScript, PHP, Ruby, Python, Less, Go, Java, Yaml, C#, C++, C languages
89 lines (76 loc) • 3.21 kB
JavaScript
// Generated by CoffeeScript 1.10.0
(function() {
var Clone, Storage, Strategy, TokenizerFactory, crypto, shjs;
shjs = require('shelljs');
TokenizerFactory = require('./tokenizer/TokenizerFactory');
crypto = require('crypto');
Storage = require('./storage/StorageMemory');
Clone = require('./clone').Clone;
Strategy = (function() {
function Strategy(options) {
this.options = options;
this.languages = options.languages;
this.storage = new Storage();
}
Strategy.prototype.detect = function(map, file, minLines, minTokens) {
var code, currentMap, firstHash, firstLine, firstToken, hash, isClone, language, lastToken, lines, mapFrame, ref, tokenNumber, tokenizer, tokensPositions;
this.minLines = minLines;
this.minTokens = minTokens;
tokenizer = TokenizerFactory.prototype.makeTokenizer(file, this.languages);
if (!tokenizer) {
return false;
}
language = tokenizer.getType();
if (shjs.test('-f', file)) {
code = shjs.cat(file);
} else {
return false;
}
lines = code.split('\n');
map.numberOfLines = map.numberOfLines + lines.length;
tokenizer.skipComments = this.options['skip-comments'];
ref = tokenizer.tokenize(code).generateMap(), tokensPositions = ref.tokensPositions, currentMap = ref.currentMap;
firstLine = 0;
tokenNumber = 0;
isClone = false;
while (tokenNumber <= tokensPositions.length - this.minTokens) {
mapFrame = currentMap.substring(tokenNumber * 33, tokenNumber * 33 + this.minTokens * 33);
hash = crypto.createHash('md5').update(mapFrame).digest('hex');
if (this.storage.hasHash(hash, language)) {
isClone = true;
if (firstLine === 0) {
firstLine = tokensPositions[tokenNumber];
firstHash = hash;
firstToken = tokenNumber;
}
} else {
if (isClone) {
lastToken = tokenNumber + this.minTokens - 2;
this.addClone(map, file, firstHash, firstToken, lastToken, firstLine, tokensPositions[lastToken], language);
firstLine = 0;
isClone = false;
}
this.storage.addHash(hash, file, tokensPositions[tokenNumber], language);
}
tokenNumber = tokenNumber + 1;
}
if (isClone) {
lastToken = tokenNumber + this.minTokens - 2;
this.addClone(map, file, firstHash, firstToken, lastToken, firstLine, tokensPositions[lastToken], language);
return isClone = false;
}
};
Strategy.prototype.addClone = function(map, file, hash, firstToken, lastToken, firstLine, lastLine, language) {
var fileA, firstLineA, hashInfo, numLines;
hashInfo = this.storage.getHash(hash, language);
fileA = hashInfo.file;
firstLineA = hashInfo.line;
numLines = lastLine + 1 - firstLine;
if (numLines >= this.minLines && (fileA !== file || firstLineA !== firstLine)) {
return map.addClone(new Clone(fileA, file, firstLineA, firstLine, numLines, lastToken - firstToken + 1));
}
};
return Strategy;
})();
exports.Strategy = Strategy;
}).call(this);