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);
}
- asyncの戻り値はプロミスのインスタンスだが、
return
した場合は値をresolve
した場合と同じ動きをする様で、.then
で取得出来る様。
async/await 入門(JavaScript) - Qiita
でもこの使い方はしない方が良いのか?
プログラム内容
} 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を読んだりググったりした。ArrayPrompt
のChoice 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
次回は出来上がったコードをクラス化したい。
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インストールしてみた。
次回は他にも必要なライブラリを調べる
Node.jsでのCLIの作り方と便利なライブラリまとめ - Qiita
とりあえず動く様になった!
非同期処理
JavaScriptのコード
- 参考にしたもの
fetch呼び出しでasync/awaitを使わないパターン、使うパターン
fetch() - Web API | MDN
初めてのJavaScript 第3版 ―ES2015以降の最新ウェブ開発 | Ethan Brown, 武舎 広幸, 武舎 るみ |本 | 通販 | Amazon
書いてみたコード
<script>
fetch('https://bootcamp.fjord.jp/')
.then(function(response) {
return response.text();
})
.then(function(text) {
console.log(text);
});
</script>
・この状態でURLをタイポしてエラーにするとコンソールは下記の様に表示される。
・エラーの場合のコンソールへの出力を追加
<script>
fetch('https://bootcamp.fjord.jp/')
.then(function(response) {
return response.text();
})
.then(function(text) {
console.log(text);
})
.catch(err => {
console.log(err);
});
</script>
。。。長くて読みづらいので
<アロー関数に書き換え>
<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
コマンドを使っていたので、単体だとどうやるんだ😵となり参考にしました。
カレンダープログラム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は書き換えられていない様。
eslint実行方法
{
"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を開き、スペースの無い状態のコードを書き保存してみた。
保存されたファイルを開くと、きちんとスペースが入っていた!