Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

alamode

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alamode

A Regex-Based Transpiler Of Source Code To Allow Writing Import And Export Statements And JSX With 0 Dependencies.

  • 2.2.0
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

ÀLaMode

npm version

ÀLaMode is a RegExp-based transpiler of source code in Node.JS. It is a fast, low-weight alternative to AST-based transpilers, such as @babel. At the moment, it supports transpilation of import and export statements which also improves JSDoc support compared to Babel which is an enemy of JSDoc.

yarn add -D alamode

The package can be used via the CLI to build packages, or via the require hook to transform modules on-the-fly.

If you're having trouble and still seeing unknown keyword export, check if your issue falls under the category described in the troubleshooting. That's the single problem that we've seen after a year of using this software.

Table Of Contents

Installation

The software can be installed either as a global dependency, or as a project dependency.

Global

When installed globally, it will be used directly via a binary, such as alamode src -o build.

Package ManagerInstallation
npmnpm i -g alamode
yarnyarn add global alamode

Project

When installed in a project, it will be used via the package.json script, e.g., yarn build or npm run build.

// package.json
{
  "name": "project",
  "version": "1.0.0",
  "description": "An example project",
  "main": "build",
  "scripts": {
    "build": "alamode src -o build"
  },
  "files": ["build"],
  "license": "MIT"
}
Package ManagerInstallation
npmnpm i --save-dev alamode
yarnyarn add -DE alamode

CLI

The binary accepts a path to a single file, or a directory with the source code as the first argument, and a path to the build folder via -o argument.

alamode src -o build

There are other arguments which can be passed.

PropertyArgumentDescription
Output Location-o, --outputWhere to save transpiled code. Passing - will print to stdout.
Watch Mode-w, --watchKeep alamode running and re-build on chages.
Show Help-h, --helpDisplay help information and quit.
Ignore Paths-i, --ignoreA list of files inside of the source directory to ignore, separated with a comma. For example, to ignore src/bin/alamode.js when building src, the -i bin/alamode.js should be passed. A directory can also be passed, e.g., -i bin but without the / at the end.
No Source Maps-s, --noSourceMapsDon't generate source maps.
Extensions-e, --extensionsWhich extensions to transform, separated by a comma. Defaults are js and jsx.
JSX-j, --jsxTranspile JSX files but keep modular system. Usually used for Depack bundler.
Preact-p, --preactAdds the Preact h pragma at the top of JSX files.

Setting the NODE_DEBUG environmental variable to alamode will print the list of processed files to the stderr.

$ NODE_DEBUG=alamode alamode src -o build -i bin/alamode.js
ALAMODE 97955: index.js
ALAMODE 97955: bin/catcher.js
ALAMODE 97955: bin/index.js
ALAMODE 97955: lib/index.js

--help

Shows all available commands.

A tool to transpile JavaScript packages using regular expressions.
Supports import/export and JSX transpilation.
https://artdecocode.com/alamode/

  alamode source [-o destination] [-i dir,file] [-s] [-jp]

	source            	The location of the input file or directory to transpile.
	--output, -o      	The location of where to save the transpiled output.
	--version, -v     	Show the version number.
	--help, -h        	Display the usage information.
	--ignore, -i      	Comma-separated list of files inside of `source` dir to
	                  	ignore, for example, `bin,.eslintrc`.
	--noSourceMaps, -s	Disable source maps.
	--extensions, -e  	Files of what extensions to transpile.
	                  	Default: js,jsx.
	--jsx, -j         	Enable JSX mode: only update JSX syntax to use hyperscript.
	                  	Does not transpile `import/export` statements.
	--preact, -p      	When transpiling JSX, automatically insert at the top
	                  	`import { h } from "preact"`.
	--debug, -d       	Will make ÀLaMode stop after replacing markers.

  Example:

    alamode src -o build

Compiling JSX: --jsx, --preact

ÀLaMode can transpile JSX syntax. In the jsx mode, the import/export statements will be left intact, but the source code will be transformed to add pragma invocations, such as h(Component, { props }, children). The default pragma is h for Preact, and to avoid writing import { h } from 'preact' in each file, the -p option can be passed for ÀLaMode to add it automatically.

