Python の PDF ライブラリ
PDF ビュワーで既存 PDF にテキストボックスを配置したり前に配置したのを編集できたりするので あれを Python でまとめてやりたくて調べたもの
フリーソフトでできるくらいなのに 無理そうな感じ


Python の有名どころ PDF ライブラリ
カッコの中は調べたタイミングでの Github スターと最終更新があった年

PyPDF2 (2721/2018)

メタデータ取り出したり 分割結合とかはできそうだけど テキスト入れたりはできなそう
サンプル見ても reportlab っていう別ライブラリ使ってる

pdfminer (3710/2016)

スターは最多だけど Python2 のみの対応
Python 3 対応はフォークした別リポジトリ

pdfminer.six (1380/2019)

pdfminer の Python2, 3 の両方対応のフォークだけど スター数的にはそこまで活発じゃなさそう
ドキュメントというドキュメントもないし リンクにあった wiki はページ一つだけでそのページもコンテンツなし
元のリポジトリのドキュメントも大したこと書かれてないし 何ができるかよくわからない
README の簡易説明見た感じだと テキスト抽出はできるけど テキストボックス編集とかはできなそうに見える

pdfrw (1032/2018)

PyPDF2 に似た感じ

pyfpdf (416/2018)

PHP の FPDF の Python 版らしい
期待してなかったけどドキュメントが一番まともで 機能的にも編集はこれが一番機能ありそう
ただ残念なことに 既存 PDF の編集は FPDI というロード用の別モジュールが必要で Python 版だとこのモジュールが無いみたい
なので新規作成のみ
HTML テスター
書いた HTML をファイルに保存せず動作確認したいときに使う
適当なページで devtools を開いてコンソールで⇩を実行

document.head.innerHTML = `<style>textarea{width:50vw;height:50vh;}</style>`
document.body.innerHTML = `<textarea></textarea><div><button>OPEN</button></div>`
document.body.querySelector("button").onclick = eve => {
const w = window.open()
w.document.write(document.querySelector("textarea").value)
w.document.close()
}

textarea に HTML を書いて OPEN ボタン
元になったページのスキームになるので https のページでやれば https 機能が使える
JSX 書いてみたら highlightjs で対応できてなかった
この記事でちゃんとハイライトされてない
途中でエラーあるみたい
Changelog みてると今年の 5 月末に JSX 関連の修正あるからアップデートで行けるかなと思ってアップデートしたけどまだダメ
探した感じ この issue みたい
https://github.com/highlightjs/highlight.js/issues/1915
今年の頭で放置されてるけど 各自修正してって感じでアップデートはされないのかな
fish で export を追加する
fish で環境変数を追加したいことがときどきあるけどよくやり方忘れてるのでメモ

~/.config/fish/config.fish

に設定を追加すればいいだけなんだけど 自分で作らないとこのファイル自体がなくて名前が config.fish だっけ fish.config だっけで迷う

fish では永続する環境変数をコマンドで作れるのでこっちのほうが楽
set -U で fish_user_paths に追加する
ユニバーサル変数って名前らしい

nodebrew の例
インストールしたら下を追加してくださいって指示が出る

export PATH=$HOME/.nodebrew/current/bin:$PATH

fish ではこのコマンドをうつ

set -U fish_user_paths $HOME/.nodebrew/current/bin $fish_user_paths

$PATH の代わりが $fish_user_paths でちょっと長い
このコマンドで設定したのは自動で生成される設定ファイルに追加されてる

.config/fish/fishd.0a0027000002

の最後に

SET fish_user_paths:/home/user/\x2enodebrew/current/bin

が増えてた

自動生成される設定ファイルの名前は環境によって違う
0a00~の部分は MacAddress らしい
自動生成ファイルはユーザが変更しても再作成でもとに戻るので直接書くのはダメ
ファイルの最初にも注意書きあり

# This file is automatically generated by the fish.
# Do NOT edit it directly, your changes will be overwritten.
Vivaldi のアラートがおかしい
いつもどこかに不具合のある Vivaldi だけど 今度はアラートの消える判定が変
ダイアログや OK ボタンをどれだけ押しても反応無いかと思ったら ダイアログの外側はどこ押しても消える
アラートのダイアログ出てることに気づく前に画面をクリックして消えてしまうことありそうだし そもそも OK ボタン押しても消えないあたりバグだよね
オブジェクトのキーに数値を使う場合
普段オブジェクトのキーには文字列か 単純な数値しか使わないから忘れがちだけど 数値を書くと評価された結果を文字列化したものがキーになる

console.log({1: 1})
// {1: 1}
console.log({0b010: 1})
// {2: 1}
console.log({0123: 1})
// {83: 1}
console.log({0x12: 1})
// {18: 1}
console.log({0.3: 1})
// {0.3: 1}
console.log({9999999999999999999999999999999999: 1})
// {1e34: 1}
console.log({1e3: 1})
// {1000: 1}
console.log({1e1000: 1})
// {Infinity: 1}

数値は単体が評価されるだけで 足し算引き算などの式は書けない
- 符号をつけるだけもダメ
計算したいなら [] つける

console.log({[1 + 1]: 1})
// {2: 1}
console.log({[-1]: 1})
// {-1: 1}

ありがちなのは 0 から始まるキーを文字列にしてなくて 8 進数扱いされてること
datepicker 系ライブラリ
input の type="datetime-local" の日付入力サポートの変わりのライブラリを探してるけど
jQuery ありのものが多めで依存なしのは少なめ
日付だけでじゃなくて時刻も設定したいけど対応してるのは少なめ

