Пример портирования Java => JavaScript на примере токенизаторов из Lucene.
lucene-tokenizers.es6 | lucene-tokenizers.babel.js | Тесты | Исходники
TL;DR
Процесс можно условно разделить на несколько этапов:
-
Зависимости от внешних библиотек дожны быть представленны в виде исходников, а незадействованный код по возможности удалён т.к. размер таки имеет значение и чем меньше весит портированный скрипт тем он быстрее отработает в браузере
-
Точно так же системные классы среды исполнения Java, например Character.java, необходимо переопределить скопировав в проект
-
На этом этапе логика должна быть полностью рабочей, если у портируемого проекта имеются юнит-тесты - прогнать их. Если что-то не работает сейчас, вряд-ли заработает после трансляции :)
-
Собственно сама трансляция добытых Java исходников в ES6
-
Точечная адаптация - например реализовать логику метода System.arraycopy, который переопределили ранее, но уже для JavaScript
Как видно на демке и несложно догадаться по названию токенайзер UAX29URLEmailTokenizer чуть более православный по вебу. Оба StandardTokenizer и UAX29URLEmailTokenizer вполне себе дружат с юникодом.
Теперь чуть подробней о процессе портирования.
ESJava
Итоговая структура папок Java проекта (Eclipse):
~$ tree
.
├── src
│ ├── org
│ │ └── apache
│ │ └── lucene
│ │ └── analysis
│ │ ├── standard
│ │ │ ├── Character.java
│ │ │ ├── Exception.java
│ │ │ ├── IndexOutOfBoundsException.java
│ │ │ ├── IOException.java
│ │ │ ├── Reader.java
│ │ │ ├── StandardAnalyzer.java
│ │ │ ├── StandardTokenizerImpl.java
│ │ │ ├── StandardTokenizer.java
│ │ │ ├── StringReader.java
│ │ │ ├── System.java
│ │ │ ├── Tokenizer.java
│ │ │ ├── TokenModel.java
│ │ │ ├── UAX29URLEmailTokenizerImpl.java
│ │ │ └── UAX29URLEmailTokenizer.java
│ │ └── tokenattributes
│ │ └── CharTermAttribute.java
│ └── Test.java
└── tests
└── org
└── apache
└── lucene
└── analysis
└── standard
├── BaseTokenStreamTestCase.java
├── Slow.java
├── TestStandardAnalyzer.java
├── TestUAX29URLEmailTokenizer.java
├── TestUtil.java
└── WordBreakTestUnicode_6_3_0.java
13 directories, 22 files
Для удобства работы с исходниками среды выполнения Java:
~$ apt-get install openjdk-7-source
И так выглядит один из переопределённых в проекте системных файлов:
src/org/apache/lucene/analysis/standardSystem.java
public final class System {
public static void arraycopy(Object s, int sp, Object d, int dp, int l) {
// :es6:
// int[] elements_to_add = s.slice(sp, sp + l);
// Array.prototype.splice.apply(d, new int[] {dp,
// elements_to_add.length}.concat(elements_to_add));
java.lang.System.arraycopy(s, sp, d, dp, l);
// :end:
}
}
В ES6 есть хорошая инструкция import
, но поведение немного отличается от аналогичной в Java - файлы из одного пространства тоже необходимо импортировать явно. Но лень. Проще закинуть все классы в один файл:
merge.sh
# find -name '*.java' | grep './src/org/apache/lucene/analysis/'
cat \
./src/org/apache/lucene/analysis/standard/Exception.java \
./src/org/apache/lucene/analysis/standard/IOException.java \
./src/org/apache/lucene/analysis/standard/IndexOutOfBoundsException.java \
./src/org/apache/lucene/analysis/standard/Reader.java \
./src/org/apache/lucene/analysis/standard/StringReader.java \
./src/org/apache/lucene/analysis/standard/Character.java \
./src/org/apache/lucene/analysis/tokenattributes/CharTermAttribute.java \
./src/org/apache/lucene/analysis/standard/TokenModel.java \
./src/org/apache/lucene/analysis/standard/Tokenizer.java \
./src/org/apache/lucene/analysis/standard/System.java \
./src/org/apache/lucene/analysis/standard/StandardAnalyzer.java \
./src/org/apache/lucene/analysis/standard/StandardTokenizerImpl.java \
./src/org/apache/lucene/analysis/standard/StandardTokenizer.java \
./src/org/apache/lucene/analysis/standard/UAX29URLEmailTokenizerImpl.java \
./src/org/apache/lucene/analysis/standard/UAX29URLEmailTokenizer.java \
| sed '/^package\s/d' | sed '/^import\s/d' \
> lucene-tokenizers.java
И просмотреть список точечных адаптаций для JavaScript:
~$ awk '/\:es6\:/,/\:end\:/' lucene-tokenizers.java
Трансляция:
~$ npm install -g esjava
~$ alias esjava10000="node --stack-size=10000 `which esjava`"
~$ esjava10000 lucene-tokenizers.java > out/lucene-tokenizers.es6
Осталось указать на export классы StringReader, StandardTokenizer, UAX29URLEmailTokenizer и добавить поддержку старых JavaScript движков:
out/js.sh
ES6FILE='lucene-tokenizers.es6'
for cls in 'StringReader' 'StandardTokenizer' 'UAX29URLEmailTokenizer'; do
sed -i "s/^class\s\+${cls}\s\+/export class ${cls} /" ${ES6FILE}
done
sed 's/\\u/\\\\u/g' "$ES6FILE" | \
node --stack-size=10000 \
"`which babel`" \
--compact=false \
--presets es2015 \
--plugins transform-es2015-modules-umd \
--module-id luceneTokenizers | \
sed 's/\\\\u/\\u/g' > lucene-tokenizers.babel.js
Скрипт на выходе lucene-tokenizers.babel.js крутится в демке.