@coffeelint/cli
Version:
Lint your CoffeeScript
86 lines (75 loc) • 2.54 kB
JavaScript
(function() {
var DuplicateKey;
module.exports = DuplicateKey = (function() {
class DuplicateKey {
constructor() {
this.braceScopes = []; // A stack tracking keys defined in nexted scopes.
}
lintToken([type], tokenApi) {
if (type === '{' || type === '}') {
this.lintBrace(...arguments);
return void 0;
}
if (type === 'PROPERTY' || type === 'STRING') {
return this.lintIdentifier(...arguments);
}
}
lintIdentifier(token, tokenApi) {
var key, m, nextToken, previousToken;
key = token[1];
if (this.currentScope == null) {
// Class names might not be in a scope
return null;
}
nextToken = tokenApi.peek(1);
if (nextToken[1] !== ':') {
// Exit if this identifier isn't being assigned. A and B
// are identifiers, but only A should be examined:
// A = B
return null;
}
previousToken = tokenApi.peek(-1);
if (previousToken[0] === '@') {
// Assigning "@something" and "something" are not the same thing
key = `@${key}`;
}
if (m = key.match(/^(["'])(.*)\1$/)) {
// Normalize property, "property", and 'property'
key = m[2];
}
// Added a prefix to not interfere with things like "constructor".
key = `identifier-${key}`;
if (this.currentScope[key]) {
return {token};
} else {
this.currentScope[key] = token;
return null;
}
}
lintBrace(token) {
if (token[0] === '{') {
if (this.currentScope != null) {
this.braceScopes.push(this.currentScope);
}
this.currentScope = {};
} else {
this.currentScope = this.braceScopes.pop();
}
return null;
}
};
DuplicateKey.prototype.rule = {
// I don't know of any legitimate reason to define duplicate keys in an
// object. It seems to always be a mistake, it's also a syntax error in
// strict mode.
// See https://jslinterrors.com/duplicate-key-a/
type: 'problem',
name: 'duplicate_key',
level: 'error',
message: 'Duplicate key defined in object or class',
description: `Prevents defining duplicate keys in object literals and classes`
};
DuplicateKey.prototype.tokens = ['PROPERTY', 'STRING', '{', '}'];
return DuplicateKey;
}).call(this);
}).call(this);