Stylus JavaScript API とプラグインの仕組みについて
先日 foovar という Stylus のライブラリを公開しました。
Stylus の変数を JS ファイルにエクスポートするためのライブラリです。
その時に調べた Stylus JavaScript API の詳細や、プラグイン作成の方法です。
仕様の変更などにより記事の内容が古くなったらすぐ分かるように、記事のテストを書いてみました。
Stylus プラグインの仕組み
プラグインの実体は関数を返す関数(高階関数)です。
これを module.exports
するだけでプラグインの体を成します(役に立たないということを除けば)。
npm で公開すればすぐにプラグインとして利用可能です。
module.exports = function() { return function() {}; };
外側の関数は use
(後述)した際に呼ばれ、オプションを引数に受取ります。
内側の関数は Renderer
のインスタンスを引数に受け取ります(コード中stylus
)。
module.exports = function(...options) { return function(stylus) {}; };
内側の関数内の this
はこの Renderer
インスタンスに束縛されて呼び出されます。
require('stylus')()
で得られるインスタンスも同じく Renderer
のインスタンスです。
module.exports = function(...options) { return function(stylus) { this.condtructor.name // 'Renderer' this === stylus; // true this.constructor === require('stylus')().constructor; // true }; };
基本的にはこの Renderer
インスタンスを介して Stylus の世界とやり取りをすることになります。
Stylus から呼び出せる関数を JS で定義したり、あらかじめ用意した .styl
ファイルへのパスを通したりといった感じです。
この Renderer
インスタンスの API については公式のドキュメントに詳しい情報があります。
プラグインの読み込みとオプションの渡し方
プラグインを読み込む方法は3つあります。
- ビルトイン関数
use(path)
を使う - JavaScript API の
.use(fn)
を使う - CLI の
--use name
オプションを使う
いずれも use
という言葉が使われており、このキーワードがプラグイン読み込みを指すと思われる。
ビルトイン関数 use(path)
JS ファイルのパスを指定して呼び出す。
プラグイン名での呼び出しは出来ない。
第2引数にはハッシュをオプションとして渡せる。
渡せるのはハッシュのみで、それ以外はエラーになる。
また第3引数以降は無視される。
use('./my-plugin.js') use('../../node_modules/plugin/index.js') // 名前での呼び出しは出来ない。 node_modules 配下のエントリポイントを直接指定することは出来る use('../../node_modules/plugin/index.js', { foo: 20px }) // オプションに渡せるのはハッシュのみ
JavaScript API の .use(fn)
前述の高階関数の内側の関数のみを渡す。
require
で読み込んだモジュールを実行して内側の関数を取り出し use
に渡すという使い方になる。
const stylus = require('stylus'); stylus(source) .use(require('plugin-name')()) .render(/*...*/);
外側の関数にはオプションを渡すことが出来る。
require
で読み込んで関数を直接呼び出すだけなので、好きな数の引数を好きな型で渡すことができる。
use(path)
、 CLI の --use
オプションとAPIを揃えるために、オプションはオブジェクト1個に限定したほうがいいかもしれない。
stylus(source) .use(require('plugin-name')({foo, 'bar'})) .render(/*...*/);
CLI の --use name
オプション
--use
に続けてプラグイン名を渡すと読み込んでくれる。
短縮形は -u
。
$ stylus --use plugin-name path/to/source.styl # あるいは $ stylus -u plugin-name path/to/source.styl
--with
に続けて文字列を渡すと、 JS としてパースされ外側の関数にオプションとして渡される。
なぜかドキュメントに載ってないし、 --help
にも出てこない。
この場合複数の引数は指定できないので、複数のオプションを扱いたい場合はオブジェクトや配列で渡す必要がある。
$ stylus -u plugin-name --with '{ foo: true }' path/to/source.styl
Stylus のトークンを表現するクラス
ここで記載する API はごく一部です。
より詳しいクラスの詳細はここらへんを見ると良さそう。
これらのコンストラクタを new
して Stylus のトークンを自前で生成することもできます。
トークンクラスへのアクセス
evaluator.renderer.nodes.*
で Stylus のトークンクラスにアクセスできる。
evaluator
は JavaScript API の define(name, fn)
で定義した関数内から this
で参照することができる。
const fn = function() { return new this.renderer.nodes.String('hello world'); }; module.exports = function() { return function(renderer) { renderer .define('hello-world', fn); }; };
以下、各クラスのコンストラクタの使い方、プロパティの型、コンソールに出力した結果です。
Expression
式を表すクラス。
nodes
内の要素が複数であれば tuple
もしくは list
となる。(要素が一つの場合を長さが1の tuple
と言うこともできる)
tuple
、list
の違いは isList
で判定できる。
constructor
Expression(isList)
isList
: boolean
instanceMethod
push(node)
:node
をthis.nodes
に追加するnode
: node
instanceProperty
nodes
: arrayisList
: boolean
{ lineno: 1, column: 14, filename: 'index.css', nodes: [ { lineno: 1, column: 14, filename: 'index.css', val: 'some string', string: 'some string', prefixed: false, quote: '\'' } ], isList: undefined }
Object
Stylus
のハッシュを表すクラス。
vals
には JS のオブジェクトが入っており、各キーにはさらに Stylus のトークンが入る。
constructor
Object()
instanceMethod
set(key, value)
:value
の値をkey
にセットするkey
: stringvalue
: node
instanceProperty
vals
: object
{ lineno: 1, column: 10, filename: 'index.css', vals: { foo: { lineno: 1, column: 19, filename: 'index.css', nodes: [Object], isList: undefined } } }
String
Stylus
の文字列を表すクラス。
constructor
String(val, quote)
val
: string
instanceProperty
string
: stringval
: string
{ lineno: 1, column: 14, filename: 'index.css', val: 'some string', string: 'some string', prefixed: false, quote: '\'' }
Unit
単位付き(あるいは無し)の数値を表すクラス。
10px
、1.7em
、200ms
、0
などは全て Unit
のインスタンスとなる。
constructor
Unit(val, type)
val
: numbertype
: string
instanceProperty
val
: numbertype
: stringraw
: string
{ lineno: 1, column: 10, filename: 'index.css', val: 20, type: 'px', raw: '20px' }
RGBA
RGBA形式の色を表現するクラス。
#112233
, #11223344
, rgb(11,22,33)
, rgba(11,22,33,44)
などは全て RGBA
のインスタンスとなる。
16進数表記の時のみ raw
プロパティが存在し、16進数表記の文字列が取得できる。
constructor
RGBA(r, g, b, a)
r
: numberg
: numberb
: numbera
: number
instanceProperty
r
: numberg
: numberb
: numbera
: numberraw
: string
{ lineno: 2, column: 16, filename: 'index.css', r: 17, g: 34, b: 51, a: 0.26666666666666666, name: '', rgba: [Circular], raw: '#11223344' }
HSLA
HSLA形式の色を表現するクラス。
hsl(11,22,33)
, hsla(11,22,33,44)
などは全て HSLA
のインスタンスとなる。
constructor
HSLA(h, s, l, a)
h
: numbers
: numberl
: numbera
: number
instanceProperty
h
: numbers
: numberl
: numbera
: number
{ lineno: 3, column: 12, filename: 'index.css', h: 11, s: 22, l: 33, a: 0.4, hsla: [Circular] }
Ident
auto
、inherit
、none
等のトークンを表現するクラス。
constructor
Ident(name, val, mixin)
name
: string
instanceProperty
name
: stringstring
: string
{ lineno: 1, column: 13, filename: 'index.css', name: 'auto', string: 'auto', val: null, mixin: false }
Call
cubic-bezier()
等の関数呼び出しを表現するクラス。
constructor
Call(name, args)
name
: stringargs
: expression
instanceProperty
name
: stringargs
: expression
{ lineno: 1, column: 40, filename: 'index.css', name: 'cubic-bezier', args: { lineno: 1, column: 20, filename: 'index.css', nodes: [ [Object], [Object], [Object], [Object] ], isList: undefined, map: {} } }
テスト
記事の公開時点では Stylus v0.54.5 を対象にテストしています。
all-user/inspect-stylus