マイナーなのも多いけど時刻も選べる jQuery いらずのライブラリのまとめ

flatpickr
https://flatpickr.js.org/

基本はこれでよさそう
各種フレームワークに対応していて star も 1 万超え
時刻入力は AM/PM じゃなくて 24 時間表記にしたいけど軽く見た感じ無理そう
カレンダーのサイズをもうちょっとコンパクトにしたい気がする

Material Design - Date & Time Picker
https://puranjayjain.github.io/md-date-time-picker/

moment.js とフォントロードの CSS が必要
見た目が結構好き
時刻をアナログ時計風に選択できるのがいいところ

simplepicker
https://priyank-p.github.io/simplepicker/index.html

パット見は良さそうだけど時刻入力がイマイチ
star もほぼないし (< 10) マイナーどころ

tail.DateTime
https://github.pytes.net/tail.DateTime/

見た目が好き
コンパクトでカレンダーの下で時刻選択ができる
時刻は 24 時間表記で選択できる
デモを試した感じ悪いところなさそうだけど star は少なめ (60)

Window Date Picker
https://cevadtokatli.github.io/window-date-picker/

見た目良さそうだけど カレンダーと時刻選択で画面変わるのがいまいち
star は 10 未満

Picker.js
https://fengyuanchen.github.io/pickerjs/

カレンダーを使わないのが特徴
タッチ操作で選択するときに出そうなそれぞれを回転させて選ぶやつ
カレンダーがいらないならこれでいいと思う
star は 200 ちょっとでそこそこある



条件外

Date Range Picker
https://www.daterangepicker.com/

日付の範囲を選ぶのに特化したライブラリ
高機能で star も 9000 以上ある
ただ jQuery 依存

Light Pick
https://wakirin.github.io/Lightpick/

時刻選択できない

pickadate.js
https://amsul.ca/pickadate.js/

star は 7000 超えと多め
だけど jQuery 依存

Pikaday
https://github.com/Pikaday/Pikaday

star は 7000 弱あって依存なし
datepicker であって時刻は対応しないみたい
時刻に対応したフォークはあるけどどれもメンテされてない
JavaScript で珍しく 0 === value を見た
コードをみてると珍しく 「0 === value」 形式の条件式をみました
0 や value は例で実際は 「値 === 変数」 です
C 言語ではよくみた記法です
なんか名前ついてたきはしますが忘れました

目的は代入と比較の入力ミスを防ぐためです
== のつもりなのに = って書いてしまうミスをしたとき 左辺が値だと実行できないので実行時(コンパイル時)にエラーになります
== が比較の言語なら 適度に見るものですが JavaScript の場合はほとんどみません

JavaScript だと == でも比較はできますが わかりづらいキャストを行った上で比較されるので基本的につかいません
使うのは 「== null」 で null か undefined という場合くらいです
「== undefined」 でもできますが 同じ意味で文字数が増えるので基本は null の方を使います
それ以外の比較では 型も一致する必要がある === を使います
数値と文字列を比較したい場合も明示的にキャストしてから === です

そうなると = か === かです
= と == ならともかく = と === なら間違うことはほぼないといってもいいですよね
だからなのか JavaScript だと 0 === value 形式の条件式はめったに見かけず珍しいです
分割代入式を代入する
普通こんなことをしようとはしないのですが 入力ミスの結果こんなことになってました

const value = { a: 1, b: 2, c: 3 }
const value2 = { a, ...x } = value

やろうとしたこともないので考えたことがなかったのですが これってどうなるのでしょうか
右側の代入式は a に 1 が入って x に残りの b と c が入るのはわかります
では value2 には何が入るんでしょう?

a や x だけとはまず考えられないので 「{ a, ...x }」 全体とすれば a と x をマージしたもので value のコピーと同じものでしょうか
分割代入ということは関係なく value がそのまま参照として代入されるのもありそうです
こっちのほうが無駄な処理がいらないですし

結果は

console.log(value2)
// { a: 1, b: 2, c: 3 }
value2.c = 30
value2.d = 40
console.log(value)
// { a: 1, b: 2, c: 30, d: 40 }

参照が代入されてるので

const value2 = value

と同じでした
IE/Edge は input で checkbox の変更を検知できない
IE でなぜか動いてないとこあるなー と思って調べてみたら
input イベントは checkbox では dispatch されないみたい

<!DOCTYPE html>

<input id="a" type="checkbox">

<script>
a.addEventListener("input", function(eve){console.log("input event dispatched")})
a.addEventListener("change", function(eve){console.log("change event dispatched")})
</script>

Chrome や Firefox は input も change も両方起きる
けど IE/Edge は change だけ
全部 input だけで変更を受け取りたいのに

いくら polyfill 入れても JavaScript 機能以外でこういうところがあるから webpack 使うしついでに IE 対応もしておこうとはならないんですよねー
Firefox でリサイズ検知されない?
body の中に div で 100vw/100vh にして全画面にしてるページをふと Firefox で開いてみたら
画面は普通に出るのにウィンドウを広げたり閉じたりしても自動で div がリサイズされなかった
拡大したらなにもない白い部分が外側にできて縮小したらスクロールバーが出る

ボタン押したりしても変化なしでリロードすればそのときの画面いっぱいに表示される
開発ツールを ON にしたらそのタイミングでリサイズされて 開発ツール出てるときや消した後はウィンドウに沿ってリサイズされた
変なバグっぽいけど単純に 100vw/100vh の要素置いたページだけだと再現してない
Rollup で minify する
Terser プラグインをいれる

