{"id":22394398,"url":"https://github.com/akamai/js2esi","last_synced_at":"2026-03-10T12:33:08.715Z","repository":{"id":50492534,"uuid":"101437964","full_name":"akamai/js2esi","owner":"akamai","description":"Bidirectional JavaScript \u003c-\u003e ESI converter. Write javascript code that will be converted to valid ESI  (Edge Side Includes), capable of running at the Edge.","archived":false,"fork":false,"pushed_at":"2018-05-21T18:12:13.000Z","size":112,"stargazers_count":16,"open_issues_count":1,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-07-31T12:30:52.500Z","etag":null,"topics":["cdn","esi","javascript","js","perf"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akamai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-25T20:00:14.000Z","updated_at":"2024-08-01T05:49:50.000Z","dependencies_parsed_at":"2022-08-31T04:10:54.502Z","dependency_job_id":null,"html_url":"https://github.com/akamai/js2esi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/akamai/js2esi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akamai%2Fjs2esi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akamai%2Fjs2esi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akamai%2Fjs2esi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akamai%2Fjs2esi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akamai","download_url":"https://codeload.github.com/akamai/js2esi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akamai%2Fjs2esi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30333503,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T05:25:20.737Z","status":"ssl_error","status_checked_at":"2026-03-10T05:25:17.430Z","response_time":106,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cdn","esi","javascript","js","perf"],"created_at":"2024-12-05T05:10:02.923Z","updated_at":"2026-03-10T12:33:08.694Z","avatar_url":"https://github.com/akamai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JS to ESI compiler and decompiler (`js2esi`, `esi2js`)\nConvert Javascript to from from ESI (Edge Side Includes). Write javascript code that will compile to ESI and run at the Edge.\n\n## Synopsis\n\n```\njs2esi | esi2js\n[--version] [-h|--help] [-v|--verbose]\n[-l|--lex] [-n|--node] [-d|--decompile]\n[-w|--no-warning] [-L|--library PATH] [-O|--optimize LEVEL]\n[-o|--output FILENAME]\n{FILENAME|-}\n```\n\n## Overview\n\n`js2esi` is a tool that can compile js 'lite' into Edge Side Includes (ESI) using the compiler of the same name, js. The language is, at it's core, nothing more than syntactic sugar to make ESI coding simpler. As a result, it is limited to the exact same constraints as ESI is. It does, however, also provide some more advanced features, such as modularization and inlining, that get resolved during compilation. The js dev must always be aware that js is converted to ESI, be aware of those limitations, and review the resulting ESI to ensure compatibility and correctness.\n\n## Getting started (dev)\n\nThe simplist way to get started is to: \n1. clone the repo\n2. run `./dev.sh` to get all the dependencies installed, etc\n3. `. venv/bin/activate` to activate your local environment\n4. run `js2esi` as below\n\nTest coverage uses Nose. Just run `nosetests`  \n\n\n## The `js2esi` Program\n\nThe program can be used to compile js files to ESI as well as the reverse, decompile ESI to js. The program accepts the following options:\n\n### Options\n\n`--version` \nDisplay program version identifier and exit.\n\n`-h | --help`\nDisplay command options and exit.\n\n`-v | --verbose`\nEnable verbose output (multiple invocations increase verbosity).\n\n`-l | --lex`\nDisplay lexical parsing tokens - primarily useful if js2esi is having trouble parsing your source file.\n\n`-n | --node`\nDisplay the Node representational form instead of the js or ESI output (primarily useful for js2esi debugging).\n\n`-d | --decompile`\nEnable ESI-to-js decompilation instead of js-to-ESI compilation. Note that this is implied if invoked as esi2js command (they are symbolic links to each other).\n\n`-w | --no-warning`\nBy default, the ESI output includes a warning that the ESI was generated as output from js2esi. This option disables the warning.\n\n`-L PATH | --library PATH`\nAdd the specified PATH to the js2esi module lookup path (for resolving \"import\" statements). The path will be append to any paths already provided by the JSLIB environment variable (see below). The option can be invoked multiple times to append multiple paths.\n\n`-O LEVEL | --optimize LEVEL`\nSet the code optimization level to LEVEL, which can range from 0 (no optimizations) to 9 (maximum optimizations). The default value, 7, is safe and will only apply non-destructive optimizations; levels above 7 should be reserved for ESI scripts that are completely independent/standalone — i.e. the script does not use, or is not used by, any eval statements that may depend on variables and functions exposed by this script. This is because variables/functions will be removed if unused and/or may be renamed to be more efficient.\n\n`-o FILENAME | --output FILENAME`\noutput the compiled code to FILENAME. Defaults to STDOUT\n\n`FILENAME | -`\nSpecifies the FILENAME that should be processed. If - is specified instead of the path to a filename, then STDIN will be used.\n\n### Environment\n\nThe js2esi program is sensitive to the following environmental variables:\n\n`JSLIB` This is a colon (\":\") delimited list of path names, similar to $PATH, that will be used to find any external js source referenced by import statements.\n\n### Example\n\n```sh\n$ cat sample.js\n# this is a sample js file.\nmyvar = 'http://'.length + HTTP_HOST.length + len(REQUEST_PATH);\n\n$ js2esi -w sample.js\n\u003cesi:assign name=\"myvar\" value=\"$len('http://')+$len($(HTTP_HOST))+$len($(REQUEST_PATH))\"/\u003e\n```\n\n## Javascript 'lite' language\n\nThe lexical parser is intended to be javascript compatible. However, it isn't very sophisticaed because of some of the underlying limitations of ESI. \n\nThe following syntax guide shows how to construct js code that compile nicely to ESI.\n\n\u003e #### Important\n\u003e Please read the [section called “Todo List”](), as several things that you may expect to work don't. Also take a look at the [section called “Known Bugs”](#knownbugs) (surprise!).\n\nSome general rules in the syntax of js:\n\n* Whitespace is irrelevant — except in literals, it will be ignored completely.\n* The \"if/else\" construct is ONLY a \"choose/when\" shorthand, and must therefore be used appropriately and leverage the \"else if\" construct when possible.\n\nSome general js limitations due to limitations in ESI:\n\n* All ESI limitations apply! Including, but not limited to: total script size, recursion, variable size and inclusion limits.\n* The js constants \"true\" and \"false\" are represented as the ESI integers 1 and 0 - although this works as expected when evaluated in boolean context, it may behave slightly differently in non-boolean contexts.\n* Doing string indexing is faster than dictionary lookups — avoid dictionary lookups.\n\nCurrently, the method to get the compiled js to output content (i.e. to get ESI to output content) is a bit of a \"workaround\". Several reserved functions exist for this purpose: print(), printv() and printraw() (see Example 9, “Composing Output”).\n\njs2esi supports one nifty thing that ESI does not: inlining either external or internal code. This feature is activated with the import function call and the inline keyword. The difference between importing and including/eval'ing is synonymous to static versus dynamic linking: importing will pull the external code in during js2esi compilation, whereas including/eval'ing will do so during ESI execution. Please see Example 12, “Imports” and Example 5, “Inlined Functions” for details.\n\n### Examples:\n\n* [Example 1, “Comments”](#example1)\n* [Example 2, “Variable Assignments”](#example2)\n* [Example 3, “Operators”](#example3)\n* [Example 4, “Function Declarations and Calls”](#example4)\n* [Example 5, “Inlined Functions”](#example5)\n* [Example 6, “Conditional Statements”](#example6)\n* [Example 7, “Match Operator”](#example7)\n* [Example 8, “For Of”](#example8)\n* [Example 9, “For Loops”](#example8)\n* [Example 10, “Composing Output”](#example9)\n* [Example 11, “Try/Catch Blocks”](#example10)\n* [Example 12, “Include and Eval Statements”](#example11)\n* [Example 13, “modules”](#example12)\n\n### Example 1. Comments\n\njs input:\n\n```\n/** anything after a long or short comment will be regarded as a comment and\n * stripped out completely, with the exception of a comment that uses the @esi-comment \n * descriptor, which will be converted into an ESI comment, eg:\n */\n//@esi-comment this ESI code is generated -- do not edit manually\n// the above will appear in the output, but nothing else\n```\n\nESI output:\n\n```\n\u003cesi:comment text=\"this ESI code is generated -- do not edit manually\"/\u003e\n```\n\n### Example 2. Variable Assignments\n\njs2esi supports all of the data structures that ESI does, as well as a few additional unary assignment operators. Note that, just like in ESI, it is possible to reference a variable without using or declaring it.\n\njs input:\n\n```\nvarName = 'someString';\nnumVal  = 919;\nboolVal = true;\nboolVal = false;\narray   = [ 'firstVal', 2, [ 'subarray', 'el', ] ];\nhash    = { 'foo': 'this', 'bar': 'that', };\nvarName += ' - and the rest';\nnumVal  -= 10;\nnumVal  *= 5;\nnumVal  /= 5;\nnumVal  %= 5;\nnumVal  ++;\nnumVal  --;\n\n# variable referencing with default values can also be done:\n\nvalue   = hash['bar'] | 'none';\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js2esi output --\u003e\n\u003cesi:assign name=\"varName\" value=\"'someString'\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"919\"/\u003e\n\u003cesi:assign name=\"boolVal\" value=\"1\"/\u003e\n\u003cesi:assign name=\"boolVal\" value=\"0\"/\u003e\n\u003cesi:assign name=\"array\" value=\"['firstVal',2,['subarray','el']]\"/\u003e\n\u003cesi:assign name=\"hash\" value=\"{'foo':'this','bar':'that'}\"/\u003e\n\u003cesi:assign name=\"varName\" value=\"$(varName)+' - and the rest'\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"$(numVal)-10\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"$(numVal)*5\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"$(numVal)/5\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"$(numVal)%5\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"$(numVal)+1\"/\u003e\n\u003cesi:assign name=\"numVal\" value=\"$(numVal)-1\"/\u003e\n\u003cesi:assign name=\"value\" value=\"$(hash{'bar'}|'none')\"/\u003e\n```\n\n### Example 3. Operators\n\nMost commonly used operators are supported, including bitwise shifting and AND/OR. Note that if you use bitwise AND/OR, bitwise ESI will be generated — but this will only work if legacy bitwise operators are disabled (on Akamai, this means setting the `\u003cedgecomputing:esi.legacy-logical-operators\u003e` tag to `off`, which by default is `on`). The js2esi optimizer is able to detect certain operations with literals (i.e. hard-coded values) that can be evaluated at compile time, and thus yield more efficient ESI code.\n\njs input:\n\n```\n# addition, subtraction, multiplication, modulus and division\nresult = ( '*' * ( ( 25 % 13 ) / ( 3 - 1 ) )  ) + ' six stars!';\n\n# equality, non-equality, lesser/greater comparison, logical AND/OR\nif ( a == 12 \u0026\u0026 ( b != 'options' || c \u003c= 4 ) \u0026\u0026 d \u003c 5 \u0026\u0026 e \u003e 15 )\n  boolval = e \u003e= 9;\n\n# bitwise AND/OR/XOR, bitwise shifting\nvalue = ( ( 1 \u003c\u003c 5 ) | ( 1 \u003c\u003c 3 ) ) \u003e\u003e 1; # == 10\nvalue = value ^ ( ~ 10 );\nif ( value \u0026 4 )\n  match = 'yup!';\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js2esi output --\u003e\n\u003cesi:assign name=\"result\" value=\"('*'*6)+' six stars!'\"/\u003e\n\u003cesi:choose\u003e\n  \u003cesi:when test=\"((($(a)==12) \u0026\u0026 (($(b)!='options') || ($(c)\u003c=4))) \u0026\u0026 ($(d)\u003c5)) \u0026\u0026 ($(e)\u003e15)\"\u003e\n    \u003cesi:assign name=\"boolval\" value=\"$(e) \u003e= 9\"/\u003e\n  \u003c/esi:when\u003e\n\u003c/esi:choose\u003e\n\u003cesi:assign name=\"value\" value=\"((1\u003c\u003c5) | (1\u003c\u003c3)) \u003e\u003e 1\"/\u003e\n\u003cesi:assign name=\"value\" value=\"$(value) ^ (~ 10)\"/\u003e\n\u003cesi:choose\u003e\n  \u003cesi:when test=\"$(value) \u0026 4\"\u003e\n    \u003cesi:assign name=\"match\" value=\"'yup!'\"/\u003e\n  \u003c/esi:when\u003e\n\u003c/esi:choose\u003e\n```\n\n### Example 4. Function Declarations and Calls\n\njs input:\n\n```\nfunction functionName() {\n  // all ESI function-scope variables exist in js as well:\n  var0 = ARGS[0];\n  // here this function will now recursively call itself\n  return functionName( var0 );\n}\n\n// js allows some nifty function parameter shortcutting:\nfunction func( arg, param = 'default' ) {\n  return arg + param;\n}\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js output --\u003e\n\u003cesi:function name=\"functionName\"\u003e\n  \u003cesi:assign name=\"var0\" value=\"$(ARGS{0})\"/\u003e\n  \u003cesi:return value=\"$functionName($(var0))\"/\u003e\n\u003c/esi:function\u003e\n\u003cesi:function name=\"func\"\u003e\n  \u003cesi:assign name=\"arg\" value=\"$(ARGS{0})\"/\u003e\n  \u003cesi:assign name=\"param\" value=\"$(ARGS{1}|'default')\"/\u003e\n  \u003cesi:return value=\"$(arg)+$(param)\"/\u003e\n\u003c/esi:function\u003e\n```\n\n### Example 5. Inlined Functions\n\njs input:\n\n```\nfunction multiply(a, b) {\n  \"inline\";\n  return a * b;\n}\n\nfunction squared(value) {\n  \"inline\";\n  return multiply(value, value);\n}\n\n// js will actually be able to expand the following to a literal result:\nfour = squared(2);\n\n// but not in the following situation (a later improvement to js may):\nsixteen = squared(multiply(four, 1));\n\n// another example\nslen = multiply(len(sixteen), 2);\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js output --\u003e\n\u003cesi:assign name=\"four\" value=\"4\"/\u003e\n\u003cesi:assign name=\"sixteen\" value=\"($(four)*1)*($(four)*1)\"/\u003e\n\u003cesi:assign name=\"slen\" value=\"$len($(sixteen))*2\"/\u003e\n```\n\nNote that, in the current implementation, there are many restrictions on inlined functions and their invocations:\n\n* Inlined functions may ONLY be called from within expression context, such as when setting and testing variables, returning a value from a function and iterating over a collection.\n* Inlined functions MUST NOT contain anything except a return statement.\n* Inlined functions MUST NOT be recursive.\n* Inlined function call arguments may ONLY be literals, function calls and simple variables (i.e. no variables with sub-keys or defaults).\n\n### Example 6. Conditional Statements\n\njs input:\n```\nif ( ! isPrinted() \u0026\u0026 exists( buck )  ) {\n  // NOTE: the parens are required after the negation (otherwise it\n  //       applies to variable \"buck\", not the \"has\")\n  if ( ! ( buck has 'muchBlame' ) )\n    var = passBuck( buck );\n  else\n    var = callPrinter();\n}\nelse if ( ! isPrinted() )\n  var = callPrinter();\nelse\n  job = nextJob();\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js2esi output --\u003e\n\u003cesi:choose\u003e\n  \u003cesi:when test=\"(!$isPrinted()) \u0026\u0026 $exists($(buck))\"\u003e\n    \u003cesi:choose\u003e\n      \u003cesi:when test=\"!($(buck) has 'muchBlame')\"\u003e\n        \u003cesi:assign name=\"var\" value=\"$passBuck($(buck))\"/\u003e\n      \u003c/esi:when\u003e\n      \u003cesi:otherwise\u003e\n        \u003cesi:assign name=\"var\" value=\"$callPrinter()\"/\u003e\n      \u003c/esi:otherwise\u003e\n    \u003c/esi:choose\u003e\n  \u003c/esi:when\u003e\n  \u003cesi:when test=\"!$isPrinted()\"\u003e\n    \u003cesi:assign name=\"var\" value=\"$callPrinter()\"/\u003e\n  \u003c/esi:when\u003e\n  \u003cesi:otherwise\u003e\n    \u003cesi:assign name=\"job\" value=\"$nextJob()\"/\u003e\n  \u003c/esi:otherwise\u003e\n\u003c/esi:choose\u003e\n```\n\n### Example 7. Match Operator\n\njs input:\n\n```\n// notes:\n//   - the \"as ...\" is optional\n//   - the \"matches\" and \"matches_i\" with the optional \"as ...\"\n//     variation can also be used with \"choose { when ( ... ) {} }\" clauses\n\nif ( myString matches_i '^preamble:([a-z0-9]*):trailer$' as mset ) {\n  var = mset[1];\n}\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js2esi output --\u003e\n\u003cesi:choose\u003e\n  \u003cesi:when test=\"$(myString) matches_i '^preamble:([a-z0-9]*):trailer$'\" matchname=\"mset\"\u003e\n    \u003cesi:assign name=\"var\" value=\"$(mset{1})\"/\u003e\n  \u003c/esi:when\u003e\n\u003c/esi:choose\u003e\n```\n\n### Example 8. For Of\njs input:\n\n```\nlet values = [0..31]\nret = 0;\nfor(const item of values) {\n  ret += assertOnePlus( item_index, item_number );\n  if ( ret \u003e 365 )\n    break;\n}\n```\n\nESI output:\n\n```\n\u003cesi:assign name=\"values\" value=\"[0..31]\"/\u003e\n\u003cesi:assign name=\"ret\" value=\"0\"/\u003e\n\u003cesi:foreach collection=\"$(values)\"\u003e\n  \u003cesi:assign name=\"ret\" value=\"$(ret)+$assertOnePlus($(item_index),$(item_number))\"/\u003e\n  \u003cesi:choose\u003e\n    \u003cesi:when test=\"$(ret) \u003e 365\"\u003e\n      \u003cesi:break/\u003e\n    \u003c/esi:when\u003e\n  \u003c/esi:choose\u003e\n\u003c/esi:foreach\u003e\n```\n\n### Example 9. For loop\njs input:\n\n```\nret = 0;\nfor(let i=0; i \u003c=31; i++) {\n  ret += i*i;\n}\n```\n\nESI output:\n\n```\n\u003cesi:assign name=\"ret\" value=\"0\"/\u003e\n\u003cesi:assign name=\"i\" value=\"0\"/\u003e\n\u003cesi:assign name=\"values\" value=\"[0..31]\"/\u003e\n\u003cesi:foreach collection=\"$(values)\"\u003e\n  \u003cesi:choose\u003e\n    \u003cesi:when test=\"!($(i) \u003c= 31)\"\u003e\n      \u003cesi:break/\u003e\n    \u003c/esi:when\u003e\n  \u003c/esi:choose\u003e\n  \u003cesi:assign name=\"ret\" value=\"$(ret) + ($(i) * $(i))\"/\u003e\n  \u003cesi:assign name=\"i\" value=\"$(i)+1\"/\u003e\n\u003c/esi:foreach\u003e\n```\n\n\n### Example 10. Composing Output\n\njs input:\n\n```\nprintraw( '\u003cesi:vars\u003e\\n' );\nprint( 'only strings, variables and function calls inside a print(): '\n       + num2str( 12 + 88 ) + '\\n' );\nprint( myvar );\nprint( 'no newline here:' );\nprint( 'foo' + output + '\\n' );\nprintraw( '\u003c/esi:vars\u003e' );\n\n// the printraw() function only accepts strings as arguments, and\n// outputs them without any escaping. this means that it is possible\n// to output ESI with printraw(), whereas print() would have escaped\n// them.\n//\n// the printv() is equivalent to print(), except that the output is\n// automatically bracketed by \u003cesi:vars\u003e and \u003c/esi:vars\u003e.\n// e.g. the following:\n//\n//   printv( 'quickly print out a var: ' + myString + '!' );\n//\n// is equivalent to:\n//\n//   printraw( '\u003cesi:vars\u003e' );\n//   print( 'quickly print out a var: ' + myString + '!' );\n//   printraw( '\u003c/esi:vars\u003e' );\n//\n```\n\nESI output:\n\n```\n\u003cesi:vars\u003e\nonly strings, variables and function calls inside a print(): $num2str(100)\n$(myvar)no newline here:foo$(output)\n\u003c/esi:vars\u003e\n```\n\n### Example 11. Try/Catch Blocks\n\njs input:\n\n```\ntry {\n  callDangerousFunction( REQUEST_PATH );\n}\ncatch(e) {\n  // the object `e` doesn't actually exist in ESI and so it really can't be used in js\n  print( '\u003cb\u003eSorry, that service is currently unavailable.\u003c/b\u003e' );\n}\n```\n\nESI output:\n\n```\n\u003cesi:try\u003e\n  \u003cesi:attempt\u003e\n    $callDangerousFunction($(REQUEST_PATH))\n  \u003c/esi:attempt\u003e\n  \u003cesi:except\u003e\n    \u003cb\u003eSorry, that service is currently unavailable.\u003c/b\u003e\n  \u003c/esi:except\u003e\n\u003c/esi:try\u003e\n```\n\n### Example 12. Include and Eval Statements\n\njs input:\n\n```\ntry {\n  eval( src='/path/to/include.esi', dca='akamaizer-\u003eesi' );\n}\ncatche(e) {\n  include( src='/path/to/errorComponent.html' );\n}\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js2esi output --\u003e\n\u003cesi:try\u003e\n  \u003cesi:attempt\u003e\n    \u003cesi:eval src=\"/path/to/include.esi\" dca=\"'akamaizer-\u003eesi'\"/\u003e\n  \u003c/esi:attempt\u003e\n  \u003cesi:except\u003e\n    \u003cesi:include src=\"/path/to/errorComponent.html\"/\u003e\n  \u003c/esi:except\u003e\n\u003c/esi:try\u003e\n```\n\n### Example 13. modules\n\nexternal js file \"include/js/math/multiply.js\":\n\n```\nfunction multiply() {\n  return ARGS[0] * ARGS[1];\n}\n```\n\njs input (with environmental variable JSLIB set to \"include/js\"):\n\n```\nrequire('math/multiply.js');\nmyval = multiply( 3, 5 );\n```\n\nESI output:\n\n```\n\u003c!-- NOTE: newlines/whitespace added for clarity - not normally in js output --\u003e\n\u003cesi:function name=\"multiply\"\u003e\n  \u003cesi:return value=\"$(ARGS{0})*$(ARGS{1})\"/\u003e\n\u003c/esi:function\u003e\n\u003cesi:assign name=\"myval\" value=\"$multiply(3,5)\"/\u003e\n```\n\nThe require() function will, by default, only import an external file the first time it is imported. This behaviour can be overriden by setting the \"force\" named parameter to true, for example:\n\n```\nrequire('math/multiply.js', force=true);\n```\n\n## TODO List\n\nSome things that are not yet supported, but eventually will be:\n\n* `\u003cesi:remove\u003e ... \u003c/esi:remove\u003e`\n* `\u003cesi:text\u003e ... \u003c/esi:text\u003e`\n* `\u003c!--esi ... --\u003e`\n\n* add support for @esi-comment decorator in long comment blocks\n\n* add support for `'''` string types in ESI... eg:\n    `\u003cesi:when test=\"$(stream_content) matches '''\\.wmv$'''\"\u003e`\n\n* detect functions that don't need a print statement when going ESI-to-js... eg:\n    ` \u003cesi:when\u003e$add_header(...)\u003c/esi:when\u003e`\n  ==\u003e\n    `print(add_header(...));`\n  * or, generally speaking, standalone functions should be understood as being `printed`?...\n\n* add \"in\" operator to js, eg:\n    input: \n    \n    ```\n    if ( var in ['a', 'b', 'c'] )\n    ```\n \n    output: \n\n    ```\n    \u003cesi:when test=\"$(var)=='a'||$(var)=='b'||$(var)=='c'\"\u003e\n    ```\n \n* do functional analysis \u0026 error/warnings, including:\n  * using variables before they are set (except pre-defined vars).\n    this must be a warning, because it is possible for a variable to\n    be defined in metadata... note that if the reference is to the\n    \"value\" key in the undefined variable, then it is likely to be\n    a metadata variable and should be ignored.\n  * calling functions without being in an ESI block, such as `esi:vars`\n  * printing variables without being in an ESI block, such as `esi:vars`\n* add support for ESI triple-quote quoting mechanism.\n* add support for \"importing\" and \"inlining\" external modules\n* add support for \"inlined\" functions, eg:\n\n    ```\n    function inline dmsg(msg)\n    {\n      dbg = dbg + msg + '\\n';\n    }\n    dbg = 'debug line 1\\n';\n    dmsg('debug line 2');\n    ```\n    \n  would get expanded to:\n\n    ```\n    dbg = 'debug line 1\\n';\n    dbg = dbg + 'debug line 2' + '\\n';\n    ```\n\n  inlining can happen in two contexts:\n  \n    1. block-context, as is the above context. this is the \"simpler\"\n       context, as in, it has fewer constraints, but it does mean\n       that more code needs to be written to be able to handle\n       variable substitution and expansion...\n    2. expression-context, where the result of the function is being\n       used in an expression, such as:\n         * `\u003cesi:assign ... name=\"VARNAME{$HERE()}\" ... /\u003e`\n         * `\u003cesi:assign ... value=\"$HERE()\" ... /\u003e`\n         * `\u003cesi:when test=\"$HERE()\"\u003e`\n         * `\u003cesi:return value=\"$HERE()\"/\u003e`\n         * `\u003cesi:(eval|include) ... src=\"$HERE()\" ... /\u003e`   //this is more of a \"vars\" context...\n         * `\u003cesi:foreach ... collection=\"$HERE()\" ... /\u003e`\n\n    \n* it would be great to support expressions in print*() statements, eg:\n\n\t```\n     printv('foo', varName * 3, 'bar');\n\t```\n\n  esi:\n  \n\t```\n    \u003cesi:assign name=\"ast_tmp_128378\" \"$(varName)*3\"/\u003e\n    \u003cesi:vars\u003efoo$(ast_tmp_128378)bar\u003c/esi:vars\u003e\n\t```\n\n* during decompiling, should unknown ESI tags cause an error instead of being converted to print() statements?\n* regarding requires:\n    * it would be nice if requires tracked what had already been inlined.\n    and if an import needed to be imported multiple times, then it\n    would have to state that explicitly. for example:\n      `require( '/path/to/file.js', allowMultiple='True' );`\n    * now that i think about it though, it makes more sense for the imported\n    object *itself* to know whether or not it is idempotent. therefore,\n    it might be interesting to have something along the `#define` and\n    `#ifdef`... or maybe a little simpler, eg:\n      `i_am_idempotent();`\n* implement unit testing of the docs, too... ie. it should pull out all\n  examples, do js=\u003enode and esi=\u003enode, and compare the result...\n* non-perfect collapse:\n\n    ```\n    dbg += nl + 'Am value is: ' + int(QUERY_STRING['am']);\n    ```\n    \n  went to:  \n  \n\t```  \n    \u003cesi:assign name=\"dbg\" value=\"$(dbg)+($(nl)+'Am value is: '+$int($(QUERY_STRING{am})))\"/\u003e\n    ```\n    \n  instead of:\n\n    ```\n    \u003cesi:assign name=\"dbg\" value=\"$(dbg)+$(nl)+'Am value is: '+$int($(QUERY_STRING{am}))\"/\u003e\n    ```\n    \n## Known Bugs\n\nThere are some known problems:\n\n* Although js supports escaping any character with a backslash (including quotes, double quotes, newlines and backslashes) these are not always correctly escaped when converted to ESI.\n* Some of the parameters to `\u003cesi:include\u003e` and `\u003cesi:eval\u003e` don't get converted correctly... no workaround currently.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakamai%2Fjs2esi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakamai%2Fjs2esi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakamai%2Fjs2esi/lists"}