npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

directr

v2.1.3

Published

directr is a JavaScript directive processor command line tool and library.

Downloads

30

Readme

directr

directr is a JavaScript directive processor command line tool and library.

Install

npm install directr -g

Usage

directr [--config config path] [--help] {sourcefiles...}

Directives

Directives are special JavaScript comments of the form:

// @@{directiveName} [space separated params...]

Example:

// @@myDirective 34 "param2 text"

Directive names can contain alphanumeric (a-z0-9), underscore (_), colon (:) or dollar ($) characters.

Example:

// @@namespace:Directive 34 "param2 text"

Directive parameters can be a null, undefined, number, boolean, single or double quoted string, unquoted single word string, an object literal or an array literal, or a global reference.

// @@myDirective null undefined 34.4 false "text with spaces"
// @@otherDirective word String { name: 'object literal', list: [1,2,3] } [ { name: 'array literal' } ]

For directives that only accept a single Object or Array literal there is an alternate block-syntax that can be used.

/* @@{directiveName}
Object or Array literal
*/

Example:

/* @@myDirective
{
  name: 'object literal',
  list: [1, 2, 3, 4]
}
*/

The following globals are available to be referenced in Object or Array literals or as a plain reference.

  • String
  • Array
  • Boolean
  • Date
  • Object
  • Number
  • JSON
  • RegExp

When passing an Object or Array literal the following symbols/characters are illegal.

  • new
  • this
  • window
  • global
  • ++
  • --
  • the following characters: =()

Directive Processors

directr recognizes these comments in your source files and will parse them into objects that look like this.

{
  name: '@@directiveName',
  params: [param1, param2, ...],
  index: 0-based-index,
  line: 1-based-number,
  position: 1-based-character-position,
  file: { name: filePath, text: fileText }
}

Each directive encountered can be passed to a processor for processing. You configure the processors using a JSON file, typically with the name directiveconfig.json.

{
  "directiveProcessors": {
    "@@myDirective": "./path/relative/to/directiveconfig.json",
    "@@other": "topLevelNodeModule"
  }
}

directr will load your configuration file from the current directory if not specified on the command line.

Loads directiveconfig.json from the current directory.

directr app.js

Loads your own config with custom file name.

directr --config myconfig.json app.js

Sometimes when processing directives you need settings or some options to be passed to the processor. You do this by setting the context config setting.

{
  "directiveProcessors": {
    "@@myDirective": {
      "module": "./path/relative/to/config",
      "context": {
        "property1": 45
      }
    }
  }
}

Contexts in the config will be merged with the top-level context. The top-level context always has a project property that is set to the directory containing the loaded config file or the current working directory if the config was specified via code.

{
  "directiveProcessors": {
    "@@myDirective": {
      "module": "./path/relative/to/directiveconfig.json",
      "context": {
        "somePath": "${project}/files/file.js',
        "property1": 45
      }
    }
  },
  "context": {
    "description": "this is the top-level context"
  }
}

The resulting context object passed to the loaded processor module would be:

{
  project: 'path/to/config/dir',
  somePath: 'path/to/config/dir/files/file.js',
  property1: 45,
  description: "this is the top-level context"
}

Additionally, any string of the form ${propertyName} will be recursively expanded to the property's value, using the merged context as the scope.

{
  "directiveProcessors": {
    "@@myDirective": {
      "module": "./path/relative/to/directiveconfig.json",
      "context": {
        "someFileName": "${webroot}/somedir/out.js"
      }
    }
  },
  "context": {
    "root": ".."
    "webroot": "${root}/wwwroot"
  }
}

The resulting context object passed to the loaded processor module would be:

{
  project: 'path/to/config/dir',
  someFileName: "../wwwroot/somedir/out.js",
  webroot: "../wwwroot"
  root: ".."
}

Directive processors are just modules that export a function with the following signature.

function myDirectiveProcessor (directive, context, done)

Where directive is the object the directive is parsed into, context is the merged top-level and processor-level contexts, and done is a standard error first Node-style callback that should be called when processing is complete.

// directives/hello.js
module.exports = function helloProcessor (directive, context, done) {
  console.log('found @@hello directive in file:', directive.file.name)
  done()
}

