このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

TypeScriptコンパイラとそのAPI

コンパイラのソースを見ているが、

  1. /src/compiler/types.ts の export const enum SyntaxKind に、構文範疇が列挙されている。機能性に直接影響しない構文範疇をトリビアと呼んでいる。
    1. SingleLineCommentTrivia,
    2. MultiLineCommentTrivia,
    3. NewLineTrivia,
    4. WhitespaceTrivia,
    5. ShebangTrivia, // We detect and preserve #! on the first line
    6. ConflictMarkerTrivia, // We detect and provide better error recovery when we encounter a git merge marker. This
      // allows us to edit files with git-conflict markers in them in a much more pleasant manner.
  2. さらにJSDocスタイルのドキュメンテーションコメントは特別扱いして、パーザーが見ている。
    1. JSDocTypeExpression,
    2. JSDocAllType,
    3. JSDocUnknownType,
    4. その他イッパイ
  3. 実質的にJSDocパーザーを含み、ASTにJSDoc構文が反映される。
  4. 構文範疇〈SyntaxKind〉は、トークン種別と文法要素の両方が含まれる。トークンは*Tokenという名前になっている。
  5. 予約語は*Keywordという名前。
    1. BreakKeyword,
    2. CaseKeyword,
    3. CatchKeyword,
    4. その他イッパイ

コンパイラAPIについては、

TypeScriptはもともとグローバル(c:/Users/hiyama/AppData/Local/Yarn/)にあるのだけど、プロジェクト内に入れてみる。

  • yarn add typescript

これだと、link機構とかは不要。

typescriptはNode.jsで実行するから、Node.jsの型宣言が必要。

  • yarn add @types/node

これで、プロジェクトのnode_modules/@types配下にNode.jsに関する型宣言が入る。

"A minimal compiler"をとりあえずやってみる。ソースをコピーしてtscコンパイル、nodeで実行。

import * as ts from "typescript";

function compile(fileNames: string[], options: ts.CompilerOptions): void {
    let program = ts.createProgram(fileNames, options);
    let emitResult = program.emit();

    let allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);

    allDiagnostics.forEach(diagnostic => {
        if (diagnostic.file) {
            let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
            let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
            console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
        }
        else {
            console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`);
        }
    });

    let exitCode = emitResult.emitSkipped ? 1 : 0;
    console.log(`Process exiting with code '${exitCode}'.`);
    process.exit(exitCode);
}

compile(process.argv.slice(2), {
    noEmitOnError: true, noImplicitAny: true,
    target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
});

この例は、トランスレートしないで、エラーをチェックするだけだ。

ts.transpileModuleという関数がトランスパイルを実行するようなので、この関数を眺めないとダメか。

[追記]transpileModuleは、

src/services/が外部に出しているAPIのエントリーポイントらしい。

[/追記]