UNPKG

grunt-zuckrig-closure

Version:

Reduce a verbose syntax for Google Closure Compiler to be more Pythonic/Rubistic.

205 lines (178 loc) 6.34 kB
var ANNO, ConstructorHook, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; require('sugar'); ANNO = { CTOR: '@constructor', EXTENDS: '@extends' }; ConstructorHook = (function() { function ConstructorHook(_extractor, _builder) { this._extractor = _extractor; this._builder = _builder; this._super_class = null; this._required = []; this._produce_pos = -1; this._to_inject = {}; this._class_name = null; } /** Injects a constructor annotation. If the annotation is provided does nothing. Also injects goog.require and @extends for a super class, if it's necessary. */ ConstructorHook.prototype.fix = function(tokens) { var i, k, tok, v, _i, _len, _ref; for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) { tok = tokens[i]; this._try_find_super_class(tok, i, tokens); this._find_constructor(tok, i, tokens); this._find_produce_position(tok, i, tokens); this._find_required(tok, i, tokens); this._find_class_name(tok, i, tokens); } _ref = this._to_inject; for (k in _ref) { v = _ref[k]; this._inject_annotations(k, v, tokens); } this._inject_class_provide(tokens); return this._inject_require_super(tokens); }; ConstructorHook.prototype._inject_annotations = function(i, comment, tokens) { var begin, end, extends_pos; if (comment.type === 'Block') { if (comment.value.indexOf(ANNO.CTOR) === -1) { extends_pos = comment.value.indexOf(" " + ANNO.EXTENDS); if (extends_pos === -1) { comment.value += " " + ANNO.CTOR + "\n "; if (this._super_class != null) { return comment.value += "" + (this._build_extends_anno()) + " "; } } else { begin = comment.value.substring(0, extends_pos); end = comment.value.substr(extends_pos); return comment.value = [begin, " " + ANNO.CTOR + "\n ", end].join(''); } } } else { return this._inject_new_block(i, this._build_ctor_token(comment.loc), tokens); } }; ConstructorHook.prototype._build_ctor_token = function(loc) { var k, tok, v; tok = { type: 'NewBlock', value: "*\n " + ANNO.CTOR + "\n", loc: {} }; if (this._super_class != null) { tok.value += " " + (this._build_extends_anno()); } for (k in loc) { v = loc[k]; tok.loc[k] = Object.clone(v, true); } if (tok.loc.start != null) { tok.loc.start.column = 0; tok.loc.start.line--; } return tok; }; ConstructorHook.prototype._build_extends_anno = function() { return " " + ANNO.EXTENDS + " {" + this._super_class + "}\n"; }; ConstructorHook.prototype._inject_new_block = function(i, tok, tokens) { return tokens.splice(i, 0, tok); }; ConstructorHook.prototype._is_constructor = function(token, next_sibling) { return token.type === 'Keyword' && token.value === 'function' && next_sibling && next_sibling.type === 'Identifier' && next_sibling.value !== 'ctor'; }; ConstructorHook.prototype._find_constructor = function(tok, i, tokens) { var next; next = tokens[i + 1]; if (!this._is_constructor(tok, next)) { return; } return this._to_inject[i] = tokens[i - 1]; }; ConstructorHook.prototype._is_extending = function(tok, next) { return tok.type === 'Identifier' && tok.value === '__extends' && next.value === '('; }; ConstructorHook.prototype._try_find_super_class = function(tok, i, tokens) { var next; next = tokens[i + 1]; if (this._is_extending(tok, next)) { this._super_class = this._extractor.parse_super_class(i, tokens); } }; ConstructorHook.prototype._find_produce_position = function(tok, i, tokens) { if (this._produce_pos !== -1) { return; } if (tok.value === 'goog' && tokens[i + 1].value === '.' && tokens[i + 2].value === 'provide') { return this._produce_pos = i + 7; } }; ConstructorHook.prototype._inject_require_super = function(tokens) { var _ref; if ((this._super_class != null) && this._produce_pos !== -1 && (_ref = this._super_class, __indexOf.call(this._required, _ref) < 0)) { return this._insert_tokens(this._build_super_require(tokens[this._produce_pos].loc), tokens, this._produce_pos); } }; ConstructorHook.prototype._insert_tokens = function(to_insert, tokens, i) { var tok, _i, _len, _results; _results = []; for (_i = 0, _len = to_insert.length; _i < _len; _i++) { tok = to_insert[_i]; tokens.splice(i, 0, tok); _results.push(i++); } return _results; }; ConstructorHook.prototype._build_super_require = function(orig) { var k, loc, v; loc = {}; for (k in orig) { v = orig[k]; loc[k] = Object.clone(v, true); } loc.start.line++; loc.end.line = loc.start.line; return this._builder.build_goog_call('require', "'" + this._super_class + "'", loc); }; ConstructorHook.prototype._build_fake_location = function() { return { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } }; }; ConstructorHook.prototype._replace_escaped_chars = function(val) { return val.replace(/\\|'/g, ''); }; ConstructorHook.prototype._find_required = function(tok, i, tokens) { if (tok.value === 'goog' && tokens[i + 1].value === '.' && tokens[i + 2].value === 'require') { return this._required.push(this._replace_escaped_chars(tokens[i + 4].value)); } }; ConstructorHook.prototype._find_class_name = function(tok, i, tokens) { if (this._class_name != null) { return; } return this._class_name = this._extractor.parse_class_from_def(i, tokens); }; ConstructorHook.prototype._inject_class_provide = function(tokens) { var provide; if (this._produce_pos === -1 && (this._class_name != null)) { provide = this._builder.build_goog_call('provide', "'" + this._class_name + "'", this._build_fake_location()); this._insert_tokens(provide, tokens, 0); return this._produce_pos = provide.length; } }; return ConstructorHook; })(); module.exports = ConstructorHook;