Javascript heredoc


109

Preciso de algo como heredoc em JavaScript. Você tem alguma ideia para isso? Preciso da funcionalidade para vários navegadores.

Eu achei isto:

heredoc = '\
<div>\
    <ul>\
        <li><a href="#zzz">zzz</a></li>\
    </ul>\
</div>';

Acho que vai funcionar para mim. :)


6
Duplicado de stackoverflow.com/questions/805107/… que tem algumas respostas mais detalhadas.
— Chadwick

4
Ter que adicionar "\" me faz franzir a testa todas as vezes. Imho, não ter sintaxe normal para strings de várias linhas é completamente injustificado. E eles poderiam ter adicionado em qualquer versão, mas não o fizeram.
— Lex

1
Possível duplicata de Criando strings de
— várias linhas

Hoje em dia, isso é feito com literais de modelo, conforme mostrado na possível duplicata (não há resposta atualizada aqui).
— brasofilo

Respostas:


77

Tente ES6 String Template , você pode fazer algo como

var hereDoc = `
This
is
a
Multiple
Line
String
`.trim()


hereDoc == 'This\nis\na\nMultiple\nLine\nString'

=> true

Você pode usar este ótimo recurso hoje com 6to5 ou TypeScript


2
Isso é aplicável se você quiser apenas strings de várias linhas. No entanto, como você não pode realmente alterar o símbolo que envolve sua string, ele não é realmente heredoc.
— Peeyush Kushwaha

3
Apenas como observação, a pergunta original foi feita 5 anos atrás, antes que ES6 estivesse disponível. Esta é a prática recomendada para avançar, pois o desempenho também é melhor.
— Henry Tseng

2
@HenryTseng, então você está sugerindo que as respostas a esta pergunta devem ser adaptadas às tecnologias antigas que existiam 5 anos atrás? Se a questão ainda estiver em aberto, então ela merece tirar proveito das novas tecnologias conforme são criadas ao longo do tempo. Dessa forma, novos usuários com o mesmo problema podem encontrar informações "não arqueológicas" aqui.
— asiby

1
Não, eu estava fazendo um comentário sobre por que essa solução não era mais proeminente anteriormente. Parece definitivamente que é o caminho com suporte para seguir em frente, se não houver problemas de compatibilidade.
— Henry Tseng,

63

Não, infelizmente o JavaScript não oferece suporte a nada como heredoc.


12
Eu sei, mas espero encontrar hack do heredoc :)
— VeroLom

Algo como os comentários da função de análise (mas não funciona em ie / firefox) =
— VeroLom

37

Que tal agora:

function MyHereDoc(){
/*HERE
<div>
   <p>
      This is written in the HEREDOC, notice the multilines :D.
   </p>
   <p>
      HERE
   </p>
   <p>
      And Here
   </p>
</div>
HERE*/
    var here = "HERE";
    var reobj = new RegExp("/\\*"+here+"\\n[\\s\\S]*?\\n"+here+"\\*/", "m");
    str = reobj.exec(MyHereDoc).toString();
    str = str.replace(new RegExp("/\\*"+here+"\\n",'m'),'').toString();
    return str.replace(new RegExp("\\n"+here+"\\*/",'m'),'').toString();
}

//Usage 
document.write(MyHereDoc());

Basta substituir "/ * AQUI" e "AQUI * /" pela palavra de sua escolha.


4
todos os navegadores / mecanismos retornam os comentários em Function.toString ()? isso é muito inteligente
— gcb

Funciona no console do Chrome
— Omn

4
Não funcionará se você tiver um comentário final */em seu heredoc.
— Narigo

2
Eu recomendaria usar a resposta de Nate Ferrero, pois seu exemplo é mais refinado e otimizado. O meu usa 3 chamadas regEx separadas e é mais uma prova de conceito.
— Zv_oDD

1
Muito inteligente ... mas você não pode garantir que funcionará no futuro. É muito dependente da implementação para ser uma boa prática.
— Pierre-Olivier Vares

33

Com base na resposta de Zv_oDD, criei uma função semelhante para facilitar a reutilização.

Aviso: Este é um recurso não padrão de muitos interpretadores JS e provavelmente será removido em algum momento, mas como estou construindo um script para ser usado apenas no Chrome, estou usando-o! Não sempre contar com isso para websites dirigidos ao cliente!

