Javascript heredoc

109

J'ai besoin de quelque chose comme heredoc en JavaScript. Avez-vous des idées pour cela? J'ai besoin d'une fonctionnalité multi-navigateurs.

J'ai trouvé ça:

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

Je pense que cela fonctionnera pour moi. :)

VeroLom
la source
6
Duplicata de stackoverflow.com/questions/805107/… qui a des réponses plus détaillées.
Chadwick
4
Le fait d'ajouter "\" me fait froncer les sourcils à chaque fois. Imho, ne pas avoir de syntaxe normale pour les chaînes multilignes est totalement injustifié. Et ils auraient pu l'ajouter à n'importe quelle version, mais ils ne l'ont pas fait.
Lex
1
Double
De nos jours, cela se fait avec les littéraux de modèle comme indiqué dans le doublon possible (il n'y a pas de réponse mise à jour ici).
brasofilo

Réponses:

77

Essayez le modèle de chaîne ES6 , vous pouvez faire quelque chose comme

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


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

=> true

Vous pouvez utiliser cette excellente fonctionnalité aujourd'hui avec 6to5 ou TypeScript

mko
la source
2
Ceci est applicable si vous vouliez simplement des chaînes multilignes. Cependant, comme vous ne pouvez pas vraiment changer le symbole qui entoure votre chaîne, ce n'est pas vraiment heredoc.
Peeyush Kushwaha
3
Pour rappel, la question initiale a été posée il y a 5 ans avant que ES6 ne soit disponible. Il s'agit de la meilleure pratique pour aller de l'avant, car les performances sont également meilleures.
Henry Tseng
2
@HenryTseng, alors suggérez-vous que les réponses à cette question soient adaptées aux technologies anciennes qui existaient il y a 5 ans? Si la question est toujours ouverte, alors elle mérite de profiter des nouvelles technologies telles qu'elles sont créées au fil du temps. De cette façon, les nouveaux utilisateurs ayant le même problème peuvent trouver ici des informations «non archéologiques».
asiby
1
Non, je faisais un commentaire sur la raison pour laquelle cette solution n'était pas plus importante plus tôt. Cela semble définitivement être la manière prise en charge d'aller de l'avant s'il n'y a pas de problèmes de compatibilité.
Henry Tseng
63

Non, malheureusement, JavaScript ne prend en charge rien de tel que heredoc.

Andrew Hare
la source
12
Je sais mais j'espère trouver heredoc hack :)
VeroLom
Quelque chose comme les commentaires de la fonction d'analyse (mais cela ne fonctionne pas dans ie / firefox) =
VeroLom
37

Que dis-tu de ça:

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

Remplacez simplement "/ * ICI" et "ICI * /" par le mot de votre choix.

Zv_oDD
la source
4
tous les navigateurs / moteurs renvoient-ils les commentaires dans Function.toString ()? c'est très intelligent
gcb
Fonctionne dans la console de Chrome
Omn
4
Ne fonctionnera pas si vous avez un commentaire de clôture */dans votre heredoc.
Narigo
2
Je recommanderais d'utiliser la réponse de Nate Ferrero, car le sien est un exemple plus raffiné et optimisé. Le mien utilise 3 appels regEx distincts et est plus une preuve de concept.
Zv_oDD
1
Très intelligent ... mais vous ne pouvez pas garantir que cela fonctionnera à l'avenir. Cela dépend trop de la mise en œuvre pour être une bonne pratique.
Pierre-Olivier Vares
33

En me basant sur la réponse de Zv_oDD, j'ai créé une fonction similaire pour une réutilisation plus facile.

Attention: il s'agit d'une fonctionnalité non standard de nombreux interpréteurs JS, et sera probablement supprimée à un moment donné, mais comme je suis en train de créer un script à utiliser uniquement dans Chrome, je l'utilise! Ne vous fiez jamais à cela pour les sites Web destinés aux clients!

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

Utilisation:

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

Retour:

"A test of horrible
Multi-line strings!"

Remarques:

  1. Le texte est coupé aux deux extrémités, donc tout espace supplémentaire à chaque extrémité est OK.

Modifications:

2/2/2014 - changé pour ne pas jouer du tout avec le prototype Function et utiliser le nom heredoc à la place.

26/05/2017 - espace blanc mis à jour pour refléter les normes de codage modernes.

Nate Ferrero
la source
1
J'utiliserais hereDoc () comme nom de fonction, mais ce code fonctionnait bien en chargeant mon vidage de journal de 40k lignes dans une variable dans la console de Chrome
Omn
Pourquoi voudriez-vous créer une instance d'une fonction et accéder à la propriété obsolète __ proto __? Pourquoi ne pas simplement faire Function.prototype.str = function () {...}?
John Kurlak
@JohnKurlak c'est encore mieux! Je ne pense pas que je savais que c'était possible lorsque j'ai écrit la réponse.
Nate Ferrero
2
@NateFerrero - Réponse géniale, merci! Ajout d'une extension de ma part comme réponse séparée.
Andrew Cheong
Sur mon Android, nexus 4, exécutant 5.0.1, cela ne fonctionne plus sur Chrome. Pour une raison quelconque, il supprime les espaces et les commentaires. Je ne peux pas savoir s'il s'agit d'un paramètre, mais c'est définitivement du côté client. Des idées pour une solution de contournement?
MLU
19

En fonction de la saveur du moteur JS / JS que vous utilisez (SpiderMonkey, AS3), vous pouvez simplement écrire du XML en ligne, dans lequel vous pouvez placer du texte sur plusieurs lignes, comme heredoc:

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

console.log(xml.toXMLString())
console.log(xml.toString()) // just gets the content
Dave Stewart
la source
13

ES6 Template Strings a la fonction heredoc.

Vous pouvez déclarer des chaînes encadrées par un back-tick (``) et peuvent être développées sur plusieurs lignes.

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

Vous pouvez également inclure des expressions dans des chaînes de modèle. Ceux-ci sont indiqués par le signe dollar et des accolades ( ${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"

Il y a en fait plus de fonctionnalités telles que Tagged Temple Strings et Raw Strings. Veuillez trouver la documentation sur

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

Charlie
la source
8

Je me sens mal d'écrire une réponse séparée pour simplement une extension de la réponse de @ NateFerrero , mais je ne pense pas que la modification de sa réponse soit appropriée non plus, alors veuillez voter @NateFerrero si cette réponse vous a été utile.

tl; dr - Pour ceux qui souhaitent utiliser des commentaires en bloc dans leur heredoc ...

J'avais principalement besoin de heredocs Javascript pour stocker un bloc de CSS, par exemple

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

Comme vous pouvez le voir cependant, j'aime commenter mon CSS, et malheureusement (comme l'indique la coloration syntaxique) le premier */termine le commentaire global, cassant l'hérédoc.


Dans ce but précis (CSS), ma solution de contournement était d'ajouter

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

à la chaîne à l'intérieur de @ NateFerrero heredoc; sous forme complète:

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

et utilisez-le en ajoutant un espace entre le *et /pour les commentaires du bloc "interne", comme ceci:

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

Le replacetrouve /* ... * /et supprime simplement l'espace à faire /* ... */, préservant ainsi l'hérédoc jusqu'à l'appel.


Vous pouvez bien sûr supprimer complètement les commentaires en utilisant

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

Vous pouvez également prendre en charge les //commentaires si vous les ajoutez à la chaîne:

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

En outre, vous pouvez faire autre chose que l'espace unique entre *et /, comme un -:

    /**
     * Nuke rounded corners.
     *-/

si vous mettez simplement à jour l'expression régulière de manière appropriée:

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

Ou peut-être souhaitez-vous une quantité arbitraire d'espaces blancs au lieu d'un seul espace?

.replace(/(\/\*[\s\S]*?\*)\s+\//g, '$1/')
                          ^^^
Andrew Cheong
la source
2
Cool! C'était une limitation connue avec ma méthode, je l'aime bien :)
Nate Ferrero
8

Vous pouvez utiliser CoffeeScript , un langage qui se compile en JavaScript. Le code compile un à un dans le JS équivalent, et il n'y a pas d'interprétation au moment de l'exécution.

Et bien sûr, il a heredocs :)

Jakob
la source
24
La bonne réponse est non. CoffeeScript et EJS peuvent être utilisés comme suggestions.
alvincrespo
4
CoffeeScript est la bonne réponse à la plupart des problèmes JS que j'ai rencontrés. Si vous écrivez plus qu'une quantité insignifiante de JS (et que vous appréciez votre temps et votre énergie), vous vous devez de l'utiliser.
Brandon
5
Je pense que c'est une bonne réponse car elle fournit un moyen simple de contourner l'absence d'heredoc en javascript. Cela m'a fait gagner beaucoup de temps.
Stofke
3
Si vous voulez juste un morceau de js mais que vous ne voulez pas vous occuper de l'écrire: coffeescript.org et utilisez le bouton "Try Coffeescript".
jcollum
1
C'est plus une réponse que la réponse la mieux notée, qui est essentiellement juste ... «non». Je déteste ce genre de réponses.
Matt Fletcher
7

ES5 et versions antérieures

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

ES6 et versions ultérieures

`some random
multi line
text here`

résultat

some random
multi line
text here
Ga1der
la source
meilleure réponse simplement
Benjamin
1
Le truc à l'ancienne est un hack incroyablement brutal: /
Shayne
1

Vous pouvez utiliser les macros Sweet.js pour l'ajouter comme tel, comme créé par Tim Disney dans cet article

Notez que cette approche utilise à la place des backticks comme séparateurs de chaîne:

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`
Brad Parks
la source
1

Comme d'autres l'ont dit, les chaînes de modèles ES6 vous donnent la plupart de ce que les heredocs traditionnels fournissent.

Si vous souhaitez aller plus loin et utiliser une chaîne de modèle balisée, theredocest une fonction utilitaire intéressante qui vous permet de faire ceci:

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.
  `)
}
Neall
la source
0

Si vous avez du HTML et du jQuery sous la main et que la chaîne est du HTML valide, cela peut être utile:

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

Si le texte contient des commentaires «<! - ->» entre les deux, cela fonctionne également, mais une partie du texte peut être visible. Voici le violon: https://jsfiddle.net/hr6ar152/1/

Max Oriola
la source
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
}

exemple

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

avec cache: - créer une fonction de modèle simple et enregistrer la fonction: (la deuxième fois fonctionne rapidement)

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)
Shimon Doodkin
la source
1
Des résultats assez différents dans FF et Chrome.
Dave Newton
Qu'est ce qui est different? Je viens de tester Chrome et FF et j'obtiens exactement les mêmes résultats. Sauf que dans Chrome, il n'y a pas de nouvelles lignes dans la console de Chrome.Si vous tapez simplement le nom de la var. mais la variable est la même. Il est possible d'imprimer avec des nouvelles lignes avec console.log ()
Shimon Doodkin
0

Je poste cette version car elle évite l'utilisation de regex pour quelque chose d'aussi trivial.

IMHO regex est une obfuscation qui a été créée comme une blague pratique parmi les développeurs perl. le reste de la communauté les a pris au sérieux et nous en payons maintenant le prix, des décennies plus tard. n'utilisez pas de regex, sauf pour la compatibilité descendante avec le code hérité. il n'y a aucune excuse de nos jours pour écrire du code qui n'est pas immédiatement lisible et compréhensible par l'homme. regex viole ce principe à tous les niveaux.

J'ai également ajouté un moyen d'ajouter le résultat à la page actuelle, non pas que cela ait été demandé.

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>

non synchronisé
la source