import { terser } from "rollup-plugin-terser"

plugins に追加する
ライセンスのコメントは残したい場合は comments オプション
正規表現を指定するとマッチするコメントは保持されるので @license を指定する

plugins: [
terser({ output: { comments: /@license/i } }),
]
クラス構文のメソッド定義
クラス構文でプロパティ代入できるようになった結果 現状メソッド定義をする方法は主に 3 種類

class C {
value = 1

x() { return this.value }

y = function() { return this.value }

z = () => this.value
}

普通に実行するならどれも結果は同じ

const c1 = new C()
c1.x()
// 1
c1.y()
// 1
c1.z()
// 1

x はクラス構文の基本のメソッド定義方法で prototype に関数がセットされる
y と z は関数を代入してるので prototype ではなくインスタンスに関数がセットされる
prototype を直接操作したりするような場合はどっちにあるべきか考える必要あり
どっちでもいいなら prototype にあるほうが無駄が少ない

const c2 = Object.create(C.prototype)
c2.x
// f x() { return this.value }
c2.y
// undefined

y と z の違いはアロー関数を使ってるかどうか
アロー関数では arguments や this が作られない
この場合の this はそのインスタンスに固定される
メソッドを関数としてどこかに渡す場合には基本的にアロー関数にしておいたほうが良い

const { x, y, z } = c1
x()
// TypeError: Cannot read property 'value' of undefined
y()
// TypeError: Cannot read property 'value' of undefined
z()
// 1
hapi のドキュメントページが新しくなってる
https://hapi.dev/api/

前のは見づらくて Github のドキュメントページ見てたくらいでしたが 見やすく改善されてました

最近は Koa を使ってますが やることが増えてくると追加パッケージをあれこれ入れたりで面倒なこともあるので hapi にしたくなることもあります
基本的に hapi はルートがベースであって Koa はルート関係なく全体のミドルウェアがベースになってるので全体共通で設定したいかルートをベースに設定したいかで選べば良さそうな気もしてます
ただ 一見簡単そうでも内部的には hapi のほうが複雑なのでどっちも詳しくないなら Koa のほうが楽かもしれないです
デフォルトスタイル
h1 とか table とかに class 指定しなくてもデフォルトでスタイル設定したい
だけど h1 自体に設定してしまうと例外的にここだけ別のにしたいってときに面倒です
デフォルトスタイルで変更した部分を全部上書きしないといけないですし

かと言って h1.default にスタイルを設定して 全部の h1 に class="default" をつけるのも面倒です
JavaScript でロード時や DOM 更新時に class 属性がないなら "default" を自動設定も可能ですが あまりそういうことはしたくないです

いい方法ないか考えたところ

(1) デフォルトを使わない場合に "no-default" クラスをつけるようにする

スタイルでは :not で "no-default" があればデフォルトスタイル当たらないようにする

h1:not(.no-default) {}

デフォルト使わないだけでわざわざクラス必要なのってどうなの?

(2) クラスがないときにデフォルトスタイルをあてる

なにか class をつけるとデフォルトスタイルが当たらないようにする
デフォルトスタイルを使いたいけど class も必要なときのために "default" クラスをつけてもデフォルトスタイルをあてるようにする

h1:not([class]), h1.default {}

class 以外の属性を条件にスタイル当てるから class に設定いらないけどデフォルト解除したいときは class="" が使える
けど class で空文字か属性なしかでスタイル変わるのは分かりづらい感もある
class 属性あればいいので (1) みたいに "no-default" って書いてもいい
再帰関数を作る
定義した名前に依存したくないし 一旦定義してから呼び出す必要もある
作ってそのまま呼び出したいから 引数として自分自身を受け取りたい
arguments.callee という良さそうなものがあるのに strict mode (es modules) だと使えない
あと arguments がないから通常の JavaScript でもアロー関数で使えない

というわけで

const rec = f => f.bind(f, f)

実行

const rf = rec((self, x) => x > 0 ? [x, ...self(x - 1)] : [x])
rf(3)
// [3, undefined]

これだと [3, 2, 1, 0] じゃない
self を呼び出すときに引数で self を入れて

const rf = rec((self, x) => x > 0 ? [x, ...self(self, x - 1)] : [x])
rf(3)
// [3, 2, 1, 0]

再帰関数の関数を途中で変えるなんてしないし self 以外を入れることはなし
なら自動で self が bind されてるようにしたい

const rec = f => {
const ff = (...a) => f(ff, ...a)
return ff
}
const rf = rec((self, x) => x > 0 ? [x, ...self(x - 1)] : [x])
rf(3)
// [3, 2, 1, 0]

ff を一旦作ってるのが気になるけど仕方なし

bind 位置を自分で選べるようにしてみた版

const recm = fn => {
const w = fn((...a) => w(...a))
return w
}
const f = function(v) { return v > 0 ? [v, ...this(v - 1)] : [v] }
const rf = recm(r => f.bind(r))
rf(3)
// [3, 2, 1, 0]

recm に渡す関数では 引数として渡される関数が自分が返した関数になる
完全同じ参照である関数にはできないから 引数はラップ関数になってて呼び出したら自分が返した関数が実行される
引数はそのまま渡されるからラップ関数経由してることは気にする必要なし
ただ 引数で受け取る関数は recm が終わるまで実行したらダメ
関数を返すまでは初期化されてないので 「Cannot access 'w' before initialization」 って言われる
knex の null と undefined の扱い
SQL じゃないライブラリだと null や undefined とか特殊な値の扱いが気になるところ
ちゃんと理解してないと思いもよらないことになってそうだし

