/expand-abbr

Expand-abbr is a command line interface for emmet, which takes command line arguments as emmet HTML abbreviation syntax, and writes expanded HTML snippets to standard output.

Primary LanguageJavaScriptMIT LicenseMIT

expand-abbr

expand-abbrは、Emmetの構文で記述した省略記法の文字列をHTML要素に展開して標準出力に書き出すコマンドラインインターフェイスです。

Installation

$ mkdir test-package
$ cd test-package/
$ npm init -y
$ echo "@kazhashimoto:registry=https://npm.pkg.github.com" > .npmrc

.npmrcに自分のPersonal access tokenを追加します。このtokenは、scopeにread:packages権限を有効にしたものをDeveloper settingsページを通じて取得する必要があります。

@kazhashimoto:registry=https://npm.pkg.github.com/

//npm.pkg.github.com/:_authToken=ghp_<PERSONAL_ACCESS_TOKEN>
$ npm install -g @kazhashimoto/expand-abbr

How to uninstall this package:

$ npm uninstall -g @kazhashimoto/expand-abbr

Usage

Usage: expand-abbr [options] abbreviation ...

Options:
  -V, --version              output the version number
  -h,--head                  prepend html header
  -w,--wrapper <parent>      wrap expanded elements with div.parent
  --local                    use local path for the src attribute of <img>
                             elements
  --path <prefix>            set the src attribute of img elements to a
                             pathname starting with prefix
  -c,--css <stylesheet>      insert a link to an external stylesheet inside
                             head element (default: [])
  -f,--load-macros <module>  load user defined macros from <module>
  -l,--list-macros           list Element macros
  -m,--macro <key_value>     add Element macro definition (default: [])
  -q,--query <key>           print Element macro that matches <key>
  --dark                     apply dark theme on the generated page
  --grayscale                get grayscale images
  -t,--tab                   use a tab character for indenting instead of
                             spaces. (default: 2 spaces)
  --without-style            If this option disabled, insert default styles by
                             using a <style> element in the <head> section
  -x                         add compiled abbreviation as HTML comment to
                             output
  --check                    check for inconsistency in macro definitions and
                             in style rules
  -d                         print debug info.
  --help                     display help for command

expand-abbrは、引数abbreviationごとにHTML要素のツリーに展開し、展開した結果を順に連結して出力します。

$ expand-abbr 'ul>li>a'
$ expand-abbr 'header>div' 'dl>(dt+dd)*3' 'footer>p'
$ expand-abbr '(header>ul>li*2>a)+footer>p'

-wオプションを指定すると、展開した要素全体を<div>要素のラッパーで包んだ1つのツリーとして出力します。

$ expand-abbr -w .wrapper 'div>p' 'ul>li*2>a'
<div class="wrapper">
  <div>
    <p></p>
  </div>
  <ul>
    <li><a href=""></a></li>
    <li><a href=""></a></li>
  </ul>
</div>

-hオプションを指定すると、出力は<head>セクションを含んだ1つのHTMLページ(HTML文書)になります。つまり、展開した要素全体は<body>タグと<html>で囲まれて出力されます。<head>セクションの内容は、emmetの省略記法!を使って生成したテンプレートが使用されます。

$ expand-abbr -h '(div>dl>(dt+dd)*3)+footer>p'

外部スタイルシートへのリンクを<head>セクションに挿入するには、-cオプションを指定します。-cオプションはコマンドラインで複数回指定できます。その場合、expand-abbrは、引数に現れた順序で<link>要素を追加します。

$ expand-abbr -h -c "reset.css" -c "https://www.example.com/style.css" ”div>p”
<head>
  .....
  <link rel="stylesheet" href="reset.css">
  <link rel="stylesheet" href="https://www.example.com/style.css">
</head>

出力行のインデント1個の幅はスペース2個です。-tオプションを指定すると、タブ文字を使用してインデントします。

Examples

デモのソースコードはこちら: https://github.com/kazhashimoto/expand-abbr-demo

次のシェルスクリプトdemo1.shは、5個のセクションとそれぞれの見出しへのナビゲーションリンクから成るHTMLページを出力します。

#!/bin/bash

header='header>h1{Title}+nav>ul.links>(li>a[href=#s$]{Section $})*5'
main='(section#s$>h2{Section $}+(p.text>lorem)*4+p.top>a[href=#]{Top})*5'
footer='footer>p{&copy; 2023 Example}'

css='style.css'

expand-abbr -h -c "$css" "$header" "$main" "$footer"

このスクリプトの出力をindex.htmlファイルに保存すれば、ブラウザーで開くことができます(macOSでの例)。

