2015-09-09 10 views
5

Próbuję użyć PageDown po stronie klienta jako edytor, a po stronie serwera, aby następnie analizować, że Markdown do HTML.PageDown przez ScriptEngine niepoprawnie analizowania Markdown

Wygląda na to, że działa dobrze po stronie klienta, ale po stronie serwera znaczniki są tylko "kodyfikujące" znak, który następuje, a nie słowo, które zawija. Więc jeśli mogę to zrobić:

test `test` test

Oczekuję tego, i to jest rzeczywiście to, co się po stronie klienta:

test <code>test</code> test

Ale po stronie serwera, ja skończyć się coraz to zamiast:

test <code>t</code>est<code> </code>test

Został utworzony plik o nazwie pageDown.js, który jest po prostu Markdown.Converter.js i Markdown.Sanitizer.js połączone w jednym pliku, z tej funkcji dodania:

function getSanitizedHtml(pagedown){ 
    var converter = new Markdown.getSanitizingConverter(); 
    return converter.makeHtml(pagedown); 
} 

Po stronie klienta, mogę użyć tego pliku tak:

<!DOCTYPE html> 
<html> 
<head> 
<script src="pageDown.js"></script> 
<script> 
function convert(){ 

    var html = getSanitizedHtml("test `test` test"); 

    console.log(html); 

    document.getElementById("content").innerHTML = html; 
} 

</script> 
</head> 

<body onload="convert()"> 
<p id="content"></p> 
</body> 
</html> 

To poprawnie wyświetla: <p>test <code>test</code> test</p>

z (Java) po stronie serwera, używam to dokładnie taki sam plik, za pośrednictwem Java ScriptEngineManager i Invocable:

import java.io.InputStreamReader; 
import javax.script.Invocable; 
import javax.script.ScriptEngine; 
import javax.script.ScriptEngineManager; 

public class PageDownTest{ 

    public static void main(String... args){ 

     try{ 
      ScriptEngineManager manager = new ScriptEngineManager(); 
      ScriptEngine engine = manager.getEngineByName("JavaScript"); 
      engine.eval(new InputStreamReader(PageDownTest.class.getResourceAsStream("pageDown.js"))); 
      Invocable inv = (Invocable) engine; 
      String s = String.valueOf(inv.invokeFunction("getSanitizedHtml", "test `test` test")); 
      System.out.println(s); 
     } 
     catch(Exception e){ 
      e.printStackTrace(); 
     } 
    } 
} 

Ten program wypisuje OUT: <p>test <code>t</code>est<code></code>test</p>

widzę podobne problemy z innymi obniżki: test **test** test prostu ignoruje ** część. Jednak ##test poprawnie zwraca jako <h2>test</h2>.

Wszystko działa dobrze, jeśli przejdę do JavaScript bezpośrednio przez HTML, ale nie wtedy, gdy przechodzę przez Javę. Co tu się dzieje? Czy powinienem obsługiwać Markdown na serwerze w inny sposób?

+0

Strona wiki projektu wspomina o użyciu Node.JS na serwerze, to twoja ostatnia deska ratunku. – approxiblue

+0

Nie wiem, dlaczego to pytanie ma nagrodę. Jedyna odpowiedź wyraźnie stwierdza, że ​​problem jest błędem w używanej bibliotece. Błąd powinien zostać zgłoszony przed opiekunami tej biblioteki. Nic więcej nie możemy zrobić, aby ci pomóc. – Waylan

+0

@Waylan Bounty dodano ** przed ** odpowiedzią. Jedynym powodem, dla którego wysłano odpowiedź, było to, że dodałem nagrodę. Tak działają nagrody. –

Odpowiedz

4

udało mi się zmniejszyć problem z następującym kodem:

function getSanitizedHtml(text) 
{ 
    return text.replace(/(a)(?!b)\1/gm, 'c'); 
} 

Wywołany w przeglądarce jako

getSanitizedHtml('aa'); 

zwraca:

c 

Wywołany z Nashorn silnik jako

String s = String.valueOf(inv.invokeFunction("getSanitizedHtml", "aa")); 

zwraca:

cc 

Dla mnie to wygląda Wsteczne \1, który powinien wskazywać (a) zamiast wskazuje (?!b), którego treść jest zrobione zerowej długości, a więc pasuje wszystko.

Odpowiednik kodu w Javie:

