お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
言語::MarkdownNode.js::Prettier

PrettierというとTypeScriptやJavaScriptのコードを整形するツールであって、Markdownを整形するツールという意識のある人は少ないかもしれない。

それが実はPrettierはMarkdownの整形に使えるのだ。例えば次の図はPrettierを使ってMarkdownを整形しているシーンを撮ったものだ。具体的にはnpx prettier -w hoge.mdした時の前後を撮っている。

prettier-md.gif

これは別の文書からコピペしたなどで書式が崩れることや単純なtypoでズレたりしたときに地味に効果を発揮してくれる。Prettier v2以前だと全角と半角文字の間の自動スペース挿入が嬉しかった人もいるだろうが、v3でこの機能は廃止されている。

他にもチーム開発だとMarkdownの細かい仕様に熟知した人は多くないので、最低限の書式を合わせるのにも役立つだろう。Markdownのインデント幅を変えたいが、コードフェンスの中のインデントは変えたくないみたいな用途みたいなカスタマイズもできるし、個人用途でも結構使える。

しかしフォーマッタの挙動がアップデートでころころ変わるのは割と不快なので、この辺りは何とかなってほしい気もする。

投稿日:
Node.js::その他サービス::GitHub::GitHub Actions

Node.jsのスクリプトを適当に書き次のようなWorkflowsを記述することで実行できる。勿論Dockerイメージを作ってそこから立ち上げることもできるので好みの問題。直に呼べる分、取り回しは楽だと思う

name: hoge
description: hoge
inputs:
  GITHUB_TOKEN:
    description: 'Workflowsを実行するリポジトリのGITHUB_TOKEN'
    required: true
on:
  workflow_call:
runs:
  using: node20
  main: dist/index.js

inputs:outputs:を記述すれば入出力の引数も定義できる。

inputs.GITHUB_TOKENについて

これを書いておくとoctokitを使ってGitHubのAPIを叩けるようになる。普通は何かAPIを叩くはずなので書いておいた方が良い。

以下は一例。

const github = require('@actions/github');
const core = require('@actions/core');

async function run() {
    const token = core.getInput('GITHUB_TOKEN');
    const octokit = github.getOctokit(token);

    const { data: pullRequest } = await octokit.rest.pulls.get({
        owner: 'octokit',
        repo: 'rest.js',
        pull_number: 123,
        mediaType: {
          format: 'diff'
        }
    });

    console.log(pullRequest);
}

参考

prettier-vscodeをPrettier v3に対応させる試みは既にあるのだが、PRがRejectされている。レビューを見た感じtypoが原因っぽいのでtypoを直してみたのだがテストが落ちる

まずテストが通らない原因だが、これはアサーション結果とテストコード、落ちた時の結果を三点比較したときに落ちた時の結果がプラグインを反映せずprettier -wされたものであることに気が付いた。次にこの解決法だが、原因が複数あるため、その切り分けが必要だと考えている。これはテスト走行時に指定されたプラグインが正しく読み込まれていればテストを通すことができるはずだが、package.jsonの指定通りインストールされているのかや、prettier側が正常に読み込めているのかなどが解らないと、真の原因が突き止められないためだ。

見た感じ割と面倒な仕組みなテストを実行してそうだったので一旦私は諦めることにした。これはprettier v3を個別にインストールすることで基本的に解決できるためだ。とはいえ、インストールできない条件だとその回避に苦労するのでネイティブに対応してほしい思いはあるが、検証するにも本家リポジトリにPRを向けないとテスト走行すらままならず、ローカルでの検証が極めて厳しいので、正直やる気が起きない。ぶっちゃけDockerで個別テストケースごとにビルドしてやるのが一番仕組みが単純で安全に思うが、敷くほど遅くなりそうだし、イメージのメンテも大変そうだし、アホほどイメージができるはずなので、容量も食いそうでなかなか微妙そうである。

そもそも論としてmainブランチを引っ張ってきてビルドすると、この時点で型エラーを吐くので、ここからどうにかしていく必要があり、割としんどい作業になりそうだ。

投稿日:
技術::プロトコル::HTTP言語::PHPNode.js::その他

動機としてはcurlだと見えない部分があるので、自分でHTTPメッセージを手組みして送ってみたかった。

Node.jsとPHPのサーバーでリクエストが期待通り取得できたので、メッセージの実装としては問題ないと思われる。

検証用サーバー

以下のコードをNode.js v20.11.1を用いて検証

import http from 'node:http';

http
  .createServer((req, res) => {
    console.log(req.headers);
    req.on('data', (chunk) => {
      // body
      console.log(Buffer.from(chunk).toString());
    });
    res.statusCode = 200;
    res.end();
  })
  .listen(9999);

netcatコマンドによるリクエスト検証

GETリクエスト

echo -e 'GET / HTTP/1.1\r\nHost: localhost:9999\r\n\r\n' | nc localhost 9999

POSTリクエスト

echo -e 'POST / HTTP/1.1\r\nHost: localhost:9999\r\nContent-Length: 4\r\n\r\nhoge' | nc localhost 9999

備考

PHPで検証サーバーを作る場合

実際にAPサーバーでリクエストの中身をパース出来るかどうかの観点で見た場合にNode.jsよりPHPのが楽なので、PHPで作ってみた結果、軽くハマったので残しておく。

以下のコードを用いてPHP 8.0.29で検証サーバーを作る場合に、php -S 0.0.0.0:9999としてサーバーを起動すると、Content-Typeヘッダがない場合に正常な動作をしなかった。

<?php

var_dump($_SERVER);
var_dump($_REQUEST);

ncで検証サーバーを作る場合

デバッグ用。生のメッセージが見れるのでダンプしてdiffを取るなどでcurlとecho + ncの差分を見るのに使える。

nc -l 9999

HTTPメソッド名を非標準的なものにした場合の挙動

前述のNode.jsサーバーでは400 Bad Request、PHPサーバーでは501 Not Implementedが応答された。

HTTPヘッダを持たないHTTPリクエストはあり得るのか?というのを検証しているときに気づいた話。

RFC 7230ではHostヘッダを持たないHTTPリクエストは禁止されており、これを受けたサーバーは400応答を返すことを必須としている。

RFC 7230:Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and RoutingHostより

A client MUST send a Host header field in an HTTP/1.1 request even if
the request-target is in the absolute-form, since this allows the
Host information to be forwarded through ancient HTTP/1.0 proxies
that might not have implemented Host.
A server MUST respond with a 400 (Bad Request) status code to any
HTTP/1.1 request message that lacks a Host header field and to any
request message that contains more than one Host header field or a
Host header field with an invalid field-value.

なお、Node.jsのHTTPサーバー機能ではHostヘッダーのない要求を受け入れることができる。

http.createServer([options][, requestListener])を見ると、以下のようにrequireHostHeader: falseを渡すことで実現可能だ。規定値はtrueであるため、基本的にはHostヘッダーなしの要求は400応答が返される。

import http from 'node:http';

http
  .createServer({requireHostHeader: false}, (req, res) => {
    console.log(req.headers);
    res.statusCode = 200;
    res.end();
  })
  .listen(3000);

nginxにおいてもHostヘッダーなしの要求は以下の応答が返されたため同様と思われる。

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.26.0</center>
</body>
</html>

但し、nginxにおいてHostなしの要求を許容する方法は見つからなかった。Server namesによるとserver_name "";とすることで出来そうに見えたが、これは機能させることができず、400応答が返された。