Write JavaScript in your JavaScript
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


polyscript experimental

Write JavaScript in your JavaScript using polyscript!

Disclaimer: this is, as far as I know, almost always a very bad idea, with the exception of some special use cases - namely, performance optimisation when dealing with data of arbitrary dimensions. Use as a *last resort*.


Here's a trivial example for adding arrays together:

var sum2d = sum(2)
var sum3d = sum(3)

sum2d([1, 1], [2, 3]) // [3, 4]

@function sum(d)(a, b) {
  var c = []
  <% for (var i = 0; i < d; i += 1) { %>
    c[@i] = a[@i] + b[@i]
  <% } %>
  return c

Essentially, polyscript gives you a special type of function which is prefixed with a @ takes two sets of arguments. This function, when called, returns a new function that's transformed according to a syntax very similar to EJS. In fact, part of the transpiler's code is a modified version of TJ Holowaychuk's implementation.

The first set of arguments will get passed to the generated code, and the second set are used by the generated function. @i is just shorthand for <%= i %>.


$ npm install polyscript


Using polyscript as a module, you get one function: it takes a string in polyscript and converts it to javascript.

var ps = require('polyscript')
var fs = require('fs')


You can use it as a CLI tool by installing it globally - it will either convert the file you specify as the first argument or read from stdin:

$ polyscript index.pjs > index.js
$ cat index.pjs | polyscript > index.js


Take a vanilla JavaScript function for adding arrays of arbitrary lengths together:

function sum(a, b) {
  var c = []
  for (var i = 0; i < a.length; i += 1) {
    c[i] = a[i] + b[i]
  return c

If you knew you were only handling arrays either 2 or 3 elements, you can just swap it out for this and skip on the for loop:

function sum2d(a, b) {
  return [a[0] + b[0], a[1] + b[1]]

function sum3d(a, b) {
  return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]

Both of these approaches would ordinarily suffice, unless you want to squeeze more performance from these functions while keeping some flexibility and avoiding duplication. A compromise you could take would be provide a function which takes a specific number of dimensions and returns a generated function tailored to your needs. This is a lot harder to read though:

function sumnd(d) {
  return Function(
    'return function sum'+d+'(a, b) {'
  + '  return ['
  + '  ' + ngroup(d, npair).join(', ')
  + '  ]'
  + '}'

function npair(d) {
  return 'a['+d+'] + b['+d+']'

function ngroup(n, fn) {
  var a = []
  for (var i = 0; i < n; i += 1) {
  return a

Here's the original polyscript example again:

@function sum(d)(a, b) {
  var c = []
  <% for (var i = 0; i < d; i += 1) { %>
    c[@i] = a[@i] + b[@i]
  <% } %>
  return c

It's essentially taking the function-generation-via-strings approach under the hood, but hiding it away into a more compact syntax. It's still a little confusing, but much easier to read, and structured almost exactly like the original generic example.

You can also treat this more or less the same as you would a normal function: it gets hoisted, can be passed around as a variable, bound, gets a lexical scope, etc.

These examples are fairly trivial - for an actual use case see the code of some of the ndarray modules on npm.

Known Issues

I haven't spent much time with this yet - feel free to fix these and submit a pull request :)

  • @functions can be created in comments/strings.
  • @i works from strings - only <%= i %> should work.


(The MIT License)

Copyright (c) 2013 Hugh Kennedy <hughskennedy@gmail.com>

Original EJS implementation copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca>