この書籍へのコントリビュート方法についてガイドです。
この書籍はHonKitで作成されています。 また、文章はMarkdownで書かれています。Markdownの記法についてはHonKitのヘルプを参照してください。
一部、{{book.console}}
やHTMLコメントを使った仕組みも含まれているため、詳しくはこのガイドで紹介します。
次のIssueを受け付けています。
- 書籍や内容に対する質問 => こちらから質問できます
- 内容のエラーや問題の報告 => こちらからバグ報告できます
- 解説の改善を提案 => こちらから提案できます
- 新しいトピックなどの提案 => こちらから提案できます
その他のIssueも歓迎しています。
Pull Requestはいつでも歓迎しています。
受け入れるPull Request
次の種類のPull Requestを受け付けています。 基本的なPull Request(特に細かいもの)は、Issueを立てずにPull Requestを送ってもらって問題ありません。
「このような修正/改善はどうでしょう?」という疑問がある場合は、Issueを立てて相談してください。
- 誤字の修正
- サンプルコードやスペルの修正
- 別の説明方法の提案や修正
- 文章をわかりやすくするように改善
- ウェブサイトの改善
- テストの改善
📝 Note: Pull Requestを受け入れるとあなたの貢献がContributorsリストに追加されます。 また、Pull Requestを送った内容はこの書籍のライセンス(MIT and CC BY-NC)が適応されます。 これは、あなたの貢献がこの書籍への努力的な寄付となることを意味しています。
受け入れていないPull Request
- CODE OF CONDUCTに反する内容を含むもの
文章の誤字の修正程度なら、直接GitHub上で編集してPull Requestを送ってください。
ローカルで編集して送りたい場合は次の手順を試してください。
- Forkする
- Branchを作る:
git checkout -b my-new-feature
- テストする:
npm install && npm test
- 変更をコミットする:
git commit -am 'Add some feature'
- Pushする:
git push origin my-new-feature
- Pull Requestを送る :D
この書籍はHonKitで作成されています。
npm start
を実行後、http://localhost:4000/へアクセスすることで、HonKitのプレビュー表示ができます。
npm run start
# open http://localhost:4000/
また、Pull Requestを出した際にNetlify上へプレビュー用のサイトが公開されます。 Pull Request下部に表示されるCI Statusからプレビュー用のサイトを見られるため、HonKit上での表示を確認できます。
$ npm test
を実行するとコードや文章に対するテストを実行できます。
npm test
$ npm run textlint
の文章表現のエラーで疑問がある場合は、とりあえずそのままPull Requestを送ってください。
IssueやPull Requestでやりとりしそのエラーを直すか無視するかを決定します。
このプロジェクトでは次のようなテストが npm test
で実行されています。
特定のSuffixを持つファイル名を対象にしているテストも存在しています。
- HonKitのビルドテスト
- textlintによる文章のLint
- ESLintによるコードのLint
- textlint + ESLintによるMarkdown中のインラインコードブロックのLint
- Markdown中のインラインコードブロックへのDoctest
- Mochaによる
*-test.js
ファイルのユニットテスト *-example.js
がJavaScriptとして実行できるかのテスト*-invalid.js
がJavaScriptとして実行できないかのテスト
Markdown中のインラインコードブロックとは次のようなjs
言語指定がされたCodeBlockを示しています。
```js
var foo = "string";
```
CIではMarkdownの文章に対してtextlintを使ったLintが実行されます。
textlintだけのテストをしたい場合は、次のコマンドを実行してください。
npm run textlint
prh.ymlに用語統一用の辞書が定義されています。
この辞書を使ってtextlintで用語の統一しています 辞書がおかしい場合(誤検知している場合)は、prh.ymlを修正してください。
prh.ymlの書き方については次のページを参照してください。
次のようにHTMLコメントで、特定の範囲のtextlintエラーを無視できます。
<!-- textlint-disable -->
すべてのtextlintエラーを無視する
<!-- textlint-enable -->
できるだけ、特定のルールのエラーを無視するようにコメントを指定してください。
textlint-disable ルール名
で特定のルールのエラーだけを無視できます。
<!-- textlint-disable preset-ja-technical-writing/no-doubled-conjunction -->
二重助詞のルールのエラーだけを無視する
<!-- textlint-enable preset-ja-technical-writing/no-doubled-conjunction -->
コメントの詳細は次のページを参照してください。
*-example.js
のJavaScriptファイルとMarkdownのインラインコードブロックを対象にDoctestが実行されます。
次のように// => 値
というコメントを書いた部分が、assert
関数に変換されテストされます。
const a = 42;
console.log(a); // => 42
このコードは、は次のようなテストコードに変換されます。
const assert = requite("assert");
const a = 42;
assert.strictEqual(a, 42); // => 42
これにより、サンプルコードのコメントに書いた評価結果と実際の出力が一致するかをテストしています。
詳しい実装は次のドキュメントを参照してください。
評価したい式; // => 期待する評価結果
or
console.log(評価したい式); // => 期待する評価結果
基本的には、console.log(式); // => 期待する評価結果
を利用します。
console.log
が冗長な場合は 式; // => 期待する評価結果
と書いても良いことにしています。
Doctestの正常系は実行結果と期待結果が一致することです。
一方、そのコードの実行結果がエラーになることを期待する場合もあります。
エラーを期待する場合は、doctest: 期待するエラー名
をHTMLコメントに書きます。
例) 実行結果がReferenceError
となることを期待するテスト
条件式
という変数が定義されていないためエラーとなる。
<!-- doctest: ReferenceError -->
```js
if (条件式)
実行する文;
```
個別の行がエラーとなることを期待する場合は、正常系のDoctestでも書けるためそちらを推奨します。
```js
NO_DEFINE++; // => ReferenceError
```
デフォルトでは、コード上の全てのDoctestが実行されまで結果を待ちます。 次のコードでは、3つのassertが実行されるまでテストコードの終了を待ちます。
```js
1; // => 1
2; // => 2
3; // => 3
```
次のように条件分岐で片方のassertのみが実行されることを期待する場合は、doctest:options:{ "runMode": "any" }
を指定してください。
一つでもassertが実行された時点でテストを終了します。
<!-- doctest:options:{ "runMode": "any" } -->
```js
if (Math.random() < 0.5 ) {
console.log(true); // => true
} else {
console.log(false); // => false
}
```
DoctestでPromiseやAsync Functionを使った非同期のテストも書けます。
非同期処理のタイムアウトを明示的に指定したい場合はdoctest:options:{ "timeout": 1000 }
をHTMLコメントに書きます。
例) 実行結果が1000
ミリ秒以内に完了する非同期処理をテストする
<!-- doctest:options:{ "timeout": 1000 } -->
```js
function wait(ms){
return new Promise((resolve) => {
setTimeout(() => resolve(ms), ms)
})
}
wait(1000).then(() => {
console.log(value); // => 1000
});
```
Note: vm
モジュールの制約からタイムアウト指定の時間が正しく指定させていることが前提となっています。
DoctestはNode.jsで実行されます。 実行するNode.jsがECMAScriptの最新のバージョンをサポートしていない場合があります。 そのため、コードのECMAScriptバージョンを指定することで、そのDoctestをスキップできます。
例) DoctestがECMAScript 2019であることを表記する
<!-- doctest:meta:{ "ECMAScript": "2019" } -->
```js
[1,[2], [3]].flat();
```
DoctestでサポートしてないECMAScriptバージョンのテストは実行されません。
CodeBlockの手前に<!-- doctest:disable -->
というHTMLコメントがある場合はDoctestをしません。
Node.jsで実行できないビルドインオブジェクトを使うパターンや例外的なケースに利用できます。
例) 無視するケース
次の例はAPIの説明のための擬似コードであるため無視しています。
<!-- doctest:disable -->
```js
array.map(コールバック関数);
```
別の手法:
ファイル名が*-invalid.js
のコードは実行できないことを検証できます。(エラーになるとテストが通る)
これを[include]
することでより正確に表現できます。
*-invalid.js
がJavaScriptとして実行できないかのテスト
関連
- console.logと// => の使い分け · Issue #195 · asciidwango/js-primer
- power-assertを使ったDoctestツール power-doctestを書き直した | Web Scratch
- JavaScriptでdoctestを行う power-doctest を作った | Web Scratch
- 25.2. doctest — 対話的な実行例をテストする — Python 2.7.x ドキュメント
source
下に章や節ごとにディレクトリを切り、
その下にコード(src/
)、テスト(test/
)、リソース(img/
)などを配置して扱います。
└── source
└── ch1
├── basic
│ └── README.md
├── comments
│ ├── README.md
│ └── src
│ └── html-like-comments-example.js
└── hello
├── README.md
├── img
├── src
│ └── hello-world.js
└── test
└── hello-world-test.js
AngularJSのGit Commit Guidelinesをベースとしています。
以下のような形で
- 1行目に概要
- 2行目は空行
- 3行目から本文
最後に関連するIssue(任意)を書きます。
feat(ngInclude): add template url parameter to events
The `src` (i.e. the url of the template to load) is now provided to the
`$includeContentRequested`, `$includeContentLoaded` and `$includeContentError`
events.
Closes #8453
Closes #8454
scope commit title
commit type / /
\ | |
feat(ngInclude): add template url parameter to events
body -> The 'src` (i.e. the url of the template to load) is now provided to the
`$includeContentRequested`, `$includeContentLoaded` and `$includeContentError`
events.
referenced -> Closes #8453
issues Closes #8454
commit type
としては次のようなものがあります。
- feat
- 新しい機能、章、節の追加など
- 更新履歴に載るような新しいページを追加
- fix
- 意味が変わる修正
- 更新履歴に載るような修正
- docs
- 基本的には使わない
- README.mdやCONTRIBUTING.mdや本体のプロジェクト全体のドキュメントについて
- refactor
- 意味が変わらない修正
- 更新履歴に載らないような修正
- style
- スペースやインデントの調整
- Lintエラーの修正など
- perf
- パフォーマンス改善
- test
- テストに関して
- chore
- その他
- typoの修正など
commit type
は、迷ったらとりあえずchore
と書きます。
scope
も省略して問題ないので以下のような形でも問題ありません。
chore: コミットメッセージ
書き方に関するルールや表記統一について
文章に対する相対的な位置の指し示す場合は、 できるかぎり「次のコード」というように事前に説明する。
読んでいる人がサンプルコードのどこに注目すればいいかが事前にわかるように書く。
次のコードは xxx について説明しています。
code
事前に説明した特定のコードを参照したい場合は、 サンプルコードのファイル名を参照に利用する。
[import, example.js](src/example.js)
色々文章...
[example.js](#example.js)では、 ....
次の変数をコードブロックの前に書くことで、コードがインタラクティブに実行できるコンソールモードとして表示されます。 (ウェブのみ)
{{book.console}}
```js
var interactive = "code";
```
importしたコードにも対応しています。
{{book.console}}
[import, example.js](src/example.js)
honkit-plugin-sandpackを使ったCodeSandboxのコードエディタ埋め込みに対応しています。
HTMLコメントで、JSやHTMLを読み込むエディタとプレビューを埋め込めます。
- isOpen:true の場合は、エディタが最初から表示されます
- isOpen:false の場合は、実行ボタンを押すまで表示はされません
- Note: いくつかの問題点があるので回避策を追加して使う場合があります
- loadイベントは正しく発生しない → window.dispatchEventで手動で発火させる
- headのCSSは無視される → CSSが読まれないので、
appendCode
などで手動でCSSを追加する
次のように、<!-- sandpack:{/*options*/} -->
のコメントを書いた場所に埋め込まれます。
<!-- sandpack:{
"files": {
"/src/index.js": {
"path": "example/index.js"
},
"/index.html": {
"path": "example/index.html"
}
},
"entry": "/src/index.js",
"main": "/src/index.js",
"environment": "static",
"template": "vanilla",
"options": {
"showLineNumbers": true,
"editorHeight": 550
},
"honkitSettings": {
"isOpen": true,
"hideExitButton": true
}
} -->
ES2015は正式な名称ですが、ES6も一般によく使われている名称です。 どちらの表記をメインに利用するかは以下のIssueで議論した結果、ES2015という表記をメインとしています。 これから出てくる仕様はES2016、ES2017と年号形式であるためそちらに揃えていこうという形です。
この書籍では"最新版のECMAScript"という定義は変更される場合があります。 2017年においてはECMAScript 2017ですが、2018年では異なります。
そのため、現在のECMAScriptバージョンを扱うときは{{book.esversion}}
という変数を利用します。
現在のECMAScriptの最新版はECMAScript {{book.esversion}}です。
この変数はbook.json
に定義されています。
基本的にコードではlet
またはconst
を利用します。
var
の機能を説明する場合においてはvar
を利用します。
別の章へのリンクを書くときは「[章のタイトル][]」の章
という形でリンクする。
章の途中の場合は「[章のタイトル][]」の[#付きのリンク][]
という形にする。
真偽値へ変換した結果が`true`となる値の種類は多いため、逆に変換した結果が`false`となる値を覚えるのが簡単です。JavaScriptでは次の値は`false`に変換され、これらの値は**falsy** と呼ばれます。(「[暗黙的な型変換][]」の章を参照)