// directiveconfig.json
{
  "directiveProcessors": {
    "@@hello": "./directives/hello"
  }
}

Module Dependencies

Under the hood directr uses the TypeScript compiler to look for dependencies between your JavaScript and TypeScript modules. These dependent modules will also have their directives processed. By using the TypeScript compiler directr can infer dependencies between AMD, CommanJS and ES6 modules interchangably, as well as be able to handle JSX syntax. The TypeScript compiler can have options passed to it via the compilerOptions config setting.

{
  "compilerOptions": "./jsconfig.json",
  "directiveProcessors": {
    "@@hello": "./directives/hello"
  }
}

The compilerOptions config setting can either be a path relative to the directiveconfig.json file to a tsconfig.json or jsconfig.json file, or an object with any of the supported compiler options.

directr uses the TypeScript compiler just to infer dependencies so no code will be emitted or errors reported. The following compiler options will be overridden to ensure this happens.

  • modeulResolution Always set to "node"
  • noEmit Always set to true
  • allowJs Defaults to true if not specified
  • listFiles Always set to false
  • watch Always set to false
  • sourceMap Always set to false
  • inlineSourceMap Always set to false
  • outDir Always set to null
  • outFile Always set to null

NOTE: If you do not want to have TypeScript infer your dependencies then set the compilerOptions config setting to false.

JSON Schema

If you use an IDE or editor that supports JSON schema files then you can take advantage of the JSON schema available for the directiveconfig.json config file. You just need to set $schema in your config file to the schma file.

{
  "$schema": "./node_modules/directr/schema/directiveconfig.json",
  ...
}

Now you'll get inline completion and code hints as you type.

Programmatic API

readDirectivesFromText()

readDirectivesFromText(text)

Reads the directives from the specified text string. Returns an array of objects of the form:

{ name, params: [param1, param2] }

readDirectivesFromFiles()

readDirectivesFromFiles(fileNames, callback)

Reads the directives from each file specified. Calls callback with an error as the first argument if an error occurs. Sends an array of objects with the following form as the second arguemnt to callback on success.

{ name, params: [param1, param2], file: { name, text } }

inferDependencies()

inferDependencies(fileNames, compilerOptions, [baseDir])

Infers module dependencies from each specified file name, taking care of duplicates. Where compilerOptions can either be a path to the TypeScript compiler config file or an object with compiler options defined. If the compilerOptions is a string then it is treated as though it were relative to baseDir. If baseDir is not specified then process.cwd() is its default value.

processDirectives()

processDirectives(directives, processorMap, context, callback, [baseDir])

Attempts to process all specified directives as returned from one of the readDirectivesFromXXX functions. Where processorMap is an object that maps directive names to either a module name, function or an object of the form: { module, [context] }; where module is a module name to load or a function and context is the optional processor-level context to pass to the processor. context is the top-level context object that will be merged with any processor-level context before processing a directive. baseDir is the base directory to resolve relative module names. If baseDir is not specified then it will default to process.cwd().

Example:

var directr = require('directr')
var files = ['app.js']
var compilerOptions = './jsconfig.json'
var baseDir = process.cwd()
var topLevelContext = {}
var directiveProcessors = {
  '@@hello': './directives/hello',
  '@@other': function (directive, context, done) {
    // TODO: implement
    done()
  },
  '@@something': {
    module: function (directive, context, done) {
      // TODO: implement
      done()
    }
  }
}

files = directr.inferDependencies(files, compilerOptions, baseDir)
directr.readDirectivesFromFiles(files, function (error, directives) {
  if (error) throw error
  directr.processDirectives(directives, directiveProcessors, topLevelContext, function (error) {
    if (error) throw error
  }, baseDir)
})

directr()

directr(sourceFiles, configPathOrConfig, callback)

Attempts to process the directives in the specified source files and their dependencies. Where configPathOrConfig can be a path to the config file to load or a config object (same properties supported by the config JSON file.)

Example:

var directr = require('directr').directr

directr(['src/app.js'], 'src/directiveconfig.json', function (error) {
  if (error) console.error(error.stack)
})