02.09.2013, 23:10
|
Особый гость
|
|
Регистрация: 02.04.2010
Сообщений: 4,260
|
|
Разметка для Google closure compiler
/** @namespace foo */
def ('foo') ({
/**
* @constructor
*/
__init__: function() {
// WARNING - Property method never defined
this.method();
},
/** @this {foo} */
method: function() {
// WARNING - Bad type annotation. Unknown type namespace
}
});
// WARNING - foo never defined
new foo;
Кто-нибудь знает как размечать такие конструкторы для GCC?
Последний раз редактировалось monolithed, 02.09.2013 в 23:30.
|
|
03.09.2013, 00:32
|
|
猫
|
|
Регистрация: 07.06.2007
Сообщений: 7,504
|
|
Он их ломает?
упс. Вижу, ломает.
__________________
Последний раз редактировалось Gozar, Сегодня в 24:14.
Последний раз редактировалось Gozar, 03.09.2013 в 00:36.
|
|
03.09.2013, 01:25
|
Особый гость
|
|
Регистрация: 02.04.2010
Сообщений: 4,260
|
|
Да много там сюрпризов:
/**
* @param {Object} object
* @param {(string|number)} name
* @param {*} value
*/
var fabric = function(object, name, value) {
object[name] = value;
};
fabric(Number, 'MAX_INTEGER', 9007199254740991);
// ...
console.log(Number.MAX_INTEGER); // 9007199254740991
// WARNING: JSC_INEXISTENT_PROPERTY: Property MAX_INTEGER never defined on Number at line 14 character 12
Без предварительного экспорта переменных через через опцию --externs=... сыпит ворнингами
|
|
03.09.2013, 10:35
|
что-то знаю
|
|
Регистрация: 24.05.2009
Сообщений: 5,176
|
|
Сообщение от monolithed
|
Разметка для Google closure compiler
|
боролся я как то с этим, хотя мне больше волновал вопрос с автокомплитом. В итоге вышло примерно так, GCC при этом не плачет и автокомплит работает хорошо:
/**
* Component является общим предком всех классов компонентов.
*
* @author <a href="mailto:spb.piksel@gmail.com">Dmitrii Pakhtinov</a>
* @requires Class
* @version 1.0 - 12/20/2012
*/
Class("SP.Component", function() {
/**
* Ссылка на родительский компонент
*
* @type {SP.Component|null}
* @private
*/
var owner = null;
/**
* Список дочерних компонентов
*
* @type {Array}
* @private
*/
var components = [];
/**
* @class SP.Component
*/
return {
/**
* Общий предок всех компонентов, каждый компонент обязан наследоватся от этого класса
*
* @namespace SP
* @constructs
* @constructor
*/
Component: function() {
// dummy
},
/**
* Устанавливает или возвращает родительский компонент
* Для удаления родительского компонента установите значение <b>null</b>
*
* Родительский компонент является владельцем компонента и может оперировать
* свойствами дочернего компонента. Присвоеный компонент является владельцем
* компонента которому его присвоили и в случае удаления владельца, будут
* удалены все его подчиненные компоненты, если вы не хотите потерять подчиненные
* копоненты, позаботьтесь об этом заранее
*
* @type {SP.Component|null}
* @property
* @public
* @final
*/
owner: {
/**
* @param {SP.Component|null} component
*/
set: function(component) {
// пропускаем только если текущая ссылка на владельца иная и это наследник компонента
if (component !== owner && (component === null || Class.instanceOf(component, this.__class__))) {
// удаляем у текущего владельца данный компонент
if (owner) {
// если владелец не позволит удалить компонет
if (owner.onremovecomponent(this) === false) {
return;
}
owner.removeComponent.call(false, this, owner);
}
// добавляем владельцу текущий компонент
if (component) {
// если компонент не позволит его добавить
if (component.oninsertcomponent(this) === false) {
return;
}
component.insertComponent.call(false, this, component);
}
// меняем ссылку на владельца
owner = component;
}
},
get: function() {
return owner;
}
},
/**
* Добавляет в список дочерний компонент
*
* @param {SP.Component} component компонент который будет дочерним
* @return {Boolean} возвращает <b>true</b> при успешном выполнении, в противном случае <b>false</b>
* @public
* @final
* @see {@link get.components}
*/
insertComponent: function(component) {
// Условие для внутреннего использования
if (this instanceof Boolean && arguments.length > 1) {
// Добавляем компонент в список
components[components.length] = component;
// информируем компонент о том что его добавли владельцу
component.oninsert(arguments[1]);
} else if (Class.instanceOf(component, this.__class__)) {
// Если объект является компонентом пробуем добавить его
return components.length < (component.owner = this, components.length);
}
return false;
},
/**
* Удаляет из списка дочерний компонент
*
* @param {SP.Component} component компонент который является дочерним этого компонента
* @return {Boolean} возвращает <b>true</b> при успешном выполнении, в противном случае <b>false</b>
* @public
* @final
* @see {@link get.components}
*/
removeComponent: function(component) {
// Условие для внутреннего использования
if (this instanceof Boolean && arguments.length > 1) {
var index = -1;
if ("indexOf" in components) {
// новая версия ECMAScript имеет поддержку метода indexOf для массивов
index = components.indexOf(component);
} else {
// для более старой версии ECMAScript
for(var i = components.length; i--;) {
if (components[i] === component) {
index = i;
break;
}
}
}
if (index >= 0) {
// удаляем компонент из стека
components.splice(index, 1);
// информируем компонент о том что его удалили из родительского компонента
component.onremove(arguments[1]);
}
} else if (Class.instanceOf(component, this.__class__)) {
// Если объект является компонентом удаляем у него родителя
return components.length > (component.owner = null, components.length);
}
return false;
},
/**
* Содержит список всех дочерних компонентов
*
* @type {Array}
* @property
* @public
* @see {@link insertComponent}
* @see {@link removeComponent}
*/
components: {
get:function() {
// не будем возвращать ссылку на оригинальный список компонентов, отдаем копию
return components.slice(0);
}
},
/**
* Устанавливает или возвращает позицию компонента
*
* Если параметр component не задан, то в случае если задан position установит
* текущий компонент у его владельца на новую позицию, если же параметр position
* так же не задан, то вернет текущую позицию у владельца.
*
* Если компонент не имеет владельца, вернет значение -1
*
* @param {SP.Component} [component]
* @param {Integer} [position]
* @return {Integer}
* @public
*/
componentPosition: function(component, position) {
// ищем компонент у владельца
if (typeof component === "number" || !component) {
return owner ? owner.componentPosition(this, component) : -1;
}
var index = -1, length = components.length;
if ("indexOf" in components) {
// новая версия ECMAScript имеет поддержку метода indexOf для массивов
index = components.indexOf(component);
} else {
// для более старой версии ECMAScript
for(var i = components.length; i--;) {
if (components[i] === component) {
index = i;
break;
}
}
}
// если позиция или компонент не определены, возвращаем текущуюю позицию
if (typeof position !== "number" || index < 0) {
return index;
}
// попытаемся нормализовать позицию
while(position < 0 || position >= length) {
position = position < 0 ? length + position : position >= length ? position - length : position;
}
// если текущая позиция не равна новой позиции
if (index !== position) {
// удаляем компонент из текущей позиции
components.splice(index, 1);
if (position === 0) {
// вставляем в начало
components.unshift(component);
} else if (position === components.length) {
// вставляем в конец
components.push(component);
} else {
// вставляем где то в середине
components = components.slice(0, position).concat(component, components.slice(position));
}
length = index < position ? position : index;
index = index < position ? index : position;
for( ; index <= length; index++ ) {
components[index].onchangeposition(index);
}
}
// возвращаем позицию компонента
return position;
},
/**
* Событие страбатывает у владельца в случае если добавляют в него новый компонент
* Верните <b>false</b> если не хотите что бы в ваш компонент что-то добавляли.
*
* @protected
* @param {SP.Component} component
*/
oninsertcomponent: function(component) {
/* virtual protected */
},
/**
* Событие срабатывает у владельца при удалении из него компонента
* Верните <b>false</b> если не хотите что бы из владельца что-то удаляли
*
* @protected
* @param {SP.Component} component
*/
onremovecomponent: function(component) {
/* virtual protected */
},
/**
* Событие срабатывает у компонента в том случае если он был успешно принят владельцем
*
* @protected
* @param {SP.Component} owner
*/
oninsert: function(owner) {
/* virtual protected */
},
/**
* Событие срабатывает если компонент успешно был удален владельцем
*
* @protected
* @param {SP.Component} owner
*/
onremove: function(owner) {
/* virtual protected */
},
/**
* Событие срабатывает если сменили позицию компонента
*
* @protected
* @param {Integer} position
*/
onchangeposition: function(position) {
/* virtual protected */
}
}
});
|
|
03.09.2013, 10:47
|
Особый гость
|
|
Регистрация: 02.04.2010
Сообщений: 4,260
|
|
Может у тебя такие ошибки игнорировались?
Потому что сразу же будет предупреждение:
JSC_TYPE_PARSE_ERROR: Bad type annotation. Unknown type SP.Component at line 12 character 9
* @type {SP.Component|null}
Больше всего меня конечно бесит это:
var global = function() {
return this;
}();
void function(global) {
global.foo = 1;
}(global);
Приходится выносить определение глобальной перменной в экстерны.
PS: мой конфиг:
#! /usr/bin/env sh
# Google closure compiler
# [url]http://code.google.com/p/closure-compiler/wiki/Warnings[/url]
timestamp=`date +%s`
compiler=../tools/closure-compiler/build/compiler.jar
output=../cache/static/__init__
java -jar ${compiler} \
--js=${output}.js \
--externs=../model/__slot__.js \
--js_output_file="${output}.${timestamp}.js" \
--create_source_map="${output}.${timestamp}.json" \
--summary_detail_level=3 \
--charset=UTF-8 \
--language_in=ECMASCRIPT5_STRICT \
--warning_level=VERBOSE \
--compilation_level=SIMPLE_OPTIMIZATIONS \
--formatting=SINGLE_QUOTES \
--jscomp_error=ambiguousFunctionDecl \
--jscomp_error=checkDebuggerStatement \
--jscomp_error=checkRegExp \
--jscomp_error=checkVars \
--jscomp_error=const \
--jscomp_error=constantProperty \
--jscomp_error=es5Strict \
--jscomp_error=internetExplorerChecks \
--jscomp_error=invalidCasts \
--jscomp_error=missingProperties \
--jscomp_error=suspiciousCode \
--jscomp_error=undefinedNames \
--jscomp_error=undefinedVars \
--jscomp_warning=uselessCode \
--jscomp_warning=globalThis \
--jscomp_warning=externsValidation \
--jscomp_warning=duplicate \
--jscomp_warning=deprecated \
--jscomp_warning=accessControls \
--jscomp_warning=visibility \
--jscomp_warning=checkTypes \
--jscomp_warning=fileoverviewTags \
--jscomp_warning=nonStandardJsDocs \
--jscomp_warning=strictModuleDepCheck \
--jscomp_warning=unknownDefines \
# --output_wrapper='void function(window){ %output %}(window);' \
# --source_map_format=DEFAULT \
# --use_types_for_optimization \
# --create_name_map_files=true \
# --print_ast \
# --print_pass_graph \
# --print_tree \
|
|
03.09.2013, 11:11
|
|
Быдлокодер;)
|
|
Регистрация: 19.11.2010
Сообщений: 4,338
|
|
Если я правильно понял, то тебе нужно продекларировать принадлежность методов к прототипу класса, а это можно сделать с помощью директивы lends, но нужно учесть 2 моменты при работе с ней:
1) В директиве указывается ссылка, а не название конструктора или тип, как в type или param
2) Директива применима только для литералов объекта.
Использование:
/** @constructor */
var MyClass = new Class(function init() {
this.myMethod();
}, /** @lends {MyClass.prototype} */ {
myMethod: function () { },
myMethod2: function () { }
});
new MyClass().myMethod();
|
|
03.09.2013, 11:17
|
что-то знаю
|
|
Регистрация: 24.05.2009
Сообщений: 5,176
|
|
Сообщение от monolithed
|
Потому что сразу же будет предупреждение:
|
хм.. а что не так я могу настраивать в GCC? Обычно компилю такой командой:
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js=Component.class.js --js_output_file=Component.class.min.js
Сообщение от monolithed
|
мой конфиг:
|
ужс
|
|
03.09.2013, 12:23
|
Особый гость
|
|
Регистрация: 02.04.2010
Сообщений: 4,260
|
|
Статический анализ, что тут ужасного?
|
|
03.09.2013, 12:45
|
Особый гость
|
|
Регистрация: 02.04.2010
Сообщений: 4,260
|
|
Сообщение от kobezzza
|
сли я правильно понял, то тебе нужно продекларировать принадлежность методов к прототипу класса, а это можно сделать с помощью директивы lends, но нужно учесть 2 моменты при работе с ней
|
Не совсем так, у меня конструктор создается динамически:
void function() {
var global = function() {
return this;
}();
var fabric = function(name, value) {
global[name] = value;
};
global.fabric = fabric;
}();
// Как тут сказать что создается конструктор window.foo, а this это ссылка на него ?
fabric('foo', function(name) {
this[name] = 1;
});
(new foo).prop; // 1
PS: правда такой код успешно компилится, а вот если сделать фабрику конструкторов чуть по сложней, то gcc валит ошибками, что ничего не понимат (
Проблема частично решена, если свойство определено через скобочную нотацию, значит доступ к нему должен быть таким же:
(new foo)['prop']; // 1
Либо экпортировать все переменные заранее, через опцию --externs
Последний раз редактировалось monolithed, 03.09.2013 в 13:17.
|
|
03.09.2013, 23:16
|
Особый гость
|
|
Регистрация: 02.04.2010
Сообщений: 4,260
|
|
Object.defineProperty(Object, 'isObject', {
value: function(object) {
return Object.prototype.toString.call(object) === '[object Object]';
},
configurable: true,
enumerable: false,
writable: true
});
Object.isObject({});
// JSC_INEXISTENT_PROPERTY: Property isObject never defined on Object at line 19 character 0
Object.isObject({});
^
Вот как такое победить чтобы не писать Object['isObject']({});?
Последний раз редактировалось monolithed, 03.09.2013 в 23:24.
|
|
|
|