diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58d2e20be5..cf8f110bf6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,8 +83,12 @@ or console.log(評価したい式); // => 期待する評価結果 ``` +基本的には、`console.log(式); // => 期待する評価結果`を利用し、 +`console.log`が冗長な場合は `式; // => 期待する評価結果`と書いても良い。 + **関連** +- [console.logと// => の使い分け · Issue #195 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/issues/195 "console.logと// => の使い分け · Issue #195 · asciidwango/js-primer") - [power-assertを使ったDoctestツール power-doctestを書き直した | Web Scratch](http://efcl.info/2015/08/10/power-doctest1.0/) - [JavaScriptでdoctestを行う power-doctest を作った | Web Scratch](http://efcl.info/2013/1201/res3494/) - [25.2. doctest — 対話的な実行例をテストする — Python 2.7.x ドキュメント](http://docs.python.jp/2/library/doctest.html "25.2. doctest — 対話的な実行例をテストする — Python 2.7.x ドキュメント") diff --git a/package.json b/package.json index 4d724394c9..8138b31891 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,8 @@ "babel-preset-power-assert": "^1.0.0", "babel-register": "^6.7.2", "eslint": "^3.0.0", + "esprima": "^3.1.3", + "esquery": "^1.0.0", "front-matter": "^2.1.0", "gitbook-cli": "^2.1.2", "gitbook-plugin-canonical-link": "^2.0.2", diff --git a/source/basic/data-type/README.md b/source/basic/data-type/README.md index 7ef9081a8d..d6ebf09dfc 100644 --- a/source/basic/data-type/README.md +++ b/source/basic/data-type/README.md @@ -127,7 +127,7 @@ JavaScriptの浮動小数点数は[IEEE 754][]を採用しています。 - `3.14159` のような `.`(ドット)を含んだ数値 - `2e8` のような `e` または `E` を含んだ数値 -`0`から始まる浮動小数点数は、`0`を省略し書くことができます。 +`0`から始まる浮動小数点数は、`0`を省略して書くことができます。 ```js .123; // => 0.123 @@ -245,7 +245,7 @@ foo;// "ReferenceError: foo is not defined" {{book.console}} ```js var foo = null; -foo; // => null +console.log(foo); // => null ``` ### オブジェクトリテラル {#object} @@ -344,7 +344,7 @@ console.log(array[array.length - 1]); // => "2番目" ```js var numberRegExp = /\d+/; // 1文字以上の数字にマッチする正規表現 // 123が正規表現にマッチするかをテストする -numberRegExp.test(123); // => true +console.log(numberRegExp.test(123)); // => true ``` `RegExp`今ストラクを使うことで文字列から正規表現オブジェクトを作成することもできますが、 diff --git a/source/basic/function-method/README.md b/source/basic/function-method/README.md index 58609e8707..a12e19afe6 100644 --- a/source/basic/function-method/README.md +++ b/source/basic/function-method/README.md @@ -58,7 +58,7 @@ function multiple(num) { return num * 2; } -multiple(10); // => 20 +console.log(multiple(10)); // => 20 ``` 値を返していない又は空の`return;`と書いた場合、関数は`undefined`を返します。 @@ -68,7 +68,7 @@ multiple(10); // => 20 function noop() { } -noop(); // => undefined; +console.log(noop()); // => undefined; ``` ### 可変長引数 diff --git a/source/basic/implicit-coercion/README.md b/source/basic/implicit-coercion/README.md index 215270bb30..22daf3a010 100644 --- a/source/basic/implicit-coercion/README.md +++ b/source/basic/implicit-coercion/README.md @@ -116,8 +116,8 @@ JavaScriptには、文字列に対するマイナス演算子(`-`)の定義 {{book.console}} ```js var x = 1, y = "2", z = 3; -x + y + z; // => "123" -y + x + z; // => "213" +console.log(x + y + z); // => "123" +console.log(y + x + z); // => "213" ``` このように、処理の過程でオペランドの型によって、 diff --git a/source/basic/operator/README.md b/source/basic/operator/README.md index 7101d72d80..ad297181f1 100644 --- a/source/basic/operator/README.md +++ b/source/basic/operator/README.md @@ -145,11 +145,11 @@ Math.pow(2, 4); // => 16 {{book.console}} ```js // 自分自身とも一致しない -NaN === NaN; // => false +console.log(NaN === NaN); // => false // Number型である -typeof NaN; // => "number" +console.log(typeof NaN); // => "number" // Number.isNaNでNaNかどうかを判定 -Number.isNaN(NaN); // => true +console.log(Number.isNaN(NaN)); // => true ``` しかし、単項演算子の`+`は文字列から数値への変換に使うべきではありません。 diff --git a/source/basic/string/README.md b/source/basic/string/README.md index 5d8094ecb1..82ce7a5fb7 100644 --- a/source/basic/string/README.md +++ b/source/basic/string/README.md @@ -112,14 +112,14 @@ ES2015で追加された`String#codePointAt`メソッドを使うことで、そ ```js // 文字列"あ"の0番目のCode Pointを取得 -"あ".codePointAt(0); // => 12354 +console.log("あ".codePointAt(0)); // => 12354 ``` 逆に、`String.fromCodePoint`メソッドを使うことで、指定したCode Pointの文字を取得できます。 ```js // 符号位置12354の文字を取得する -String.fromCodePoint(12354); // => "あ" +console.log(String.fromCodePoint(12354)); // => "あ" ``` また、文字列リテラル中にはUnicodeエスケープシーケンスで、直接Code Pointを書くこともできます。 @@ -128,7 +128,7 @@ Code Pointは`\u{Code Pointの16進数の値}`で書くことができます。 ```js // "あ"のCode Pointは12354 // 12354の16進数表現は3042 -"\u{3042}"; // => "あ" +console.log("\u{3042}"); // => "あ" ``` Code Pointの16進数表現は次のようにして求めることができます。 @@ -139,7 +139,7 @@ var codePointOfあ = "あ".codePointAt(0); // 12354の16進数表現は"3042" var hexOfCodePoint = codePointOfあ.toString(16); // \はエスケープシーケンスであるため、\自体を表現するにはエスケープが必要 -"\\u{" + hexOfCodePoint + "}"; // => "\\u{3042}" +console.log("\\u{" + hexOfCodePoint + "}"); // => "\\u{3042}" ``` 直接キーボードから入力が難しい特殊な文字や絵文字などは、Unicodeエスケープシーケンスを使うことでソースコード上に安全に書くことができます。 @@ -423,7 +423,8 @@ JavaScriptでは、ECMAScriptの関連仕様として国際化API(ECMAScript I // numericをtrueとすると数字が数値として比較されるようになる var collator = new Intl.Collator("ja", { numeric: true }); // collator.compareはsortに渡せる関数となっている -["1", "10", "2"].sort(collator.compare); // => ["1", "2", "10"] +var sortedValues = ["1", "10", "2"].sort(collator.compare); +console.log(sortedValues); // => ["1", "2", "10"] ``` 文字列の比較においては、単純な比較であれば、`===`(厳密比較演算子)や`>`(大なり演算子)を利用します。 diff --git a/test/lib/console-comment.js b/test/lib/console-comment.js new file mode 100644 index 0000000000..07e865a379 --- /dev/null +++ b/test/lib/console-comment.js @@ -0,0 +1,87 @@ +// MIT © 2017 azu +"use strict"; +const esprima = require("esprima"); +const esquery = require("esquery"); +const path = require("path"); +const ignoreFileList = [ + // 演算子はいいかな + "source/basic/operator", + // これもリテラルの話なので… + "source/basic/implicit-coercion" +]; +/** + * 変数を含んでいるか + * @param {Object} AST + * @returns {boolean} + */ +const isIncludeVariableInExpression = (AST) => { + // 例外 + // call({ x : 1}) + const Identifiers = esquery(AST, "*:not(Property) Identifier"); + if (Identifiers.length > 0) { + return true; + } + return false; +}; +/** + * コードで `評価式; // => 評価値` を利用している箇所で + * `console.log`を付けるかどうかを判定する + * https://github.com/asciidwango/js-primer/issues/195 + * + * - 基本的にはconsole.logを利用する + * - リテラルや変数が登場しないコードでは`console.log`を省いても良い + * + * lineが問題ある行ならばErrorオブジェクトを返す + * @param {string} text + * @param {string} filePath ファイルパスは無視したい対象の指定に使う + * @returns {Error|undefined} + */ +module.exports = function shouldConsoleWithComment(text, filePath) { + const lines = text.split("\n"); + // 1行以下なら無視する + if (lines.length <= 1) { + return; + } + lines.forEach(line => { + const error = checkLineThatShouldHaveComment(line, filePath); + if (error instanceof Error) { + throw error; + } + }); +}; +/** + * @param {string} line + * @param {string} filePath + * @returns {Error|undefined} + */ +function checkLineThatShouldHaveComment(line, filePath) { + if (!/\/\/\s*=>\s*/.test(text)) { + return; + } + if (text.includes("console.")) { + return; + } + // エラーの場合は無視 + if (/=>.*Error/.test(text)) { + return; + } + // template literalっぽいのは無視 + if (text.includes("`")) { + return; + } + + const AST = esprima.parse(text); + // 変数を含まないリテラルのみであるならパスする + if (!isIncludeVariableInExpression(AST)) { + return; + } + // 無視リストに含まれているなら無視 + const isIgnored = ignoreFileList.some(ignoreFilePath => { + return filePath.includes(path.normalize(ignoreFilePath)); + }); + if (isIgnored) { + return; + } + return new Error(`console.log(式); // => 評価結果 にそろえてください +該当コード: ${text}`); +} diff --git a/test/markdown-doc-test.js b/test/markdown-doc-test.js index 570b5e4e90..e3ffc749db 100644 --- a/test/markdown-doc-test.js +++ b/test/markdown-doc-test.js @@ -9,6 +9,7 @@ const sourceDir = path.join(__dirname, "..", "source"); const toDoc = require("power-doctest"); const remark = require("remark")(); const select = require('unist-util-select'); +const shouldConsoleWithComment = require('./lib/console-comment'); /** * 指定した文字列を含んだコードは実行環境によってはサポートされてないので無視する @@ -35,7 +36,11 @@ const disableComment = "disable-doc-test"; * CodeBlockは必ず実行できるとは限らないので、 * AssertionError(doctestにおける失敗)以外は成功したことにして無視する * Node.js v6はES2016-が実行できないのでスルーする - * 詳細は CONTRIBUTING.md を読む + * + * `console.log(式); // => 結果` の書式で書かれているをチェックする + * https://github.com/asciidwango/js-primer/issues/195 + * + * その他詳細は CONTRIBUTING.md を読む **/ describe("doctest:md", function() { const files = globby.sync([`${sourceDir}/**/*.md`, `!${sourceDir}/**/node_modules{,/**}`]); @@ -56,6 +61,8 @@ describe("doctest:md", function() { return codeValue.includes(version); }); try { + // console.logと// => の書式をチェック + shouldConsoleWithComment(codeBlock.value, filePath); const poweredCode = toDoc.convertCode(codeBlock.value, filePath); strictEval(poweredCode); } catch (error) {