試した感じ キーなしでも明示的に undefined でも更新対象にはならない
inert の場合は undefined 問わず全レコードのオブジェクトに対してキー一覧を取り出して undefined になってれば DEFAULT が設定される
DEFAULT は接続時のオプションで null に置き換えできるみたい

pg("foo").update({a: 1, b: null, c: undefined, d: pg.raw("DEFAULT")}).toString()
// "update "foo" set "a" = 1, "b" = NULL, "d" = DEFAULT"

pg("foo").insert([{a: 1, b: null, c: undefined}, {}]).toString()
// "insert into "foo" ("a", "b", "c") values (1, NULL, DEFAULT), (DEFAULT, DEFAULT, DEFAULT)"

update で DEFAULT 値にしたいなら raw で DEFAULT 指定必要

inert 構文ではカラム名を列挙するので 配列で複数レコードがあるとどれかのレコードにあるキーは値問わずカラムとして追加される
それで各レコードに対してカラムの値を列挙してる感じ

事前に DB 接続してると言ってもテーブル名からテーブル定義を参照したりはしないので実際に存在しないキーがあればカラム名になるし 実行すればエラーが起きる
上の例を実行したときは foo テーブルなんて作ってないし
差分更新 DOM ライブラリ作ってると POST も楽
久々にサーバに POST するもの作ってみると hyperhtml や lit-html を使ってると楽だった
テンプレートに埋め込むために データは変数上にすでに持ってるから form からいちいち取り出したりしなくても JSON で送れる
エラーチェックも変数のデータなので好きに処理できるし form のバリデーション機能より柔軟にできる
form の POST じゃなくて ajax でバックグラウンドリクエストだから 画面遷移せずレスポンスに応じて遷移したり警告出したり DOM 書き換えのみだったり色々選べる
それと form の POST だと disabled のときに送られないとか面倒な仕様があるけど変数で持ってるデータを送るだけなら DOM 上で disabled かどうかなんて関係なし

もう lit-html とかを使わないくらいシンプルに作るとき以外は全部 ajax で JSON POST でいいくらい
find はみつかったかわからないので
const found = [1, undefined, 2].find(x => !x)
// undefined

const not_found = [1, 2].find(x => !x)
// undefined

find はみつからないと undefined
みつかったのが undefined のときも undefined

見つかったか知りたい場合は配列にラップすればわかりやすい

const result1 = [1, undefined, 2].map(x => [x]).find(([x]) => !x)
// [undefined]

const result2 = [1, 2].map(x => [x]).find(([x]) => !x)
// undefined

map する手間と find で配列の中身を取り出す手間を省くために関数にすると

const find = (arr, cb) => {
const result = arr.map(x => [x]).find((x, i, a) => cb(x[0], i, a))
return {
found: !!result,
value: result && result[0]
}
}

find([1, undefined, 2], x => !x)
// {found: true, value: undefined}
find([1, 2], x => !x)
// {found: false, value: undefined}

作ったはいいけど よく考えたら findIndex でよかった
こっちのほうが index も取れるし 配列の要素のラップ版を作るコストもなし

const find2 = (arr, cb) => {
const index = arr.findIndex(cb)
return {
found: index >= 0,
value: arr[index],
index,
}
}

find2([1, undefined, 2], x => !x)
// {found: true, value: undefined, index: 1}

find2([1, 2], x => !x)
// {found: false, value: undefined, index: -1}
長い文字列だと処理遅くなる?
画像ファイルとかのバイナリの base64 文字列を扱ってると ただの文字列でも普段使うものの何百や何万倍もの文字数になってます
そう言えば文字列ってオブジェクトじゃなくてプリミティブ
関数の引数に渡したり受け取ったりを繰り返すと 多少は遅くなるのかな

C レベルでいえば ポインタで最初だけ渡して全コピーはしないはず
JavaScript (V8) みたいな最適化が強力な言語だと ただ受け渡しするだけなら文字列の長さなんて関係ない……はず
とはいえ一応試してみることに

function x(s, i) {
if(i > 300) {
return s
}
return y(s, i + 1)
}

function y(s, i) {
return z(s, i + 1)
}

function z(s, i) {
return x(s, i + 1)
}

const shortstr = "short"
const longstr = Math.random().toString().slice(2).repeat(1024 * 1024 * 30)

function measure(name, value){
console.time(name)
for(let i=0;i<100000;i++) {
console.assert(x(value, 0) === value)
}
console.timeEnd(name)
}

measure("s", shortstr)
measure("l", longstr)
measure("s", shortstr)
measure("l", longstr)
measure("s", shortstr)
measure("l", longstr)

結果は

s: 23.27099609375ms
l: 17.584228515625ms
s: 12.656982421875ms
l: 11.31884765625ms
s: 10.472900390625ms
l: 11.520751953125ms

1 回目だけ遅いのはいつものことなので みるのは 2 つ目以降
短いほうが速かったり 長いほうが速かったりで違いも誤差レベル
文字数が多くても 特に気にする必要はなさそう