System.out.println(("aa").replaceAll("(a)(?!b)\\1", "c")); 

zwraca poprawny wynik mimo:

c 

Wnioski

Jestem całkiem pewien, że to jest błąd w silniku Nashorn.
Złożyłem raport o błędzie i opublikuję jego identyfikator, jeśli zostanie opublikowany.

Jeśli chodzi o twój problem, myślę, że jedyną opcją jest przejście do innego środowiska JavaScript, przynajmniej tymczasowo.

Minimalny uruchamianemu przykłady

JS przeglądarkę:

function x(s){return s.replace(/(a)(?!b)\1/gm, 'c');} 
 
document.write(x('aa'));

JS w silniku Nashorn:

[Ideone]

Czysta Java:

[Ideone]

Możliwa poprawka

Jak już wspomniano, jedyną opcją (w tym momencie) jest, aby przełączyć się do innego środowiska JavaScript.
Dostępnych jest wiele z nich, a Wikipedia ma numer a comparison page. W tym przykładzie wybrałem io.js (ufam, że uda się zainstalować go samodzielnie).

Jeśli chcesz użyć swojej strony.plik js, musisz najpierw do zakomentuj exports kontrole i używać Plain Old zmienne, podobnie jak to:

/*if (typeof exports === "object" && typeof require === "function") // we're in a CommonJS (e.g. Node.js) module 
    Markdown = exports; 
else*/ 
    Markdown = {}; 

i

/*if (typeof exports === "object" && typeof require === "function") { // we're in a CommonJS (e.g. Node.js) module 
    output = exports; 
    Converter = require("./Markdown.Converter").Converter; 
} else {*/ 
    output = Markdown; 
    Converter = output.Converter; 
//} 

(Zauważ, że ja również zmienić output = window.Markdown; do output = Markdown; - ty Musiałeś zrobić to samo (Nashorn dałby ci błąd inaczej), ale po prostu zapomniałem o tym wspomnieć w twoim pytaniu.)

Alternatywnie możesz oczywiście użyć systemu eksportu i oddzielnych plików, ale nie mam doświadczenia z tym, więc zrobię to w ten sposób.

Teraz io.js akceptuje kodu JavaScript z stdin, można napisać do stdout poprzez process.stdout.write(), więc możemy wykonać następujące czynności (w linii poleceń):

{ cat pageDown.js; echo 'process.stdout.write(getSanitizedHtml("test `test` test"));'; } | iojs; 

i otrzymujemy następujące powrotem :

<p>test <code>test</code> test</p> 

Jeśli trzeba to zrobić z Java, można zrobić to tak:

import java.io.*; 

class Test 
{ 
    public static void main(String[] args) throws Exception 
    { 
     Process p = Runtime.getRuntime().exec("/path/to/iojs"); 
     OutputStream stdin = p.getOutputStream(); 
     InputStream stdout = p.getInputStream(); 
     File file = new File("/path/to/pageDown.js"); 
     byte[] b = new byte[(int)file.length()]; 
     FileInputStream in = new FileInputStream(file); 
     for(int read = 0; read < b.length; read += in.read(b, read, b.length - read)); // <-- note the semicolon 
     stdin.write(b); 
     stdin.write("process.stdout.write(getSanitizedHtml('test `test` test'));".getBytes()); 
     stdin.close(); // <-- important to close 
     p.waitFor(); 
     b = new byte[stdout.available()]; 
     stdout.read(b); 
     System.out.println(new String(b)); 
    } 
} 

Należy zanotować średnik bezpośrednio po numerze for (tak, aby za każdym razem był to tylko read += in.read(b, read, b.length - read) i nic więcej), a także, że wywołanie .close() w strumieniu jest zwykle opcjonalne, ponieważ zostanie wykonane automatycznie po wykryciu obiektu poza zakresem, stdin.close() musi zostać wywołane tutaj, lub iojs będzie nadal czekać na dane wejściowe, a p.waitFor() nigdy nie wróci.

+0

Dzięki za odpowiedź. Do jakich innych środowisk JavaScript mogę się przełączyć? –

+0

[tutaj] (https://github.com/markdown/markdown.github.com/wiki/Implementations) to długa (choć niekompletna) lista znanych implementacji Markdown. Nie mogę mówić do jakości żadnej z wymienionych tam bibliotek JavaScript, ale być może jedna z nich przyda się. – Waylan