For example, the following file can be compiled:

import { render } from 'preact'

const Component = ({ test, ...props }) => (
  <div id="example" {...props}>
    {test}
  </div>
)
render(<Component cool>Example</Component>, document.body)

Using the alamode example/index.jsx -j -p command:

import { h } from 'preact'
import { render } from 'preact'

const Component = ({ test, ...props }) => (
   h('div',{...props,'id':"example"},
    test,
  )
)
render( h(Component,{cool:true},`Example`), document.body)

ÀLaNode

To be able to spawn modules without having to create a proxy file as below:

require('alamode')()
require('./package')

ÀLaMode bundles a binary called alanode. It will do the same thing as above, so that running modules with import and export statements becomes really easy.

$ alanode source

It changes import and export statements into require calls and module.export expressions. It also normalises process.argv to hide its presence, so that programs can safely keep using the argv array without unexpected results.

With the following file that uses an import:

import { constants } from 'os'
console.log(process.argv)
console.log(constants.signals.SIGINT)

$ alanode t will generate the result successfully:

[ '/Users/zavr/.nvm/versions/node/v8.15.0/bin/node',
  '/Users/zavr/a-la/alamode/test/fixture/t' ]
2

ÀLaNode is also available as a standalone package alanode.
npm version

.alamoderc.json

A transform can support options which can be set in the .alamoderc.json configuration file which is read from the same directory where the program is executed. Options inside of the env directive will be active only when the ALAMODE_ENV environmental variable is set to the env key.

{
  "env": {
    "test-build": {
      "import": {
        "replacement": {
          "from": "^((../)+)src",
          "to": "$1build"
        }
      }
    }
  }
}

Transforms

There are a number of built-in transforms, which don't need to be installed separately because their size is small enough to be included as direct dependencies.

@a-la/import

Changes all import statements into require statements. Although the specification between the ECMAScript Modules and Modules is different, most developers will prefer to use import just because of its neater syntax.

import argufy from 'argufy'
import restream, {
  Replaceable,
  makeMarkers, makeCutRule, makePasteRule,
} from 'restream'
import { resolve, join } from 'path'
import { version } from '../../package.json'
import erte, { c } from './erte'
let argufy = require('argufy'); if (argufy && argufy.__esModule) argufy = argufy.default;
let restream = require('restream'); const {
  Replaceable,
  makeMarkers, makeCutRule, makePasteRule,
} = restream; if (restream && restream.__esModule) restream = restream.default;
const { resolve, join } = require('path');
const { version } = require('../../package.json');
const erte = require('./erte'); const { c } = erte;
esModule

The if (dependency && dependency.__esModule) dependency = dependency.default; check is there to make alamode compatible with Babel and TypeScript, which export default modules as the default property of module.exports object and set the __esModule marker to true, e.g.,

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = method;

The check will only work for external modules, and the dependencies that start with . or / will be required without the __esModule check. To enforce the check for any file, the esCheck: always should be set in the transform configuration.

{
  "import": {
    "esCheck": "always"
  }
}
Replace Path

This transform supports an option to replace the path to the required file using a regular expression. This can be useful when running tests against the build directory, rather than source directory.

{
  "import": {
    "replacement": {
        "from": "^((../)+)src",
          "to": "$1build"
      }
    }
  }
}
import myPackage from '../src'

(async () => {
  await myPackage()
})()
const myPackage = require('../build');

(async () => {
  await myPackage()
})()

@a-la/export

Transforms all export statements into module.exports statements.

InputOutput
export async function example () {}

const example2 = () => {}

export default class Example {
  constructor() {
    example()
  }
}

export { example2 as alias }
async function example () {}

const example2 = () => {}

               class Example {
  constructor() {
    example()
  }
}



module.exports = Example
module.exports.example = example
module.exports.alias = example2

There are some limitations one should be aware about, however they will not typically cause problems for a Node.JS package. The line and column numbers are preserved for easier generation of the source maps, however this is likely to change in the future.

Require Hook

The purpose of the require hook is to be able to transpile files automatically when they are imported.

To use this feature, alamode needs to be required in a separate file, after which the import and export statements will become available.