ちなみに longstr.length は 503,316,480 (だいたい 500 MB) でした
そんなメモリ取って大丈夫かなと思ったけど Chrome のタスクマネージャで見る限りメモリ消費量は特に増えてなし
repeat を使ってるから最適化されてるのかな
通常のオブジェクトより new class のほうがいいかも?
普通のオブジェクト定義だとこれができない

const x = {
a(v) { return p => p + v },
b: x.a(10),
}

プロパティ b の値を作る段階では x はまだ初期化前
x.a にはアクセスできない

やろうとするとこうなる

const x = {
a(v) { return p => p + v }
}
x.b = x.a(10)

見た目的にあまりやりたくない

new class だとこういうことができる

const x = new class {
a(v) { return p => p + v }
b = this.a(10)
}

デメリットは __proto__ が Object.prototype じゃなくなって プレーンなオブジェクトじゃなくなること
プレーンオブジェクトを想定してるところでは動かないこともある

たとえば Object.keys() で関数(メソッド)部分は取得できない
- のあとに文字列あるのがわかりづらい
name.slice(idx, -".jpg".length)

書くときは普通に書くけどあとから読むと 脳内構文パースがフリーズする
これくらいならともかくもうちょい複雑だと結構困る

name.slice(idx, ".jpg".length * -1)

-1 掛けるとわかりやすいかと思ったけど そんな変わらなかった
Microsoft がまた新しい言語を作ったみたい
Bosque

Microsoft って

有名どころの C#, F#, VB.NET
Windows 用の JScript, VBScript
Excel の VBA
altJS の TypeScript
マイナーどころの JScript.NET, F*, P

など色々作ってるけど また増えたみたい
今回の言語は 「人間にとっても機械にとってもシンプルで 明白で 推論しやすいコード」 を書けるようデザインしてるらしい

軽く見た感じでは コードは 100% TypeScript で Node.js がランタイムぽいので TypeScript を置き換えるのかな?
TypeScript は JavaScript の Superset なので JavaScript そのままで動くから始めやすいのがメリットだけど altJS なんだし構文変えてでももっと便利にしてくれたほうがいい気もする
ただ そのメリットがないと その他 altJS に埋もれそうな気もする

見た目は基本的に JavaScript というか TypeScript ぽい
例を見る限りは TypeScript にない構文でも見た目でなんとなくなにしてるかわかるから見やすさ的にはよさそう
ただ 個人的に TypeScript で嫌な部分の 「型の指定がインラインにある」 というのがこれにもある
型は補足情報でしかないからインラインにあるとすごく邪魔で視認性が落ちる
なのでアノテーションみたいに別の行で指定できてほしい
「0.12 Errors and Checks」 のところにある requires と ensures はいい感じ
引数と返り値の型もこういう感じで分けれたらいいのに
Chrome のわかりづらいエラーメッセージ
配列をマージする処理

const a = []
const b = [{x: 1}]
const c = [...(a[0] || []), ...(b[0] || [])]
// Uncaught TypeError: undefined is not a function

これで undefined is not a function って言われる
遭遇したときはもっと複雑なコードで 関数実行してないのに 関数実行しようとしてるけど関数じゃないってエラーなので原因見つけるのに苦労しました

原因は b[0] が通常のオブジェクトなこと
配列とかイテラブルなオブジェクトじゃないとダメ

... に続くのが変数だとわかりやすくなります

const aa = a[0] || []
const bb = b[0] || []
const cc = [...aa, ...bb]
// Uncaught TypeError: bb is not iterable

式の場合は bb って名前が出せないのでエラーメッセージが違うみたい
だけど not a function じゃなくて not iterable って言ってほしい
bat の ~ の使いみち
たまにみかけるもののあまり気にしてなかった ~ がけっこう重要なものでした
bat の if 文で空文字チェックしたいとき

if %1 == "" echo ERROR

としたら %1 が空だと

if  == "" echo ERROR

になって構文エラー
クオートをつけて

if "%1" == "" echo ERROR

にすると %1 が空のときにうまく動くけど 半角スペースを含む場合に引数に "" がすでにあるので

if ""a b"" == "" echo ERROR

になって構文エラー
展開時にクオート外したいと思って調べたら ~ を使えばはずせるというものでした

if "%~1" == "" echo ERROR

にすると

if "a b" == "" echo ERROR

となってうまくいきます
data vs func
ある処理を行うとき その設定をデータにするか関数にするか
データ: JSON 形式のデータで全設定を書いて それを処理する 1 つの関数を実行する
関数: それぞれの設定を関数で作ってそれを組み合わせる

関数はひとつひとつが関数なので部分実行できるし 最終的な関数も関数を組み合わせたもの
途中のものと最後のもので扱いの違いはない
部分的に実行できるし 細かい単位で動作確認できるので そういう意味ではデバッグしやすい
ただ JSON で設定があるわけじゃないので その関数が何をするものなのかは分かりづらい
JSON データがあればそれを見るだけで設定(=処理内容)がわかる
最小単位の関数ならともかく それらを複雑に組み合わせた関数だと中で何するかを確認するのが難しい
await は then を呼び出してる
await すると内部で then メソッドを呼び出してる

!async function(){
console.log(await { then(resolve, reject){ resolve(10) } })
}()
// 10
// false

!async function(){
console.log(await { then(resolve, reject){ reject(10) } })
}()
// false
// Uncaught (in promise) 10

ということは knex で .then(x => x) をわざわざ追加しなくても

console.log(await knex("table").select("*"))

でクエリが実行されるはず
やってみたら

