Создание собственных аннотаций
Java-фреймворк, на котором построен Google Closure Compiler, может быть расширен. Например, можно добавить новые аннотации, которые делают что-то с кодом.
К примеру, можно добавить @strip - аннотацию, которая уберет из итогового кода все вызовы объекта.
Работать будет так:
/** @strip */
console = {
debug: function() { /* ... */ }
}
function doSomething() {
console.log()
alert(1);
}
Превратится в:
function doSomething(){alert(1)};
Создавать аннотации можно практически любые. В частности, аннотация может иметь параметры: @param {string} . Действия, которые компилятор будет совершать с аннотированным объектом (объектом, функцией и т.п.) описываются на языке Java и могут быть практически любыми.
Единственно, следует иметь в виду, что аннотация - это все же для компилятора, а не для браузера. Отлаживать удобнее всего несжатый код, а в нем аннотации будут простыми комментариями.
Хотя, даже сжатый код можно поотлаживать, используя Closure Inspector в Firefox.
Таким образом, в общем случае заведомо полезны аннотации, помогающие лучше сжать/обработать код.
Добавление аннотаций состоит из нескольких частей. Нужно указать ее в парсере javascript, добавить в список возможных аннотаций JSDoc, создать функцию для проверки аннотации, описать действия компилятора и т.п. Разберем шаги поподробнее на примере @strip .
За структуру данных JSDoc отвечает класс com.google.javascript.rhino.JSDocInfo ,
Для новой аннотации следует создать флаг в общем списке:
...
private static final int MASK_FILEOVERVIEW = 0x00001000; // @fileoverview
private static final int MASK_IMPLICITCAST = 0x00002000; // @implicitCast
private static final int MASK_NOSIDEEFFECTS = 0x00004000; // @nosideeffects
// допишем нашу аннотацию в конец, создадим ей новую маску
private static final int MASK_STRIP = 0x00008000; // @strip
И добавим методы установки и проверки, аналогично setExport :
void setStrip(boolean value) {
setFlag(value, MASK_STRIP);
}
public boolean isStrip() {
return getFlag(MASK_STRIP);
}
Наша аннотация - бинарная (есть/нет), поэтому последующие действия по сути состоят в создании рядом с export аналогов с именем strip .
Класс com.google.javascript.rhino.JSDocInfoBuilder отвечает за построение объекта JSDoc из аннотаций. Добавим новую аннотацию и туда:
// аналогично recordExport..
public boolean recordStrip() {
if (!currentInfo.isStrip()) {
currentInfo.setStrip(true);
populated = true;
return true;
} else {
return false;
}
}
Класс com.google.javascript.jscomp.parsing.JsDocInfoParser - последний класс парсера, требующий исправления. Он отвечает за разбор текста скрипта. Допишем новую аннотацию в список enum Annotation :
...
EXTENDS,
EXPORT,
// наша аннотация
STRIP,
.. И добавим ее в общий список recognizedAnnotations :
...
put("enum", Annotation.ENUM).
put("export", Annotation.EXPORT).
// наша новая строка
put("strip", Annotation.STRIP).
Кроме того, добавим фрагмент в метод parse , который будет записывать найденную аннотацию в JSDoc.
Можно это сделать аналогично case EXPORT :
case EXPORT:
...
case STRIP:
if (!jsdocBuilder.recordStrip()) {
parser.addWarning("msg.jsdoc.strip",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
Итак, парсер готов. Аннотация будет распознана и превращена в JSDoc. При обходе синтаксического дерева javascript, компилятор сможет вызовом node.getJSDocInfo() получить JSDoc, и затем проверить isStrip() - нет ли у данного объекта аннотации @strip .
Для того, чтобы аннотация заработала, необходимо действие. Почти все действия google closure compiler реализуются путем прохода компилятора по синтаксическому дереву.
Проход может осуществлять любой класс с интерфейсом CompilerPass . Он осуществляется в обратном порядке (Post-Order).
Мы не будем патчить существующие проходы, а создадим свой. Он будет проходить по дереву, и при нахождении узла с isStrip() == true - добавлять имя объекта в список stripTypes .
В последующих проходах этот список будет обработан компилятором, и все обращения к указанному объекту будут удалены из кода.
Вот код для такого прохода.
package com.google.javascript.jscomp;
import com.google.common.collect.Sets;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.FunctionNode;
class ApplyAnnotationStrip extends NodeTraversal.AbstractPostOrderCallback implements CompilerPass {
private final Compiler compiler;
ApplyAnnotationStrip(Compiler compiler) {
this.compiler = compiler;
}
public void visit(NodeTraversal t, Node n, Node parent) {
JSDocInfo jsDocInfo = n.getJSDocInfo();
if (jsDocInfo == null || !jsDocInfo.isStrip()) return;
/* получить имя объекта/функции */
String name = null;
if (n.getType() == Token.FUNCTION) {
name = ((FunctionNode)n).getFunctionName();
} else if (n.getType() == Token.ASSIGN) {
name = n.getFirstChild().getQualifiedName();
}
/* добавить в список */
CompilerOptions options = compiler.getOptions();
if (options.stripTypes.isEmpty()) {
options.stripTypes = Sets.newHashSet();
}
options.stripTypes.add(name);
}
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
}
Метод process требуется для интерфейса CompilerPass и осуществляет, собственно, проход компилятора - путем обхода дерева скрипта.
Третий аргумент NodeTraversal.traverse - объект, производящий обработку узлов во время обхода. Для этого у него должен быть метод visit . Мы реализуем его здесь же.
Метод visit , как видно из исходного кода, отрабатывает только для узлов с JSDoc и isStrip == true .
Он получает имя объекта и добавляет соответствующую строку в опцию компилятора stripTypes , которая более подробно описана в статье Автоудаление отладочных свойств и объектов.
Если коротко - последующие проходы компилятора используют эту опцию для удаления всех обращений к указанным в ней символам.
Для того, чтобы получать имя объекта, и вообще делать какие-то операции, компилятор использует Синтаксическое дерево.
Для того, чтобы в общих чертах представлять, как устроено дерево разбора javascript, можно почитать стандарт языка, документацию к Rhino, а впрочем - вполне можно что-то понять, запустив компилятор с опциями --use_only_custom_externs --print_tree --js ваш_скрипт . Такой вызов распечатает синтаксическое дерево вашего скрипта.
Итак, структура JSDoc готова, проход компилятора тоже описан, остается добавить этот проход к исполнению компилятором.
За это отвечает класс com.google.javascript.jscomp.DefaultPassConfig . Добавление прохода осуществляется посредством фабричного метода PassFactory .
Добавим новый метод аналогично уже существующим:
private final PassFactory applyAnnotationStrip =
new PassFactory("applyAnnotationStrip", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ApplyAnnotationStrip((Compiler)compiler);
}
};
Наш проход должен осуществится до оптимизационных проходов компилятора (В частности, до прохода, удаляющего strip'нутые символы), чтобы список stripTypes был использован.
Поэтому имеет смысл добавить его в конец метода getChecks , перед assertAllOneTimePasses(checks);
protected List<PassFactory> getChecks() {
// ...
checks.add(processDefines);
checks.add(applyAnnotationStrip);
assertAllOneTimePasses(checks);
return checks;
}
Google Closure Compiler с нашими дополнениями должен корректно обрабатывать исходный пример.
В частности:
/** @strip */
console = {
debug: function() { /* ... */ }
}
function doSomething() {
console.log()
alert(1);
}
Должно становиться (обычная оптимизация, не продвинутая):
function doSomething(){alert(1)};
У меня не составило особого труда пропатчить исходники по этому документу с нуля, но на всякий случай - вот патч к ревизии 9: stripann.patch.txt.
У кода в этой статье два основных недостатка.
Во-первых, я не использовал его в production достаточно долго. Конечно, допилить и оттестировать - вопрос (не очень большого) времени, но честно говоря, я предпочитаю опцию stripTypes командной строки компилятора.
Во-вторых, добавление аннотации требует патча нескольких файлов компилятора.
Впрочем, это не должно быть проблемой, т.к. патчи не нарушают структуру кода и будут успешно мержится с SVN.
Надеюсь, пример из статьи послужит хорошей иллюстрацией, как можно добавлять собственные аннотации к Google Closure Compiler.
В зависимости от проекта, они могут оказаться не менее полезными, чем стандартные аннотации компилятора.
|
if (n.getType() == Token.FUNCTION) {
name = ((FunctionNode)n).getFunctionName();
}
Не работает приведение:
"com.google.javascript.rhino.Node cannot be cast to com.google.javascript.rhino.FunctionNode".
Удалось ли кому-то заставить работать?
Да
член
нехорошо так делать
член
член
Этот метод процесса требуется для интерфейса CompilerPass и фактически выполняет переключение компилятора - путем обхода дерева сценария. Третий аргумент NodeTraversal.traverse - это объект, который обрабатывает узлы во время обхода. Для этого его необходимо посетить. Этот процесс обычно показывает код ошибки #
The city itself is on the Savannah River, but if you'd rather spend your time at the beach, you'll be only a free games short drive from some of Georgia's finest coastline, including Tybee Island.
Этот метод процесса требуется для интерфейса CompilerPass и фактически выполняет переключение компилятора - путем обхода дерева сценария. Третий аргумент NodeTraversal.traverse - это объект, который обрабатывает узлы во время обхода. Для этого его необходимо посетить. Этот процесс обычно показывает код ошибки #2048 cupcakes
Ну все так приемрно и работает - но с разными массивами данных и приразных вводных. Такие функции как правило нужны почти всем. Если заниматься кодировкой на джаве - в первую очередь будет надо еще знать алгоритмы перебора
Ну все так приемрно и работает - но с разными массивами данных и приразных вводных. Такие функции как правило нужны почти всем. Если заниматься кодировкой на джаве - в первую очередь будет надо еще знать алгоритмы перебора
Спасибо, полезные советы и рекомендации всегда нужны и лишними не будут. Мы в нашей сео компании be1 используем библиотеку скриптов для разных целей. Также редактор html кода который применяется в нашей работе над анализом сайтов построен с применением уникальных токенов на базе джава-скрипт. Ну и проверка позиции сайта в поисковиках также основана на подобных алгоритмах и позволяет найти поддомены сайта даже в сложных случаях. Джава скрипты не самое нужное в сео продвижении но тем не менее использование этой технологии помогает в нужных случаях
Good post. This sounds like a very good podcast. We are looking forward to listening to the actual podcast. Click Here
Sunset Beach is only one of Oahu's numerous surf places. If you have some surf expertise, you should be able to geometry dash enjoy the waves here since they aren't too big. Furthermore, according to its name, it's a terrific place to hang out after dusk.
Thank you for sharing this data. I really enjoy what you've written on your blog. You've shared a very useful and entertaining blog post with the public. getting over it
Pixelart123 — это сайт для всех, кто хочет заниматься пиксель-артом самостоятельно! Все наши шаблоны просты в создании. Откройте для себя сотни пиксельных шаблонов, которые легко создавать, копировать или создавать! Хотите покататься на своем радужном единороге? Путешествовать по планетам Солнечной системы на борту космического корабля? Прогулка в компании жирафов, слонов и попугаев? Или помочь Марио найти свою принцессу в замке Боузера? Pixelart123 предлагает вам множество различных стилей и идей для вашего собственного маленького пиксельного мира.
Roxa grudziadz
Roksa ¿Funcionan realmente los sitios de citas sexuales? ¡Claro que sí y yo soy un testigo viviente! De verdad, puede ser difícil aceptar que hay chicas por ahí que están dispuestas a dejarte esa galleta gratis, pero seguro que hay muchas de estas chicas que no quieren nada de amor. Como que no están de humor para poemas deslizantes, o para que les cojan la mano. Todo lo que quieren es echar un polvo de la forma más orgásmica posible con un tipo o tipos que necesiten un coño en el que puedan disparar un cañón de semen. Así que, en lugar de que estas putas vayan de puerta en puerta buscando penes desocupados que puedan empalarlas desde el coño hasta el intestino delgado, acuden a sitios de citas sexuales gratuitas y se registran. De ti depende encontrar a estas chicas y darles lo que quieren. Y me refiero a cada maldito centímetro de tu polla.
Erfahrene Nutten hat einen netten Chat und Unterhaltungsinhalte für Erwachsene, was die Seite zu einer aufregenden und amüsanten Plattform für wilden Spaß im Bett macht.
Thanks for sharing this information. I really like your blog post very much. You have really shared a informative and interesting blog post with people. play dordle game
Interesting thank you, this is valuable information and I find it very helpful. mesothelioma attorney in California
Хороший сайт. Откуда вы взяли материал для этой статьи? Я прочитал несколько ваших статей, и мне очень нравится ваш стиль письма. Я также столкнулся с этим на странице Paper Minecraft и люблю такой позитив. Большое спасибо, и продолжайте в том же духе.
If you're looking for a great way to online radio luisteren Nederland, then Radiofmluisteren is the perfect website for you. With a wide selection of radio stations to choose from, you're sure to find something that you'll love listening to. Whether you're looking for music, news, or talk radio, Radiofmluisteren has it all. And best of all, it's absolutely free to use. So why not give it a try today?
Anywhere, at any time, free solitaire is a fun way to spend the time. Play a game of solitaire to liven up your day, whether you're at home on a leisurely day, taking a break at work, or sitting outdoors with your laptop in the sunshine. Get out of a boring chore with a swift victory that will lift your spirits!
Interesting, and thank you; I appreciate the insight. geometry dash
Interesting, and thank you; I appreciate the insight.
As a last resort, if you're feeling very retro, you may always track down the original physical color by number
Secondly, adding an annotation requires patching several compiler files. foundation repair
When you save enough characters and go pizza tower through the final exit door, you will complete a level.
Thanks for your post, it's very helpful rainbow friends I hope in the future you will provide more information.
Отлаживать удобнее всего несжатый код, а в нем аннотации будут простыми комментариями. painting services near atlanta ga
Drift Boss offers a simple yet challenging drifting experience. Can you navigate the tricky corners and bumps without falling off
https://descargarsnaptube.org/
In the vast landscape of online games, there's a new and exciting addition that's making waves - the Watermelon Game ! Developed to provide players with a unique and refreshing gaming experience, this game combines elements of strategy, skill, and pure, juicy fun.
At the heart of infinite craft is its robust crafting and building system. Players can gather resources from their surroundings to craft tools, weapons, and various items essential for survival and creativity.
Every papa's game has a clear objective; you could be saving money for a park pass or a new car, but the only way to achieve your goal is to earn money and serve others.
Every papa's games has a clear objective; You could be saving money for a park pass or a new car, but the only way to achieve your goal is to earn money and serve others.
Добавление аннотаций состоит из нескольких geometry dash частей.
This code with the Create your own annotations is the best, and it provides us what we need. I saw a lot of people searching for the best options that we can use. When you will Check This Out you will see the best services that provide us the right results.
Get ready for a nostalgic football experience with Retro Bowl College ! This exciting game combines retro visuals with engaging gameplay, allowing you to manage your own football team. Make critical decisions, draft players, and lead your squad to victory on the field. With its intuitive mechanics, Retro Bowl is a must-play for football fans!
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.