// Multiline Function String - Nate Ferrero - Public Domain
function heredoc(fn) {
  return fn.toString().match(/\/\*\s*([\s\S]*?)\s*\*\//m)[1];
};

Usar:

var txt = heredoc(function () {/*
A test of horrible
Multi-line strings!
*/});

Retorna:

"A test of horrible
Multi-line strings!"

Notas:

  1. O texto é cortado em ambas as extremidades, portanto, qualquer espaço em branco extra em qualquer uma das extremidades está OK.

Editar% s:

02/02/2014 - alterado para não mexer no protótipo de Função de forma alguma e usar o nome heredoc.

26/05/2017 - espaço em branco atualizado para refletir os padrões de codificação modernos.


1
Eu usaria hereDoc () como meu nome de função, mas este código funcionou bem carregando meu despejo de log de linha de 40k em uma variável no console do Chrome
— Omn

Por que você criaria uma instância de uma função e acessaria a propriedade obsoleta __ proto __? Por que não apenas Function.prototype.str = function () {...}?
— John Kurlak

@JohnKurlak isso é ainda melhor! Acho que não sabia que isso era possível quando escrevi a resposta.
— Nate Ferrero

2
@NateFerrero - Resposta incrível, obrigado! Adicionada uma extensão minha como uma resposta separada.
— Andrew Cheong

No meu Android, nexus 4, rodando 5.0.1, isso não funciona mais no Chrome. Por algum motivo, ele está excluindo espaços em branco e comentários. Não consigo descobrir se isso é uma configuração, mas é definitivamente do lado do cliente. Alguma ideia para uma solução alternativa?
— MLU

19

Dependendo de qual tipo de mecanismo JS / JS você está executando (SpiderMonkey, AS3), você pode simplesmente escrever XML embutido, no qual você pode colocar texto em várias linhas, como heredoc:

var xml = <xml>
    Here 
    is 
    some 
    multiline 
    text!
</xml>

console.log(xml.toXMLString())
console.log(xml.toString()) // just gets the content

13

ES6 Template Strings tem recurso heredoc.

Você pode declarar strings delimitadas por back-tick (``) e podem ser expandidas por várias linhas.

var str = `This is my template string...
and is working across lines`;

Você também pode incluir expressões dentro de Template Strings. Eles são indicados pelo sinal de dólar e chaves ( ${expression}).

var js = "Java Script";
var des = `Template strings can now be used in ${js} with lot of additional features`;

console.log(des); //"Template strings can now be used in Java Script with lot of additional features"

Na verdade, há mais recursos, como Tagged Temple Strings e Raw Strings. Encontre a documentação em

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings


8

Sinto-me mal por escrever uma resposta separada meramente como uma extensão da resposta de @NateFerrero , mas também não acho que editar a resposta dele seja apropriado, portanto, vote positivamente em @NateFerrero se esta resposta foi útil para você.

tl; dr — Para aqueles que desejam usar comentários em bloco dentro de seu heredoc ...

Eu precisava principalmente de heredocs Javascript para armazenar um bloco de CSS, por exemplo

var css = heredoc(function() {/*
    /**
     * Nuke rounded corners.
     */
    body div {
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
*/});

Como você pode ver, no entanto, gosto de comentar meu CSS e, infelizmente (conforme sugerido pelo realce de sintaxe), o primeiro */finaliza o comentário geral, quebrando o heredoc.


Para este propósito específico (CSS), minha solução alternativa foi adicionar

.replace(/(\/\*[\s\S]*?\*) \//g, '$1/')

à corrente dentro de @NateFerrero's heredoc; na forma completa:

function heredoc (f) {
    return f.toString().match(/\/\*\s*([\s\S]*?)\s*\*\//m)[1].replace(/(\/\*[\s\S]*?\*) \//g, '$1/');
};

e use-o adicionando um espaço entre *e /para comentários de bloco "internos", como:

var css = heredoc(function() {/*
    /**
     * Nuke rounded corners.
     * /
    body div {
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
*/});

O replacesimplesmente localiza /* ... * /e remove o espaço para fazer /* ... */, preservando assim o heredoc até ser chamado.


Você pode, é claro, remover todos os comentários usando

.replace(/\/\*[\s\S]*?\* \//g, '')

Você também pode oferecer suporte a //comentários se adicioná-los à rede:

.replace(/^\s*\/\/.*$/mg, '')

Além disso, você pode fazer algo diferente do único espaço entre *e /, como -:

    /**
     * Nuke rounded corners.
     *-/

se você apenas atualizar o regex apropriadamente:

.replace(/(\/\*[\s\S]*?\*)-\//g, '$1/')
                          ^

Ou talvez você queira uma quantidade arbitrária de espaços em branco em vez de um único espaço?

.replace(/(\/\*[\s\S]*?\*)\s+\//g, '$1/')
                          ^^^

2
Legal! Essa era uma limitação conhecida do meu método, eu gosto :)
— Nate Ferrero

8

Você pode usar CoffeeScript , uma linguagem que compila em JavaScript. O código compila um a um no JS equivalente e não há interpretação no tempo de execução.

E, claro, tem heredocos :)


24
A resposta correta é não. CoffeeScript e EJS podem ser usados ​​como sugestões.
— alvincrespo

4
CoffeeScript é a resposta correta para a maioria dos problemas de JS que encontrei. Se você escreve mais do que uma quantidade trivial de JS (e você valoriza seu tempo e energia), você deve a si mesmo usá-lo.
— Brandon

5
Acho que esta é uma boa resposta, pois fornece uma maneira fácil de contornar a ausência de heredoc no javascript. Me economizou muito tempo.
— Stofke de

3
Se você quer apenas um pedaço de js, mas não quer realmente escrevê-lo: coffeescript.org e use o botão "Experimentar o Coffeescript".
— jcollum

1
Esta é mais uma resposta do que a mais bem avaliada, que é basicamente ... "não". Eu odeio esse tipo de resposta.
— Matt Fletcher

7

ES5 e versões anteriores

(function(){/**
some random
multi line
text here
**/}).toString().slice(15,-5);

ES6 e versões posteriores

`some random
multi line
text here`

resultado

some random
multi line
text here

melhor simplesmente responder
— Benjamin

1
O estilo antigo é um hack incrivelmente brutal: /
— Shayne

1

Você pode usar as macros Sweet.js para adicioná-lo assim, conforme criado por Tim Disney neste post

Observe que essa abordagem usa crases como delimitadores de string em vez disso:

let str = macro {
    case {_ $template } => {
        var temp = #{$template}[0];
        var tempString = temp.token.value.raw;
        letstx $newTemp = [makeValue(tempString, #{here})];
        return #{$newTemp}
    }
}

str `foo bar baz`

1

Como já foi dito, as strings de template ES6 oferecem muito do que os heredocs tradicionais fornecem.

Se você quiser dar um passo adiante e usar uma string de modelo com tag, theredocé uma boa função de utilitário que permite fazer isso:

if (yourCodeIsIndented) {
  console.log(theredoc`
    Theredoc will strip the
    same amount of indentation
    from each line.

      You can still indent
      further if you want.

    It will also chop off the
    whitespace-only first and
    last lines.
  `)
}

0

Se você tiver algum html e jQuery em mãos e a string for HTML válido, isso pode ser útil:

<div id="heredoc"><!--heredoc content
with multiple lines, even 'quotes' or "double quotes",
beware not to leave any tag open--></div>
<script>
var str = (function() {
   var div = jQuery('#heredoc');
   var str = div.html();
   str = str.replace(/^<\!--/, "").toString();
   str = str.replace(/-->$/, "").toString();
   return str;
})();
</script>

Se o texto tiver comentários "<! - ->" entre eles, também funcionará, mas uma parte do texto pode estar visível. Aqui está o violino: https://jsfiddle.net/hr6ar152/1/


0
// js heredoc - http://stackoverflow.com/a/32915549/466363
// a function with comment with eval-able string, use it just like regular string

function extractFuncCommentString(func,comments) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return undefined;
  var str=matches[1];

   // i have made few flavors of comment removal add yours if you need something special, copy replacement lines from examples below, mix them
  if(comments===1 )
  {
   // keep comments, in order to keep comments  you need to convert /**/ to / * * / to be able to put them inside /**/ like /*    / * * /    */
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   )
  }
  else if(comments===2)
  {
   // keep comments and replace singleline comment to multiline comment
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
   )
  }
  else if(comments===3)
  {
   // remove comments
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
     )
  }
  else if(comments===4)
  {
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===5)
  {
   // keep comments comments and replace strings, might not suit when there are spaces or comments before and after quotes 
   // no comments allowed before quotes of the string
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */
      .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
      .trim() // trim space around quotes to not escape it and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else 
  return str
}

exemplo

var week=true,b=123;
var q = eval(extractFuncCommentString(function(){/*!

// this is a comment     


'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc
'
*/},4));

com cache: - crie uma função de modelo simples e salve a função: (a segunda vez funciona rápido)

var myfunction_sql1;
function myfunction(week,a){


    if(!myfunction_sql1) eval('myfunction_sql1=function(week,a){return ('+extractFuncCommentString(function(){/*!
'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc

'*/},4)+')}');
    q=myfunction_sql1(week,a);
    console.log(q)
}
myfunction(true,1234)

1
Resultados bastante diferentes em FF e Chrome.
— Dave Newton

o que é diferente? Acabei de testar no Chrome e FF e obtenho exatamente os mesmos resultados. Exceto que no Chrome não há novas linhas no console do Chrome se você apenas digitar o nome da var. mas a variável é a mesma. É possível imprimir com novas linhas com console.log ()
— Shimon Doodkin

0

Estou postando esta versão porque evita o uso de regex para algo tão trivial.

IMHO regex é uma ofuscação que foi criada como uma piada entre os desenvolvedores de perl. o resto da comunidade os levou a sério e agora pagamos o preço, décadas depois. não use regex, exceto para compatibilidade com versões anteriores com código legado. não há desculpa hoje em dia para escrever código que não seja imediatamente legível e compreensível por humanos. regex viola este princípio em todos os níveis.

Também adicionei uma maneira de adicionar o resultado à página atual, não que isso tenha sido solicitado.

function pretty_css () {
/*
    pre { color: blue; }

*/
}
function css_src (css_fn) {
   var css = css_fn.toString();
   css = css.substr(css.indexOf("/*")+2);
   return css.substr(0,css.lastIndexOf("*/")).trim();
}

function addCss(rule) {
  let css = document.createElement('style');
  css.type = 'text/css';
  if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
  else css.appendChild(document.createTextNode(rule)); // Support for the rest
  document.getElementsByTagName("head")[0].appendChild(css);
}

addCss(css_src(pretty_css));

document.querySelector("pre").innerHTML=css_src(pretty_css);
<pre></pre>

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.