javascriptクラス4

オプションrで選択したファイル内容を表示させるコード

  • 初めに書いたものはネストがすごく読みずらかった。
プログラム内容
 async function get_data() {
    const filedata = [];
    try {
      await fs.access(directoryPath, fs.constants.F_OK);
      const files = await fs.readdir(directoryPath);
      if (files.length === 0) {
        console.log("memoはありません");
      } else {
        for (let fileName of files) {
          const filePath = path.join(directoryPath, fileName);
          const text = await fs.readFile(filePath, { encoding: "utf8" });
          const firstLine = text.split("\n")[0];
          filedata.push({ message: firstLine, value: fileName });
        }

        const prompt = new Select({
          name: "file_name",
          message: "Choose a note you want to see:",
          choices: filedata,
        });
        prompt
          .run()
          .then((answer) => {
            console.dir(answer);
            
            async function output_text() {
              try {
                const fileContent = await fs.readFile(`./memolist/${answer}`, "utf8”);
                console.log(fileContent);
              } catch (err) {
                console.error(err.message);
              }
            }
            output_text();
          })
          .catch(console.error);
      }
    } catch (err) {
      if (err.code === "ENOENT") {
        console.log("memoはありません");
      } else {
        console.log(err);
      }
    }
  }
  get_data();
  • 下記に書き換えてみた所、choicesに値が入らない
    そもそも戻り値がプロミスのインスタンスなのでreturnと書いたところで戻り値にならない。
プログラム内容
} else if (argv.reference) {
  async function get_data() {
    const filedata = [];
    try {
      await fs.access(directoryPath, fs.constants.F_OK);
      const files = await fs.readdir(directoryPath);
      if (files.length === 0) {
        console.log("memoはありません");
      } else {
        for (let fileName of files) {
          const filePath = path.join(directoryPath, fileName);
          const text = await fs.readFile(filePath, { encoding: "utf8" });
          const firstLine = text.split("\n")[0];
          filedata.push({ message: firstLine, value: fileName });
        }
      }
    } catch (err) {
      if (err.code === "ENOENT") {
        console.log("memoはありません");
      } else {
        console.log(err);
      }
    }
    return filedata;
  }

  async function output_text() {
    try {
      const fileContent = await fs.readFile(`./memolist/${answer}`, "utf8");
      console.log(fileContent);
    } catch (err) {
      console.error(err.message);
    }
  }

  const arr = get_data();
  if (arr.length > 0) {
    const prompt = new Select({
      name: "file_name",
      message: "Choose a note you want to see:",
      choices: get_data(),
    });
    prompt
      .run()
      .then((answer) => {
        console.dir(answer);
        output_text();
      })
      .catch(console.error);
  }
プログラム内容
} else if (argv.reference) {
  async function get_data() {
    const filedata = [];
    try {
      await fs.access(directoryPath, fs.constants.F_OK);
      const files = await fs.readdir(directoryPath);
      if (files.length === 0) {
        console.log("memoはありません");
      } else {
        for (let fileName of files) {
          const filePath = path.join(directoryPath, fileName);
          const text = await fs.readFile(filePath, { encoding: "utf8" });
          const firstLine = text.split("\n")[0];
          filedata.push({ message: firstLine, value: fileName });
        }
      }
    } catch (err) {
      if (err.code === "ENOENT") {
        console.log("memoはありません");
      } else {
        console.log(err);
      }
    }
    return filedata;
  }

  async function output_text(answer) {
    try {
      const fileContent = await fs.readFile(`./memolist/${answer}`, "utf8");
      console.log(fileContent);
    } catch (err) {
      console.error(err.message);
    }
  }

  get_data().then((filedata) => {
    if (filedata.length > 0) {
      const prompt = new Select({
        name: "file_name",
        message: "Choose a note you want to see:",
        choices: filedata,
      });
      prompt
        .run()
        .then((answer) => {
          output_text(answer);
        })
        .catch(console.error);
    }
  });

さらに修正

async function get_data() {
    const filedata = [];
    try {
      await fs.access(directoryPath, fs.constants.F_OK);
      const files = await fs.readdir(directoryPath);
      if (files.length === 0) {
        console.log("memoはありません");
      } else {
        for (let fileName of files) {
          const filePath = path.join(directoryPath, fileName);
          const text = await fs.readFile(filePath, { encoding: "utf8" });
          const firstLine = text.split("\n")[0];
          filedata.push({ message: firstLine, value: fileName });
        }
      }
    } catch (err) {
      if (err.code === "ENOENT") {
        console.log("memoはありません");
      } else {
        console.log(err);
      }
    }
    return filedata;
  }

  async function output_text(filename) {
    try {
      const filePath = path.join(directoryPath, filename);
      const fileContent = await fs.readFile(filePath, "utf8");
      console.log(fileContent);
    } catch (err) {
      console.log(err);
    }
  }

//以下の部分を.thenではなく、awaitを使ったものに書き換えました。
  async function select_filename_and_show_content() {
    try {
      const filedata = await get_data();
      if (filedata.length > 0) {
        const prompt = new Select({
          name: "file_name",
          message: "Choose a note you want to see:",
          choices: filedata,
        });
        prompt
          .run()
          .then((filename) => {
            output_text(filename);
          })
          .catch(console.error);
      }
    } catch (err) {
      console.log(err);
    }
  }
  select_filename_and_show_content();

javascriptクラス3

やった事

  • 前回に引き続き、memolistディレクトリが無い場合の処理を書いた。

分かった事

コールバックで書くと、1つの処理ごとにエラー処理を書いた関数を作るので、いくつか順番に実行する時にすごく読みにくい。
async/awaitを使うと、nodeにある元からプロミスとなっているものを使い書けるのですごく楽。(例えばfsの場合、const fs = require("fs”).promisesすると初めからプロミスになっているものが使える)
エラーは最後にcatch文を入れて、そこに纏めることが出来るのですごく楽に書ける事が分かった!

エラー

下記のコードでエラーが出た

コード詳細
const filename = Math.random().toString(32).substring(2);
const data = [];
const directoryPath = './memolist';

async function checkDirectory(directoryPath){
  try{
//下記でawaitを入れ忘れていた
    fs.promises.access(directoryPath)
      }catch (err) {
      if (err.code === "ENOENT"){
        try{
          await fs.promises.mkdir(directoryPath);
        }catch (err) {
          console.error(err);
        }
     }else{
       console.error(err);
       }
    }
};

const reader = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
reader.on("line", (line) => {
  data.push(line);
});
reader.on("close", () => {
  async function get_fileData() {
    try{
      await checkDirectory(directoryPath);
      await fs.promises.writeFile(`./memolist/${filename}.txt`,data.join("\n"))
    }catch (err) {
      console.error(err);
  }
}
get_fileData();
});

エラー内容

node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[Error: ENOENT: no such file or directory, access './memolist'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'access',
  path: './memolist'
}

awaitを入れ忘れたのが原因だが、プロミスを実行する順番がよく理解出来て良かった。
この記事が分かりやすく説明してくれて参考になった。
then メソッドは常に新しい Promise を返す|イベントループとプロミスチェーンで学ぶJavaScriptの非同期処理

fs.promises.〜としているのは、const fs = require("fs”);の部分をconst fs = require("fs”).promises;と書き換えた。

javascriptクラス2

readline

Node.jsで、ファイルから1行ずつ読み込むためのreadlineモジュール - Qiita

enquirer

メモ1行目のリストを表示し(Select)、選択されたもののファイル名を取得したい。
が、やり方が全く分からずひたすらREADMEを読んだりググったりした。
ArrayPromptChoice propertiesについての説明で使えそうなオプションがあり、使ってみた所うまくいった。
enquirer/enquirer: Stylish, intuitive and user-friendly prompts, for Node.js. Used by eslint, webpack, yarn, pm2, pnpm, RedwoodJS, FactorJS, salesforce, Cypress, Google Lighthouse, Generate, tencent cloudbase, lint-staged, gluegun, hygen, hardhat, AWS Amplify, GitHub Actions Toolkit, @airbnb/nimbus, and many others! Please follow Enquirer's author: https://github.com/jonschlinkert

Pasted Graphic.png

次回は出来上がったコードをクラス化したい。

javascriptクラス1

やった事

  • 標準入力を受け取れる様にした
  • Yargsをインストールして使い方を調べた

参考にしたもの

標準入力

【Node.js Tips】定番のCLI用パッケージyargsの使い方
リードライン | Node.js v19.8.1 ドキュメント

yargs

yargs
Node.jsで定番のCLI用パッケージyargsを理解する | マサトッシュブログ

npmインストールするとpackge.jsonとpackge-lock.jsonにも反映されるので、npmインストールしてみた。

npm i yargs.png

次回は他にも必要なライブラリを調べる
Node.jsでのCLIの作り方と便利なライブラリまとめ - Qiita

とりあえず動く様になった!

非同期処理

JavaScriptのコード

書いてみたコード
<プロミスを使ったもの>
<script>
    fetch('https://bootcamp.fjord.jp/')
    .then(function(response) { 
      return response.text();
    })
    .then(function(text) {
      console.log(text);
    });
</script>   

・この状態でURLをタイポしてエラーにするとコンソールは下記の様に表示される。

to fetch.png

・エラーの場合のコンソールへの出力を追加

<script>
    fetch('https://bootcamp.fjord.jp/')
    .then(function(response) { 
      return response.text();
    })
    .then(function(text) {
      console.log(text);
    })
    .catch(err => {
      console.log(err);
    });
</script>  

TypeError Failed to fetch.png

。。。長くて読みづらいので
<アロー関数に書き換え>

<script>
    fetch('https://bootcamp.fjord.jp/')
    .then(response => response.text())
    .then(text => {
      console.log(text);
    })
    .catch(err => {
      console.log(err);
    });
</script> 

ラクティスで指定された
<async/awaitを使ったものに書き換え>

<script>
  async function get_data() {
    try{
      const response = await fetch('https://bootcamp.fjord.jp/');
      const text = await response.text();
      console.log(text);
    }catch(err) {
      console.log(err);
    }
  }
  get_data();
</script>   

prettier

prettierをかけようとして、今までESlintと一緒にnpm runコマンドを使っていたので、単体だとどうやるんだ😵となり参考にしました。

npmとnpxの違いを理解して使い分けられるようになろう

カレンダープログラムJavaScript版

minimist

コードを書いて実行しようとしてエラーが出た。
どうやらnpmインストールが必要らしい。

> npm install minimist

すると、package-lock.jsonとpackage.jsonにも内容が追記され、エラーが出たファイルも無事実行出来る様になった。

リファレンス

下記を読みながら、少しコードを書いた。
標準組み込みオブジェクト - JavaScript | MDN
コードの書き方がrubyと違うのですごく書きづらく、一度心折れる😑

 

ESLintとPrettier

やった事

  • コマンドラインでESLintを使えるようにする。
  • 自分のエディターでESLintを使えるようにする。(常にLintが動くようにする)
  • コマンドラインでPrettierを使えるようにする。
  • 自分のエディターでPrettierを使えるようにする。(常にFormatが動くようにする)

ESLint

ESLint をグローバルにインストールせずに使う - Qiita

npm のエコシステムでは、コマンドもプロジェクト ローカルにインストールして使うのが主流です。
そうすることで、package.jsonに依存バージョンとともに記述して共有することができます。
npm install 一発で、チームが同じ環境を揃えられるわけですね。

js-practices/02.calendar でESLintを使えるようにしたい

同じ環境の01.fizzbuzzで色々やってみた

分からなかった事

01.fizzbuzzのフォルダで

npm install --save-dev eslint

とし、eslintをインストールしてみたが、元からあったpackage-lock.jsonとバージョンが変わりpackage-lock.jsonが書き換えられてしまう。
package.jsonの内容を基に選ばれたバージョンだからそれでいいのかとも思ったが、依存関係など関係しているのか変更内容がすごい事に😵
package-lock.jsonがあるからこれと同じ環境にしなければいけないのか?と思い、色々ググってみた。

解決方法

npm ciというコマンドを使うと、「package-lock.json から依存関係をインストールします」とある。
npm ciを使おう あるいはより速く - Qiita
実行後にgit diffしてみても何も出てこないので、package-lock.jsonは書き換えられていない様。

added 113 packages, and audited 114 packages in 1s.png

eslint実行方法

01.fizzbuzz/package.json

{
  "scripts": {
    "fix": "prettier --write . && eslint --fix .",
    "lint": "prettier --check . && eslint ."
  },
  "devDependencies": {
    "eslint": "^8.24.0",
    "eslint-config-prettier": "^8.5.0",
    "prettier": "^2.7.1"
  }
}

package.json"scripts": { }内に記述するとnpm runで使える様になる。
だからnpm run lintで prettier --check . && eslint .を実行してくれる。
ESLint をグローバルにインストールせずに使う

VSCodeのESLintの設定

VSCodeでESLintを使いましょう
を読んだけど、他の設定はほぼ終わっていたので、結局VSCodeに「ESLint」というプラグインをインストールするだけで良かった。

VSCodeのPrettierの設定

【自動整形】VSCodeでPrettierを使う方法【設定必要です】 | RalaCode
この通りに設定した。

試しにVSCodeを開き、スペースの無い状態のコードを書き保存してみた。

Pasted Graphic 10.png

保存されたファイルを開くと、きちんとスペースが入っていた!

for (let x = 1; X  21; X++).png