!async function () {
const [a, b, c] = await Promise.all([1, 2, 3].map(x => knex.select(pg.raw(`${x} + 100`))))
console.log(a, b, c)
}()
// [ { '?column?': 101 } ] [ { '?column?': 102 } ] [ { '?column?': 103 } ]

うまくいった
Webp プログラムが Norton に消された
誤検出が多いと言われる Norton 先生だけど最近はほとんどそういうこともなくていい感じでした
だけど webp ツールをここからダウンロードしたら「削除しました」通知がいっぱい
ほとんど消されてしまいました
webp の変換ツールってそのへんのフリーソフトよりもメジャーじゃないの?
Remote Fetch
拡張機能でバックグラウンド側で fetch するためのもの
以前どこかで作ったのを ESModules 対応で新しく作り直した

バックグラウンド側で行うので CORS 無視かつ https から http の fetch ができる
ページ内に JavaScript を埋め込む content_script で使うのが主な用途

fetch の API と完全な互換性はなし

export const remoteFetch = (url, type, option) => {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({ url, type, option }, res => {
if (res) {
if (res.error) {
reject(new Error(res.error))
return
}
if (res.result) {
if (type === "buffer") {
resolve(Uint8Array.from(res.result).buffer)
} else {
resolve(res.result)
}
return
}
} else {
reject("Something went wrong.")
}
})
})
}

const remoteFetchListener = (req, sender, sendResponse) => {
if (!req.url) {
sendError("missing url")
return false
}
try {
new URL(req.url)
} catch {
sendError("Invalid URL: " + req.url)
return false
}

fetch(req.url, req.option)
.then(async res => {
if (!res.ok) {
throw new Error("Rensponse is not ok: " + res.status)
}
let result = null
if (req.type === "json") {
result = await res.json()
} else if (req.type === "buffer") {
const ab = await res.arrayBuffer()
result = Array.from(new Uint8Array(ab))
} else {
result = await res.text()
}
sendResponse({ result })
})
.catch(err => {
sendError("Fetch error: " + err.message)
})
return true

function sendError(message) {
sendResponse({ error: message })
}
}

export const listenRemoteFetch = () => {
chrome.runtime.onMessage.addListener(remoteFetchListener)
}

export const unlistenRemoteFetch = () => {
chrome.runtime.onMessage.removeListener(remoteFetchListener)
}

content_script 側では remoteFetch をインポートして使う
2 つ目の引数に text, json, buffer のどれかを指定する

import { remoteFetch } from "./remoteFetch.js"

remoteFetch(url, "text").then(console.log)

バックグラウンド側では listenRemoteFetch を実行しておく

import { listenRemoteFetch } from "./remoteFetch.js"

listenRemoteFetch()

作ったはいいけど このまま使う機会は少なそう
1 ファイルにまとめてるけど 使う側で実行する関数も別で共通処理もないから ロードする量減らすならファイル分けたほうが良いかもだし
拡張機能で Modules のロードは不便なところもあるから直接スクリプトに埋め込んだり バンドルしたほうが良さそう
knex の実行がわかりづらい
knex って then を呼び出したらクエリ実行だから 実行して Promise を取得したいと

knex("table").select("*").then(e => e)

みたいな then が必要ぽい
普通の Promise なら then はなくてもすでに実行済みで 非同期処理が終わって結果が来たら実行するための関数を指定するためにつかうのが then
だからそのまま返すだけの then ならつけなくても一緒
だけど knex は then が実行も兼用してるから then がないと実行されない

knex("table").select("*").execute()

みたいのがあればいいのに

基本的には then で結果を処理すればいいかもだけど 全部終わってから処理したい場合もあるし そのまま返して Promise 化するだけの then が必要になる

const [t1, t2, t3] = await Promise.all([
knex("table1").select("*").then(e => e),
knex("table2").select("*").then(e => e),
knex("table3").select("*").then(e => e),
])

かと言って これをまとめる関数を作るのものなぁ

const execAll = builders => Promise.all(builders.map(e => e.then(x => x)))

const [t1, t2, t3] = await execAll([
knex("table1").select("*"),
knex("table2").select("*"),
knex("table3").select("*"),
])
セッションの保存先
Node.js の Framework だとセッション情報って cookie に直接保存するのがほとんど
と言っても主流な Koa と Hapi のデフォルトってだけだけど

一応署名したり暗号化したりでユーザが勝手に変えても無意味なようにはなってる
それでも cookie のデータは文字数制限がある
PHP みたいにローカルファイルに保存してくれたほうが良い気がする

だけどローカルに置くとサーバを増やすということができなくなるから そういう機能はサポートしないみたい
要望があったけど すべきじゃないって却下されてたり
どうしてもやりたいってユーザが作ったプラグインとかがあるけど公式の機能だけだとできない

ユーザに見せたくないとかデータが多いなら redis とか mongodb で保存するのが良いみたい
複数のサーバで共有できるからね
大きなサービスだとそういうのが理想だろうけど サーバ 1 つでプロセスも 1 つで良いような個人レベルのでそこまでやるのはハードル高いと思う
サーバひとつならローカルにインストールするだけで良いと言えば良いんだけど手間が増えるだけだし

