deno v0.29.0の変更点

## 概要

https://github.com/denoland/deno/releases/tag/v0.29.0

denoのv0.29.0がリリースされたため、変更点をまとめます。

## xevalサブコマンドが削除された

`deno xeval`は標準入力から受け取ったスクリプトを評価することのできるサブコマンドでしたが、

独自の規則等も多かったため、削除されたようです。

https://github.com/denoland/deno/pull/3630

## `Deno.argv`にスクリプト名が含まれなくなった

https://github.com/denoland/deno/pull/3628

```typescript:cmd.ts
console.log(Deno.args);
```

```sh:v0.28.1
$ deno run ./cmd.ts
[ "./index.ts" ]
```

```sh:v0.29.0
$ deno run ./cmd.ts
[]
```

## スクリプト引数は`--`以降に指定するように変更された

```typescript:cmd.ts
console.log(Deno.args);
```

```sh:v0.28.1
$ deno run --allow-env ./cmd.ts -- arg1 arg2
[ "./index.ts", "--", "arg1", "arg2" ]

$ deno run --allow-env ./cmd.ts arg1 arg2
[ "./index.ts", "arg1", "arg2" ]
```

```sh:v0.29.0
$ deno run --allow-env ./cmd.ts -- arg1 arg2
[ "arg1", "arg2" ]

$ deno run --allow-env ./cmd.ts arg1 arg2
error: Found argument 'arg1' which wasn't expected, or isn't valid in this context
```

また、本修正にともない、`--allow`フラグの前にスクリプトを指定できるようになっています。

```typescript:cmd.ts
console.log(Deno.env());
```

```sh
# v0.29.0より前のバージョンでは、下記実行時にエラーが発生します
$  deno run ./cmd.ts --allow-env
{ ... }
```

- https://github.com/denoland/deno/pull/3621
- https://github.com/denoland/deno/issues/3469

## `Deno.mkdir`の型定義が修正された