$ cd demo1
$ chmod +x demo1.sh
$ ./demo1.sh > index.html
$ open index.html

demo1.shでの変数headerなどのように、Emmetの構文で書かれた文字列をシェルの変数に代入するときは、文字列中の$記号をシェルが変数展開するのを防ぐため、文字列全体をシングルクォート(')で囲みます。

変数をexpand-abbrの引数に指定するときは、ひとまとまりの省略記法として扱われるようにダブルクォート(")で囲みます(例:"$footer")。これは、変数の値が空白を含む文字列の場合、コマンドラインに指定したダブルクォートなしの$変数の解釈がシェルによって異なるためです。

例:
bashの場合、テキスト中の空白文字で2つの引数に分割されてしまい、Emmetが文法エラーになります。

bash$ foo='p{hello world}'
bash$ expand-abbr $foo
<p>hello</p>
...
Error: Unexpected character at 5

zshの場合、ダブルクォートがなくても1つの引数として解釈されます。

zsh% foo='p{hello world}'
zsh% expand-abbr $foo
<p>hello world</p>

ダミーHTML文書の生成

expand-abbrを使って、ランダムなコンテンツを含んだダミーHTML文書を生成することができます。 引数にキーワード%root%を指定すると、expand-abbrはHTML要素をランダムに組み合わせたツリーを出力します。ランダムとはいえ、Emmetを使ってツリーに展開しているため、出力されるHTML文書は文法的に正しいものが得られます。

$ expand-abbr -h '%root%' > index.html            
$ open index.html

現在、expand-abbrが生成できるダミーHTML文書には次の2種類があり、それぞれインデックス付(後述)のキーワード%root@0%, %root@1%が割り当てられています。

キーワード ダミーHTMLのタイプ
%root@0% 数個のセクションから成る記事風のページ
%root@1% ブログ風のページ

$ expand-abbr -h --dark "%root@0%" > article.html
$ expand-abbr -h --dark "%root@1%" > blog.html

img要素のsrc属性

expand-abbrが生成するダミーHTML文書では、<img>要素のsrc属性に設定されるリソースは、デフォルトの場合、Lorem Picsumのランダムな画像へのURLです。

<img src="https://picsum.photos/800/450?random=338" alt="Maxime voluptatem" width="800" height="450">

--localオプションを指定すると、<img>要素のsrc属性の値は既定のファイル名が設定されます。

$ expand-abbr --local '%root%'

出力例(一部)

<img src="photo4x3_1.jpg" alt="Alias ducimus?" width="600" height="450">

src属性の値を/ を含んだパス名にするには、--pathオプションの引数にディレクトリのパス名を指定します。

$ expand-abbr --path /path/to  "img[src=foo.jpg]"
<img src="/path/to/foo.jpg" alt="">

コマンドラインに--pathが与えられた場合、--localオプションも暗黙に有効になります。

$ expand-abbr --path /path/to  '%root%' > index.html
$ grep "img src" index.html
<img src="/path/to/photo4x3_1.jpg" alt="Odit excepturi" width="240" height="180">
....

ダミーHTML文書のスタイルシート

-hオプションが与えられた場合、expand-abbrは出力されるHTML文書の<head>セクションに<style>要素を挿入し既定のスタイルシートを埋め込みます。

$ expand-abbr -h '%root%' | more
<style>
._x-pg-header-content_header {box-sizing: border-box; width: 100%; padding: 10px 4%}
._x-pg-footer-content_footer {box-sizing: border-box; width: 100%; padding: 20px 4%; margin-top: 50px}
....
</style>

このスタイリングのために、expand-abbrは主要なHTML要素に対してclass属性を設定します。設定されるクラスは名前に接頭辞_x-が付きます。

$ expand-abbr -h '%root%' | grep class | more
<div class="_x-pg-header_div">
  <header class="_x-pg-header-content_header">
    <nav class="_x-nav_nav">
    ....

既定のスタイルにはOpen PropsのCSSカスタムプロパティが使用されるため、次の外部スタイルシートを参照する<link>要素が<head>セクションに挿入されます。

<link rel="stylesheet" href="https://unpkg.com/open-props">
<link rel="stylesheet" href="https://unpkg.com/open-props/normalize.min.css">

--darkオプションを指定すると、既定のスタイルにダークモードの配色を適用します(デフォルトはライトモード)

$ expand-abbr -h --dark "%root%"

--without-styleオプションを指定すると、expand-abbrは既定のスタイルシートの埋め込みを抑止し、要素にクラス属性も挿入しません。

$ expand-abbr -h --without-style '%root%'

Extended Syntax

expand-abbrはダミーHTML文書の生成を可能とするために、Emmetの構文を独自に拡張した次の機能をサポートしています: Elementマクロ, Textマクロ、繰り返し(%)オペレーター。

Elementマクロ

Elementマクロは%name%という書式の文字列であり、nameは別のElementマクロおよびEmmet省略記法を含む式expressionへの参照です。expand-abbrはElementマクロを再起的に式に展開し、最終的に1つのEmmet構文に置き換えます。

組み込みのElementマクロ%root%は、展開されるとダミーHTML文書の<body>要素のコンテンツを表すEmmet構文に置き換わります。

-lオプションを指定すると、expand-abbrはElementマクロの一覧を表示します。

$ expand-abbr -l

組み込みElementマクロの一覧はmacros.jsで確認できます。

ユーザー定義のElementマクロ

ユーザー定義のElementマクロを追加できます。コマンドラインから指定する方法と、外部ファイルから読み込ませる方法があります。いずれの場合も、ユーザー定義のElementマクロは組み込みのElementマクロの一覧に追加されます。

-mオプションの引数にkeyvalueのペアを指定することにより、keyという名前のElementマクロを追加します。

$ expand-abbr -m 'foo:p>span' -m 'bar:div>%foo%' 'div>h3+(%bar%)'
<section>
  <h3></h3>
  <div>
    <p><span></span></p>
  </div>
</section>

-mオプションで指定したkeyに一致する名前を持つElementマクロがすでに存在する場合、そのマクロの値のリストに追加されます。

$ expand-abbr -m 'root:div>p' -q root
[ '(%pg-header%)+(%pg-main-content%)+(%pg-footer%)', 'div>p' ]

ユーザー定義のElementマクロを記述したJavaScriptのモジュールを-fオプションまたは--load-macroオプションの引数に指定して、expand-abbrに読み込ませることができます。 読み込ませるファイルはCommonJSのモジュールとして記述し、macroMapオブジェクトをエクスポートするように設定します。

const macroMap = new Map();
module.exports.macroMap = macroMap;

そして、マクロ名をkeyとして、macroMapオブジェクトのsetメソッドでvalueの配列を値として登録します。

macroMap.set('key', [ value, ... ]);

例: my-macro.js

const macroMap = new Map();
module.exports.macroMap = macroMap;

macroMap.set('my-root', [
  'div>(%root%)',
  '(%my-header%)+(%my-content%)'
]);
macroMap.set('my-header', [
  'header>h1{__HEADING__}'
]);
macroMap.set('my-content', [
  'div*3>p>lorem10'
]);

オプションの引数に指定するモジュールのパス名は、カレントディレクトリからの相対もしくは絶対パスです。ファイルの検索順序に関して、Node.jsのnode_modulesディレクトリは関係ありません。

$ expand-abbr -f my-macro.js -h '%my-root%'

マクロの値のインデックス指定

マクロ%name%が与えられた時、expand-abbrは、キー値nameを持つmacroMapの値の配列の中から1個をランダムに選び、その文字列でマクロを置換します。 配列の中で、置換に使用される値を固定するには、書式%name@index%により配列のインデックスを指定します。

$ expand-abbr -m 'box:div{1}' -m 'box:div{2}' -m 'box:div{3}' -q box   
[ 'div{1}', 'div{2}', 'div{3}' ]
$ expand-abbr -m 'box:div{1}' -m 'box:div{2}' -m 'box:div{3}' '%box@2%'
<div>3</div>

Textマクロ

Textマクロは__keyword__という書式の文字列であり、その文字列はEmmet省略記法の展開時もしくはHTML文書の出力時に別の文字列に置き換わります。Textマクロは、Emmetの構文において通常のテキストを埋め込める箇所で使用できます。(例: {...}の内側, タグの属性[attr]表記に指定する値など)

ダミーテキストを生成するTextマクロ。これらは、見出しやリンクの文字列など短いダミーテキストを埋め込むのに役立ちます。このマクロが返すダミーテキストはEmmetのLorem Ipsumジェネレーターを使って生成されますが、書き出しが"lorem ipsum"以外の文字列も返されるように調整されています。

Textマクロ 置換される内容 ワード数 コンマとピリオド Capitalize
__HEADING__ 見出しに適した長さのダミーテキスト 4〜8 なし 各単語
__HEADING_SHORT__ 大見出しに適した短いダミーテキスト 4〜6 なし 各単語
__PHRASE__ リンクのテキストなどに適した2語からなるダミーテキスト 2 なし 最初の語
__NAME__ 人名のような2語からなるダミーテキスト 2 なし 各単語
__DIGEST__ 短い文のダミーテキスト 4〜8 あり 最初の語
__MESSAGE__ ブログの投稿のような短い文のダミーテキスト 9〜15 あり 最初の語
__COMMENT__ ブログのコメントのような短い文のダミーテキスト。絵文字を含む 10〜30 あり 最初の語
__HYPERTEXTwordsXcount__ 文章中にハイパーリンクや数字、括弧などを含む、記事本文に適した長さのテキスト words * count 含む 各文の最初の語

ダミーテキスト以外の文字列を生成するTextマクロには次のものがあります。

Textマクロ 置換される内容
__SEQ__
__SEQid__
順序番号(1,2,...)
__IMAGEwidthXheight__ Lorem Picsumが提供するランダム画像のURL
__DATETIME__ "YYYY-MM-DD HH:mm"形式の文字列で表されたランダムな日時
__DATE__ <time>要素のdatetime属性の値から日付表現に変換した文字列

Textマクロの使用例

$ expand-abbr 'h2{__HEADING__}'
<h2>Eum Sed Quidem Voluptatem Facilis Nulla</h2>

$ expand-abbr 'h1{__HEADING_SHORT__}'
<h1>Unde Quo Blanditiis Rerum Beatae</h1>

$ expand-abbr 'ul>li*3>a[href=#]{__PHRASE__}'
<ul>
  <li><a href="#">Culpa amet</a></li>
  <li><a href="#">Laborum non</a></li>
  <li><a href="#">Enim obcaecati</a></li>
</ul>

$ expand-abbr 'span{__NAME__}'
<span>Dolores Porro</span>

$ expand-abbr 'p{__DIGEST__}'
<p>Quis quidem nobis nisi hic aspernatur?</p>

$ expand-abbr 'p{__MESSAGE__}'
<p>Optio architecto nihil porro atque eius est animi quod ipsum.</p>

__COMMENT__マクロは文末に絵文字が0〜5個、ランダムに追加されたダミーテキストを生成します。

% expand-abbr 'p{__COMMENT__}'
<p>Provident voluptatibus maiores eveniet quia dicta vitae nesciunt repellendus vel aliquam enim cum distinctio quos, porro neque quasi optio!&#x1F44D;&#x1F600;&#x1F3B5;</p>

__HYPERTEXTwordsXcount__マクロは、ワード数words個からなる文をcount個連結した文章を生成します。Lorem ipsumのダミーテキストに加えて、次の要素がランダムに埋め込まれます(テキストの長さが短い場合、すべての要素が出現するとは限りません)。

  • ハイパーリンク
  • 数字
  • 括弧"(", ")"

また、記事本文に使える「読みやすい」文章に見せるため、expand-abbrは、ダミーテキストに対して次の加工を施した文章を出力します。

  • 過剰なコンマ","を取り除く
  • 文末の"!"や"?"記号を高い確率でピリオド"."に置き換える
  • 1語や2語だけの文を、前後の文いずれかと連結し、文の長さを調節する

$ expand-abbr 'p{__HYPERTEXT10X2__}'
<p>Accusantium nam omnis ipsam nesciunt odit ea aperiam quos placeat. Odit voluptatum harum quisquam pariatur <a href="https://www.google.com/search?q=dolore">dolore</a> 1,167 aliquid explicabo iste nemo.</p>

__SEQ__マクロは、1から始まる番号で置き換えます。Emmetの$オペレータとの違いは、*オペレーターによって要素が繰り返されたスコープ(親要素)を超えても、番号が1にリセットされない点です。つまり、異なるスコープに渡って通し番号を振ることができます。

$ expand-abbr 'ul>li*3>{item __SEQ__}' 'ul>li*3>{item __SEQ__}'
<ul>
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
</ul>
<ul>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6</li>
</ul>

$ expand-abbr 'a[href=page__SEQ__.html]*3{click}'
<a href="page1.html">click</a>
<a href="page2.html">click</a>
<a href="page3.html">click</a>

接頭辞SEQの後に任意の名前を付けることにより、順序番号を発生させる"レジスター"を必要なだけ複数個定義することができます。名前に使用できる文字は、英大文字・数字・アンダースコアです。

次の例では、<a>要素のテキストに現れる番号と、<img>要素の画像ファイル名に含まれる番号とを異なる連番で割り当てています。

$ expand-abbr 'a{page__SEQ1__}' 'div*3>a{page__SEQ1__}+div*2>img[src=photo__SEQ2__.jpg]' 'a{page__SEQ1__}'
<a href="">page1</a>
<div>
  <a href="">page2</a>
  <div><img src="photo1.jpg" alt=""></div>
  <div><img src="photo2.jpg" alt=""></div>
</div>
<div>
  <a href="">page3</a>
  <div><img src="photo3.jpg" alt=""></div>
  <div><img src="photo4.jpg" alt=""></div>
</div>
<div>
  <a href="">page4</a>
  <div><img src="photo5.jpg" alt=""></div>
  <div><img src="photo6.jpg" alt=""></div>
</div>
<a href="">page5</a>

__IMAGEwidthXheight__マクロは、Lorem Picsumが提供するランダム画像のURLに置き換えます。画像の寸法はwidthheightで指定します。

$ expand-abbr 'img[src=__IMAGE800X600__]'
<img src="https://picsum.photos/800/600?random=230" alt="">

__DATETIME__マクロは、ランダムな日時を"YYYY-MM-DD HH:mm"形式の文字列で置き換えます。値となる日時は、実行時に現在の日時を基点として約1年前までの期間の中からランダムに生成されます。__DATETIME__マクロは<time>要素のdatetime属性の値として使用します。

__DATE__マクロは、<time>要素のコンテントとして使用し、datetime属性の値から日付表現に変換した文字列で置き換えます。日付の書式はen-USロケールで表記され、datetime属性の値をローカルタイムゾーンで解釈したものを表す文字列です。

$ expand-abbr 'time[datetime=__DATETIME__]{__DATE__}'
<time datetime="2022-03-15 12:52">Mar 15, 2022</time>

繰り返し(%)オペレーター

繰り返しオペレーターは、Emmet省略記法の構文の式や項の後ろに%specifier%の書式で指定される文字列です。specifierは、繰り返しの対象と回数を表します。

説明
(expression)%+max%
(expression)%+min, max%
expression+オペレーターでN個結合した式に展開します。
minNmax
default: min = 1
element%*max%
element%*min,max%
要素element*オペレーターでN個繰り返した式に展開します。
minNmax
default: min = 1
parentTag%>tag{max}
parentTag%>tag{min,max}
親要素parentTagと子要素の間にタグtagN階層入れ子で挿入する式に展開します。
minNmax
default: min = 0

%オペレーターの使用例

-xオプションを指定してexpand-abbrを実行すると、%オペレーターによって展開された結果の式を表示させることができます。

expand-abbr -x '(div>p)%+3%'

これは次の3通りのEmmet省略記法のいずれか1つに展開されます。

(div>p)
(div>p)+(div>p)
(div>p)+(div>p)+(div>p)

expand-abbr -x '(div>p)%+2,4%'

これは次の3通りの記法のいずれか1つに展開されます。

(div>p)+(div>p)
(div>p)+(div>p)+(div>p)
(div>p)+(div>p)+(div>p)+(div>p)

expand-abbr -x '(div>p)%+3%+(p>span)%+2,2%'

これは次の3通りの記法のいずれか1つに展開されます。

(div>p)+(p>span)+(p>span)
(div>p)+(div>p)+(p>span)+(p>span)
(div>p)+(div>p)+(div>p)+(p>span)+(p>span)

%+オペレーターが修飾する式の中にさらに%+を指定することもできます。

expand-abbr -x '((div>p)%+3%+(p>span))%+2,2%'

これは次に示した多数のバリエーションのうちいずれか1つに展開されます。

 ((div>p)+(p>span))+((div>p)+(p>span))
 ((div>p)+(p>span))+((div>p)+(div>p)+(p>span))
 ((div>p)+(div>p)+(div>p)+(p>span))+((div>p)+(p>span))
 ((div>p)+(div>p)+(div>p)+(p>span))+((div>p)+(div>p)+(p>span))
 ...

expand-abbr -x 'p%3%>span{item $}'

これは次の3通りのEmmet省略記法のいずれか1つに展開されます。

p*1>span{item $}
p*2>span{item $}
p*3>span{item $}

$ expand-abbr -x '(p>span{item $})%3%'

これは次のいずれか1つに展開されます。

(p>span{item $})*1
(p>span{item $})*2
(p>span{item $})*3

expand-abbr -x '(p>span{item $})%2,4%'

これは次のいずれか1つに展開されます。

(p>span{item $})*2
(p>span{item $})*3
(p>span{item $})*4

expand-abbr -x 'header%>div{3}%p'

これは次のいずれか1つに展開されます。

header>p
header>div>p
header>div>div>p
header>div>div>div>p