2015-09-09 14 views
5

Sto cercando di utilizzare PageDown sul lato client come editor e sul lato server per analizzare quindi Markdown in HTML.PageDown tramite ScriptEngine che analizza erroneamente Markdown

Sembra funzionare bene sul lato client, ma sul lato server, i segni di spunta stanno solo "codificando" il carattere che segue, non la parola che avvolge. Quindi, se faccio questo:

test `test` test

mi aspetto che questo, e questo è davvero quello che ottengo sul lato client:

test <code>test</code> test

Ma sul lato server, che finiscono per essere questo, invece:

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

ho creato un file chiamato pageDown.js, che è semplicemente Markdown.Converter.js e Markdown.Sanitizer.js combinati in un unico file, con questa funzione ha aggiunto:

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

Sul lato client, posso utilizzare questo file in questo modo:

<!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> 

che visualizza correttamente: <p>test <code>test</code> test</p>

Sul (Java) lato server, io uso questo stesso file esatto, attraverso il Java di ScriptEngineManager e 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(); 
     } 
    } 
} 

Questo programma stampa questa: <p>test <code>t</code>est<code></code>test</p>

vedo problemi simili con altre Markdown: test **test** test ignora semplicemente la parte **. Tuttavia, ##test restituisce correttamente come <h2>test</h2>.

Questo funziona perfettamente se si passa al JavaScript direttamente tramite HTML, ma non quando passo attraverso Java. Cosa sta succedendo qui? Devo gestire Markdown sul server in modo diverso?

+0

Il wiki del progetto menziona l'utilizzo di Node.JS sul server, questa è l'ultima risorsa. – approxiblue

+0

Non sono sicuro del motivo per cui questa domanda ha una taglia. L'unica risposta afferma chiaramente che il problema è un bug nella libreria utilizzata. Il bug dovrebbe essere segnalato a monte ai manutentori di quella libreria. Non c'è nient'altro che possiamo fare qui per aiutare. – Waylan

+0

@Waylan La taglia è stata aggiunta ** prima ** della risposta. L'unica ragione per cui la risposta è stata pubblicata era perché ho aggiunto la taglia. Ecco come funzionano le taglie. –

risposta

4

sono riuscito a ridurre il problema al seguente codice:

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

quando viene chiamato nel browser come

getSanitizedHtml('aa'); 

restituisce:

c 

Quando viene chiamato dal Nashorn motore come

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

restituisce:

cc 

Per me, questo sembra il backreference \1, che dovrebbe puntare a (a), invece punta a (?!b), il cui contenuto è catturato di lunghezza zero e corrisponde quindi nulla.

Il codice equivalente in Java:

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

restituisce il risultato corretto però:

c 

Conclusione

Sono abbastanza sicuro che questo è un bug nel motore Nashorn.
Ho archiviato un bug report e posterò il suo ID qui, se diventa pubblico.

Per quanto riguarda il problema, ritengo che l'unica opzione sia passare a un altro ambiente JavaScript, almeno temporaneamente.

Minimal, esempi eseguibili

JS in del browser:

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

JS a motore Nashorn:

[Ideone]

puro Java:

[Ideone]

correzione possibile

Come già sottolineato, l'unica opzione (a questo punto) è quello di passare ad un altro ambiente JavaScript.
Ci sono molti di quelli disponibili e Wikipedia ha a comparison page. Per questo esempio, ho scelto io.js (credo che riuscirai a installarlo da solo).

Se si desidera utilizzare la pagina di destinazione.il file js, per prima cosa ha bisogno di commentare le exports controlli e utilizzare i vecchi variabili semplici, come questo:

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

e

/*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; 
//} 

(Si noti che ho anche cambiato output = window.Markdown;-output = Markdown; - voi deve aver fatto lo stesso (ma Nashorn ti avrebbe dato un errore altrimenti), ma ho dimenticato di menzionarlo nella tua domanda)

In alternativa, potresti ovviamente usare il sistema di esportazione e file separati, ma non ho esperienza ce con quello, quindi lo farò in questo modo.

Ora, io.js accetta il codice JavaScript da stdin, e si può scrivere sullo standard output via process.stdout.write(), in modo che possiamo effettuare le seguenti operazioni (nella riga di comando):

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

e otteniamo la seguente indietro :

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

Se avete bisogno di farlo da Java, si può fare in questo modo:

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)); 
    } 
} 

Nota il punto e virgola direttamente dopo lo for (quindi fa solo read += in.read(b, read, b.length - read) ogni volta e nient'altro) e nota che mentre si chiama .close() su uno streaming di solito è facoltativo, poiché verrà eseguito automaticamente quando l'oggetto esce dall'ambito, stdin.close() deve essere chiamato qui, o iojs continuerà ad attendere l'input e p.waitFor() non tornerà mai più.

+0

Grazie per la risposta. Quali altri ambienti JavaScript posso passare? –

+0

[Qui] (https://github.com/markdown/markdown.github.com/wiki/Implementations) è una lunga lista (anche se incompleta) di implementazioni note di Markdown. Non posso parlare della qualità di nessuna delle librerie JavaScript elencate qui, ma forse una di queste sarà utile. – Waylan

Problemi correlati