あと cookie 自体にデータがあると 同じオリジンに別のサーバができたときに 前のサービスのデータが見れたりしそう
暗号化してればいいけど Koa の session は署名だけで base64 デコードすれば見れたはず
ユーザ自身が見るならともかく第三者が見るのってちょっと抵抗あるし やっぱり ID だけ cookie に入れて 実際のデータはサーバ側のほうが良い気がするかなー
単なる使う側ならどういう情報持ってるのか見れたほうが面白いけど
Google Maps で Polyline の表示
Google Maps で線引くときって中では SVG を使ってるのかなと思ったら タイルごとに canvas を用意してその canvas に線を引いてた
なので Polyline を SVG で取得は無理そう
canvas もタイルごとに分かれてるので 取り出すにも結合必要で面倒そう

SVG のパスじゃないならクリックイベントは座標でヒットテストして ドラッグで移動はマウス動かすたびに canvas 再描画してるのかな
チャート系ツールの感じだと SVG のほうが軽いように思うけどどうなんだろう
非同期処理を順番にする書き方
// 1
async function case1() {
try{
await asyncAction1()
await asyncAction2()
await asyncAction3()
} catch (err) {
console.error(err)
}
}

// 2
function case2() {
return chain([
asyncAction1,
asyncAction2,
asyncAction3,
]).catch(console.error)
}

function chain(afns) {
return afns.reduce((a, b) => a.then(b), Promise.resolve())
}

// 3
function case3() {
return Promise.resolve()
.then(asyncAction1)
.then(asyncAction2)
.then(asyncAction3)
.catch(console.error)
}

1 は async/await な方法
各処理の間に何かやりたいときにやりやすい
動的に実行関数変えるなら配列にして for-of で回すだけ

2 は Promise をチェーンさせる関数を使ったもの
関数作る必要あるけど chain は汎用的なものだし 1 回つくれば使い回せるからそこまで気にならない
関数の配列渡すだけなのでシンプル

3 は自分でチェーンさせたもの
2 よりこれのほうが見やすいかもだけど 動的に項目変わると対応しづらい
配列だけ作って渡せばいい 2 のほうが扱いやすい
Chrome 76 で設定画面がちょっと変わった
chrome://settings/help (about:chrome で表示されるところ) がちょっと変わった
75 だと左側にメニューはなしで ヘッダーのハンバーガーメニューで表示された
76 はハンバーガーメニューはなしでデフォルトで左側にメニューがでてる
lit-html で大文字のタグ名・属性名はどうとってるのか
lit-html 風なもの作ったり jsx 代わりのものを作ったとき テンプレートリテラルの文字列から DocumentFragment 作って DOM をパースしてってやったけどタグ名や属性名は大文字でも小文字になる

html`
<Component fooBar=${value}></Component>
`

って書いても DOM になったときには属性名は foobar になってて B が大文字って情報は消えてる
だから lit-html でプロパティに代入するときに .fooBar って書いてもダメかなと考えてたけど普通に使えた

どうやってるのか気になってソースみてみたら 属性名は分割点の直前なので一つ前のパートに対して正規表現で元々の属性名を抽出してた
正規表現は lastAttributeNameRegex って変数名に入ってる
外部 stylesheet のロードも style タグにしたい
JavaScript は script タグでインラインもできて src タグで外部ファイルのロードもできる
なのに style はインラインで書けるだけで外部ファイルのロードはできない
link タグとかぱっと分かりづらいし href 以外に rel="stylesheet" って属性も必要

style に揃えたいと思って考えみたら import するだけでいけた

<!doctype html>

<style>@import url(style.css)</style>

<h1>a</h1>

プロトタイプ拡張せずメソッド追加する
プロトタイプを追加してメソッドや getter を追加すれば便利なシーンは多いけど なんかプロトタイプ拡張は抵抗もあって積極的にはやってない
ふと クラスの extend で割といい感じになるんじゃないのって思ったのでやってみた

class SuperArray extends Array {
get first() { return this[0] }
get last() {return this[this.length - 1] }
}

const sa = SuperArray.from([1,2,3])
sa.last
// 3

sa.map(e => e + 10).last
// 13

作るときはリテラルじゃ書けずに変換必要で面倒だけど Uint8Array みたいなものと考えたらありといえばありかも
map とかで返ってくる配列も SuperArray になってるし

と思ったけど使えるのはオブジェクトのみで プリミティブ値の String などではダメだった
クラス構文なので new が必須になるけど new にするとオブジェクト版になってしまう
プリミティブ値に対してメソッド追加するのはやっぱりビルトインプロトタイプの拡張しかなさそう
Koa のラッパー
この記事見直してて もうちょっと改造したくなったのでやってみたもの
今 routes ではルーティング設定として各ルートの設定の配列だけをオプションで受け取るけど オブジェクトを受け取ってその一つの routes プロパティで今の配列にしたほうがいいかなって思う
そこで routes プロパティ以外に何を設定できるのか だけど ルーティングってサーバのメインみたいなものでその他ミドルウェアはそこでの処理をするためのおまけの前処理みたいな感じがするし サーバ設定や前段ミドルウェアをそこに書いてしまえば Koa 自体のインスタンス作ったり app.use したりという手間もなくなりそう
ルーティングだけじゃなくて Koa 自体のラッパーにする感じ
使い方はこんなイメージ

const koaServer = require("./path/to/koa-sever.js")
const static = require("koa-static")
const koaBody = require("koa-body")

koaServer({
server: {
keys: ["koakey"],
},
context: {
data: { x: 10 },
},
pre: [
static("."),
koaBody(),
],
routes: [
{
path: "/",
method: "GET",
handler(ctx) {
ctx.body = "ok"
},
},
],
})(8000)

