s2sのプラグインをTypeScript用に改変したメモ

[以前試した](https://qiita.com/hibohiboo/items/1e9c2351551df7416e4d)、[s2s-redux-saga](https://github.com/cndlhvn/s2s-redux-actions-sample/blob/master/JAREADME.md)をTypeSCript用に修正してみる。

今回はbabel-plugin-s2s-redux-actions-rootを修正する。
といっても、 `import a from 'a.ts'`となる部分を ` import a from 'a'` とする程度。

## 動作環境

* windows10
* vagrant1.9.7
* virtualbox5.1.26
* ubuntu-16.04
* Docker version 17.09.0-ce, build afdb6d4
* docker-compose version 1.17.1, build 6d101fb

## ソースコード

`getImportPath`メソッドを修正する。[kamijin](https://github.com/kamijin-fanta/babel-plugins/blob/master/packages/babel-plugin-s2s-action-root-ts/src/index.js)さんのts対応のコードを参考にさせていただいた。

```ts:src/s2s-utils-ts/index.ts
import {  getImportPath as origGetImportPath } from 's2s-utils'; // tslint:disable-line

export const getImportPath = (from: string, to: string) => {
  const path = origGetImportPath(from, to);
  const formatted = path.replace(/\.\w+$/, '');
  if (!/^\.\.?/.test(formatted)) {
    return `./${formatted}`;
  }
  return formatted;
};
```


```ts:src/babel-plugin-s2s-redux-actions-root-ts/index.ts
import syntaxTypeScript from '@babel/plugin-syntax-typescript';
import { PluginObj } from 'babel-core';
import { NodePath } from 'babel-traverse';
import { Program } from 'babel-types';
import * as globby from 'globby';
import PluginArgs from '../PluginArgs';
import { getImportPath } from '../s2s-utils-ts';

export default (babel: PluginArgs): PluginObj => {
  if (babel === undefined) { return { visitor:{} }; }
  const { types:t } = babel;
  const defaultExport = (source => t.exportAllDeclaration(t.stringLiteral(source)));

  return {
    name: 's2s-redux-actions-root-ts',
    inherits: syntaxTypeScript,
    visitor: {
      Program: {
        exit(path: NodePath<Program>, state) {
	      const { input, output } = state.opts;
          if (!input) {
            throw new Error('require input option');
          }

          if (!output) {
            throw new Error('require output option');
          }

          const files = globby.sync(input);
          const index = files.indexOf(output);

          if (index > -1) {
            files.splice(index, 1);
          }

          const imports = files.map(f => defaultExport(getImportPath(output, f)));

          path.node.body = [
            ...imports,
          ];
        },
      },
    },
  };
};
```
## テスト

```ts:src/babel-plugin-s2s-redux-actions-root-ts/index.ts
import * as pluginTester from 'babel-plugin-tester';
import * as path from 'path';
import { default as plugin } from '.';

const cwd = __dirname;

// index.tsが作成されることを確認
const output = path.resolve(cwd, 'src', 'actions', 'index.ts');
const input = `${__dirname}/__fixtures__/**/*.ts`;

// コードがあるとき
pluginTester({
  plugin,
  snapshot: true,
  pluginOptions: { input, output },
  tests: [
    {
      title: 'index.tsが作成されて、内容が正しいこと',
      code: `empty`,
    },
  ],
});

pluginTester({
  plugin,
  tests: [
    {
      title: 'error',
      code: `// throw error`,
      error: /require input option/,
    },
  ],
});

pluginTester({
  plugin,
  pluginOptions: { input: 'src/__fixtures__/**/*.js' },
  tests: [
    {
      title: 'error',
      code: `// throw error`,
      error: /require output option/,
    },
  ],
});
```

## 設定ファイル

```js:s2s.config.js
var reduxActionsRoot = require('./packages/babel-plugin-s2s-redux-actions-root-ts').default;

module.exports = {
  watch: './**/*.ts',
  plugins: [
    {
      test: /src\/actions\/(?!.*index).*\.ts/,
      plugin: ['s2s-redux-actions', {autocomplete: false}]
    },
    {
      test: /src\/actions\/(?!.*index).*\.ts/,
      output: "index.ts",
      plugin: [reduxActionsRoot,
      { input: 'src/actions/*.ts', output: "src/actions/index.ts" }]
    },
  ],

  templates: [
    {
      test: /src\/actions\/.*\.ts/, input: 'redux-action.ts'
    },
  ]
}
```

[この時点のソース](https://github.com/hibohiboo/develop/blob/0f660fce6e0391589383c4743a6e7624a715d487/tutorial/lesson/s2s-plugins-ts/)

## 参考
https://github.com/cndlhvn/babel-plugin-s2s-redux-actions-root
https://github.com/akameco/babel-plugin-s2s-action-root/blob/master/src/index.js
https://github.com/kamijin-fanta/babel-plugins/blob/master/packages/babel-plugin-s2s-action-root-ts/src/index.js