`Deno.mkdir`が[スタイルガイド](https://deno.land/std/style_guide.md#exported-functions-max-2-args-put-the-rest-into-an-options-object)に準拠するよう修正されました。

v0.28.1以前では下記のようにオプションを指定していましたが、

```typescript:v0.28.1
// 再帰的にディレクトリを作成する
await Deno.mkdir('a/b', true);

// パーミッションを指定してディレクトリを作成する
await Deno.mkdir('a/b', true, 0o755);
```

v0.29.0では下記のようにオブジェクトを渡すことができます。

```typescript
// 再帰的にディレクトリを作成する
await Deno.mkdir('a/b', { recursive: true });

// パーミッションを指定してディレクトリを作成する
await Deno.mkdir('a/b', { recursive: true, mode: 0o755 });
```

https://github.com/denoland/deno/pull/3617

## `Deno.create`が追加された

`Deno.open(filename, 'w+')`と同様の挙動をします。

```typescript
const file = await Deno.create('hoge.txt');
try {
  const encoder = new TextEncoder();
  const data = encoder.encode('Hello');
  await file.write(data);
} finally {
  file.close();
}
```

https://github.com/denoland/deno/pull/3629

## コンパイラAPIが実装された

https://deno.land/std@v0.29.0/manual.md#compiler-api

denoに組み込まれているTypeScriptにアクセスするためのAPIが追加されました。

#### `Deno.compile(rootName, sources, options)`

`rootName`で指定されたファイルをコンパイルし、結果をキャッシュします。(Linux環境で確認したところ、コンパイル結果は `~/.cache/deno/gen`ディレクトリにキャッシュされているようです)

`sources`及び`options`引数の指定は必須ではありません。

`options`引数には`Deno.CompilerOptions`型(TypeScriptのコンパイラオプションのサブセット)のデータを渡せます。

`sources`オプションの有無によって挙動が異なります。

###### `sources`引数なし

下記のようなファイルを用意します。

```typescript:mod.ts
import { hoge } from './hoge.ts';

console.log(hoge());
```

```typescript:hoge.ts
export function hoge(): string {
  return 'hoge';
}
```

```typescript:index.ts
const [diagnostics, emitMap] = await Deno.compile('./mod.ts');
console.log(diagnostics); // コンパイルエラー等に関する情報. コンパイルに成功した際は`null`が返却されます。
console.log(JSON.stringify(emitMap, null, 2)); // コンパイル結果
```

`index.ts`を実行すると、`mod.ts`及びそこから再帰的にimportされているTypeScriptファイルがコンパイルされます。

```sh
$ deno run ./index.ts
null
{
  "file:///home/uki00a/work/hoge.js.map": "{\"version\":3,\"file\":\"hoge.js\",\"sourceRoot\":\"\",\"sources\":[\"hoge.ts\"],\"names\":[],\"mappings\":\"AAAA,MAAM,UAAU,IAAI;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC\"}",
  "file:///home/uki00a/work/hoge.js": "export function hoge() {\n    return 'hoge';\n}\n//# sourceMappingURL=hoge.js.map",
  "file:///home/uki00a/work/mod.js.map": "{\"version\":3,\"file\":\"mod.js\",\"sourceRoot\":\"\",\"sources\":[\"mod.ts\"],\"names\":[],\"mappings\":\"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC\"}",
  "file:///home/uki00a/work/mod.js": "import { hoge } from './hoge.ts';\nconsole.log(hoge());\n//# sourceMappingURL=mod.js.map"
}
```

###### `sources`引数あり

`sources`引数で指定された内容を元に、コンパイル時のモジュールの解決を行います。

`sources`引数には、キーにモジュール名、値にそのモジュールのソースを設定したオブジェクトを渡します。

```typescript:index.ts
const [diagnostics, emitMap] = await Deno.compile('/mod.ts', {
  '/mod.ts': `
      import { piyo } from "./piyo.ts";
      console.log(piyo());
    `,
  '/piyo.ts': 'export const piyo = () => "piyo";'
});
console.log(diagnostics);
console.log(JSON.stringify(emitMap, null, 2));
```

```sh
$ deno run ./index.ts
null
{
  "/piyo.js.map": "{\"version\":3,\"file\":\"piyo.js\",\"sourceRoot\":\"\",\"sources\":[\"piyo.ts\"],\"names\":[],\"mappings\":\"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC\"}",
  "/piyo.js": "export const piyo = () => \"piyo\";\n//# sourceMappingURL=piyo.js.map",
  "/mod.js.map": "{\"version\":3,\"file\":\"mod.js\",\"sourceRoot\":\"\",\"sources\":[\"mod.ts\"],\"names\":[],\"mappings\":\"AACQ,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC\"}",
  "/mod.js": "import { piyo } from \"./piyo.ts\";\nconsole.log(piyo());\n//# sourceMappingURL=mod.js.map"
}
```

#### `Deno.bundle(rootName, sources, options)`

引数の形式は`Deno.compile`と同様です。

`Deno.bundle`はモジュールのバンドルを行い、その結果を単一の文字列として返却します。

```typescript
(async () => {
  const [diagnostics, emit] = await Deno.bundle('/mod.ts', {
    '/mod.ts': `
        import { piyo } from "./piyo.ts";
        console.log(piyo());
      `,
    '/piyo.ts': 'export const piyo = () => "piyo";'
  });
  console.log(diagnostics);
  console.log(emit); // バンドル後のプログラム(文字列)
})();
```

#### `Deno.transpileOnly(sources, options)`

`sources`引数で渡された内容を元にトランスパイルを行い、その結果をソースファイル名をキー、トランスパイル結果を値として持つオブジェクトとして返却します。

型チェックやモジュールの依存解決は行われません。

`sources`及び`options`引数は、`Deno.compile`や`Deno.bundle`と同様の形式で指定します。

```typescript
const result = await Deno.transpileOnly({
  '/mod.ts': `
      import { piyo } from "./piyo.ts";
      console.log(piyo());
    `,
  '/piyo.ts': 'export const piyo = () => "piyo";'
});
console.log(JSON.stringify(result, null, 2));
/*
  {
    "/piyo.ts": {
      "source": "export const piyo = () => \"piyo\";\r\n//# sourceMappingURL=piyo.js.map",
      "map": "{\"version\":3,\"file\":\"piyo.js\",\"sourceRoot\":\"\",\"sources\":[\"piyo.ts\"],\"names\":[],\"mappings\":\"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC\"}"
    },
    "/mod.ts": {
      "source": "console.log(piyo());\r\n//# sourceMappingURL=mod.js.map",
      "map": "{\"version\":3,\"file\":\"mod.js\",\"sourceRoot\":\"\",\"sources\":[\"mod.ts\"],\"names\":[],\"mappings\":\"AAEQ,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC\"}"
    }
  }
*/
```

https://github.com/denoland/deno/pull/3442

## その他修正点

### WebSocketサーバに接続する際に、クエリパラメータが空であれば`?`が送信されないように修正された(std/ws)

https://github.com/denoland/deno/pull/3587

### std/encoding/yaml.tsから`parseAll`がエクスポートされた

https://github.com/denoland/deno/pull/3592

### `TextEncoder`のパフォーマンス向上

UTF-8文字列のエンコーディングがおよそ4.5倍程向上したようです。

https://github.com/denoland/deno/pull/3596


### libdenoがrusty_v8に置き換えられた

C++で実装されていたlibdenoが[rusty_v8](https://crates.io/crates/rusty_v8)に置き換えられました。

https://github.com/denoland/deno/pull/3556

### v8のバージョンが8.1.108にアップデートされた

https://github.com/denoland/deno/pull/3623