For example, take the following directory structure, with a main and library files:

example/require
├── index.js
├── lib.js
├── multiple.js
└── require.js
index.jslib.js
import getInfo from './lib'

console.log(getInfo())
import { platform, arch } from 'os'

export default () => {
  return `${platform()}:${arch()}`
}

The require hook would work in the following way:

require('alamode')()
require('.')

By executing the node require.js command, alamode will be installed and it will do its job dynamically for every .js file that is required, enabling to use import and export statements.

darwin:x64

_alamode.HookConfig: The options for ÀLaMode Hook.

NameTypeDescriptionDefault
pragmastringWhat pragma to add on top of JSX programs. Default const { h } = require('preact');.-
noWarningbooleanDisable warnings when resetting existing hooks.false
matcherfunction(string): booleanThe function that will be called with the path and return whether the file should be transpiled.null
ignoreNodeModulesbooleanAuto-ignore node_modules. Independent of any matcher.true

Multiple Calls To Alamode()

When the call is made multiple times in the program, the latter calls will revert the previous hooks and installed the new ones. The warning will be shown unless the noWarning option is set to true.

const alamode = require('alamode')
alamode()

// in other file
const path = require('path')
const preact = path.relative('', path
  .dirname(require.resolve('preact/package.json')))
alamode({
  pragma: `const { h } = require("./${preact}");`,
  // noWarning: true, // to disable output
})
Reverting JS hook to add new one.
Reverting JSX hook to add new one, pragma:
const { h } = require("./node_modules/preact");

This can happen when the tests are set up to run with Zoroaster with the -a flag for alamode, and the source code also tries to install the require hook.

Source Maps

The source maps are supported by this package, but implemented in a hack-ish way. The transforms will aim to preserve line and column numbers, so that no additional remapping is required. However this is not enough to generate a source map good enough for a debugger -- it needs to know about mappings of positions between segments which can be operators, function calls, etc. alamode simply breaks the source code into distinct chunks such as white-spaces, identifiers and comments, and down into individual symbols. Using this method, the size of a source map is larger, but it still works. In further versions, this will be improved to allow to extract real segments.

source map visualistion

Click to View: debug session
Alt: Debugging a source code with source maps.

Troubleshooting

Because there can be many intricacies when transpiling with regular expressions, problems might arise from time to time. If using the require hook, the best solution is to build the source code using alamode binary, and see where the error occurs. Then it must be analysed why it happens, for example:

  • The import or export transform does not match the case.
  • A portion of source code is cut out before the transform with markers so that the line does not participate in a transform.

So the single most common problem that we've experienced, is using the // and /* inside string literals (`), e.g.,

const host = 'localhost'
const port = 9999
const url = `https://${host}:${port}`

export const test = 'hello world'

const otherUrl = `https://${host}:${port}`
/Users/zavr/a-la/alamode/example/trouble.js:5
export const test = 'hello world'
^^^^^^

SyntaxError: Unexpected token export
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:617:28)
    at Module.p._compile (/Users/zavr/a-la/alamode/node_modules/alamode/depack/depack-lib.js:48:18)
    at Module._extensions..js (module.js:664:10)
    at Object.k.(anonymous function).u._extensions.(anonymous function) [as .js] (/Users/zavr/a-la/alamode/node_modules/alamode/depack/depack-lib.js:50:7)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)

This is because //${host}:${port}` will be cut until the end of the line as a comment prior to the template, and the template will match until the next opening backtick rather than the correct one, taking out the export from the transformation. To validate that, we can run the alamode src -d command:

const host = %%_RESTREAM_STRINGS_REPLACEMENT_0_%%
const port = 9999
const url = %%_RESTREAM_LITERALS_REPLACEMENT_0_%%https:%%_RESTREAM_INLINECOMMENTS_REPLACEMENT_1_%%

Now to fix this issue, either use ' to concatenate strings that have /* and //, or use import { format } from 'url' to dynamically create addresses.

Art Deco © Art Deco for À La Mode 2019 Tech Nation Visa Tech Nation Visa Sucks

Keywords

FAQs

Package last updated on 12 May 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc