archive用のソースを追加する

This commit is contained in:
ry.yamafuji 2025-03-20 21:56:10 +09:00
parent 183eb20fd9
commit 4ff8259c17
25 changed files with 2586 additions and 3 deletions

4
.gitignore vendored
View File

@ -130,3 +130,7 @@ dist
.yarn/install-state.gz
.pnp.*
csv_output/
output/
output.*
docments/

View File

@ -1,7 +1,7 @@
# js-common-code
Javascriptで活用できるコードを開発する。
Node.jsによりサーバーサイドも作成する
Node.jsによりサーバーサイドも作成

156
docs/archive.md Normal file
View File

@ -0,0 +1,156 @@
# [Node.js]ファイルをZIP圧縮してダウンロードする方法
## 圧縮処理について
* 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
* 方法2:サーバサイドで圧縮処理しファイルを出力する
* 方法3:サーバサイドで圧縮処理しフロントでBlobによりファイルを取得する
### 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
* **ファイル量が多い場合(30MB以上など)はサーバーサイドで処理するほうがいい**
* 大容量データの処理には向かない
* ユーザーのデバイスの性能に依存する
```mermaid
sequenceDiagram
User->>Front: ダウンロードボタンを要求する
loop ファイル毎に処理する
Front->>Storage: ファイルを要求する(fetch)
Storage-->>Front: ファイル情報を返す
end
Front-->>Front: Zip処理を実行する(JSZip)
Front-->>User: ダウンロード処理を実行する(blob)
```
* https://stuk.github.io/jszip/documentation/examples.html
* [サンプルコード](../src/front/assets/download.js)
```
import JSZip from "jszip";
```
**CDNでインポートする場合**
```js
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
```
---
### 方法2:サーバサイドで圧縮処理しファイルを出力する
サーバーサイドでarchiverを使ってZIPを作成し、
一時ファイルとして保存してからダウンロード用のURLを返します
* archiverモジュールで実行する
* Zipファイルの保存のためにストレージが別で必要
* ライフサイクルを考慮しないと不要なファイルが溜まる
* 大容量データの圧縮に適してい
* 複数のリクエストに対応しやすい
```mermaid
sequenceDiagram
User->>Front: ダウンロードボタンを要求する
Front->>Server: ダウンロードを要求する
Server->>Storage: ファイルデータ取得API
Storage->>Server: レスポンス
Server->>Server: Zip処理を実行する(archiver)
Server->>Storage: 作成した Zipを保存する
Storage->>Server: レスポンス
Server-->>Front: ファイルのURLを返す
Front->>Storage: URLをリンクする(HTTP)
Storage-->>User: ファイルをダウンロードする
```
```sh
npm install archiver
```
---
### 方法3:サーバサイドで圧縮処理しフロントでBlobによりファイルを取得する
ZIPを一時ファイルとして保存せずに
直接フロントエンドにストリームとして送信します。
* archiverモジュールで実行する
* 保存せずにファイルコンテンツを返す
* リアルタイムでファイルをストリーミング可能
* ストレージの管理が不要
* クライアントがダウンロードを途中でキャンセルするとデータが失われる可能性がある
```mermaid
sequenceDiagram
User->>Front: ダウンロードボタンを要求する
Front->>Server: ダウンロードを要求する
Server->>Storage: ファイルデータ取得API
Storage->>Server: レスポンス
Server->>Server: Zip処理を実行する(archiver)
Storage->>Front: Zipされたファイルコンテンツを返す
Front-->>User: ダウンロード処理を実行する(blob)
```
## サンプルソース
### Blobを使用してZIPファイルを処理する(フロント側の処理)**
```js
fetch("https://example.com/sample.zip")
.then(response => response.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "downloaded.zip";
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
})
.catch(error => console.error("Error downloading ZIP:", error));
```
#### Gloudにあるファイルをzip形式でファイルを出力するサンプルソース
(スクリプト)
```js
const { Storage } = require('@google-cloud/storage');
const archiver = require('archiver');
const fs = require('fs');
const storage = new Storage();
const bucketName = 'your-bucket-name';
const filesToDownload = ['file1.csv', 'file2.csv']; // 圧縮したいファイルリスト
const outputZip = 'output.zip';
async function downloadAndZip() {
const output = fs.createWriteStream(outputZip);
const archive = archiver('zip', { zlib: { level: 9 } });
output.on('close', () => {
console.log(`Zip file created: ${outputZip} (${archive.pointer()} bytes)`);
});
archive.pipe(output);
for (const fileName of filesToDownload) {
const file = storage.bucket(bucketName).file(fileName);
const [exists] = await file.exists();
if (exists) {
console.log(`Adding ${fileName} to archive...`);
archive.append(file.createReadStream(), { name: fileName });
} else {
console.warn(`File not found: ${fileName}`);
}
}
archive.finalize();
}
downloadAndZip().catch(console.error);
```

View File

@ -0,0 +1,56 @@
# [GCP][GCS]ファイルのライフサイクルと運用について
* [[GCP]Google Cloud Storageを活用する・静的ファイルをデプロイする方法](https://wiki.pglikers.com/en/private/cloud/gcp/gcs/hosting)
## Bucketのファイルにライフサイクルを設定する
- **活用できるユースケース**
- ○○日経過にファイルを削除する
[公式ドキュメント](https://cloud.google.com/storage/docs/lifecycle?hl=ja)
### GUIでの設定
1. Google Cloudコンソールで、Cloud Storageの[バケット]を開く
* https://console.cloud.google.com/storage/browser?hl=ja
2. 対象のBucketを開く
3. `ライフサイクル`タブを押下する
4. ルールを追加する
### コマンドで設定する場合
#### 1. 構成ファイルを作成する
1日経過後に削除する場合の構成
[(構成についてはこちら)](https://cloud.google.com/storage/docs/lifecycle-configurations?hl=ja)
```json
{
"lifecycle": {
"rule": [
{
"action": { "type": "Delete" },
"condition": {
"age": 1
}
}
]
}
}
```
#### 2. ライフサイクル構成を設定する
```sh
cloud storage buckets update gs://BUCKET_NAME \
--lifecycle-file=LIFECYCLE_CONFIG_FILE
```
- LIFECYCLE_CONFIG_FILEは、作成したJSONファイルのパスです
#### ライフサイクル構成を削除する場合のコマンド
```sh
gcloud storage buckets update gs://BUCKET_NAME --clear-lifecycle
```

15
docs/httpserver.md Normal file
View File

@ -0,0 +1,15 @@
## NodeでHttpサーバーを起動する方法
### `http-server`を使う
```sh
# http-server をグローバルインストール(初回のみ)
npm install -g http-server
# ファイルがあるディレクトリへ移動
cd src/front
# サーバー起動(デフォルトは http://localhost:8080
http-server
# http-server -p 3000
```

130
docs/jsDoc.md Normal file
View File

@ -0,0 +1,130 @@
# [Javascript][JSDoc]ドキュメントを自動生成する(TypeScript対応)
* JSDocコメントの有効活用
* JavaScriptやTypeScriptのドキュメントを生成する方法
- [\[Javascript\]\[JSDoc\]ドキュメントを自動生成する(TypeScript対応)](#javascriptjsdocドキュメントを自動生成するtypescript対応)
- [インストール方法](#インストール方法)
- [packeage.jsonの設定](#packeagejsonの設定)
- [TypeScriptの場合](#typescriptの場合)
- [書き方について](#書き方について)
- [ファイルを出力する](#ファイルを出力する)
- [1つの対象ファイルを出力する](#1つの対象ファイルを出力する)
- [markdownで出力する場合](#markdownで出力する場合)
- [HTMLで出力する場合](#htmlで出力する場合)
## インストール方法
```sh
npm install jsdoc -D
```
### packeage.jsonの設定
スクリプトを記載する
`-r`オプションを用いて、出力させたい対象のフォルダーを指定します
```json
{
"scripts": {
"doc": "jsdoc -r src"
}
}
```
### TypeScriptの場合
インストール方法
```sh
npm install typedoc -D
```
packeage.jsonの設定
```json
{
"scripts": {
"doc": "typedoc --entryPointStrategy expand ./src"
}
}
```
tsconfig.jsonファイルの設定
```json
{
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"sourceMap": true,
"strict": true
},
"exclude": [
"node_modules"
]
}
```
## 書き方について
JSDocはJavascriptのコメントルールです
VSCodeとの相性が良い。プラグインなしで自動で生成できる
* コメントが必要なところで`/**`を入力すると自動的に生成される
* autocompleteが自動に表示しますので、`Enter`を入力する
```js
/**
```
## ファイルを出力する
### 1つの対象ファイルを出力する
#### markdownで出力する場合
**markdownのモジュールをインストール**
```sh
npm install -g jsdoc-to-markdown
```
**ファイルを出力する**
```sh
npx jsdoc-to-markdown your-file.js > output.md
# npx jsdoc-to-markdown src/script/sampleScript.js > output.md
```
#### HTMLで出力する場合
**ファイルを直接指定する場合**
```sh
jsdoc your-file.js -d doc
# jsdoc src/script/sampleScript.js -d docments
```
**設定ファイルを仕様する場合**
`jsdoc.json`を生成する
```json
{
"source": {
"include": ["src/script/sampleScript.js"]
},
"opts": {
"destination": "./docments"
}
}
```
**ファイルを出力する**
```sh
jsdoc -c jsdoc.json
```

319
docs/mermaid.md Normal file
View File

@ -0,0 +1,319 @@
# 【Mermaid】概要及び基本的な使い方
- [【Mermaid】概要及び基本的な使い方](#mermaid概要及び基本的な使い方)
- [各図形の基本的な書き方](#各図形の基本的な書き方)
- [フローチャート図](#フローチャート図)
- [シーケンス図](#シーケンス図)
- [クラス図](#クラス図)
- [ER図(データ概念図 CDMD)](#er図データ概念図-cdmd)
- [アーキテクチャ図](#アーキテクチャ図)
- [ガントチャート](#ガントチャート)
- [図形の設定について](#図形の設定について)
- [テーマの設定](#テーマの設定)
- [Tips](#tips)
- [VSCodeにスぺニットを設定する(シーケンス図)](#vscodeにスぺニットを設定するシーケンス図)
**(参考リンク)**
* [公式サイト](https://mermaid.js.org/intro/)
* [公式 WEB Editor](https://mermaid.live/edit#p)
* [notepm-Mermaid記法の書き方](https://help.notepm.jp/hc/ja/articles/17267311368729-Mermaid%E8%A8%98%E6%B3%95%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9-Markdown%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%A7%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88-%E3%82%B0%E3%83%A9%E3%83%95%E3%81%8C%E6%8F%8F%E3%81%91%E3%82%8B-
)
Mermaidが対応していないコンテンツでも公式サイトのエディタを
活用することで図形をリンクさせることが可能です
---
## 各図形の基本的な書き方
### フローチャート図
````
```mermaid
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
```
````
```mermaid
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
```
### シーケンス図
* **古いバージョンではactor、participantが対応していない**
````
```mermaid
sequenceDiagram
actor User
participant Front
participant Server
User->>Front: URLをリンクする
Front-->>User: 一覧画面を表示する
User->>Front: 検索する
loop 対象商品
Front->>Server: 商品情報を取得する
Server-->>Front: レスポンス
end
Front-->>User: 検索結果を表示する
Note right of Front: Product Find <br/>sequence
```
````
[![sequence](https://mermaid.ink/img/pako:eNptkU9LwzAYxr9KyHnFe5GexJOKOHaRXmKTbYU1qVkiyBi4Fr14UPyLsIkbQ0WEMVRwCvsysev8FqatpYi7Je_7e9734X1a0GGYQBM2ya4k1CErLqpx5NncpgAgRzAOKk3Cs7-PuHAd10dUgFXOqPhfLhO-l-GJzLCslDNBZWtNBWcqfFLhiwpGqnOjguMES_uGBhPeBF_vB_P7h_ji87s30IJ5_zEefhT036GzYTd-HRTdBmM-iEbT-bgfXR5F551igWVlzkyQdWbhYXQ31huik6toel3MyDCjWKLCZxVMVNhLnU8ShlC8wHrmJn47nd12F1jfYIIA7tbqArAq-B2-yRmWjr6mSzFY3uFLVh5EIoEl6BHuIRfrhFrJqW0o6sQjNjT1E5Mqkg1hQ5u2NYqkYOV96kBTcElKUPoYiTxQaFZRo6mrBLs61PUs9TT8EuRM1uq5TMe4zVguaP8AZJXvtw?type=png)](https://mermaid.live/edit#pako:eNptkU9LwzAYxr9KyHnFe5GexJOKOHaRXmKTbYU1qVkiyBi4Fr14UPyLsIkbQ0WEMVRwCvsysev8FqatpYi7Je_7e9734X1a0GGYQBM2ya4k1CErLqpx5NncpgAgRzAOKk3Cs7-PuHAd10dUgFXOqPhfLhO-l-GJzLCslDNBZWtNBWcqfFLhiwpGqnOjguMES_uGBhPeBF_vB_P7h_ji87s30IJ5_zEefhT036GzYTd-HRTdBmM-iEbT-bgfXR5F551igWVlzkyQdWbhYXQ31huik6toel3MyDCjWKLCZxVMVNhLnU8ShlC8wHrmJn47nd12F1jfYIIA7tbqArAq-B2-yRmWjr6mSzFY3uFLVh5EIoEl6BHuIRfrhFrJqW0o6sQjNjT1E5Mqkg1hQ5u2NYqkYOV96kBTcElKUPoYiTxQaFZRo6mrBLs61PUs9TT8EuRM1uq5TMe4zVguaP8AZJXvtw)
APIのサンプル例
```mermaid
sequenceDiagram
App ->> API: request
alt OK
API -->> App: 200
else error
API -->> App: 400
end
```
### クラス図
````
```mermaid
classDiagram
Animal <|-- Duck
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Zebra{
+bool is_wild
+run()
}
```
````
```mermaid
classDiagram
Animal <|-- Duck
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Zebra{
+bool is_wild
+run()
}
```
### ER図(データ概念図 CDMD)
データベースのスキーマを表現したりするのに使われるER図です
「概念データモデルCDM: Conceptual Data Model
````
```mermaid
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
````
```mermaid
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
(リレーション用のsymbol)
* `||--||` : 1対1 (One to One)
* `}o--||` : 多対1 (Many to One)
* `o{--||` : 1対多 (One to Many)
* `}o--o{` : 多対多 (Many to Many)
### アーキテクチャ図
**古いバージョンではアーキテクチャ図が対応していない**
````
```mermaid
architecture-beta
group public_api(cloud)[Public API]
group private_api(cloud)[Private API] in public_api
service database(database)[Database] in private_api
service server(server)[Server] in private_api
server:R -- L:database
```
````
[![](https://mermaid.ink/img/pako:eNptkMFqwzAQRH9F7MkG-wd0K-RSaCE0t1qlrKWNLbAlsZYCJeTfK9sVTUN12WH1ZhbmCtobAgnIerSRdExMbU8RFSsn8hvYpyBC6ierPzHYSk8-mbo7bhvxdHz-eEDZXjDSH3ZfbbCw7i6tWBfii9UkDEbscaGqiLo7_Kjd-Rv-aF0ncbWPujtt8z_TvZFYvom2FS-yHFx_oYGZeEZrcjPXlVYQR5pJgczS0BnTFBUod8sopuhPX06DjJyogRRyFh0sDoxzWZKx0fPrXvbWeQO5rmEsQED37n3mzzgtdPsG-VmP1Q?type=png)](https://mermaid.live/edit#pako:eNptkMFqwzAQRH9F7MkG-wd0K-RSaCE0t1qlrKWNLbAlsZYCJeTfK9sVTUN12WH1ZhbmCtobAgnIerSRdExMbU8RFSsn8hvYpyBC6ierPzHYSk8-mbo7bhvxdHz-eEDZXjDSH3ZfbbCw7i6tWBfii9UkDEbscaGqiLo7_Kjd-Rv-aF0ncbWPujtt8z_TvZFYvom2FS-yHFx_oYGZeEZrcjPXlVYQR5pJgczS0BnTFBUod8sopuhPX06DjJyogRRyFh0sDoxzWZKx0fPrXvbWeQO5rmEsQED37n3mzzgtdPsG-VmP1Q)
### ガントチャート
````
```mermaid
gantt
title work
dateFormat YYYY-MM-DD
section work_A
準備 :a1 ,2023-08-12 ,1d
作業 :a2 ,2023-08-14 ,2d
リリース :a3 ,after a2 ,1d
section work_B
準備 :b1 ,after a2 ,1d
作業_1 :b2 ,after b1 ,3d
作業_2 :b3 ,after b1 ,2d
リリース :b4 ,after b2 ,1d
```
````
```mermaid
gantt
title work
dateFormat YYYY-MM-DD
section work_A
準備 :a1 ,2023-08-12 ,1d
作業 :a2 ,2023-08-14 ,2d
リリース :a3 ,after a2 ,1d
section work_B
準備 :b1 ,after a2 ,1d
作業_1 :b2 ,after b1 ,3d
作業_2 :b3 ,after b1 ,2d
リリース :b4 ,after b2 ,1d
```
## 図形の設定について
### テーマの設定
**参考記事:**
* [zenn-Mermaid のテーマ・スタイルの変更方法](https://zenn.dev/junkawa/articles/zenn-mermaidjs-theme-config)
```sh
%%{init:{'theme':'base'}}%%
```
**default**
設定しない場合もこのスタイルになります
```mermaid
%%{init:{'theme':'default'}}%%
graph LR
q(QEMU) --> qemu-boot-shim --> physboot --> zircon
```
**base**
```mermaid
%%{init:{'theme':'base'}}%%
graph LR
q(QEMU) --> qemu-boot-shim --> physboot --> zircon
```
**forest**
```mermaid
%%{init:{'theme':'forest'}}%%
graph LR
q(QEMU) --> qemu-boot-shim --> physboot --> zircon
```
**dark**
```mermaid
%%{init:{'theme':'dark'}}%%
graph LR
q(QEMU) --> qemu-boot-shim --> physboot --> zircon
```
**neutral**
```mermaid
%%{init:{'theme':'neutral'}}%%
graph LR
q(QEMU) --> qemu-boot-shim --> physboot --> zircon
```
## Tips
### VSCodeにスぺニットを設定する(シーケンス図)
1. [Ctrl] + [Shift] + [P]を入力する
2. "Snippets: Configure Snippets"を入力する
3. mermaid.jsonというスニペットファイルを作成する
4. 使って確かめてみる
1. Mermaidをサポートするファイルを開く(.mdまたは.mmd)
2. "mermaid:sequence"と入力する
3. Tabキーを押下する
```json
{
"Mermaid sequence Diagram": {
"prefix": "mermaid:sequence",
"body": [
"sequenceDiagram",
" actor User",
" participant Front",
" participant Server",
" User->>Front: Click Button",
" Front->>Server: Request Data",
" Server-->>Front: Return Data",
" Front-->>User: Display Data"
],
"description": "Create a sequence diagram"
}
}
```
でない場合はデフォルトでスニペットが無効に
なっている場合があります
markdownでも有効にする場合は`markdown.json`に以下を追記する
```json
"Mermaid sequence Diagram": {
"prefix": "mermaid:sequence",
"body": [
"```mermaid",
"sequenceDiagram",
" actor User",
" participant Front",
" participant Server",
" User->>Front: Click Button",
" Front->>Server: Request Data",
" Server-->>Front: Return Data",
" Front-->>User: Display Data",
"```"
],
"description": "Create a sequence diagram"
}
```

95
docs/vs-code-md.md Normal file
View File

@ -0,0 +1,95 @@
# [VSCODE]MarkDownを活用する
- [\[VSCODE\]MarkDownを活用する](#vscodemarkdownを活用する)
- [ライブラリ・機能一覧](#ライブラリ機能一覧)
- [基本的な操作](#基本的な操作)
- [Markdown All in One](#markdown-all-in-one)
- [Markdown PDF](#markdown-pdf)
- [Markdown Preview Enhanced](#markdown-preview-enhanced)
- [Markdown Preview Mermaid Support](#markdown-preview-mermaid-support)
- [Markdown Table](#markdown-table)
- [Excel to Markdown table](#excel-to-markdown-table)
- [Tips](#tips)
- [目次作成機能](#目次作成機能)
**(参考リンク)**
* [github markdown-preview-enhanced](https://github.com/shd101wyy/markdown-preview-enhanced/blob/master/docs/ja-jp/file-imports.md)
* [qiita 便利な拡張機能5選](https://qiita.com/sola-msr/items/cfe448db958da3d08863#excel-to-markdown-table)
## ライブラリ・機能一覧
* Markdown All in One
* Markdown PDF
* Markdown Preview Enhanced :PDF出力機能
### 基本的な操作
#### Markdown All in One
1. キーボードショートカット機能
1. コード入力候補/補助
2. 目次作成機能(ctrl+shift+p -> Markdown All in One: Create Table of Contents)
3. 自動補完機能
1. 見出しナンバリング
2. リスト編集補完
3. HTML変換機能
4. その他機能
1. 数式機能
2. テーブル等幅機能
5. 画像リンク貼付機能
コード入力候補/補助
#### Markdown PDF
1. PDF出力機能
#### Markdown Preview Enhanced
(サイド:Ctrl+K -> V,全面:ctrl+shift+v)
1. 拡張性の高いマークダウンのプレビュー拡張機能
2. ファイル分割機能
##### Markdown Preview Mermaid Support
MermaidをViewに表示できるようにする
[【Mermaid】概要及び基本的な使い方](https://wiki.pglikers.com/en/private/docs/markdown/mermaid)
#### Markdown Table
1. 等幅機能、入力補完機能:テーブルを作成中に[`Tab`]キーを使用する
#### Excel to Markdown table
エクセル、スプレッドシートからテーブルをコピーする
(Shift + Alt + v )
- Markdown Preview Mermaid Support : MermaidをViewに表示できるようにする
---
## Tips
### キーボードショートカット機能
| キー | 説明 |
| ---------------- | ---------------------------- |
| **Ctrl+B** | 選択した文字の太字にする。 |
| **Ctrl+I** | 文字を斜体 |
| **Ctrl+K -> V** | エディタの横にプレビュー表示 |
| **Ctrl+Shift+]** | 見出しレベルを上げる |
| **Ctrl+Shift+[** | 見出しレベルを下げる |
| Ctrl+M | 数式入力の文字入れる($$) |
| Alt+C | チェックリストのオンオフ |
| Ctrl+Shift+V | プレビューの表示切替 |
### 目次作成機能
1. [`ctrl` +`shift` + `p`]
2. "Markdown All in One: Create Table of Contents"を選択する

1244
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,5 +10,12 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"archiver": "^7.0.1",
"csv-writer": "^1.6.0"
},
"devDependencies": {
"jsdoc": "^4.0.4"
}
}

70
src/classes/TimeWatch.js Normal file
View File

@ -0,0 +1,70 @@
/**
* TimeWatch class
* @class
* @classdesc TimeWatch class to measure elapsed time
*/
class TimeWatch{
/**
* TimeWatch constructor
* @constructor
* @description TimeWatch constructor
* @param {number} startTime - start time
* @param {number} endTime - end time
*/
constructor(){
this.startTime = 0;
this.endTime = 0;
}
/**
* Start the timer
* @function
* @description Start the timer
*/
start(){
this.startTime = new Date().getTime();
}
/**
* Stop the timer
* @function
* @description Stop the timer
*/
stop(){
this.endTime = new Date().getTime();
}
/**
* Get the elapsed time
* @function
* @description Get the elapsed time
* @param {string} unit - unit of time (ms, s, min, h)
* @returns {number} - elapsed time
*/
getElapsedTime(unit = "ms") {
const elapsedTime = this.endTime - this.startTime;
switch (unit) {
case "s":
return elapsedTime / 1000;
case "min":
return elapsedTime / (1000 * 60);
case "h":
return elapsedTime / (1000 * 60 * 60);
case "ms":
default:
return elapsedTime;
}
}
/**
* Print the elapsed time
* @function
* @description Print the elapsed time
* @param {string} unit - unit of time (ms, s, min, h)
*/
printElapsedTime(unit = "ms") {
console.log(`Elapsed Time: ${this.getElapsedTime(unit)} ${unit}`);
}
}
// commonJS module
module.exports = TimeWatch;

View File

@ -0,0 +1,11 @@
ID,Name,Age,Email
1,User_1,44,user1@example.com
2,User_2,20,user2@example.com
3,User_3,67,user3@example.com
4,User_4,49,user4@example.com
5,User_5,56,user5@example.com
6,User_6,63,user6@example.com
7,User_7,31,user7@example.com
8,User_8,67,user8@example.com
9,User_9,41,user9@example.com
10,User_10,30,user10@example.com
1 ID Name Age Email
2 1 User_1 44 user1@example.com
3 2 User_2 20 user2@example.com
4 3 User_3 67 user3@example.com
5 4 User_4 49 user4@example.com
6 5 User_5 56 user5@example.com
7 6 User_6 63 user6@example.com
8 7 User_7 31 user7@example.com
9 8 User_8 67 user8@example.com
10 9 User_9 41 user9@example.com
11 10 User_10 30 user10@example.com

View File

@ -0,0 +1,11 @@
ID,Name,Age,Email
1,User_1,37,user1@example.com
2,User_2,30,user2@example.com
3,User_3,63,user3@example.com
4,User_4,42,user4@example.com
5,User_5,31,user5@example.com
6,User_6,63,user6@example.com
7,User_7,28,user7@example.com
8,User_8,20,user8@example.com
9,User_9,42,user9@example.com
10,User_10,69,user10@example.com
1 ID Name Age Email
2 1 User_1 37 user1@example.com
3 2 User_2 30 user2@example.com
4 3 User_3 63 user3@example.com
5 4 User_4 42 user4@example.com
6 5 User_5 31 user5@example.com
7 6 User_6 63 user6@example.com
8 7 User_7 28 user7@example.com
9 8 User_8 20 user8@example.com
10 9 User_9 42 user9@example.com
11 10 User_10 69 user10@example.com

View File

@ -0,0 +1,79 @@
/**
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
*/
// ダウンロードボタン
const downloadButton = document.getElementById('download-button');
const downloadButtonFile = document.getElementById('download-button-file');
// ダウンロードボタンを押下した時の処理を記載する
downloadButton.addEventListener('click', async () => {
// ダウンロードボタンを無効化する
downloadButton.disabled = true;
// ダウンロード処理を実行する
try {
const zip = new JSZip();
// ZIPにファイルを追加
zip.file("hello.txt", "Hello, this is a ZIP file!");
zip.file("world.txt", "Hello, this is a ZIP file!");
// ZIPを生成してダウンロード
const zipBlob = await zip.generateAsync({ type: "blob" });
const a = document.createElement("a");
a.href = URL.createObjectURL(zipBlob);
a.download = "example.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
} finally {
// ダウンロードボタンを有効化する
downloadButton.disabled = false;
}
});
downloadButtonFile.addEventListener('click', async () => {
// ダウンロードボタンを無効化する
downloadButtonFile.disabled = true;
try {
const files = [
{ name: "text1.csv", url: "assets/data/test_data_1.csv" },
{ name: "text2.csv", url: "assets/data/test_data_2.csv" }
];
const zip = new JSZip();
// CSV ファイルを取得して ZIP に追加
await Promise.all(
files.map(async (file) => {
const response = await fetch(file.url);
if (!response.ok) throw new Error(`Failed to fetch ${file.name}`);
const text = await response.text();
zip.file(file.name, text);
})
);
// ZIP を生成してダウンロード
zip.generateAsync({ type: "blob" }).then((blob) => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "files.zip";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}).catch(console.error)
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
}
finally {
// ダウンロードボタンを有効化する
downloadButtonFile.disabled = false;
}
});

13
src/front/assets/lib/jszip.min.js vendored Normal file

File diff suppressed because one or more lines are too long

16
src/front/download.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<title>Download</title>
</head>
<body>
<h1>JavaScript Develop Download To Front Side</h1>
<p >Zip File Download</p>
<button id="download-button">Zip Download(From Content)</button>
<button id="download-button-file">Zip Download(From File)</button>
<script src="assets/download.js"></script>
</body>
</html>

View File

@ -8,6 +8,6 @@
<body>
<h1>JavaScript Develop Debug</h1>
<p id="message">Open the console to see the output</p>
<script src="index.js"></script>
<script src="assets/index.js"></script>
</body>
</html>

129
src/script/archiveFiles.js Normal file
View File

@ -0,0 +1,129 @@
/**
* @requires archiver
* - npm install archiver
* @example
* node src/script/archiveFiles.js data output.zip
*/
const archiver = require('archiver');
const fs = require('fs');
const path = require('path');
const TimeWatch = require('../classes/TimeWatch');
/**
* 特定のディレクトリからzipファイルを作成する
*
* @param {*} sourceDir
* @param {*} outputFilePath
* @returns
*/
const createZipFile = (sourceDir, outputFilePath) => {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outputFilePath);
const archive = archiver('zip', {
zlib: { level: 9 } // 圧縮レベル
});
output.on('close', () => {
console.log(`ZIPファイル作成完了: ${outputFilePath}`);
resolve();
});
archive.on('error', (err) => {
reject(err);
});
archive.pipe(output);
archive.directory(sourceDir, false);
archive.finalize();
});
};
/**
* ディレクトリのサイズを測定する
* @description デバッグ用途で本番ではコメントアウトする
* @param {*} dir
* @returns
*/
const _debugDirectorySize = (dir) => {
let size = 0;
const files = fs.readdirSync(dir);
for (let file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isFile()) {
size += stat.size;
} else if (stat.isDirectory()) {
size += _getDirectorySize(filePath);
}
}
// デバッグ用にサイズを表示する
if (size < 1000) {
// 1000バイトまでの場合はbytesで表示する
console.log(`Directory: ${dir}, Size: ${size} Biytes`);
} else if(size < 1000000) {
// 1000バイト以上、1000000バイト未満の場合はKBで表示する 小数点は第2位まで表示する
console.log(`Directory: ${dir}, Size: ${Math.round(size / 1000 * 100) / 100} KB`);
} else if(size < 1000000000) {
// 1000000バイト以上、1000000000バイト未満の場合はMBで表示する 小数点は第2位まで表示する
console.log(`Directory: ${dir}, Size: ${Math.round(size / 1000000 * 100) / 100} MB`);
} else {
// 1000000000バイト以上の場合はGBで表示する 小数点は第2位まで表示する
console.log(`Directory: ${dir}, Size: ${Math.round(size / 1000000000 * 100) / 100} GB`);
}
return size;
};
/**
* エントリーポイント
*
* @function main
* @param {string[]} args - コマンドライン引数 (process.argv を除いたもの)
* @returns {void}
*
* @example
* // フォルダ data を output.zip に圧縮する
* node src/script/archiveFiles.js csv_output output.zip
*
*/
const main = (args) => {
if (args.includes('--help')) {
console.log(`
Usage: node archiveFiles.js [sourceDir] [outputFile]
args:
sourceDir : 圧縮するディレクトリ
outputFile : 出力ファイル名
Options:
--help ヘルプを表示
`);
return
}
// 引数が2つ以外の場合はエラー
if (args.length !== 2) {
console.error('エラー: 引数が正しくありません。');
console.error('Usage: node script.js [sourceDir] [outputFile]');
return;
}
const sourceDir = args[0];
// ファイルの存在チェック
if (!fs.existsSync(sourceDir)) {
console.error(`エラー: ディレクトリが存在しません: ${sourceDir}`);
return;
}
const outputFilePath = args[1];
// prodモード以外の場合は表示する
if(process.env.NODE_ENV !== 'production') _debugDirectorySize(sourceDir);
const timeWatch = new TimeWatch();
timeWatch.start();
createZipFile(sourceDir, outputFilePath);
timeWatch.stop();
timeWatch.printElapsedTime();
}
console.log(`start ${process.argv[1]}`);
main(process.argv.slice(2));

73
src/script/generateCSV.js Normal file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env node
/**
* CSVファイルを生成するスクリプト
*
* @requires csv-writer
* - npm install csv-writer
* @example
* // コマンドラインから実行する場合:
* node src/script/generateCSV.js
*/
const fs = require('fs');
const path = require('path');
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
/**
* 乱数を使ってダミーデータを生成する
* @param {*} numRecords
* @returns
*/
const generateData = (numRecords) => {
const data = [];
for (let i = 1; i <= numRecords; i++) {
data.push({
id: i,
name: `User_${i}`,
age: Math.floor(Math.random() * 50) + 20, // 2069歳
email: `user${i}@example.com`,
});
}
return data;
};
/**
* 指定した数のCSVファイルを作成
* @param {*} numFiles
* @param {*} numRecordsPerFile
* @param {*} outputDir
*/
const createCsvFiles = async (numFiles, numRecordsPerFile, outputDir) => {
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
for (let i = 1; i <= numFiles; i++) {
const filePath = path.join(outputDir, `test_data_${i}.csv`);
const csvWriter = createCsvWriter({
path: filePath,
header: [
{ id: 'id', title: 'ID' },
{ id: 'name', title: 'Name' },
{ id: 'age', title: 'Age' },
{ id: 'email', title: 'Email' },
],
});
const data = generateData(numRecordsPerFile);
await csvWriter.writeRecords(data);
console.log(`CSVファイル作成完了: ${filePath}`);
}
};
// **設定**
const numFiles = 3; // 作成するファイル数
const numRecordsPerFile = 10; // 各ファイルのレコード数
const outputDir = './csv_output'; // 保存ディレクトリ
createCsvFiles(numFiles, numRecordsPerFile, outputDir)
.then(() => console.log('全てのCSVファイルの作成が完了しました'))
.catch(err => console.error('エラー:', err));

View File

@ -0,0 +1,89 @@
#!/usr/bin/env node
/**
* シンプルなコマンドラインスクリプト
*
* このスクリプトは引数を受け取りその内容を表示します
* `--help` オプションを指定すると使い方を表示します
*
* @module script
*/
/**
* スクリプトのエントリーポイント
*
* @function main
* @param {string[]} args - コマンドライン引数 (process.argv を除いたもの)
* @returns {void}
*
* @example
* // メッセージを表示する
* node src/script/sampleScript.js Hello
*
* @example
* // ヘルプを表示する
* node src/script/sampleScript.js --help
*/
const main = (args) => {
if (args.includes('--help')) {
displayHelp();
return;
}
// 引数がない場合のデフォルトメッセージ
if (args.length === 0) {
handleError('エラー: 引数が必要です。\n`node script.js --help` で使い方を確認してください。');
return;
}
processArguments(args);
}
/**
* ヘルプメッセージを表示する
*
* @function displayHelp
* @returns {void}
*/
const displayHelp = () => {
console.log(`
Usage: node script.js [message]
Options:
--help ヘルプを表示
`);
};
/**
* エラーメッセージを表示し終了する
*
* @function handleError
* @param {string} message - エラーメッセージ
* @returns {void}
*
* @example
* handleError("エラー: 引数が必要です。");
*/
const handleError = (message) => {
console.error(message);
process.exit(1);
}
/**
* 引数を処理してメッセージを表示する
*
* @function processArguments
* @param {string[]} args - コマンドライン引数
* @returns {void}
*
* @example
* processArguments(["Hello", "World"]);
* // 出力: "Hello World"
*/
function processArguments(args) {
const message = args.join(' ');
console.log(`入力されたメッセージ: ${message}`);
}
// コマンドライン引数を取得して main 関数を実行
main(process.argv.slice(2));

View File

@ -0,0 +1,32 @@
#!/usr/bin/env node
/**
* 処理を測定するスクリプト
*
* @module script
*/
/**
* TimeWatch クラス
*/
const TimeWatch = require('../classes/TimeWatch');
/**
* スクリプトのエントリーポイント
*
* @function main
* @returns {void}
*
* node src/script/timeWatchTest.js
*/
const main = () => {
const timeWatch = new TimeWatch();
timeWatch.start();
// 処理
for (let i = 0; i < 100000000; i++) {
// do nothing
}
timeWatch.stop();
timeWatch.printElapsedTime();
}
main();

22
src/server/archive01.js Normal file
View File

@ -0,0 +1,22 @@
/**
* ZIPファイルを作成してダウンロードサーバ
*
* @description
* - ZIPファイルを作成してダウンロードするサーバー
* - Node.js + Express + archiver
*/
const express = require("express");
const fs = require("fs");
const path = require("path");
const archiver = require("archiver");
const app = express();
const PORT = 3000;
app.get("/download-zip", async (req, res) => {
});
// ZIPのダウンロード用エンドポイント
app.use(express.static(__dirname));
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

12
src/server/index.js Normal file
View File

@ -0,0 +1,12 @@
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
const port = 3000;
server.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});