server に app のプロパティ設定で context に app.context の設定
pre がミドルウェアで routes がルーティングの設定
これだけで困らない気がする
思いつくのであるとしたら https/http2 くらいだけど最後の関数呼び出しを http2 みたいなメソッド呼び出しでできるようにすれば十分そうだけど基本 http でいいし

作ってみるとすごく短く書けて感じこうなった(動作確認はしてない)

const Koa = require("koa")
const compose = require("koa-compose")
const routes = require("./path/to/routes.js")

export default options => {
options = options || {}
const app = new Koa()
Object.assign(app.context, options.context)
Object.assign(app, options.server)
app.use(compose([...pre, routes(options.routes)]))

const start = (...a) => app.listen(...a)
start.app = app
return start
}
Document の adoptedStyleSheets は全体に反映して欲しい
ShadowRoot のならその ShadowDOM の中で良いけど Document に設定したならすべての ShadowRoot にも反映して欲しい
ドキュメントなんだからコンポーネントも含めてグローバルでいいと思う
WebComponents 使ってると body 直下にルートコンポーネントを置いて ShadowRoot 外の要素なんてないことが普通
それだと Document に対する adoptedStyleSheets なんていらないし

一応こういう風に document.adoptedStyleSheets を継承させるベースクラスを作っておくことはできるけど毎回は面倒

class CustomHTMLElement extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: "open" }).adoptedStyleSheets = [
...document.adoptedStyleSheets,
this.cssstylesheet,
]
}

static css = ``

get cssstylesheet() {
if (!this.constructor.cssstylesheet) {
const cssss = new CSSStyleSheet()
cssss.replaceSync(this.constructor.css)
this.constructor.cssstylesheet = cssss
}
return this.constructor.cssstylesheet
}
}

使用例⇩

const cssss = new CSSStyleSheet()
cssss.replaceSync(`
button { background: black; color: white; border: 0; border-radius; 5px; padding: 3px 15px; }
`)
document.adoptedStyleSheets = [cssss]

customElements.define("ex-ample", class extends CustomHTMLElement {
static css = "button:hover { background: darkgray; }"

constructor() {
super()
this.shadowRoot.innerHTML = `<button>in component</button>`
}
})

document.body.innerHTML = `
<button>in document</button>
<ex-ample></ex-ample>
`
koa-body はファイルは絶対ローカルディスクに保存されるみたい
Koa の multipart パーサの @koa/multer 系は busboy を中で使ってる
これはファイルを stream として扱えるもの
ファイルにしたいなら pipe でファイルに保存するなど
multer では指定しない場合は MemoryStorage になって変数上に Buffer として持ってる
オプションでディスクへの書き込みもできる

koa-body は multipart も json も x-www-urlencoded も対応してる
けどファイル部分は Formidable 任せになってて ctx.request.files で取得できるデータも formidable の File インスタンス
formidable 自体が自動でディスクに書き込むアップロード用ツールみたいなので koa-body でファイルを受け取ると絶対ディスクに書き込まれる

ローカルに保存する必要はなくて変数上で操作するくらいなら koa-body より @koa/multer のほうが良さそう
アップロードされたファイルを read して delete する必要もあるのを考えると面倒そう
some, every の配列が空の時に逆になる版がほしい
どれかが true なら true が結果となる some で配列が空ということはどれも true じゃないので false という結果は正しいと言えば正しいです
しかし 条件を指定した場合にフィルタする目的の場合に 指定なしということは true という扱いは少なくないです
なので some と every に配列が空の場合に逆の値を返すバージョンがあると便利です
配列を取得してから一旦変数に入れて もし空ならと判断するより取得してからそのままメソッドに渡せたほうがいいですから
なので any, all メソッドを作りました
名前は .NET で some, every に当たるものです
.NET とは結果が違うので混乱しそうでもありますが JavaScript ですし some, every があるので別にいいかなと

Object.assign(Array.prototype, {
any(...a) {
if (this.length === 0) return true
return this.some(...a)
},
all(...a) {
if (this.length === 0) return false
return this.every(...a)
},
})

[1].some(e => true)
// true

[1].some(e => false)
// false

[].some(e => true)
// false

[].some(e => false)
// false

[1].any(e => true)
// true

[1].any(e => false)
// false

[].any(e => true)
// true

[].any(e => false)
// true

[1].every(e => true)
// true

[1].every(e => false)
// false

[].every(e => true)
// true

[].every(e => false)
// true

[1].all(e => true)
// true

[1].all(e => false)
// false

[].all(e => true)
// false

[].all(e => false)
// false
@koa/router で複数のメソッドのルートを登録する
router の get や post メソッドだとひとつずつの登録なので この方法にするとミドルウェア関数を別に作って get と post に同じミドルウェアを設定することになる
他と同じように登録する流れで直接ミドルウェア関数を定義したい場合は register メソッドが使える

const Koa = require("koa")
const Router = require("@koa/router")

const app = new Koa()
const router = new Router()

router.register("/getorpost", ["get", "post"], ctx => {
ctx.body = "get or post request"
})

app.use(router.routes())
app.listen(4000)
ブラウザからリクエストした結果
const res = await fetch("/getorpost", { method: "GET" })
const body = await res.text()
console.log(body)
// get or post request

const res = await fetch("/getorpost", { method: "POST" })
const body = await res.text()
console.log(body)
// get or post request

const res = await fetch("/getorpost", { method: "DELETE" })
const body = await res.text()
console.log(body)
// DELETE http://localhost:4000/getorpost 404 (Not Found)
// Not Found