Full Code of theseanl/tscc for AI

master 7c0a7a5194e5 cached
185 files
459.6 KB
129.2k tokens
449 symbols
1 requests
Download .txt
Showing preview only (513K chars total). Download the full file or copy to clipboard to get everything.
Repository: theseanl/tscc
Branch: master
Commit: 7c0a7a5194e5
Files: 185
Total size: 459.6 KB

Directory structure:
gitextract_d855frd2/

├── .circleci/
│   └── config.yml
├── .editorconfig
├── .github/
│   └── dependabot.yml
├── .gitignore
├── .vscode/
│   └── settings.json
├── LICENSE
├── README.md
├── jest.config.js
├── lerna.json
├── package.json
├── packages/
│   ├── rollup-plugin-tscc/
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── MultiMap.ts
│   │   │   ├── goog_shim_mixin.ts
│   │   │   ├── index.ts
│   │   │   ├── merge_chunks.ts
│   │   │   ├── sort_chunks.ts
│   │   │   └── spec/
│   │   │       ├── ITsccSpecRollupFacade.ts
│   │   │       └── TsccSpecRollupFacade.ts
│   │   ├── test/
│   │   │   ├── __snapshots__/
│   │   │   │   └── golden_test.ts.snap
│   │   │   ├── golden_test.ts
│   │   │   ├── merge_chunks.ts
│   │   │   ├── sample/
│   │   │   │   ├── external-modules/
│   │   │   │   │   ├── entry.js
│   │   │   │   │   └── tscc.spec.json
│   │   │   │   ├── external-modules-in-many-module-build/
│   │   │   │   │   ├── common/
│   │   │   │   │   │   └── index.js
│   │   │   │   │   ├── dependent.js
│   │   │   │   │   ├── entry.js
│   │   │   │   │   └── tscc.spec.json
│   │   │   │   ├── goog-shim/
│   │   │   │   │   ├── dependent.js
│   │   │   │   │   ├── entry.js
│   │   │   │   │   ├── tscc.spec.json
│   │   │   │   │   └── tscc.spec.module.json
│   │   │   │   └── many-module-build/
│   │   │   │       ├── common.js
│   │   │   │       ├── dir/
│   │   │   │       │   └── dependency.js
│   │   │   │       ├── entry.js
│   │   │   │       ├── tscc.spec.json
│   │   │   │       └── tscc.spec.module.json
│   │   │   └── sort_chunks.ts
│   │   ├── third_party/
│   │   │   └── closure_library/
│   │   │       ├── README.md
│   │   │       ├── goog_shim.js
│   │   │       └── reflect_shim.js
│   │   └── tsconfig.json
│   ├── tscc/
│   │   ├── .npmignore
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── default_libs.ts
│   │   │   ├── external_module_support.ts
│   │   │   ├── graph/
│   │   │   │   ├── Cache.ts
│   │   │   │   ├── ClosureDependencyGraph.ts
│   │   │   │   ├── ISourceNode.ts
│   │   │   │   ├── TypescriptDependencyGraph.ts
│   │   │   │   └── source_node_factory.ts
│   │   │   ├── log/
│   │   │   │   ├── Logger.ts
│   │   │   │   └── spinner.ts
│   │   │   ├── main.ts
│   │   │   ├── shared/
│   │   │   │   ├── PartialMap.ts
│   │   │   │   ├── array_utils.ts
│   │   │   │   ├── escape_goog_identifier.ts
│   │   │   │   ├── sourcemap_splice.ts
│   │   │   │   └── vinyl_utils.ts
│   │   │   ├── spawn_compiler.ts
│   │   │   ├── spec/
│   │   │   │   ├── ITsccSpecWithTS.ts
│   │   │   │   └── TsccSpecWithTS.ts
│   │   │   ├── transformer/
│   │   │   │   ├── decorator_property_transformer.ts
│   │   │   │   ├── dts_requiretype_transformer.ts
│   │   │   │   ├── goog_namespace_transformer.ts
│   │   │   │   ├── rest_property_transformer.ts
│   │   │   │   ├── transformer_utils.ts
│   │   │   │   └── ts_helper_transformer.ts
│   │   │   ├── tscc.ts
│   │   │   └── tsickle_patches/
│   │   │       ├── facade.ts
│   │   │       ├── patch_tsickle_decorator_transformer.ts
│   │   │       └── patch_tsickle_module_resolver.ts
│   │   ├── test/
│   │   │   ├── e2e/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── golden_test.ts.snap
│   │   │   │   ├── golden_test.ts
│   │   │   │   └── sample/
│   │   │   │       ├── case_1/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── ab.ts
│   │   │   │       │   ├── b.ts
│   │   │   │       │   ├── bb.ts
│   │   │   │       │   ├── bc.ts
│   │   │   │       │   ├── c.ts
│   │   │   │       │   ├── cc.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_10_unsafe_module_name_and_script_dts/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── script_dts.d.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_11_referencing_goog/
│   │   │   │       │   ├── dependent.ts
│   │   │   │       │   ├── entry.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_12_using_jsFiles/
│   │   │   │       │   ├── entry.ts
│   │   │   │       │   ├── jsfile.d.ts
│   │   │   │       │   ├── jsfile.js
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_13_chunk_format_global/
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_14_chunk_format_module/
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_2_sourcemaps/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_3_sourcemaps_with_decorators/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_4_external/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_5_object_spread/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_6_type_only_references/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── b.ts
│   │   │   │       │   ├── c.ts
│   │   │   │       │   ├── d.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_7_lodash_style_external_module_declaration/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_8_dts_requiretype/
│   │   │   │       │   ├── imported.d.ts
│   │   │   │       │   ├── module.ts
│   │   │   │       │   ├── transtively_imported.d.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       └── case_9_ts_in_node_modules/
│   │   │   │           ├── index.ts
│   │   │   │           ├── tscc.spec.json
│   │   │   │           └── tsconfig.json
│   │   │   ├── graph/
│   │   │   │   ├── ClosureDependencyGraph.ts
│   │   │   │   ├── TypescriptDependencyGraph.ts
│   │   │   │   └── source_node_factory.ts
│   │   │   ├── main.ts
│   │   │   ├── sample/
│   │   │   │   ├── decorator/
│   │   │   │   │   └── decorates.ts
│   │   │   │   ├── dts_requiretype/
│   │   │   │   │   ├── entry.ts
│   │   │   │   │   └── required.d.ts
│   │   │   │   ├── goog_module.js
│   │   │   │   ├── rest/
│   │   │   │   │   ├── case_1.ts
│   │   │   │   │   └── combined_with_decorators.ts
│   │   │   │   ├── tsconfig.json
│   │   │   │   └── tsdepsgraph/
│   │   │   │       ├── a.ts
│   │   │   │       ├── ab.d.ts
│   │   │   │       ├── b.d.ts
│   │   │   │       ├── bb.d.ts
│   │   │   │       ├── entry.ts
│   │   │   │       └── tsconfig.json
│   │   │   ├── shared/
│   │   │   │   ├── escape_goog_identifier.ts
│   │   │   │   └── sourcemap_splice.ts
│   │   │   ├── spec/
│   │   │   │   ├── TsccSpecWithTS.ts
│   │   │   │   └── sample/
│   │   │   │       ├── empty.ts
│   │   │   │       ├── nested_directory/
│   │   │   │       │   ├── empty.ts
│   │   │   │       │   └── tsconfig.json
│   │   │   │       └── tsconfig.1.json
│   │   │   ├── transformer/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── transformers.ts.snap
│   │   │   │   └── transformers.ts
│   │   │   ├── tsconfig.test_files.json
│   │   │   └── tsickle_patches/
│   │   │       └── patch_tsickle_module_resolver.ts
│   │   ├── third_party/
│   │   │   ├── closure_library/
│   │   │   │   ├── base.d.ts
│   │   │   │   ├── base.js
│   │   │   │   ├── reflect.d.ts
│   │   │   │   └── reflect.js
│   │   │   └── tsickle/
│   │   │       ├── closure_externs.js
│   │   │       └── third_party/
│   │   │           └── tslib/
│   │   │               ├── LICENSE.txt
│   │   │               ├── README.google
│   │   │               ├── externs.js
│   │   │               └── tslib.js
│   │   └── tsconfig.json
│   └── tscc-spec/
│       ├── .npmignore
│       ├── index.ts
│       ├── package.json
│       ├── src/
│       │   ├── ITsccSpec.ts
│       │   ├── ITsccSpecJSON.ts
│       │   ├── TsccSpec.ts
│       │   └── shared/
│       │       └── Graph.ts
│       ├── test/
│       │   ├── TsccSpec.ts
│       │   ├── sample/
│       │   │   ├── invalid_json.json
│       │   │   ├── spec_with_relative_external.json
│       │   │   ├── tscc.spec.json
│       │   │   └── unsupported_spec.json
│       │   └── shared/
│       │       └── Graph.ts
│       └── tsconfig.json
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
cache_key: &cache_key tscc-{{ checksum "yarn.lock" }}
save_cache: &save_cache
  save_cache:
    key: *cache_key
    paths:
      - "node_modules"

version: 2

jobs:
  build:
    parallelism: 3
    docker:
      - image: circleci/openjdk:9-node
    working_directory: ~/tscc
    steps:
      - checkout
      - run:
          name: update node
          command: |
            curl -sSL "https://nodejs.org/dist/v14.17.3/node-v14.17.3-linux-x64.tar.xz" | sudo tar --strip-components=2 -xJ -C /usr/local/bin/ node-v14.17.3-linux-x64/bin/node
      - restore_cache:
          key: *cache_key
      - run: yarn install
      - run: yarn lerna bootstrap
      - run:
          name: run tests
          command: yarn jest --ci --runInBand --reporters=default --reporters=jest-junit
          environment:
            JEST_JUNIT_OUTPUT: "reports/junit/results.xml"
      - run:
          name: compile typescript
          command: yarn lerna exec -- -- tsc --noEmit
      - *save_cache
      - store_test_results:
          path: reports/junit
      - store_artifacts:
          path: reports/junit


================================================
FILE: .editorconfig
================================================
root = true

[*]
end_of_line = lf
insert_final_newline = true

[*.{js,jsx,ts,tsx,css,html,json}]
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
max_line_length = 100

[*.md]
trim_trailing_whitespace = false



================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: npm
  directory: "/"
  schedule:
    interval: weekly
  open-pull-requests-limit: 20
  ignore:
  - dependency-name: typescript
    versions:
    - "> 3.9.7"
  - dependency-name: tslib
    versions:
    - 2.1.0


================================================
FILE: .gitignore
================================================
/node_modules
/packages/*/node_modules
dist
lerna-debug.log
junit.xml
.tscc_temp
yarn-error.log
.vscode/**/*.log


================================================
FILE: .vscode/settings.json
================================================
{
	"editor.rulers": [
		100
	],
	"editor.formatOnSave": true,
	"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
	"javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
	"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
	"typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
	"jest.jestCommandLine": "jest"
}


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Sean Lee

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# TSCC

[![tscc npm version](https://img.shields.io/npm/v/@tscc/tscc.svg?style=popout&color=blue&label=%40tscc%2Ftscc)](https://www.npmjs.com/package/@tscc/tscc)
[![rollup-plugin-tscc npm version](https://img.shields.io/npm/v/@tscc/rollup-plugin-tscc.svg?style=popout&color=blue&label=%40tscc%2Frollup-plugin-tscc)](https://www.npmjs.com/package/@tscc/rollup-plugin-tscc)
[![CircleCI](https://circleci.com/gh/theseanl/tscc.svg?style=svg)](https://circleci.com/gh/theseanl/tscc)

TSCC is a collection of tools to seamlessly bundle and minify Typescript project using Closure Compiler.

## Migrate

It is easy to migrate an existing Typescript project to TSCC.
To get a sense of what it is like, check out [todomvc apps](https://github.com/theseanl/todomvc/) forked from the original [tastejs/todomvc](https://github.com/tastejs/todomvc) and modified to use TSCC.

---

## Features

 - Automatically configures settings for [tsickle](https://github.com/angular/tsickle) and [closure compiler](https://github.com/google/closure-compiler), and wires up tsickle js outputs and sourcemaps to closure compiler, sorted in accordence with dependency information, as required by closure compiler.
 - Provides an alternative [rollup](https://rollupjs.org) build using `rollup-plugin-tscc` plugin, emulating the chunking behaviour of closure compiler to get the same set of output files as what closure compiler would produce.
 - External module support: looks up `require`d nodejs modules and wires them so that externs are generated, and transforms any code that uses externally imported variables. Think of it as an analogue of ["external" option of webpack](https://webpack.js.org/configuration/externals/#externals) or ["globals" option of rollup](https://rollupjs.org/guide/en/#outputglobals) for closure compiler.

## Background

Closure is a wonderful system of tools. The closure compiler is the best javascript minifier and bundler, but it is known to be very difficult to use. Documentations are scarce, and integration with external tools is not well-established.

Tsickle is another wonderful tool. It has finally made it ergonomic to write codes that can naturally be consumed by closure compiler — it transforms `.ts` files to well-annotated `.js` files, which would otherwise not even be consumed by the compiler and automatically generates [externs](https://developers.google.com/closure/compiler/docs/api-tutorial3#externs) file from declaration files. However, as in closure compiler, one has to be careful with setting it up, otherwise strange bugs can occur which are not actively worked on as of now. Also, it only performs transpilation — there is no tool to feed transpiled files to closure compiler, which is another painful part.

TSCC aims to encapsulate these tools in a minimal, ergonomic API, and provides a faster and easier alternative bundling method using [Rollup](https://rollupjs.org) via a companion rollup-plugin-tscc plugin, which is great for rapid development. TSCC can be used as a drop-in replacement for rollup in existing projects using rollup, after moving chunk information in `rollup.config.js` to [`tscc.spec.json`](#tscc-spec-files). TSCC spec file is a single source of truth for all of your module bundling information.

## Getting started

Suppose that we have a project with the following directory structure.
```
my_project
├───tsconfig.json
├───rollup.config.js
└───src
    ├───Components
    │   ...
    └───app.ts
```

1. Install tscc cli:
    ```
    yarn global add @tscc/tscc
    ```
2. Create a [_spec file_](#tscc-spec-files) `tscc.spec.json` next to `tsconfig.json`.
    ```jsonc
    {
        "modules": {
            "out": "src/app.ts" // entry file path
        }
    }
    ```
3. Execute at the project root:
    ```
    tscc
    ```
In order to setup an alternative rollup build,

1. In your project's directory, install `@tscc/rollup-plugin-tscc` by executing:
    ```
    yarn add -D @tscc/rollup-plugin-tscc
    ```
2. Import `rollup-plugin-tscc` plugin in rollup config file.
    ```js
    // rollup.config.js
    import tscc from '@tscc/rollup-plugin-tscc';
    export default {
        output: {
            ...,
            dir: '.'
        },
        plugins: [
            tscc(),
            typescript()
        ]
    }
    ```
3. Execute `rollup` at the project root.

## Usage

### Command line

@tscc/tscc package provides a single command line interface `tscc`.

```
tscc [--help] [--clean] [--spec <spec_file_path>] [-- <typescript_flags> [-- <closure_compiler_flags>]]
```

It will compile & bundle typescript sourced based on module spec described in `spec_file`. Alternatively, one can provide the spec file's key-value pairs via command line arguments, see below. Note that one have to provide a spec file or at least a value for a 'module' - if both are omitted, it will assume that the spec file's path is implicitly set as the current working directory.

Arguments passed after the first `--`, if exists, will be passed to the typescript compiler as one would pass to `tsc`, and arguments after the second `--` will be passed to the closure compiler. e.g. `tscc --spec src -- --target ES5 -- --assume_function_wrapper`. Note that `tsc` assumes that the project root (`--project`) is the current working directory when it is omitted, but `tscc` assumes that it is the containing directory of the spec file.

### JS API

Simply provide contents of spec file as an argument:

```js
import tscc from 'tscc';

tscc({
    modules: {
        bundle: 'entry.ts'
    },
    prefix: 'dist/'
    // ...
}).then(() => console.log('Done'));
```

The default export `tscc` function accepts up to 3 arguments.
```ts
tscc(
    json_content_of_spec_file_or_path_to_spec_file,
    path_to_search_for_tsconfig?:string,
    typescript_compiler_option_override?
):Promise<void>
```
The first argument is either a string representing the path of the spec file or a JSON content of the spec file. The JSON object can additionally have `specFile` property, whose value is a path to a spec file. TSCC will lookup tscc spec file at that path and merge its contents.

```js
tscc({
    /* Contents of spec JSON */
    specFile: "path_to_spec_file.json"
})
// To load spec file from the path and override it.
```

The second argument should be self-explanatory; the third argument is what would you put in tsconfig.json's "compilerOption" key, it will override those provided with the second argument.

### Usage with rollup

@tscc/rollup-plugin-tscc package provides a rollup plugin which will provide chunking information in your spec file to rollup.

Install `rollup-plugin-tscc` by executing `yarn add -D @tscc/rollup-plugin-tscc`.
```js
// rollup.config.js
const tscc = require('@tscc/rollup-plugin-tscc');
module.exports = {
    output: {
        dir: '.' // output.dir option will be provided by the plugin, but
                 // rollup currently requires something to be present in order to
                 // work properly.
    },
    // ...
    plugins: [
        tscc({
            /* Contents of spec JSON */
            // or,
            specFile: "path_to_spec_file.json"
        })
    ]
};
```
Then it will provide the information in your spec file to rollup, and post-process code-splitting chunks produced by rollup to match the behavior of Closure Compiler, so that you can use `rollup` build interchangeably with `tscc` build.
The plugin will control the `input`, `output.dir`, `output.entryFileNames`, `output.chunkFileNames` option.
Note that it does not transpile TS to JS, one has to provide another plugin manually, such as [rollup-plugin-typescript2](https://github.com/ezolenko/rollup-plugin-typescript2).

## Tscc spec files

Tscc spec file is a single source of truth of your bundling information. It describes each of output bundle's entry file and dependencies among them. It also describes which modules imported in your source shall be treated as an external module and aliased with which global variable.

```js
{
    modules, /* required */
    external,
    prefix,
    chunkFormat,
    compilerFlags,
    jsFiles,
    debug
}
```

### `modules`

```jsonc
    "modules": {
        "index": "index.ts",
        "dependent_a": {
            "entry": "dependent_a_entry_file.ts",
            "dependencies": [ "index" ],
            "extraSources": [ "css_renaming_map.js" ]
        }
    }
```
`modules` option is a key-value pair of module name and module's specification. If a specification only consists of a entry file name, it can simply be a string representing the entry file's path, which is sufficient for most of build situation where no code splitting is applied. In general, module's specification consists of `entry`, `dependencies`, and `extraSources`. `dependencies` is an array of module names that this module depends on. It can be omitted if empty. Module names specified here will be provided to closure compiler via  `--chunk` flags, so check out a more detailed description of it in [Closure Compiler repo](https://github.com/google/closure-compiler/wiki/JS-Modules#code-splitting-output-modules). `extraSources` is an array of file names, which are not included in the Typescript project or not reacheable from a specified entry file via `import`s, but still needed to be provided to the closure compiler, such as css renaming maps generated by [Closure Stylesheets](https://github.com/google/closure-stylesheets). It can be omitted if empty. A module's name is an identifier to be used as a output chunk's name. To control the output directory, use `prefix` option.

CLI equivalent is `--module <module_name>:<entry_file>:<comma_separated_dependencies>:<comma_separated_extra_sources>`.

### `external`

```jsonc
{
    "external": {
        "react": "React",
        "react-dom": "ReactDOM",
    }
}
```

It is mostly identical to the [`output.global` option](https://rollupjs.org/guide/en#core-functionality) of rollup. It is a key-value pair, where key is a module name whose content will not be included in the bundle output, and value is a name of a global variable to which an `module.exports` of the module will be aliased.

If a module name is a relative path, the file it _resolves to_ will be treated as an external module. This is similar to rollup's case, but is different in that only relative path can be used and absolute paths can't. Such paths are resolved in the same convention how other relative paths in the spec file are resolved, see `prefix` option description.

CLI equivalent is `--external <module_name>:<global_variable_name>`.

### `prefix`

```jsonc
    "prefix": "dist/"
    // or,
    "prefix": { "rollup": "dev/", "cc": "dist/" }
```
It is a name that will be prepended to the output chunk's name. It is prepended _as is_, which means that if no trailing path separator was provided, it will modify the output file's name. If it is a relative path starting from the current directory ("."), it will be resolved relative to the spec file's location. Otherwise, any relative path will be resolved relative to the current working directory, and absolute paths are used as is.

CLI equivalent is `--prefix dist/` (or `--prefix.rollup dev/ --prefix.cc dist/`).

### `chunkFormat`

```jsonc
    "chunkFormat": "global" /* default */ | "module"
```
It is a value of `"global"` or `"module"` designating the output chunks' format. In case of `"global"`, which is the default behavior if this key isn't specified, output chunks will be plain Javascript that is suitable for `<script src="">` HTML tag, and cross-chunk references will be done by exposing them to the global scope. In case of `"module"`, output chunks will be [Javascript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) which has to be included via `<script type="module" src="">` tags, and cross-chunk references will be done by `import` and `export` statements. Currently, when `"module"` option is used, `external` option cannot be used.

### `compilerFlags`

```jsonc
    "compilerFlags": {
        "assume_function_wrapper": true,
        "rewrite_polyfills": true,
        "language_out": "ECMASCRIPT_2019",
        "variable_renaming_report": "out/report.map"
    }
```
It is a key-value pair of flags to be passed to the closure compiler. Keys are literally [closure compiler options](https://github.com/google/closure-compiler/wiki/Flags-and-Options) minus the leading `--`. flags which accepts multiple values can be represented as an array of values. TSCC sets default values for many flags, in particular, the compilation works even without the `compilerOptions` key in the spec. Any values provided here will override default flags. TSCC will treat these values as opaque data.

### `jsFiles`

```jsonc
    "jsFiles": [
        "./glob/*/for/js/files.js"
    ]
```

It is a string or an array of string, containing glob expressions of JS files to be provided to closure compiler. In order to import closure-style JS to TS file, use `import "goog:moduleName"` in TS, and provide the JS file declaring `goog.module('moduleName')` via this flag. A difference with `extraSources` in module spec is that these files will be included in dependency graph just like other TS files, but extraSources will be included in the compilation even if they are not reachable from entry files.

### `debug`

```jsonc
    "debug": {
        "persistArtifacts": true,
        "ignoreWarningsPath": ["/node_modules/", "/vendor/"]
    }
```
It is a key-value pair of debugging options.
 - `persistArtifacts`: writes intermediate tsickle output to a directory `.tscc_temp`.
 - `ignoreWarningsPath`: Paths to ignore warnings produced by tsickle. It uses a simple substring search. This value defaults to `["/node_modules/"]`.

### Importing external libraries from NPM

Best practice is to provide them as a separate script tag instead of bundling it together, as such libraries do not in general safe to be compiled by Closure Compiler. Declare them as external modules in the spec file, and import them like you would usually do. Then you can benefit from IDE's type checking functionality while tscc can lookup their type definitions and include them as closure compiler's externs.

#### Detailed description of external modules handling

 1. Users write `import React from 'react'`, so that users' IDE can find necessary typings.
 2. TSCC configures tsickle to process type declaration files of module 'react' that Typescript located for us -- usually in node_modules directory.
 3. TSCC creates a hypothetical "gluing modules" for each of external modules that looks like
    ```javascript
    goog.module('react')
    /** Generated by TSCC */
    exports = React
    ```
 4. To inform Closure about such a user-provided global variable name, TSCC generates additional externs for such a global variable, like
    ```javascript
    /**
     * @const
     * @type {some$file$name$mangled$by$tsickle}
     */
    var React = {};
    ```
    tsickle writes module-scoped externs to certain mangled namespace like this, so by declaring a global variable to be a type of that namespace, this provides type information of the external module to Closure Compiler.

### How compilation source files are determined

In order to generate externs for external modules, TSCC has to provide declaration files to tsickle. Which files are provided? Typescript compiler's default behavior is hidden in most of cases, because `.d.ts` files does not anyway affect the compilation output. However, `.d.ts` files are used to generate externs in TSCC, so sometimes you may need to know this for troubleshooting.

The Typescript compiler's default behavior is to include every type declarations in `./node_modules/@types/`, `../node_modules/@types/`, `../../node_modules/@types/`, ..., and if you specify `"types": ["a", "b", ...]` in compiler options, it instead only includes files in `(../)node_modules/@types/a/` -- See official documentation on [`types`](https://www.typescriptlang.org/tsconfig#types) and [`typeRoots`](https://www.typescriptlang.org/tsconfig#typeRoots).

In comparison, TSCC will only include a file when it is reachable from _root files_ via transitive `import`s, triple-slash reference directives `///<reference path="..."/>` and `///<reference types="..."/>`. Root files will be the following:
 - module entry points designated in the spec file,
 - external module's base type declaration files,
 - modules included in tsconfig.json `types` key.

### Importing typescript sources in node_modules

In order for typescript sources in node_modules directory to be compiled, you need to explicitly include those files in your `tsconfig.json`. This is a rule imposed by the typescript compiler; it has some special handling for files in node_modules directory, it won't transpile such files unlike usual transitive dependencies (that is, files not explicitly included in `tsconfig.json` via `"files"` or `"include"` keys, but is referenced via `import` or `///<reference path="..." />` from a file that is included in `tsconfig.json`). In order to have them compiled, you need to explicitly mention those files in node_modules directory. For instance, if you are using a package `my_package` that contains typescript sources, you can add a key `{"include": ["node_modules/my_package/**/*.ts"]}` to your tsconfig.

### Using closure compiler primitives

Certain JS expressions, such as `goog.define(...)` or `goog.reflect.objectProperty(...)`, get special treatment from Closure Compiler. In order to use them, you need access to the `goog` variable or the export object of `goog.reflect` closure library module.

In order to access `goog`, first include a triple slash directive that points to a `base.d.ts` file that comes with the npm package.
```ts
///<reference path="node_modules/@tscc/tscc/third_party/closure_library/base.d.ts" >
```
The exact path may differ in your configuration. This file contains a declaration for a module `"goog:goog"`, so you can now write 
```ts
import * as goog from 'goog:goog'
```
to obtain a reference to the `goog` object. In order for this to work, the imported namespace's name should be `goog` as in above. As a matter of good practice, it'd better not to use `goog` as a variable name unless it _is_ the closure compiler's goog object.

Similarly, to use `goog.reflect`, reference `reflect.d.ts`, and then write
```ts
import * as googReflect from 'goog:goog.reflect';
```

`rollup-plugin-tscc` will wire these module to an appropriate 'polyfill' modules so that runtime behaviors are unchanged.

### Things to know

#### Closure compiler handles modern javascript natively

Closure compiler is capable of minifying modern javascript up to ECMASCRIPT 2019. If you only support modern environments, you can set closure compiler output langauge to ES6 or higher, it will provide smaller output in general.

#### Use `declare interface` to prevent property name renaming

Often you will need to prevent closure compiler renaming certain property names. Since you are writing typescript, such a property name will be a part of a certain interface. Add `declare` to that `interface` declaration. This does not produce additional meanings in typescript, but it will inform tsickle to create externs for the type so that properties of the interface are not renamed by closure compiler. Check out the tsickle's [documentation](https://github.com/angular/tsickle#declare).

#### Sourcemaps

In order to enable sourcemaps, enable `compilerOptions.sourceMap` flag in `tsconfig.json`. Then TSCC will configure closure compiler to emit appropriate sourcemaps.

#### Using prebuilt closure compiler images

By default, `tscc` command will use the java version of the compiler, which requires `java` to exist in `PATH` environment variable. Platform specific binary images are available in npm: [google-closure-compiler-windows](https://www.npmjs.com/package/google-closure-compiler-windows), [google-closure-compiler-osx](https://www.npmjs.com/package/google-closure-compiler-osx), [google-closure-compiler-linux](https://www.npmjs.com/package/google-closure-compiler-linux), and these are optional dependency of @tscc/tscc package. If you install one of them, `tscc` command will use it and it will provide significantly faster compile time in most cases.

#### Rules imposed by closure compiler and tsickle

Although TSCC tries to hide closure compiler specifics as much as it can, it's good to have some knowledge on it:
 - Read the [official documentation](https://developers.google.com/closure/compiler/) in order to get used to some notions used.
 - Not all code works directly with closure compiler (even if it is well-annotated). Read about [compiler assumptions](https://github.com/google/closure-compiler/wiki/Compiler-Assumptions) from their wiki; Basically, you should not use some dynamic nature of JS (the bad part!). Below are some common situations.
   - Do not access an object's property with a string literal, as closure compiler won't try to rename it. If you access `foo.bar` in your code and also do `foo["bar"]` at another part of the code, closure compiler may rename `foo.bar` to something like `foo.a` whereas the latter to `foo.bar`, so it will break the code.
   - Circular references of Javascript modules are not allowed.
   - Output module spec must have a single root module, making it a connected tree.[Ref](https://stackoverflow.com/questions/10395810/how-do-i-split-my-javascript-into-modules-using-googles-closure-compiler/10401030#10401030)
 - Tsickle [officially states](https://github.com/angular/tsickle#warning-work-in-progress) that it is still in experimental phase, and there are some caveats.
   - Tsickle does not support annotation of all typescript types. For example, it does not convert indexed properties of Typescript to closure type, so if an interface is `declare`d with a property, such an interface won't be preserved -- keep an eye on tsickle warnings about unknown types. A good news is that closure compiler is still able to guess unknown types in most of cases, so it does not break the output code often.
   - TS `namespace`s are not converted to something like those in closure library, so it does not benefit from closure compiler's property flattening. (Apparently google internally prevents use of [namespaces](https://github.com/angular/tsickle/issues/713#issuecomment-358806943).)
 - Some objects are present in Typescript but not in closure compiler, so sometimes you may need to provide externs to those manually.

## Motivation

This project came out from the experience I have had with developing several Javascript apps,
 as frontend projects, browser extensions, and userscripts injected into client's browsers. In many cases "content script" are `eval`ed, so the source holds a string form of a JS code, so there was a rather strong motivation for squizing bundle size as much as one can in order to reduce client's memory footprint. Closure tools, albeit not "trendy", was the best tool for it -- the compiler is simply the best, Closure Templates directly compiles into JS and required runtime libraries are extremely small, and Closure Stylesheets provides class name shortening. However, incorporating all of these and at the same time providing an alternative build for debugging required a lot of work due to lack of support and community tooling.

On the other hand, currently most of available tooling using tsickle and closure compiler is limited to angular community. Tsickle is integrated into Angular's compiler and it provides some angular-specific code transformations (they are not enabled in TSCC). However, after all tsickle is a general-purpose transpiler. It seemed a pity that such a great tooling cannot benefit much broader audiences.

TSCC is meant to provide a framework-agnostic tooling that can be used to bridge this gap.

## Milestones

 - Integration with [Closure Templates](https://github.com/google/closure-templates) and [Closure Stylesheets](https://github.com/google/closure-stylesheets). Both tools produce Javascript sources that are meant to be consumed by Closure Compiler. As separate companion packages `tscc-templates` and `tscc-styles`, it will be possible to pipe these intermediate output to closure compiler, and produce typescript module declaration files that will provide type information of templates.
 - Providing an ergonomic API for using closure-annotated JS files together with transpiled TS files.
 - Providing an API for returning gulp stream.



================================================
FILE: jest.config.js
================================================
const {compilerOptions} = require('./tsconfig.json');
compilerOptions.strict = false;

module.exports = {
	preset: 'ts-jest',
	testEnvironment: 'node',
	testMatch: ["**/test/**/*.ts"],
	testPathIgnorePatterns: ['/node_modules/', "/sample/"],
	reporters: ["default", "jest-junit"],
	globals: {
		'ts-jest': {
			tsconfig: compilerOptions
		}
	},
	snapshotFormat: {
		escapeString: true,
		printBasicPrototype: true
	}
};


================================================
FILE: lerna.json
================================================
{
  "packages": ["packages/*"],
  "version": "0.9.4",
  "npmClient": "yarn",
  "useWorkspaces": true
}


================================================
FILE: package.json
================================================
{
	"name": "tscc",
	"version": "1.0.0",
	"private": true,
	"workspaces": [
		"packages/*"
	],
	"license": "MIT",
	"scripts": {
		"clean": "yarn lerna run clean",
		"tsc": "yarn lerna exec -- -- tsc",
		"refresh": "yarn lerna clean --yes; yarn clean; yarn lerna bootstrap; yarn tsc; cd packages/tscc; npm remove -g .; npm i -g .; rm -rf node_modules/@tscc; yarn link @tscc/tscc-spec"
	},
	"devDependencies": {
		"@types/jest": "^29.2.0",
		"jest": "^29.2.1",
		"jest-junit": "^14.0.1",
		"lerna": "^6.0.1",
		"prettier": "^2.7.1",
		"ts-jest": "^29.0.3",
		"typescript": "~4.7.2"
	},
	"dependencies": {}
}


================================================
FILE: packages/rollup-plugin-tscc/.npmignore
================================================
index.ts
/src
test
node_modules
tsconfig.json
yarn.lock
yarn-error.log



================================================
FILE: packages/rollup-plugin-tscc/README.md
================================================
# rollup-plugin-tscc

This is a companion plugin for tscc which lets you perform an isomorphic build with rollup.
The code splitting strategy of Closure Compiler is rather different from any other bundling tools – it relies on providing an exact set of expected chunks and their interdependencies, whereas most of the available bundlers may create dynamic unnamed chunks. In some cases, the rigid approach of Closure Compiler is more suitable.

This plugin operates solely on the bundling level, and in particular, it does not require Typescript at all, so it can be used in any Javascript projects.

## Usage

Feed the output module dependency to `rollup-plugin-tscc` via [tscc spec file](https://github.com/theseanl/tscc#modules),
[input files](https://rollupjs.org/guide/en/#input), [external](https://rollupjs.org/guide/en/#external), and output file names will be taken care by the plugin.

```js
// rollup.config.js
export default {
    plugins: [
        output: {
            dir: '.'
        }
        require('@tscc/rollup-plugin-tscc')({
            /* Contents of spec JSON */
            modules: {
                "root-module": "./src/root-entry-file.js",
                "deferred-chunk-1": {
                    "entry": "./src/unimportant-feature-entry-file.js",
                    "dependencies": [
                        "root-module"
                    ]
                }
            }
            // or, you can provide the above contents via a separate file.
            specFile: "path_to_spec_file.json"
        })
    ]
}
```

Then invoking rollup with the above will produce precisely two files, `root-module.js` and `deferred-chunk-1.js`.

### Chunk format

By specifying `"chunkFormat": "global"` or `"chunkFormat": "module"`, you can designate how the code-splitted output chunks will reference variables and functions in another chunk. `"global"` corresponds to rollup's `"iife"`, and `"module"` corresponds to rollup's `"es"`.

### External modules

Especially in code-splitting builds, it is required to use the spec file's [`external`](https://github.com/theseanl/tscc#external) field instead of the rollup input option's external property, because this information has to be propagated down to the plugin.

### Dynamic imports

It does not support dynamic imports. It is mostly because Closure Compiler doesn't, and this package's goal is to
provide isomorphic build with closure compiler. Closure Compiler's wiki says it supports pass-through handling of `import()`, but it appears to be broken: https://github.com/google/closure-compiler/issues/3941 – apparently this ECMAScript feature is not widely used within Google. Closure Compiler's focus on _sequential_ nature of JS, which makes it extremely robust, doesn't seem to be a good fit with dynamic imports.

---

For more detailed description, we refer to the [README of the main package](https://github.com/theseanl/tscc).


================================================
FILE: packages/rollup-plugin-tscc/package.json
================================================
{
  "name": "@tscc/rollup-plugin-tscc",
  "author": "theseanl",
  "description": "A rollup plugin to use tscc module specification",
  "keywords": [
    "typescript",
    "closure-compiler",
    "tree-shaking",
    "minify-javascript"
  ],
  "version": "0.9.4",
  "license": "MIT",
  "homepage": "https://github.com/theseanl/tscc",
  "repository": {
    "type": "url",
    "url": "https://github.com/theseanl/tscc.git"
  },
  "bugs": {
    "url": "https://github.com/theseanl/tscc"
  },
  "main": "./dist/index.js",
  "scripts": {
    "clean": "rm -rf dist"
  },
  "publishConfig": {
    "access": "public"
  },
  "gitHead": "cb605b055c7947989d64daeb3d95c123c27c70c0",
  "dependencies": {
    "@tscc/tscc-spec": "^0.9.4",
    "rollup": "^2.78.0",
    "upath": "^2.0.1"
  },
  "devDependencies": {
    "@types/node": "^18.11.2"
  }
}


================================================
FILE: packages/rollup-plugin-tscc/src/MultiMap.ts
================================================
export default class MultiMap<K, V> {
	private map: Map<K, Set<V>> = new Map();
	add(key: K, value?: V) {
		let ar: Set<V>;
		if (!this.map.has(key)) {
			ar = new Set();
			this.map.set(key, ar);
		} else {
			ar = this.map.get(key)!;
		}
		if (arguments.length > 1) {
			ar.add(value!);
		}
	}
	find(key: K, value: V): boolean {
		if (!this.findKey(key)) return false;
		let values = this.map.get(key)!;
		return values.has(value);
	}
	findKey(key: K): boolean {
		return this.map.has(key);
	}
	findValue(value: V): K | undefined {
		for (let [key, values] of this.map) {
			if (values.has(value)) return key;
		}
	}
	get(key: K): V[] {
		if (!this.map.has(key)) return [];
		return [...this.map.get(key)!];
	}
	putAll(key: K, values: Iterable<V>) {
		this.map.set(key, new Set(values));
		return this;
	}
	*[Symbol.iterator]() {
		for (let [key, values] of this.map) {
			for (let value of values) {
				yield [key, value];
			}
		}
	}
	iterateValues(key: K): IterableIterator<V> | undefined {
		let values = this.map.get(key);
		if (values) return values.values();
	}
	keys() {
		return this.map.keys();
	}
	get size() {
		return this.map.size;
	}
	static fromObject<V>(object: {[key: string]: V[]}): MultiMap<string, V> {
		const map = new MultiMap<string, V>();
		for (let [key, values] of Object.entries(object)) {
			map.add(key);
			for (let value of values) {
				map.add(key, value);
			}
		}
		return map;
	}
	static toObject<K, V>(
		map: MultiMap<K, V>,
		stringifyKey: (k: K) => string = String,
		stringifyValue: (v: V) => string = String
	) {
		const out: {[key: string]: string[]} = {};
		for (let key of map.keys()) {
			out[stringifyKey(key)] = [...map.iterateValues(key)!].map(stringifyValue);
		}
		return out;
	}
}


================================================
FILE: packages/rollup-plugin-tscc/src/goog_shim_mixin.ts
================================================
/**
 * @fileoverview Provides a mixin for Rollup plugins that loads shim files for default libraries.
 * These are goog.goog and goog.reflect, which are always included if one is bundling with
 * @tscc/tscc.
 */
import {Plugin, FunctionPluginHooks} from 'rollup';
import * as fs from 'fs';
import * as path from 'path';

const SHIM_ROOT = path.resolve(__dirname, "../third_party/closure_library");

const moduleNameToShim = new Map([
	["goog:goog", fs.readFileSync(path.join(SHIM_ROOT, "goog_shim.js"), "utf8")],
	["goog:goog.reflect", fs.readFileSync(path.join(SHIM_ROOT, "reflect_shim.js"), "utf8")]
]);

// Rollup convention, see https://rollupjs.org/guide/en/#conventions
const PREFIX = "\0tscc\0";

// Interlaces a plugin loading shim files with an existing plugin.
export function googShimMixin<T extends {resolveId: FunctionPluginHooks["resolveId"], load: FunctionPluginHooks["load"]}>(plugin: T): T {
	const {resolveId, load} = plugin;
	plugin.resolveId = function (id, importer) {
		if (moduleNameToShim.has(id)) return PREFIX + id;
		return Reflect.apply(resolveId!, this, arguments);
	}
	plugin.load = function (id) {
		if (id.startsWith(PREFIX)) return moduleNameToShim.get(id.substring(PREFIX.length));
		return Reflect.apply(load!, this, arguments);
	}
	return plugin;
}


================================================
FILE: packages/rollup-plugin-tscc/src/index.ts
================================================
import {IInputTsccSpecJSON} from '@tscc/tscc-spec';
import * as rollup from 'rollup';
import {googShimMixin} from './goog_shim_mixin';
import {ChunkMergeError, ChunkMerger} from './merge_chunks';
import computeChunkAllocation, {ChunkSortError} from './sort_chunks';
import ITsccSpecRollupFacade from './spec/ITsccSpecRollupFacade';
import TsccSpecRollupFacade from './spec/TsccSpecRollupFacade';
import path = require('path');

const pluginImpl: (options: IInputTsccSpecJSON) => rollup.Plugin = (pluginOptions) => {
	const spec: ITsccSpecRollupFacade = TsccSpecRollupFacade.loadSpec(pluginOptions);

	const isManyModuleBuild = spec.getOrderedModuleSpecs().length > 1;
	const globals = spec.getRollupExternalModuleNamesToGlobalMap();

	/* Plugin methods start */
	const name = "rollup-plugin-tscc";
	const options: rollup.Plugin["options"] = (options = {}) => {
		// Add entry files read fom tsccconfig
		options.input = spec.getRollupOutputNameToEntryFileMap();
		options.external = spec.getExternalModuleNames();
		return options;
	};
	const outputOptions: rollup.Plugin["outputOptions"] = (outputOptions = {}) => {
		outputOptions.dir = '.';
		outputOptions.entryFileNames = "[name].js";
		outputOptions.chunkFileNames = "_"; // rollup makes these unique anyway.
		outputOptions.globals = globals;
		if (isManyModuleBuild) {
			// For many-module build, currently only iife builds are available.
			// Intermediate build format is 'es'.
			outputOptions.format = 'es';
		} else {
			outputOptions.format = spec.getRollupOutputModuleFormat();
		}
		return outputOptions;
	};
	const resolveId: rollup.ResolveIdHook = (id, importer) => {
		/**
		 * Getting absolute paths for external modules working has been pretty tricky. I haven't
		 * tracked down the exact cause, but sometimes external modules' paths are relative to CWD,
		 * sometimes relative to the common demoninator of files (check inputBase of rollup source).
		 * It seems that this is consistent internally, but not when user-provided absolute paths
		 * are involved. In particular the "external-modules-in-many-module-build" test case fails.
		 *
		 * Prior to rollup 2.44.0, we have used "paths" output option to force rollup to keep use
		 * absolute paths for external modules internally. "paths" option is mainly intended to
		 * replace external module paths to 3rd-party CDN urls in the bundle output, so our use is
		 * more like an 'exploit'. One place where one replaces an absolute path to a relative path
		 * is `ExternalModule.setRenderPath` which sets `renderPath` which is later resolved
		 * relatively from certain path to compute final path in import statements. If
		 * outputOption.path function is provided, the value produced by this function is used as
		 * `renderPath` instead, so we are hooking into it so that `renderPath` is set to an
		 * absolute path.
		 *
		 * Since 2.44.0, it has supported returning {external: 'absolute'} value from `resolveId`
		 * hook, which seems to be achieving what we have done using `output.paths` option. In
		 * particular it disables rollup's 'helpful' renormalization of paths, see
		 * https://github.com/rollup/rollup/blob/a8647dac0fe46c86183be8596ef7de25bc5b4e4b/src/ExternalModule.ts#L94,
		 * https://github.com/rollup/rollup/blob/983c0cac83727a13af834fe79dfeef89da4fb84b/src/Chunk.ts#L699.
		 * The related PR is https://github.com/rollup/rollup/pull/4021.
		 *
		 * These paths are then used in intermediate chunks, and will not be emitted in final bundle
		 * due to the helpful renormalization which we do not disable in the secondary bundling.
		 */
		if (importer) {
			const resolved = path.resolve(path.dirname(importer), id);
			if (resolved in globals) {
				return {id: resolved, external: "absolute"};
			}
		}
		let depsPath = spec.resolveRollupExternalDeps(id);
		if (depsPath) {
			return path.resolve(process.cwd(), depsPath);
			// Using 'posix' does not work well with rollup internals
		}
	};
	// Returning null defers to other load functions, see https://rollupjs.org/guide/en/#load
	const load: rollup.LoadHook = (id: string) => null;

	const generateBundle = handleError<NonNullable<rollup.FunctionPluginHooks["generateBundle"]>>(async function (
		this: rollup.PluginContext, options, bundle, isWrite
	) {
		// Quick path for single-module builds
		if (spec.getOrderedModuleSpecs().length === 1) return;

		// Get entry dependency from spec
		const entryDeps = spec.getRollupOutputNameDependencyMap();

		// Get chunk dependency from rollup.OutputBundle
		const chunkDeps: {[chunkName: string]: string[]} = {};
		for (let [fileName, chunkInfo] of Object.entries(bundle)) {
			// TODO This is a possible source of conflicts with other rollup plugins. Some plugins
			// may add unexpected chunks. In general, it is not clear what TSCC should do in such
			// cases. A safe way would be to strip out such chunks and deal only with chunks that
			// are expected to be emitted. We may trim such chunks here.
			if (!isChunk(chunkInfo)) continue;
			chunkDeps[fileName] = [];
			for (let imported of chunkInfo.imports) {
				chunkDeps[fileName].push(imported);
			}
		}

		// Compute chunk allocation
		const chunkAllocation = computeChunkAllocation(chunkDeps, entryDeps);
		const chunkMerger = new ChunkMerger(chunkAllocation, bundle, globals);
		/**
		 * Hack `bundle` object, as described in {@link https://github.com/rollup/rollup/issues/2938}
		 */
		// 0. Merge intermediate chunks to appropriate entry chunk
		const mergedChunks = spec.getRollupOutputModuleFormat() === 'iife' ?
			await Promise.all([...entryDeps.keys()]
				.map((entry: string) => chunkMerger.performSingleEntryBuild(entry, 'iife'))) :
			await chunkMerger.performCodeSplittingBuild('es');
		// 1. Delete keys for intermediate chunks
		for (let entry of chunkAllocation.keys()) {
			for (let chunk of chunkAllocation.iterateValues(entry)!) {
				delete bundle[chunk];
			}
		}
		// 2. Add the merged chunks to the bundle object
		for (let chunk of mergedChunks) {
			bundle[chunk.fileName] = chunk;
		}

		return;
	});

	return googShimMixin({name, generateBundle, options, outputOptions, resolveId, load});
};

function isChunk(output: rollup.OutputChunk | rollup.OutputAsset): output is rollup.OutputChunk {
	return output.type === 'chunk';
}

function handleError<H extends (this: rollup.PluginContext, ..._: any[]) => unknown>(hook: H): H {
	return <H>async function () {
		try {
			return await Reflect.apply(hook, this, arguments);
		} catch (e) {
			// Handle known type of errors
			if (e instanceof ChunkSortError || e instanceof ChunkMergeError) {
				this.error(e.message);
			} else {
				throw e;
			}
		}
	}
}

export default pluginImpl;



================================================
FILE: packages/rollup-plugin-tscc/src/merge_chunks.ts
================================================
import * as rollup from 'rollup';
import {googShimMixin} from './goog_shim_mixin';
import MultiMap from './MultiMap';
import path = require('path');
import upath = require('upath');

type CodeSplittableModuleFormat = Exclude<rollup.ModuleFormat, 'iife' | 'umd'>;

// Merge chunks to their allocated entry chunk.
// For each entry module, create a facade module that re-exports everything from chunks
// allocated to it, and call rollup to create a merged bundle.
// Each chunk's export object is exported as a separate namespace, whose name is chosen
// so as not to collide with exported names of the entry module. We pass this namespace
// as rollup's global option in order to reference those from other chunks.
export class ChunkMerger {
	private entryModuleNamespaces!: Map<string, string> // Initialized in getBundleOutput call.
	private chunkNamespaces!: Map<string, string>
	private unresolveChunk!: Map<string, string>;
	constructor(
		private chunkAllocation: MultiMap<string, string>,
		private bundle: Readonly<rollup.OutputBundle>,
		private globals?: {[id: string]: string}
	) {
		this.populateEntryModuleNamespaces();
		this.populateUnresolveChunk();
	}
	private resolveGlobalForPrimaryBuild(id: string) {
		if (typeof this.globals !== 'object') return;
		if (!this.globals.hasOwnProperty(id)) return;
		return this.globals[id];
	}
	private populateEntryModuleNamespaces() {
		this.entryModuleNamespaces = new Map();
		for (let entry of this.chunkAllocation.keys()) {
			let fileName = path.basename(entry, '.js');
			let fileNamespace = fileName.replace(/[^0-9a-zA-Z_$]/g, '_').replace(/^[^a-zA-Z_$]/, '_');
			this.entryModuleNamespaces.set(entry, fileNamespace);
		}
	}
	private populateChunkNamespaces() {
		const DOLLAR_SIGN = "$";
		this.chunkNamespaces = new Map();
		for (let entry of this.chunkAllocation.keys()) {
			let counter = -1;
			for (let chunk of this.chunkAllocation.iterateValues(entry)!) {
				if (entry === chunk) continue;
				let namesExportedByEntry = (this.bundle[entry] as rollup.OutputChunk).exports;
				do {
					counter++
				} while (namesExportedByEntry.includes(DOLLAR_SIGN + counter))
				this.chunkNamespaces.set(chunk, DOLLAR_SIGN + counter);
			}
		}
	}
	private populateUnresolveChunk() {
		this.unresolveChunk = new Map();
		for (let [entry, chunk] of this.chunkAllocation) {
			this.unresolveChunk.set(path.resolve(chunk), chunk);
		}
	}
	static readonly FACADE_MODULE_ID = `facade.js`;
	private createFacadeModuleCode(entry: string): string {
		const importStmts: string[] = [];
		const exportStmts: string[] = [];
		// nodejs specification only allows posix-style path separators in module IDs.
		exportStmts.push(`export * from '${upath.toUnix(entry)}'`);
		for (let chunk of this.chunkAllocation.iterateValues(entry)!) {
			if (chunk === entry) continue;
			let chunkNs = this.chunkNamespaces.get(chunk);
			importStmts.push(`import * as ${chunkNs} from '${upath.toUnix(chunk)}'`);
			exportStmts.push(`export { ${chunkNs} }`);
		}
		const facadeModuleCode = [...importStmts, ...exportStmts].join('\n');
		return facadeModuleCode;
	}
	private createFacadeModuleLoaderPlugin(entry: string): rollup.Plugin {
		const resolveId: rollup.ResolveIdHook = (id, importer) => {
			if (id === ChunkMerger.FACADE_MODULE_ID) return id;
		};
		const load: rollup.LoadHook = (id) => {
			if (id === ChunkMerger.FACADE_MODULE_ID) return this.createFacadeModuleCode(entry);
		}
		const name = "tscc-facade-loader";
		return {name, resolveId, load};
	}
	private createLoaderPlugin(shouldLoadID: (id: string) => boolean): rollup.Plugin {
		const resolveId: rollup.ResolveIdHook = (id, importer) => {
			if (this.resolveGlobalForPrimaryBuild(id)) {return {id, external: true}}
			if (shouldLoadID(id)) return id;
			if (importer) {
				const resolved = path.resolve(path.dirname(importer), id);
				let unresolved = this.unresolveChunk.get(resolved);
				if (typeof unresolved === 'string') {
					if (shouldLoadID(unresolved)) return unresolved;
					return {id: resolved, external: "absolute"};
				}
			}
			// This code path should not be taken.
			ChunkMerger.throwUnexpectedModuleError(id, importer);
		};
		const load: rollup.LoadHook = (id) => {
			if (shouldLoadID(id)) {
				let outputChunk = this.bundle[id] as rollup.OutputChunk;
				return {
					code: outputChunk.code,
					map: toInputSourceMap(outputChunk.map)
				};
			}
			// This code path should not be taken.
			ChunkMerger.throwUnexpectedModuleError(id);
		};
		const name = "tscc-merger";
		return googShimMixin({name, resolveId, load});
	}
	private resolveGlobalForSecondaryBuild(id: string): string {
		if (this.resolveGlobalForPrimaryBuild(id)) return this.globals![id]!;
		if (path.isAbsolute(id)) {
			id = this.unresolveChunk.get(id) || ChunkMerger.throwUnexpectedModuleError(id);
		}
		let allocated = this.chunkAllocation.findValue(id);
		if (allocated === undefined) ChunkMerger.throwUnexpectedModuleError(id);
		// The below case means that the chunk being queried shouldn't be global. Rollup expects
		// outputOption.globals to return its input unchanged for non-global module ids, but this
		// code path won't and shouldn't be taken.
		// if (allocated === this.entry) ChunkMerger.throwUnexpectedModuleError(id);
		// Resolve to <namespace-of-entry-module-that-our-chunk-is-allocated>.<namespace-of-our-chunk>
		let ns = this.entryModuleNamespaces.get(allocated)!;
		if (allocated !== id) ns += '.' + this.chunkNamespaces.get(id);
		return ns;
	}
	/**
	 * Merges chunks for a single entry point, making output bundles reference each other by
	 * variables in global scope. We control global variable names via `output.globals` option.
	 * TODO: inherit outputOption provided by the caller
	 */
	async performSingleEntryBuild(entry: string, format: rollup.ModuleFormat): Promise<rollup.OutputChunk> {
		this.populateChunkNamespaces();
		const myBundle = await rollup.rollup({
			input: ChunkMerger.FACADE_MODULE_ID,
			plugins: [
				this.createFacadeModuleLoaderPlugin(entry),
				this.createLoaderPlugin(id => this.chunkAllocation.find(entry, id))
			]
		});
		const {output} = await myBundle.generate({
			...ChunkMerger.baseOutputOption,
			name: this.entryModuleNamespaces.get(entry),
			file: ChunkMerger.FACADE_MODULE_ID,
			format,
			globals: (id) => this.resolveGlobalForSecondaryBuild(id),
		});
		if (output.length > 1) {
			ChunkMerger.throwUnexpectedChunkInSecondaryBundleError(output);
		}
		const mergedBundle = output[0];

		// 0. Fix fileName to that of entry file
		mergedBundle.fileName = entry;
		// 1. Remove facadeModuleId, as it would point to our virtual module
		mergedBundle.facadeModuleId = null;
		// 2. Fix name to that of entry file
		const name = (<rollup.OutputChunk>this.bundle[entry]).name;
		Object.defineProperty(mergedBundle, 'name', {
			get() {return name;} // TODO: FIXME
		});
		// 3. Remove virtual module from .modules
		delete mergedBundle.modules[ChunkMerger.FACADE_MODULE_ID];

		return mergedBundle
	}
	/**
	 * We perform the usual rollup bundling which does code splitting. Note that this is unavailable
	 * for iife and umd builds. In order to control which chunks are emitted, we control them by
	 * feeding `chunkAllocation` information to rollup via `output.manualChunks` option.
	 * TODO: inherit outputOption provided by the caller
	 */
	async performCodeSplittingBuild(format: CodeSplittableModuleFormat) {
		const myBundle = await rollup.rollup({
			input: [...this.chunkAllocation.keys()],
			plugins: [
				this.createLoaderPlugin(id => !!this.bundle[id])
			],
			// If this is not set, rollup may create "facade modules" for each of entry modules,
			// which somehow "leaks" from `manualChunks`. On the other hand, setting this may make
			// rollup to drop `export` statements in entry files from final chunks. However, Closure
			// Compiler does this anyway, so it is ok in terms of the goal of this plugin, which
			// aims to provide an isomorphic builds.
			preserveEntrySignatures: false
		});
		const {output} = await myBundle.generate({
			...ChunkMerger.baseOutputOption,
			dir: '.', format,
			manualChunks: (id: string) => {
				let allocatedEntry = this.chunkAllocation.findValue(id);
				if (!allocatedEntry) ChunkMerger.throwUnexpectedModuleError(id);
				return trimExtension(allocatedEntry);
			},
		});
		if (output.length > this.chunkAllocation.size) {
			ChunkMerger.throwUnexpectedChunkInSecondaryBundleError(output);
		}
		for (let outputChunk of output) {
			// These chunks are treated as non-entry chunks, which are subject to different naming
			// convention. This in particular removes all the paths components and retains only the
			// basename part. This is undesirable, so we restore the fileName from facadeModuleId
			// here.
			let {facadeModuleId} = outputChunk as rollup.OutputChunk;
			if (!facadeModuleId) throw new ChunkMergeError(`Output file name in unrecoverable for a module ${outputChunk.fileName}`);
			outputChunk.fileName = facadeModuleId;
		}
		return output as rollup.OutputChunk[];
	}
	private static readonly baseOutputOption: rollup.OutputOptions = {
		interop: 'esModule',
		esModule: false,
		freeze: false
	}
	private static throwUnexpectedModuleError(id: string, importer = ""): never {
		throw new ChunkMergeError(`Unexpected module in primary bundle output: ${id} ${importer}`);
	}
	private static throwUnexpectedChunkInSecondaryBundleError(output: (rollup.OutputChunk | rollup.OutputAsset)[]) {
		throw new ChunkMergeError(`Unexpected chunk in secondary bundle output: ${output[output.length - 1].name}. Please report this error.`)
	}
}

export class ChunkMergeError extends Error {}

/**
 * Converts SourceMap type used by OutputChunk type to ExistingRawSourceMap type used by load hooks.
 */
function toInputSourceMap(sourcemap: rollup.SourceMap | undefined): rollup.ExistingRawSourceMap | undefined {
	if (!sourcemap) return;
	return {...sourcemap};
}

function trimExtension(name: string) {
	return name.slice(0, name.length - path.extname(name).length)
}


================================================
FILE: packages/rollup-plugin-tscc/src/sort_chunks.ts
================================================
/**
 * @fileoverview Rollup generates at most one chunk per each combination of entry points. In our case
 * of emulating closure compiler's bundling, entry points are also nodes of a graph.
 * We determine what chunk should included in what output module in which order.
 */
import {DirectedTreeWithOrdering, DirectedTreeWithLeafs} from '@tscc/tscc-spec'
import MultiMap from './MultiMap';

/**
 * This algorithm is based on an assumption that rollup creates at most one chunk for
 * each combination of entry points.
 */
export default function computeChunkAllocation(
	chunkImportedMap: {[chunkName: string]: string[] /* imported chunk names */},
	entryMap: MultiMap<string, string> /* This is assumed to be sorted, root-to-leaf. */
): MultiMap<string, string> {
	const chunkMap = MultiMap.fromObject(chunkImportedMap);

	// ChunkGraph is a directed tree where there is an edge from module A to a module B
	// iff B imports A.
	const chunkGraph = new DirectedTreeWithLeafs<string>();
	for (let chunkName of chunkMap.keys()) {
		chunkGraph.addNodeById(chunkName); // Make sure that chunks without dependencies get added
	}
	for (let [chunkName, importedName] of chunkMap) {
		// Skip dependencies among entry modules
		if (entryMap.findKey(chunkName) && entryMap.findKey(importedName)) continue;
		chunkGraph.addEdgeById(importedName, chunkName);
	}
	chunkGraph.populateLeafs();
	const sortedChunks = chunkGraph.sort();

	const leafGraph = new DirectedTreeWithOrdering<string>()
	for (let entry of entryMap.keys()) {
		leafGraph.addNodeById(entry); // Add nodes by order - root to leaf
	}
	for (let [aModule, prerequisiteModule] of entryMap) {
		leafGraph.addEdgeById(prerequisiteModule, aModule);
	}

	leafGraph.populateDecendents();

	const leafToDependents = new MultiMap<string, string>();

	for (let chunkName of chunkMap.keys()) {
		let infimum = leafGraph.getInfimum(chunkGraph.getLeafsOfNode(chunkName));
		if (infimum === null) {throw new ChunkSortError(`Cannot find a common root of a chunk`);}
		leafToDependents.add(infimum, chunkName);
	}
	for (let entry of entryMap.keys()) {
		let sorted = leafToDependents.get(entry).sort((chunk1, chunk2) => {
			// As the same order as they appear in sortedChunks (root-to-leaf)
			return sortedChunks.indexOf(chunk1) - sortedChunks.indexOf(chunk2);
		});
		leafToDependents.putAll(entry, sorted);
	}
	return leafToDependents;
}

export class ChunkSortError extends Error {}


================================================
FILE: packages/rollup-plugin-tscc/src/spec/ITsccSpecRollupFacade.ts
================================================
import {ITsccSpec} from '@tscc/tscc-spec'
import MultiMap from '../MultiMap';
import {ModuleFormat} from 'rollup';

export default interface ITsccSpecRollupFacade extends ITsccSpec {
	resolveRollupExternalDeps(id: string): string
	/**
	 * It must respect prefix option of the spec.
	 */
	getRollupOutputNameToEntryFileMap(): {[name: string]: string}
	/**
	 * Maps an entry module's fileName to other entry module's fileNames which the module
	 * depends on. Here filenames are those which bundles generated by rollup will be written to.
	 * This map is supposed to be ordered by an order that is provided by user, or yet topologically
	 * sorted.
	 */
	getRollupOutputNameDependencyMap(): MultiMap<string, string>
	/**
	 * Returns a key-value pair that can be directly used to rollup output.globals option.
	 */
	getRollupExternalModuleNamesToGlobalMap(): {[moduleName: string]: string}
	/**
	 * Returns a module format that final bundles will use, based on spec.chunkFormat.
	 */
	getRollupOutputModuleFormat(): ModuleFormat
}



================================================
FILE: packages/rollup-plugin-tscc/src/spec/TsccSpecRollupFacade.ts
================================================
import {TsccSpec, TsccSpecError} from '@tscc/tscc-spec';
import ITsccSpecRollupFacade from './ITsccSpecRollupFacade'
import MultiMap from '../MultiMap';
import {ModuleFormat} from 'rollup';

export default class TsccSpecRollupFacade extends TsccSpec implements ITsccSpecRollupFacade {
	resolveRollupExternalDeps(moduleId: string) {
		return ''; // Just a stub
	}
	protected getOutputPrefix(target: "cc" | "rollup"): string {
		let prefix = this.tsccSpec.prefix;
		if (typeof prefix === 'undefined') return '';
		if (typeof prefix === 'string') return prefix;
		return prefix[target];
	}
	private getResolvedRollupPrefix() {
		let prefix = this.getOutputPrefix("rollup");
		let resolvedPrefix = this.relativeFromCwd(prefix);
		if (resolvedPrefix.startsWith('.')) {
			throw new TsccSpecError(
				`Output file prefix ${resolvedPrefix} escapes the current working directory`
			);
		}
		return resolvedPrefix;
	}
	private rollupPrefix = this.getResolvedRollupPrefix();
	private addPrefix(name: string) {
		return this.rollupPrefix + name;
	}
	private addPrefixAndExtension(name: string) {
		return this.rollupPrefix + name + '.js';
	}
	getRollupOutputNameToEntryFileMap() {
		let out: {[name: string]: string} = {};
		for (let {moduleName, entry} of this.getOrderedModuleSpecs()) {
			// If entryFile is a relative path, resolve it relative to the path of tsccSpecJSON.
			out[this.addPrefix(moduleName)] = this.absolute(entry);
		}
		return out;
	}
	getRollupOutputNameDependencyMap() {
		let out = new MultiMap<string, string>();
		for (let {moduleName, dependencies} of this.getOrderedModuleSpecs()) {
			// we set outputOption.entryFileName as [name].js - gotta add .js to match
			// an expected output file name.
			out.putAll(
				this.addPrefixAndExtension(moduleName),
				dependencies.map(this.addPrefixAndExtension, this));
		}
		return out
	}
	getRollupExternalModuleNamesToGlobalMap() {
		const globals: {[moduleName: string]: string} = {};
		let external = this.getExternalModuleDataMap();
		for (let [moduleName, {globalName}] of external) {
			globals[moduleName] = globalName;
		}
		return globals;
	}
	getRollupOutputModuleFormat(): ModuleFormat {
		switch (this.tsccSpec.chunkFormat) {
			case 'module':
				return 'es';
			case 'global':
			default:
				return 'iife';
		}
	}
}



================================================
FILE: packages/rollup-plugin-tscc/test/__snapshots__/golden_test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Golden Tests: external-modules/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/external-modules/golden/generated_entry.js 1`] = `
"(function (externalInNodeModules, externalWithFilePaths) {
	'use strict';

	console.log(externalInNodeModules.someProperty);
	console.log(externalWithFilePaths.anotherProperty);

})(externalInNodeModules, externalWithFilePaths);
"
`;

exports[`Golden Tests: external-modules-in-many-module-build/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/golden/generated_dependent.js 1`] = `
"(function (_, b) {
	'use strict';

	_.c();
	_.e();
	console.log(b);

})(generated_entry.$0, b);
"
`;

exports[`Golden Tests: external-modules-in-many-module-build/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/golden/generated_entry.js 1`] = `
"var generated_entry = (function (exports, c, a) {
	'use strict';

	function common(n) {
		console.log(\\"common\\");
	}
	console.log(c.a);

	function entry() {
		common();
		console.log(\\"entry\\");
	}

	entry();
	console.log(a);

	var _ = {
		__proto__: null,
		c: common,
		e: entry
	};

	exports.$0 = _;
	exports.entry = entry;

	return exports;

})({}, c, a);
"
`;

exports[`Golden Tests: goog-shim/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/goog-shim/golden/generated_dependent.js 1`] = `
"(function (_) {
	'use strict';

	/**
	 * @fileoverview Hand-modified shim file for Closure Library \`goog/reflect.js\`. References to the
	 * global \`goog\` variables have been removed.
	 */

	function objectProperty(prop, object) {
		return prop;
	}

	var dictionary = {
		\\"key\\": \\"value\\"
	};

	if (_.g.name === objectProperty(\\"key\\")) {
		console.log(dictionary[_.g.name]);
	}

})(generated_entry.$0);
"
`;

exports[`Golden Tests: goog-shim/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/goog-shim/golden/generated_entry.js 1`] = `
"var generated_entry = (function (exports) {
	'use strict';

	/**
	 * @fileoverview Hand-modified shim file for Closure Library \`goog/goog.js\`. References to the
	 * global \`goog\` variables have been removed.
	 */
	const global = self; // Use rollup \\"context\\" option to prevent \`this\` rewrite

	let DEBUG = true;

	function isDebugging() {
		return DEBUG;
	}

	{
		console.log(\\"Debugging\\");
	}

	var _ = {
		__proto__: null,
		g: global,
		i: isDebugging
	};

	exports.$0 = _;
	exports.isDebugging = isDebugging;

	return exports;

})({});
"
`;

exports[`Golden Tests: goog-shim/tscc.spec.module.json module: packages/rollup-plugin-tscc/test/sample/goog-shim/golden/generated_dependent.js 1`] = `
"import { g as global } from './generated_entry.js';

/**
 * @fileoverview Hand-modified shim file for Closure Library \`goog/reflect.js\`. References to the
 * global \`goog\` variables have been removed.
 */

function objectProperty(prop, object) {
	return prop;
}

var dictionary = {
	\\"key\\": \\"value\\"
};

if (global.name === objectProperty(\\"key\\")) {
	console.log(dictionary[global.name]);
}
"
`;

exports[`Golden Tests: goog-shim/tscc.spec.module.json module: packages/rollup-plugin-tscc/test/sample/goog-shim/golden/generated_entry.js 1`] = `
"/**
 * @fileoverview Hand-modified shim file for Closure Library \`goog/goog.js\`. References to the
 * global \`goog\` variables have been removed.
 */
const global = self; // Use rollup \\"context\\" option to prevent \`this\` rewrite

{
	console.log(\\"Debugging\\");
}

export { global as g };
"
`;

exports[`Golden Tests: many-module-build/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/many-module-build/golden/generated_dependent.js 1`] = `
"(function (_) {
	'use strict';

	console.log(_.s([1, _.b]));

})(generated_entry.$0);
"
`;

exports[`Golden Tests: many-module-build/tscc.spec.json: packages/rollup-plugin-tscc/test/sample/many-module-build/golden/generated_entry.js 1`] = `
"var generated_entry = (function (exports) {
	'use strict';

	function swap([a, b]) {
		return [b, a];
	}

	function sort([a, b]) {
		return a > b ? [a, b] : swap([a, b]);
	}

	const a = [1, 2];
	const b = swap(a);

	console.log(b);

	var _ = {
		__proto__: null,
		b: b,
		s: sort
	};

	exports.$0 = _;
	exports.b = b;

	return exports;

})({});
"
`;

exports[`Golden Tests: many-module-build/tscc.spec.module.json module: packages/rollup-plugin-tscc/test/sample/many-module-build/golden/generated_dependent.js 1`] = `
"import { s as sort, b } from './generated_entry.js';

console.log(sort([1, b]));
"
`;

exports[`Golden Tests: many-module-build/tscc.spec.module.json module: packages/rollup-plugin-tscc/test/sample/many-module-build/golden/generated_entry.js 1`] = `
"function swap([a, b]) {
	return [b, a];
}

function sort([a, b]) {
	return a > b ? [a, b] : swap([a, b]);
}

const a = [1, 2];
const b = swap(a);

console.log(b);

export { b, sort as s };
"
`;


================================================
FILE: packages/rollup-plugin-tscc/test/golden_test.ts
================================================
///<reference types="jest"/>
import tsccPlugin from '../src/index';
import * as rollup from 'rollup';
import fg = require('fast-glob');
import path = require('path');
import upath = require('upath');

const samplesRoot = path.join(__dirname, 'sample');
// Using cwd as __dirname in order to produce jest snapshots that are independent of cwd.
// Providing cwd in order to produce jest snapshots that are independent of cwd calling jest

function upathGlob(glob: string): string[] {
	return fg.sync(glob, {cwd: samplesRoot})
		.map(p => upath.toUnix(p)); // Normalize so that snapshots have the same name on Linux and on Windows
}

describe(`Golden Tests:`, () => {
	const bundleSpecs = upathGlob(`*/tscc.spec.json`);
	const moduleBundleSpecs = upathGlob(`*/tscc.spec.module.json`);

	test.each(bundleSpecs)(`%s`, testBundle);
	test.each(moduleBundleSpecs)(`%s module`, testBundle);
})

async function testBundle(specPath: string) {
	const specFile = path.join(samplesRoot, specPath);
	const bundle = await rollup.rollup({
		plugins: [
			tsccPlugin({specFile})
		],
		onwarn(warning, warn) {
			// Silence warning "The 'this' keyword is equivalent to 'undefined' at the top level of
			// an ES module, and has been rewritten"
			if (warning.code === 'THIS_IS_UNDEFINED') return;
			warn(warning);
		}
	});
	const {output} = await bundle.generate({
		dir: '.',
		interop: 'esModule'
	});

	Object.keys(output).sort().forEach(name => {
		let chunk = output[name];
		let normalizedChunkFileName = upath.toUnix(chunk.fileName);
		expect(chunk.code).toMatchSnapshot(normalizedChunkFileName);
	})
}


================================================
FILE: packages/rollup-plugin-tscc/test/merge_chunks.ts
================================================
///<reference types="jest"/>
import {ChunkMerger} from "../src/merge_chunks";
import MultiMap from "../src/MultiMap";
import * as rollup from "rollup";
import path = require("path");

async function mergeIIFE(
	entry: string,
	chunkAllocation: MultiMap<string, string>,
	bundle: Readonly<rollup.OutputBundle>,
	globals?: {[id: string]: string}
) {
	return await new ChunkMerger(chunkAllocation, bundle, globals).performSingleEntryBuild(entry, 'iife');
}

async function mergeES(
	chunkAllocation: MultiMap<string, string>,
	bundle: Readonly<rollup.OutputBundle>,
	globals?: {[id: string]: string}
) {
	return await new ChunkMerger(chunkAllocation, bundle, globals).performCodeSplittingBuild('es');
}

describe(`mergeChunk`, function () {
	test(`merges chunks for a single entry`, async function () {
		const entry = "entry.js";
		const chunkAllocation = MultiMap.fromObject({
			"entry.js": ["chunk-0.js", "chunk-1.js", "entry.js"],
		});
		const bundle: rollup.OutputBundle = {
			"entry.js": mockChunk({
				fileName: "entry.js",
				code: `export const a = 'a'; export const b = 'b';`,
				exports: ["a", "b"],
				name: "entry",
			}),
			"chunk-0.js": mockChunk({
				fileName: "chunk-0.js",
				code: `export const a = 'c'; export const b = 'd';`,
				exports: ["a", "b"],
				name: "chunk-0",
			}),
			"chunk-1.js": mockChunk({
				fileName: "chunk-1.js",
				code: `export const a = 'e'; export const b = 'f';`,
				exports: ["a", "b"],
				name: "chunk-1",
			}),
		};
		const mergedChunk = await mergeIIFE(entry, chunkAllocation, bundle);

		expect(mergedChunk.name).toBe("entry");
		expect(mergedChunk.code).toMatchInlineSnapshot(`
		"var entry = (function (exports) {
			'use strict';

			const a$2 = 'c'; const b$2 = 'd';

			var chunk0 = {
				__proto__: null,
				a: a$2,
				b: b$2
			};

			const a$1 = 'e'; const b$1 = 'f';

			var chunk1 = {
				__proto__: null,
				a: a$1,
				b: b$1
			};

			const a = 'a'; const b = 'b';

			exports.$0 = chunk0;
			exports.$1 = chunk1;
			exports.a = a;
			exports.b = b;

			return exports;

		})({});
		"
	`);
		expect(mergedChunk.exports).toEqual(["$0", "$1", "a", "b"]);
		expect(mergedChunk.fileName).toBe(entry);
	});
	test(`merge chunks for a single entry with relative path imports and conflicting import name`, async function () {
		const entry = "entry.js";
		const chunkAllocation = MultiMap.fromObject({
			"entry.js": ["a/chunk-0.js", "b/c/chunk-1.js", "entry.js"],
		});
		const bundle: rollup.OutputBundle = {
			"entry.js": mockChunk({
				fileName: "entry.js",
				code: `import { a as A } from './a/chunk-0.js'; export const a = A; export const b = 'b'; export const $0 = 'c';`,
				exports: ["a", "b", "$0"],
				name: "entry",
			}),
			"a/chunk-0.js": mockChunk({
				fileName: "a/chunk-0.js",
				code: `import { b as B } from '../b/c/chunk-1.js'; export const a = 'c'; export const b = B;`,
				exports: ["a", "b"],
				name: "chunk-0",
			}),
			"b/c/chunk-1.js": mockChunk({
				fileName: "b/c/chunk-1.js",
				code: `export const a = 'e'; export const b = 'f';`,
				exports: ["a", "b"],
				name: "chunk-1",
			}),
		};
		const mergedChunk = await mergeIIFE(entry, chunkAllocation, bundle);

		expect(mergedChunk.name).toBe("entry");
		expect(mergedChunk.code).toMatchInlineSnapshot(`
		"var entry = (function (exports) {
			'use strict';

			const a$2 = 'e'; const b$2 = 'f';

			var chunk1 = {
				__proto__: null,
				a: a$2,
				b: b$2
			};

			const a$1 = 'c'; const b$1 = b$2;

			var chunk0 = {
				__proto__: null,
				a: a$1,
				b: b$1
			};

			const a = a$1; const b = 'b'; const $0 = 'c';

			exports.$0 = $0;
			exports.$1 = chunk0;
			exports.$2 = chunk1;
			exports.a = a;
			exports.b = b;

			return exports;

		})({});
		"
	`);
		expect(mergedChunk.exports).toEqual(["$0", "$1", "$2", "a", "b"]);
		expect(mergedChunk.fileName).toBe(entry);
	});

	test(`merge chunks for with imports from external chunks`, async function () {
		const entry = "entry.js",
			chunk0 = "a/chunk-0.js",
			chunk1 = "b/c/chunk-1.js",
			anotherEntry = "d/another-entry.js",
			chunk2 = "e/f/chunk-2.js",
			chunk3 = "chunk-3.js",
			chunk4 = "chunk-4.js";
		const chunkAllocation = MultiMap.fromObject({
			[entry]: [chunk0, chunk1, entry],
			[anotherEntry]: [chunk2, chunk3, chunk4, anotherEntry],
		});
		const bundle: rollup.OutputBundle = {
			[entry]: mockChunk({
				fileName: entry,
				code:
					`import { b as e } from './${chunk3}'; import { c as f } from './${chunk0}';` +
					`export const a = 'a'; export const b = 'b'; export const c = e; export const d = f;`,
				exports: ["a", "b", "c", "d"],
				name: "entry",
			}),
			[chunk0]: mockChunk({
				fileName: chunk0,
				code: `import { a as c } from '../${chunk2}'; export const a = 'c'; export const b = 'd'; export { c };`,
				exports: ["a", "b", "c"],
				name: "chunk-0",
			}),
			[chunk1]: mockChunk({
				fileName: chunk1,
				code: `export const a = 'e'; export const b = 'f';`,
				exports: ["a", "b"],
				name: "chunk-1",
			}),
			[anotherEntry]: mockChunk({
				fileName: anotherEntry,
				code: `export const a = 'g'; export const b = 'h'; export const $0 = '$0';`,
				exports: ["a", "b", "$0"],
				name: "another-entry",
			}),
			[chunk2]: mockChunk({
				fileName: chunk2,
				code: `import { a as c } from '../../${chunk4}'; export const a = 'i'; export const b = c;`,
				exports: ["a", "b"],
				name: "chunk-2",
			}),
			[chunk3]: mockChunk({
				fileName: chunk3,
				code: `export const a = 'k'; export const b = 'l';`,
				exports: ["a", "b"],
				name: "chunk-3",
			}),
			[chunk4]: mockChunk({
				fileName: chunk4,
				code: `export const a = 'm'; export const b = 'n';`,
				exports: ["a", "b"],
				name: "chunk-4",
			}),
		};
		const mergedChunk = await mergeIIFE(entry, chunkAllocation, bundle);
		const anotherMergedChunk = await mergeIIFE(anotherEntry, chunkAllocation, bundle);
		expect(mergedChunk.code).toMatchInlineSnapshot(`
		"var entry = (function (exports, chunk2_js, chunk3_js) {
			'use strict';

			const a$2 = 'c'; const b$2 = 'd';

			var chunk0 = {
				__proto__: null,
				a: a$2,
				b: b$2,
				c: chunk2_js.a
			};

			const a$1 = 'e'; const b$1 = 'f';

			var chunk1 = {
				__proto__: null,
				a: a$1,
				b: b$1
			};

			const a = 'a'; const b = 'b'; const c = chunk3_js.b; const d = chunk2_js.a;

			exports.$0 = chunk0;
			exports.$1 = chunk1;
			exports.a = a;
			exports.b = b;
			exports.c = c;
			exports.d = d;

			return exports;

		})({}, another_entry.$1, another_entry.$2);
		"
	`);
		expect(anotherMergedChunk.code).toMatchInlineSnapshot(`
		"var another_entry = (function (exports) {
			'use strict';

			const a$3 = 'm'; const b$3 = 'n';

			var chunk4 = {
				__proto__: null,
				a: a$3,
				b: b$3
			};

			const a$2 = 'i'; const b$2 = a$3;

			var chunk2 = {
				__proto__: null,
				a: a$2,
				b: b$2
			};

			const a$1 = 'k'; const b$1 = 'l';

			var chunk3 = {
				__proto__: null,
				a: a$1,
				b: b$1
			};

			const a = 'g'; const b = 'h'; const $0 = '$0';

			exports.$0 = $0;
			exports.$1 = chunk2;
			exports.$2 = chunk3;
			exports.$3 = chunk4;
			exports.a = a;
			exports.b = b;

			return exports;

		})({});
		"
	`);
		// Test that bundled code evaluates well when concatenated
		expect(new Function(anotherMergedChunk.code + mergedChunk.code + `return entry.d`)()).toBe(
			"i"
		);
	});
	test(`Correctly merge chunks referencing external modules`, async function () {
		const chunkAllocation = MultiMap.fromObject({
			"entry.js": ["entry.js"],
			"entry2.js": ["entry2.js"],
		});
		const bundle: rollup.OutputBundle = {
			"entry.js": mockChunk({
				fileName: "entry.js",
				code: `import * as A from 'external'; console.log(A); export const a = 1;`,
				exports: ["a"],
				name: "entry",
			}),
			"entry2.js": mockChunk({
				fileName: "entry2.js",
				code: `import * as A from 'external'; import { a } from './entry.js'; console.warn(A); console.log(a);`,
				exports: [],
				name: "entry2",
			}),
		};
		const globals = {
			external: "External",
		};
		const mergedChunk = await mergeIIFE("entry.js", chunkAllocation, bundle, globals);
		const anotherMergedChunk = await mergeIIFE("entry2.js", chunkAllocation, bundle, globals);
		expect(mergedChunk.code).toMatchInlineSnapshot(`
		"var entry = (function (exports, A) {
			'use strict';

			console.log(A); const a = 1;

			exports.a = a;

			return exports;

		})({}, External);
		"
	`);
		expect(anotherMergedChunk.code).toMatchInlineSnapshot(`
		"(function (A, entry_js) {
			'use strict';

			console.warn(A); console.log(entry_js.a);

		})(External, entry);
		"
	`);
	});

	test(`Correctly merge chunks referencing external modules via relative paths`, async function () {
		const entry = "entry.js";
		const entry2 = "entry2.js";
		const chunk1 = "chunk1.js";
		const externalRelative = "external_relative";
		const externalAbsolute = path.posix.resolve("external/absolute.js"); // Always use forward slash
		const chunkAllocation = MultiMap.fromObject({
			[entry]: [chunk1, entry],
			[entry2]: [entry2],
		});
		const bundle: rollup.OutputBundle = {
			[entry]: mockChunk({
				fileName: entry,
				code:
					`import { C } from "${externalRelative}";` +
					`import { D } from "${externalAbsolute}";` +
					`export const c = C + D;`,
				exports: ["c"],
				name: "entry",
			}),
			[entry2]: mockChunk({
				fileName: entry2,
				code:
					`import { a } from "${externalRelative}";` +
					`import { e } from "${chunk1}";` +
					`export const d = a;` +
					`export const f = e;`,
				exports: ["d"],
				name: "entry2",
			}),
			[chunk1]: mockChunk({
				fileName: chunk1,
				code:
					`import { A } from "${externalAbsolute}";` +
					`import { B } from "${externalRelative}";` +
					`export const e = A + B;`,
				exports: ["e"],
				name: "chunk1",
			}),
		};
		const globals = {
			[externalRelative]: "ExternalRelative",
			[externalAbsolute]: "ExternalAbsolute",
		};

		const [mergedChunk, mergedChunk2] = await Promise.all([
			mergeIIFE(entry, chunkAllocation, bundle, globals),
			mergeIIFE(entry2, chunkAllocation, bundle, globals),
		]);
		expect(mergedChunk.code).toMatchInlineSnapshot(`
		"var entry = (function (exports, absolute_js, external_relative) {
			'use strict';

			const e = absolute_js.A + external_relative.B;

			var chunk1 = {
				__proto__: null,
				e: e
			};

			const c = external_relative.C + absolute_js.D;

			exports.$0 = chunk1;
			exports.c = c;

			return exports;

		})({}, ExternalAbsolute, ExternalRelative);
		"
	`);
		expect(mergedChunk2.code).toMatchInlineSnapshot(`
		"var entry2 = (function (exports, external_relative, chunk1_js) {
			'use strict';

			const d = external_relative.a;const f = chunk1_js.e;

			exports.d = d;
			exports.f = f;

			return exports;

		})({}, ExternalRelative, entry.$0);
		"
	`);
	});

	test(`merges chunk without external modules in ES6 modules format`, async function () {
		const entry = "entry.js";
		const entry2 = "entry2.js";
		const chunk1 = "chunk1.js";
		const chunkAllocation = MultiMap.fromObject({
			[entry]: [chunk1, entry],
			[entry2]: [entry2],
		});
		const bundle: rollup.OutputBundle = {
			[entry]: mockChunk({
				fileName: entry,
				code:
					`import { a, sum } from '${chunk1}'; ` +
					`export const c = sum(a, 1); ` +
					`console.log(sum(c, -1)); `,
				exports: ["c"],
			}),
			[entry2]: mockChunk({
				fileName: entry2,
				code:
					`import { b, sum } from "${chunk1}"; ` +
					`export const d = b + 2; ` +
					`export function add3(a, b, c) { return sum(sum(a, b), c); } ` +
					`console.log(add3(1, 2, 3)); `,
				exports: ["d"],
			}),
			[chunk1]: mockChunk({
				fileName: chunk1,
				code:
					`export const a = 3; ` +
					`export const b = 4; ` +
					`export function sum(a, b) { return a + b; } `,
				exports: ["a", "b"],
			}),
		};
		const [mergedESModuleChunk, mergedESModuleChunk2] = await mergeES(
			chunkAllocation,
			bundle,
			{}
		);
		expect(mergedESModuleChunk.code).toMatchInlineSnapshot(`
		"const a = 3; function sum(a, b) { return a + b; }

		const c = sum(a, 1); console.log(sum(c, -1));

		export { sum as s };
		"
	`);
		expect(mergedESModuleChunk2.code).toMatchInlineSnapshot(`
		"import { s as sum } from './entry.js';

		function add3(a, b, c) { return sum(sum(a, b), c); } console.log(add3(1, 2, 3));
		"
	`);
	});
	test(`merges chunk containing external modules in ES6 module format`, async function () {
		const entry = "entry.js";
		const entry2 = "entry2.js";
		const chunk1 = "chunk1.js";
		const externalNonAbsolute = "external";
		const chunkAllocation = MultiMap.fromObject({
			[entry]: [chunk1, entry],
			[entry2]: [entry2],
		});
		const bundle: rollup.OutputBundle = {
			[entry]: mockChunk({
				fileName: entry,
				code: `import { sum } from "${externalNonAbsolute}";` + `console.log(sum(1, 2));`,
				exports: ["c"],
			}),
			[entry2]: mockChunk({
				fileName: entry2,
				code:
					`import { multiply } from "${externalNonAbsolute}";` +
					`import { sum3 } from "${chunk1}";` +
					`console.log(sum3(1, 2, multiply(3, 4)));`,
				exports: ["d"],
			}),
			[chunk1]: mockChunk({
				fileName: chunk1,
				code:
					`import { sum } from "${externalNonAbsolute}";` +
					`export function sum3(a, b, c) {
						return sum(a, sum(b, c));
					};`,
				exports: ["e"],
			}),
		};
		const globals = {
			[externalNonAbsolute]: "ExternalNonAbsolute",
		};
		const [mergedESModuleChunk, mergedESModuleChunk2] = await mergeES(
			chunkAllocation,
			bundle,
			globals
		);
		expect(mergedESModuleChunk.code).toMatchInlineSnapshot(`
		"import { sum } from 'external';

		console.log(sum(1, 2));

		function sum3(a, b, c) {
								return sum(a, sum(b, c));
							}

		export { sum3 as s };
		"
	`);
		expect(mergedESModuleChunk2.code).toMatchInlineSnapshot(`
		"import { multiply } from 'external';
		import { s as sum3 } from './entry.js';

		console.log(sum3(1, 2, multiply(3, 4)));
		"
	`);
	});
	test.todo(
		`merges chunk containing external modules referenced via relative path in ES6 module format`
	);
});

function mockChunk(chunk: Partial<rollup.OutputChunk>): rollup.OutputChunk {
	if (!("dynamicImports" in chunk)) chunk.dynamicImports || [];
	if (!("isEntry" in chunk)) chunk.isEntry = true;
	if (!("modules" in chunk)) chunk.modules = {};
	if (!("facadeModuleId" in chunk)) chunk.facadeModuleId = null;
	if (!("imports" in chunk)) chunk.imports = [];
	if (!("isDynamicEntry" in chunk)) chunk.isDynamicEntry = false;
	return <rollup.OutputChunk>chunk;
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/external-modules/entry.js
================================================
import * as externalInNodeModules from 'external';
import * as externalWithFilePaths from './external_with_file_paths';

console.log(externalInNodeModules.someProperty);
console.log(externalWithFilePaths.anotherProperty);


================================================
FILE: packages/rollup-plugin-tscc/test/sample/external-modules/tscc.spec.json
================================================
{
	"modules": {
		"entry": "./entry.js"
	},
	"external": {
		"external": "externalInNodeModules",
		"./external_with_file_paths": "externalWithFilePaths"
	},
	"prefix": {
		"rollup": "./golden/generated_",
		"cc": "."
	}
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/common/index.js
================================================
import * as c from './external/from/common';
let counter = 0;
export function common(n) {
	console.log("common");
	counter += n;
}
console.log(c.a);


================================================
FILE: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/dependent.js
================================================
import {common} from './common/index';
import {entry} from './entry';
import * as b from './external-dependent';
common(3);
entry();
console.log(b);


================================================
FILE: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/entry.js
================================================
import {common} from './common/index';
import * as a from './external-entry';

export function entry() {
	common(0);
	console.log("entry");
}

entry();
console.log(a);


================================================
FILE: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/tscc.spec.json
================================================
{
	"modules": {
		"entry": "./entry.js",
		"dependent": {
			"entry": "./dependent.js",
			"dependencies": [
				"entry"
			]
		}
	},
	"external": {
		"./external-entry": "a",
		"./external-dependent": "b",
		"./common/external/from/common": "c"
	},
	"prefix": {
		"rollup": "./golden/generated_",
		"cc": "."
	}
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/goog-shim/dependent.js
================================================
import * as entry from './entry';

import * as goog from 'goog:goog';

// This module is only used in "dependent" module, so the corresponding shim file's content should
// only be included in the "dependent" chunk.
import * as googReflect from 'goog:goog.reflect';

var dictionary = {
	"key": "value"
};

if (entry.isDebugging() && goog.global.name === googReflect.objectProperty("key", dictionary)) {
	console.log(dictionary[goog.global.name]);
};


================================================
FILE: packages/rollup-plugin-tscc/test/sample/goog-shim/entry.js
================================================
import * as goog from 'goog:goog';

export function isDebugging() {
	return goog.DEBUG;
}

if (isDebugging()) {
	console.log("Debugging");
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/goog-shim/tscc.spec.json
================================================
{
	"modules": {
		"entry": "./entry.js",
		"dependent": {
			"entry": "./dependent.js",
			"dependencies": [
				"entry"
			]
		}
	},
	"prefix": {
		"rollup": "./golden/generated_",
		"cc": "."
	}
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/goog-shim/tscc.spec.module.json
================================================
{
	"modules": {
		"entry": "./entry.js",
		"dependent": {
			"entry": "./dependent.js",
			"dependencies": [
				"entry"
			]
		}
	},
	"prefix": {
		"rollup": "./golden/generated_",
		"cc": "."
	},
	"chunkFormat": "module"
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/many-module-build/common.js
================================================
export function swap([a, b]) {
	return [b, a];
}

export function sort([a, b]) {
	return a > b ? [a, b] : swap([a, b]);
}



================================================
FILE: packages/rollup-plugin-tscc/test/sample/many-module-build/dir/dependency.js
================================================
import * as utils from '../common';
import {b} from '../entry';

console.log(utils.sort([1, b]));



================================================
FILE: packages/rollup-plugin-tscc/test/sample/many-module-build/entry.js
================================================
import {swap} from './common';

const a = [1, 2];
const b = swap(a);

console.log(b);

export { b };



================================================
FILE: packages/rollup-plugin-tscc/test/sample/many-module-build/tscc.spec.json
================================================
{
	"modules": {
		"entry": "./entry.js",
		"dependent": {
			"entry": "./dir/dependency.js",
			"dependencies": [
				"entry"
			]
		}
	},
	"prefix": {
		"rollup": "./golden/generated_",
		"cc": "."
	}
}


================================================
FILE: packages/rollup-plugin-tscc/test/sample/many-module-build/tscc.spec.module.json
================================================
{
	"modules": {
		"entry": "./entry.js",
		"dependent": {
			"entry": "./dir/dependency.js",
			"dependencies": [
				"entry"
			]
		}
	},
	"prefix": {
		"rollup": "./golden/generated_",
		"cc": "."
	},
	"chunkFormat": "module"
}


================================================
FILE: packages/rollup-plugin-tscc/test/sort_chunks.ts
================================================
///<reference types="jest"/>
import computeChunkAllocation from '../src/sort_chunks';
import MultiMap from '../src/MultiMap';

describe(`computeChunkAllocation`, function () {
	test(`Returns a trivial map when only one chunk is provided`, function () {
		const trivialChunkMap = {"entry.js": []};
		const trivialEntryDep = MultiMap.fromObject({"entry.js": []});
		const expectedChunkAlloc = {"entry.js": ["entry.js"]};
		const computedChunkAlloc = computeChunkAllocation(trivialChunkMap, trivialEntryDep);
		expect(MultiMap.toObject(computedChunkAlloc)).toEqual(expectedChunkAlloc);
	})
	test(`Returns an expected allocation map for a diamond dependency graph`, function () {
		const diamondEntryDep = new MultiMap<string, string>();
		diamondEntryDep.putAll("a.js", []);
		diamondEntryDep.putAll("b.js", ["a.js"]);
		diamondEntryDep.putAll("c.js", ["a.js"]);
		diamondEntryDep.putAll("d.js", ["b.js", "c.js"]);

		const chunkDep = {
			"a.js": ["ab.js", "ac.js", "ad.js", "abc.js", "abd.js", "acd.js", "abcd.js"],
			"b.js": ["ab.js", "bc.js", "bd.js", "abc.js", "abd.js", "bcd.js", "abcd.js"],
			"c.js": ["ac.js", "bc.js", "cd.js", "abc.js", "acd.js", "bcd.js", "abcd.js"],
			"d.js": ["ad.js", "bd.js", "cd.js", "abd.js", "acd.js", "bcd.js", "abcd.js"],
			"ab.js": ["abc.js", "abd.js", "abcd.js"],
			"ac.js": ["abc.js", "acd.js", "abcd.js"],
			"ad.js": ["abd.js", "acd.js", "abcd.js"],
			"bc.js": ["abc.js", "bcd.js", "abcd.js"],
			"bd.js": ["abd.js", "bcd.js", "abcd.js"],
			"cd.js": ["acd.js", "bcd.js", "abcd.js"],
			"abc.js": ["abcd.js"],
			"abd.js": ["abcd.js"],
			"acd.js": ["abcd.js"],
			"bcd.js": ["abcd.js"],
			"abcd.js": []
		};

		const expectedAlloc = { // Order may vary
			"a.js": ["abcd.js", "abc.js", "abd.js", "acd.js", "bcd.js", "ab.js", "ac.js", "ad.js", "bc.js", "a.js"],
			"b.js": ["bd.js", "b.js"],
			"c.js": ["cd.js", "c.js"],
			"d.js": ["d.js"]
		}
		const computedAlloc = MultiMap.toObject(computeChunkAllocation(chunkDep, diamondEntryDep));
		expect(new Set(Object.keys(computedAlloc))).toEqual(new Set(["a.js", "b.js", "c.js", "d.js"]));
		expect(computedAlloc["b.js"]).toEqual(expectedAlloc["b.js"]);
		expect(computedAlloc["c.js"]).toEqual(expectedAlloc["c.js"]);
		expect(computedAlloc["d.js"]).toEqual(expectedAlloc["d.js"]);
		expect(computedAlloc["a.js"][0]).toBe("abcd.js"); // This is necessary
		for (let [chunk, deps] of Object.entries(chunkDep)) {
			for (let dep of deps) {
				let dependencyOccurence = computedAlloc["a.js"].indexOf(dep);
				let chunkOccurence = computedAlloc["a.js"].indexOf(chunk);
				if (dependencyOccurence !== -1 && chunkOccurence !== -1) {
					expect(dependencyOccurence).toBeLessThan(chunkOccurence);
				}
			}
		}
	})
	test(`Removes dependencies among entry points`, function () {
		const entryDep = MultiMap.fromObject(({
			"entry-1.js": [],
			"entry-2.js": ["entry-1.js"]
		}));
		const chunkDep = {
			"chunk-1.js": [],
			"chunk-2.js": [],
			"entry-1.js": ["chunk-1.js"],
			"entry-2.js": ["chunk-1.js", "chunk-2.js", "entry-1.js"]
		};
		const computedAlloc = MultiMap.toObject(computeChunkAllocation(chunkDep, entryDep));
		expect(computedAlloc).toEqual({
			"entry-1.js": ["chunk-1.js", "entry-1.js"],
			"entry-2.js": ["chunk-2.js", "entry-2.js"]
		});
	})
	test(`Does not drop entry points that are refrenced in no edge`, function () {
		const entryDep = MultiMap.fromObject(({
			"root.js": [],
			"1.js": []
		}));
		const chunkDep = {
			"root.js": [],
			"1.js": ["root.js"]
		};
		const computedAlloc = MultiMap.toObject(computeChunkAllocation(chunkDep, entryDep));
		expect(computedAlloc).toEqual({
			"root.js": ["root.js"],
			"1.js": ["1.js"]
		});

	})
})


================================================
FILE: packages/rollup-plugin-tscc/third_party/closure_library/README.md
================================================
Original source: https://github.com/google/closure-library
License: Apache 2.0
Description:
When `rollup-plugin-tscc` bundle files that reference `goog:goog.goog` or `goog:goog.reflect`, the
plugin will link such modules to files contained in this directory to enable correct runtime
behavior.


================================================
FILE: packages/rollup-plugin-tscc/third_party/closure_library/goog_shim.js
================================================
/**
 * @fileoverview Hand-modified shim file for Closure Library `goog/goog.js`. References to the
 * global `goog` variables have been removed.
 */
export const global = this || self; // Use rollup "context" option to prevent `this` rewrite

export function define(name, value) {
	var uncompiledDefines = global.CLOSURE_UNCOMPILED_DEFINES;
	var defines = global.CLOSURE_DEFINES;
	if (uncompiledDefines) value = uncompiledDefines[name];
	else if (defines) value = defines[name];
	return value;
}

export let DEBUG = true;

export function typeOf(value) {
	var s = typeof value;
	if (s != 'object') return s;
	if (!value) return 'null';
	if (Array.isArray(value)) return 'array';
	return s;
};
export function isArrayLike(val) {
	var type = typeOf(val);
	return type == 'array' || type == 'object' && typeof val.length == 'number';
}
export function isObject(val) {
	var type = typeof val;
	return type == 'object' && val != null || type == 'function';
}
export function getCssName(className, opt_modifier) {
	return className;
}
export function getMsg(str, opt_values, opt_options) {
	if (opt_options && opt_options.html) {
		// Note that '&' is not replaced because the translation can contain HTML
		// entities.
		str = str.replace(/</g, '&lt;');
	}
	if (opt_options && opt_options.unescapeHtmlEntities) {
		// Note that "&amp;" must be the last to avoid "creating" new entities.
		str = str.replace(/&lt;/g, '<')
			.replace(/&gt;/g, '>')
			.replace(/&apos;/g, '\'')
			.replace(/&quot;/g, '"')
			.replace(/&amp;/g, '&');
	}
	if (opt_values) {
		str = str.replace(/\{\$([^}]+)}/g, function (match, key) {
			return (opt_values != null && key in opt_values) ? opt_values[key] :
				match;
		});
	}
	return str;
}
export function exportSymbol(publicPath, object, objectToExportTo) {
	var parts = publicPath.split('.');
	var cur = objectToExportTo || global;
	for (var part; parts.length && (part = parts.shift());) {
		if (!parts.length && object !== undefined) {
			cur[part] = object;
		} else if (cur[part] && cur[part] !== Object.prototype[part]) {
			cur = cur[part];
		} else {
			cur = cur[part] = {};
		}
	}
}
export function exportProperty(object, publicName, symbol) {
	object[publicName] = symbol;
}


================================================
FILE: packages/rollup-plugin-tscc/third_party/closure_library/reflect_shim.js
================================================
/**
 * @fileoverview Hand-modified shim file for Closure Library `goog/reflect.js`. References to the
 * global `goog` variables have been removed.
 */

export function object(type, object) {
	return object;
}

export function objectProperty(prop, object) {
	return prop;
}

export function sinkValue(x) {
	sinkValue[' '](x);
	return x;
}
sinkValue[' '] = function () {};

export function canAccessProperty(obj, prop) {
	try {
		sinkValue(obj[prop]);
		return true;
	} catch (e) {}
	return false;
}

export function cache(cacheObj, key, valueFn, opt_keyFn) {
	const storedKey = opt_keyFn ? opt_keyFn(key) : key;

	if (Object.prototype.hasOwnProperty.call(cacheObj, storedKey)) {
		return cacheObj[storedKey];
	}

	return (cacheObj[storedKey] = valueFn(key));
};


================================================
FILE: packages/rollup-plugin-tscc/tsconfig.json
================================================
{
	"extends": "../../tsconfig.json",
	"compilerOptions": {
		"outDir": "dist",
		"rootDir": "src"
	},
	"include": [
		"src/**/*.ts"
	]
}


================================================
FILE: packages/tscc/.npmignore
================================================
index.ts
/src
test
node_modules
tsconfig.json
yarn.lock
yarn-error.log
Makefile



================================================
FILE: packages/tscc/Makefile
================================================
.PHONY: fetch_tslib clean fetch_closure_lib fetch_tsickle_externs

all: $(shell find dist) fetch_tslib

dist/%.js: src/%.ts
	tsc;

WGET=wget --no-check-certificate --content-disposition
GH_USER_CONTENT=https://raw.githubusercontent.com/
THIRD_PARTY=third_party/
CLOSURE_VER=v20191111

fetch_tslib:
	svn export https://github.com/angular/tsickle/trunk/${THIRD_PARTY}tslib ${THIRD_PARTY}tsickle/third_party/tslib --force

fetch_closure_lib:
	${WGET} ${GH_USER_CONTENT}google/closure-library/${CLOSURE_VER}/closure/goog/base.js \
		-O ${THIRD_PARTY}closure_library/base.js
	${WGET} ${GH_USER_CONTENT}google/closure-library/${CLOSURE_VER}/closure/goog/reflect/reflect.js \
		-O ${THIRD_PARTY}closure_library/reflect.js

fetch_tsickle_externs:
	${WGET} ${GH_USER_CONTENT}angular/tsickle/master/src/closure_externs.js \
		-O ${THIRD_PARTY}tsickle/closure_externs.js

upd_3rd_party: fetch_tslib fetch_tsickle_externs fetch_closure_lib

local_install: $(shell find dist) 
	npm i -g .

clean:
	sudo rm -rf dist



================================================
FILE: packages/tscc/README.md
================================================
# TSCC

We refer to the [README of the main package](https://github.com/theseanl/tscc).


================================================
FILE: packages/tscc/package.json
================================================
{
  "name": "@tscc/tscc",
  "author": "theseanl",
  "description": "A typescript transpiler and bundler that wires up tsickle and closure compiler seamlessly",
  "keywords": [
    "typescript",
    "closure-compiler",
    "tree-shaking",
    "minify-javascript"
  ],
  "version": "0.9.4",
  "main": "./dist/tscc.js",
  "bin": {
    "tscc": "./dist/main.js"
  },
  "license": "MIT",
  "homepage": "https://github.com/theseanl/tscc",
  "repository": {
    "type": "url",
    "url": "https://github.com/theseanl/tscc"
  },
  "bugs": {
    "url": "https://github.com/theseanl/tscc"
  },
  "scripts": {
    "clean": "rm -rf dist"
  },
  "engines": {
    "node": ">=10.3.0"
  },
  "devDependencies": {
    "@types/fs-extra": "^9.0.13",
    "@types/node": "^18.11.2",
    "@types/stream-json": "^1.7.1",
    "@types/vinyl": "^2.0.6",
    "@types/vinyl-fs": "^2.4.12",
    "@types/yargs": "^17.0.13",
    "magic-string": "^0.26.7"
  },
  "optionalDependencies": {
    "google-closure-compiler-linux": "^20221004.0.0",
    "google-closure-compiler-osx": "^20221004.0.0",
    "google-closure-compiler-windows": "^20221004.0.0"
  },
  "dependencies": {
    "@tscc/tscc-spec": "^0.9.4",
    "chalk": "^4.1.1",
    "fs-extra": "^10.0.1",
    "google-closure-compiler-java": "^20221004.0.0",
    "ora": "^5.4.1",
    "resolve-from": "^5.0.0",
    "rimraf": "^3.0.2",
    "source-map": "^0.7.4",
    "stream-json": "^1.7.2",
    "tsickle": "^0.46.3",
    "tslib": "^2.3.0",
    "typescript": "~4.7.2",
    "upath": "^2.0.1",
    "vinyl": "^3.0.0",
    "vinyl-fs": "^3.0.3",
    "yargs": "^17.6.0"
  },
  "publishConfig": {
    "access": "public"
  },
  "gitHead": "7d00e4fc6b79ae208622f699a3a59d4d11121562"
}


================================================
FILE: packages/tscc/src/default_libs.ts
================================================
/**
 * @fileoverview Files described here are provided to closure compiler by default.
 */
import fs = require('fs');
import path = require('path');
import resolve = require('resolve-from');

// Resolves file path relative to tscc package root. Prefers that in node_modules directory
// of the caller. (Such file paths might be included in sourcemaps if user have it enabled,
// so if it uses files in the global npm/yarn installation directory, it may expose file structure
// of the build machine.)
// TODO consider providing a dummy path.
function resolveTSCCAssets(relPath: string, projectRoot: string): string {
	// Below returns `null` when the package is not found.
	const packageRoot = resolve.silent(projectRoot, `@tscc/tscc/package.json`);
	if (packageRoot) {
		const resolved = path.resolve(packageRoot, '..', relPath);
		if (fs.existsSync(resolved)) return resolved;
	}
	return path.resolve(__dirname, '..', relPath);
}

const tsickleDir = 'third_party/tsickle';
const tsickleExternsPath = path.join(tsickleDir, 'closure_externs.js');
const tsLibDir = path.join(tsickleDir, 'third_party/tslib');
const tsLibPath = path.join(tsLibDir, 'tslib.js');
const tslibExternsPath = path.join(tsLibDir, 'externs.js');

const closureLibDir = 'third_party/closure_library';
const googBasePath = path.join(closureLibDir, 'base.js');
const googReflectPath = path.join(closureLibDir, 'reflect.js');

export default function (projectRoot: string) {
	const libs = [
		{id: "tslib", path: resolveTSCCAssets(tsLibPath, projectRoot)},
		{id: "goog", path: resolveTSCCAssets(googBasePath, projectRoot)},
		{id: "goog.reflect", path: resolveTSCCAssets(googReflectPath, projectRoot)}
	];
	const externs = [
		resolveTSCCAssets(tslibExternsPath, projectRoot),
		resolveTSCCAssets(tsickleExternsPath, projectRoot)
	]
	return {libs, externs};
}



================================================
FILE: packages/tscc/src/external_module_support.ts
================================================
/**
 * @fileoverview Transforms `import localName from "external_module"` to
 * `const localName = global_name_for_the_external_module`.
 * Also transforms `import tslib_any from 'tslib'` to `goog.require("tslib")`.
 */
import ITsccSpecWithTS from './spec/ITsccSpecWithTS';
import {TsickleHost} from 'tsickle';
import {moduleNameAsIdentifier} from 'tsickle/out/src/annotator_host';

export function getExternsForExternalModules(tsccSpec: ITsccSpecWithTS, tsickleHost: TsickleHost): string {
	const header = `\n/** Generated by TSCC */`
	let out = '';
	for (let [moduleName, {globalName}] of tsccSpec.getExternalModuleDataMap()) {
		// If a module's type definition is from node_modules, its path is used as a namespace.
		// otherwise, it comes from declare module '...' in user-provided files, in which the module name string
		// is used as a namespace.
		let typeRefFile = tsccSpec.resolveExternalModuleTypeReference(moduleName) || moduleName;
		out += `
/**
 * @type{typeof ${moduleNameAsIdentifier(tsickleHost, typeRefFile)}}
 * @const
 */
var ${globalName} = {};\n`;
	}
	if (out.length) out = header + out;
	return out;
}

export function getGluingModules(tsccSpec: ITsccSpecWithTS, tsickleHost: TsickleHost) {
	const out: {path: string, content: string}[] = [];
	for (let [moduleName, {globalName}] of tsccSpec.getExternalModuleDataMap()) {
		// This is just no-op for normal external modules.
		moduleName = tsickleHost.pathToModuleName('', moduleName);
		const content = `goog.module('${moduleName.replace(/([\\'])/g, '\\$1')}')\n` +
			`/** Generated by TSCC */\n` +
			`exports = ${globalName};`;
		// A hypothetical path of this gluing module.
		// Note that if the alternative code path is taken, it means that something may be wrong
		// with the provided typescript project. TODO find a repro which the second code path is
		// taken and add it as a test case.
		let path = tsccSpec.resolveExternalModuleTypeReference(moduleName) || moduleName + `.ts`;
		path = path.replace(/(?:\.d)?\.ts$/, '.js');
		out.push({path, content});
	}
	return out;
}



================================================
FILE: packages/tscc/src/graph/Cache.ts
================================================
import fs = require('fs');

const fsp = fs.promises;

export class Cache<T> {
	private cache: {
		[key: string]: {
			content: T,
			mtime: number
		}
	}
	private dirty = false;
	constructor(
		private cacheFilePath: string
	) {
		try {
			this.cache = JSON.parse(fs.readFileSync(cacheFilePath, 'utf8'));
		} catch (e) {
			fs.writeFileSync(cacheFilePath, '{}');
			this.cache = {};
		}
	}
	get(key: string): T {
		return this.cache[key] && this.cache[key].content;
	}
	getMtime(key: string): number {
		return this.cache[key] && this.cache[key].mtime;
	}
	put(key: string, content: T, mtime: number) {
		this.dirty = true;
		this.cache[key] = {content, mtime};
	}
	remove(key: string) {
		delete this.cache[key];
	}
	async commit() {
		if (!this.dirty) return;
		await fsp.writeFile(this.cacheFilePath, JSON.stringify(this.cache));
	}
}

export class FSCacheAccessor<T> {
	constructor(
		private cache: Cache<T>,
		private dataFactory: (path: string) => Promise<T>
	) {}
	async getFileData(path: string) {
		let stat: fs.Stats;
		try {
			stat = await fsp.stat(path);
		} catch (e) {
			this.cache.remove(path);
			throw new FSCacheAccessError(`${path}: ${(e as NodeJS.ErrnoException).code}`);
		}
		if (!stat.isFile()) {
			this.cache.remove(path);
			throw new FSCacheAccessError(`${path}: not a file`);
		}
		let cacheMtime = this.cache.getMtime(path);
		if (!cacheMtime || stat.mtimeMs > cacheMtime) {
			let content = await this.dataFactory(path);
			this.cache.put(path, content, stat.mtimeMs);
			return content;
		}
		return this.cache.get(path);
	}
	async updateCache() {
		await this.cache.commit();
	}
}

export class FSCacheAccessError extends Error {}



================================================
FILE: packages/tscc/src/graph/ClosureDependencyGraph.ts
================================================
import {FSCacheAccessor} from './Cache';
import {ISourceNode} from './ISourceNode';
import {sourceNodeFactoryFromContent, ClosureSourceError} from './source_node_factory';
import {INamedModuleSpecsWithId} from '@tscc/tscc-spec'
import {flatten, riffle} from '../shared/array_utils'

// To be used as arguments of DepsSorter#getDeps
export interface IEntryPoint {
	readonly moduleId: string | null,
	readonly extraSources: ReadonlyArray<string> // Array of file names for extra sources.
}

export default class ClosureDependencyGraph {
	async addSourceByFileNames(fileNames: string[], fsCacheAccessor: FSCacheAccessor<ISourceNode>) {
		await Promise.all(fileNames.map(async (fileName) => {
			try {
				this.addSourceNode(await fsCacheAccessor.getFileData(fileName));
			} catch (e) {
				if (e instanceof ClosureSourceError && !e.fatal) {
					// pass
				} else throw e;
			}
		}));
	}
	addSourceByContent(fileName: string, content: string) {
		try {
			this.addSourceNode(sourceNodeFactoryFromContent(fileName, content));
		} catch (e) {
			if (e instanceof ClosureSourceError && !e.fatal) {
				// pass
			} else throw e;
		}
	}
	addSourceNode(sourceNode: ISourceNode) {
		// Raise error on duplicate module names.
		for (let provided of sourceNode.provides) {
			if (this.moduleNameToNode.has(provided)) {
				throw new ClosureDepsError(`Duplicate provides for ${provided}`);
			}
		}
		for (let provided of sourceNode.provides) {
			this.moduleNameToNode.set(provided, sourceNode);
		}
		this.fileNameToNode.set(sourceNode.fileName, sourceNode);
	}

	private fileNameToNode: Map<string, ISourceNode> = new Map();
	private moduleNameToNode: Map<string, ISourceNode> = new Map();

	hasModule(moduleName: string): boolean {
		return this.moduleNameToNode.has(moduleName);
	}

	/**
	 * Start walker
	 */
	private forwardDeclared: Set<ISourceNode> = new Set();
	private required: Set<ISourceNode> = new Set();
	clear() {
		this.forwardDeclared.clear();
		this.required.clear();
	}
	private getSourceNode(moduleName: string) {
		let sourceNode = this.moduleNameToNode.get(moduleName);

		if (!sourceNode) {
			throw new ClosureDepsError(
				`Module name ${moduleName} was not provided as a closure compilation source`
			);
		} else {
			return sourceNode;
		}
	}
	// Walks the graph, marking type-required nodes and required nodes
	// (with DepsSorter#forwardDeclared, DepsSorter#required Sets)
	// required-marker has precedence over type-required-marker.
	// yields sources which are required by the source it is called with.
	private *getRequiredNodes(node: string | ISourceNode): IterableIterator<ISourceNode> {
		if (typeof node === 'string') {
			node = this.getSourceNode(node);
		}

		if (this.forwardDeclared.has(node)) {
			this.forwardDeclared.delete(node);
		}
		if (this.required.has(node)) {
			return;
		}
		this.required.add(node);

		yield node;

		// TODO perf improvement: do not visit forwardDeclared nodes which are known to be required.
		for (let forwardDeclared of node.forwardDeclared) {
			let fwdNode = this.getSourceNode(forwardDeclared);
			// Mark this node and its transitive dependencies as 'forwardDeclare'd.
			this.walkTypeRequiredNodes(fwdNode);
		}

		for (let required of node.required) {
			let reqNode = this.getSourceNode(required);
			yield* this.getRequiredNodes(reqNode);
		}
	}
	// Walks the graph marking required/type-required nodes as forwardDeclared.
	private walkTypeRequiredNodes(node: ISourceNode) {
		if (this.forwardDeclared.has(node) || this.required.has(node)) return;

		this.forwardDeclared.add(node);

		for (let forwardDeclared of node.forwardDeclared) {
			let fwdNode = this.getSourceNode(forwardDeclared);
			this.walkTypeRequiredNodes(fwdNode);
		}
	}

	private static getFileName(sourceNode: ISourceNode) {
		return sourceNode.fileName;
	}
	getSortedFilesAndFlags(entryPoints: Omit<INamedModuleSpecsWithId, 'entry'>[]): IFilesAndFlags {
		let sortedFileNames = entryPoints.map(entryPoint => {
			let deps: string[];
			if (entryPoint.moduleId === null) {
				// For empty chunks included to allow code motion moving into it
				deps = [];
			} else {
				deps = [...this.getRequiredNodes(entryPoint.moduleId)].map(ClosureDependencyGraph.getFileName);
			}
			if (entryPoint.extraSources) {
				deps.push(...entryPoint.extraSources);
			}
			return deps;
		});

		let forwardDeclaredFileNames = [...this.forwardDeclared].map(ClosureDependencyGraph.getFileName);
		// prepend modules which are only forwardDeclare'd to the very first module.
		sortedFileNames[0] = [...forwardDeclaredFileNames, ...sortedFileNames[0]];
		const flags = entryPoints.length === 1 ?
			// single chunk build uses --js_output_file instead of --chunk, which is set in tsccspecwithts.
			// when --chunk is used, closure compiler generates $weak$.js chunks.
			[] :
			riffle("--chunk", sortedFileNames.map((depsOfAModule, index) => {
				let entryPoint = entryPoints[index];
				const args: (string | number)[] = [entryPoint.moduleName, depsOfAModule.length];
				if (index !== 0) {
					// Do not specify dependencies for the very first (root) chunk.
					args.push(...entryPoint.dependencies!);
				}
				return args.join(':');
			}));

		return {src: flatten(sortedFileNames), flags}
	}
}

interface IFilesAndFlags {
	readonly src: ReadonlyArray<string>,
	readonly flags: ReadonlyArray<string>
}

export class ClosureDepsError extends Error {};



================================================
FILE: packages/tscc/src/graph/ISourceNode.ts
================================================
export interface ISourceNode {
	readonly fileName: string
	readonly provides: ReadonlyArray<string>
	readonly required: ReadonlyArray<string>
	readonly forwardDeclared: ReadonlyArray<string>
}



================================================
FILE: packages/tscc/src/graph/TypescriptDependencyGraph.ts
================================================
/**
 * @fileoverview Starting from a provided set of files, it walks Typescript SourceFiles that are
 * referenced from previous SourceFiles.
 *
 * This information is provided to tsickleHost so that only such referenced files are processed by
 * tsickle. This is mainly concerned with what files to use to generate externs. Why not just feed
 * every `.d.ts` file to generate externs? Currently Typescript's type inclusion often includes "too
 * many files" -- If tsconfig.json does not specify `types` compiler option, it will include every
 * type declarations in `./node_modules/@types`, `../node_modules/@types`,
 * `../../node_modules/@types`. Such a behavior is actually OK for usual TS usecase, because types
 * anyway do not affect the Typescript transpilation output. However, in our setup they are all used
 * to generate externs, and the more the type declarations, the more it takes to compile and the
 * more it is prone to errors.
 *
 * An easy way(for me) would be to require users to provide every such package's name. But sometimes
 * a package(A) may implicitly refers to another package(B)'s type declarations, and that package B
 * also needs to be provided to tsickle, so this way requires users to __know__ what other packages
 * this package A refers to, which requires users to inspect its contents, and this is not
 * ergonomic.
 *
 * At the other extreme, we can include every .d.ts that typescript "sees". This will lead to the
 * most correct behavior in some sense, because this is something you see in your IDE. But this may
 * potentially lead to enormous amount of externs file and slow down the compilation as it will
 * include everything in `node_modules/@types` directory unless you use types[root] compiler option.
 * This may also cause more bugs coming from incompatibility between typescript and the closure
 * side.
 *
 * Therefore, an intermediate approach is taken here. We use the same module resolution logic to
 * find out which files were explicitly referenced by user-provided file. This requires discovering
 * files that are either (1) imported (2) triple-slash-path-referenced (3)
 * triple-slash-types-referenced. However, some declaration files that augments the global scope may
 * not be discoverable in this way, so we add external modules provided in spec file and any module
 * that is indicated in `compilerOptions.types` tsconfig key to this.
 *
 * There are some work going on from TS's side in a similar vein.
 * {@link https://github.com/microsoft/TypeScript/issues/40124}
 *
 * Currently, this is done using an unexposed API of Typescript. I'm not sure why this is unexposed
 * -- there are APIs such as `getResolvedModuleFileName/setResolvedModuleFileName`, but not
 * something to iterate over resolved module file names.
 */
import * as ts from 'typescript';
import {getPackageBoundary} from '../tsickle_patches/patch_tsickle_module_resolver';
import path = require('path');


interface SourceFileWithInternalAPIs extends ts.SourceFile {
	// Internal fields which exists, but not declared in .d.ts. See SourceFile interface declaration
	// at Microsoft/Typescript/src/compiler/types.ts.
	resolvedModules?: ts.ModeAwareCache<ts.ResolvedModuleFull | undefined>;
	resolvedTypeReferenceDirectiveNames: ts.ModeAwareCache<ts.ResolvedTypeReferenceDirective | undefined>;
}

export default class TypescriptDependencyGraph {
	constructor(
		private host: ts.ScriptReferenceHost
	) {}
	private visited: Set<string> = new Set();
	private defaultLibDir = path.normalize(path.dirname(
		ts.getDefaultLibFilePath(this.host.getCompilerOptions())
	));
	private isDefaultLib(fileName: string) {
		return fileName.startsWith(this.defaultLibDir);
	}
	private isTslib(fileName: string) {
		return getPackageBoundary(fileName).endsWith(path.sep + 'tslib' + path.sep);
	}
	private isTsccAsset(fileName: string) {
		return getPackageBoundary(fileName).endsWith(path.sep + '@tscc' + path.sep + 'tscc' + path.sep)
	}
	private walk(fileName: string | undefined | null) {
		if (typeof fileName !== 'string') return;
		// Typescript may use unix-style path separators in internal APIs even on Windows environment.
		// We should normalize it because we use string === match on file names, for example in
		// shouldSkipTsickleProcessing.
		fileName = path.normalize(fileName);
		// Default libraries (lib.*.d.ts) files and tslib.d.ts are not processed by tsickle.
		if (this.isDefaultLib(fileName) || this.isTslib(fileName) || this.isTsccAsset(fileName)) return;
		// add file to visited set
		if (this.visited.has(fileName)) return;
		this.visited.add(fileName);
		const sf = <SourceFileWithInternalAPIs>this.host.getSourceFile(fileName);
		/**
		 * Files imported to the current file are available in `resolvedModules` property.
		 * See: Microsoft/Typescript/src/compiler/programs.ts `ts.createProgram > processImportedModules`
		 * function. It calls `setResolvedModule` function for all external module references -->
		 * This is the (only, presumably) place where all the external module references are available.
		 */
		if (sf.resolvedModules) {
			sf.resolvedModules.forEach(this.walkModeAwareResolvedFileCache);
		}
		/**
		 * Files referenced from the current file via /// <reference path="...." /> are available in
		 * `referencedFiles` property. Unlike the previous `resolvedModules`, this is a public API.
		 * See: Microsoft/Typescript/src/compiler/programs.ts `ts.createProgram > processReferencedFiles`
		 * These are always initialized, so no if check is needed: see ts.Parser.parseSourceFile
		 */
		for (let ref of sf.referencedFiles) {
			// Unlike the above API, this is not a resolved path, so we have to call TS API
			// to resolve it first. See the function body of `processReferencedFiles`.
			const resolvedReferencedFileName = ts.resolveTripleslashReference(ref?.fileName, fileName);
			this.walk(resolvedReferencedFileName);
		}
		/**
		 * Files referenced from the current file via /// <reference type="..." /> are available in
		 * `resolvedTypeReferenceDirectiveNames` internal API. This is also available in `typeReferencedFile`,
		 * but it does not contain information about the file path a type reference is resolved to.
		 * See: Microsoft/Typescript/src/compiler/programs.ts `ts.createProgram > processTypeReferenceDirectives`
		 * see how this function calls `setResolvedTypeReferenceDirective` to mutate `sf.resolvedTypeRefernceDirectiveNames`.
		 */
		if (sf.resolvedTypeReferenceDirectiveNames) {
			sf.resolvedTypeReferenceDirectiveNames.forEach(this.walkModeAwareResolvedFileCache);
		}
	}
	private walkModeAwareResolvedFileCache = (elem: {resolvedFileName?: string} | undefined) => {
		this.walk(elem?.resolvedFileName);
	};
	addRootFile(fileName: string | undefined | null) {
		this.walk(fileName);
	}
	hasFile(fileName: string) {
		return this.visited.has(fileName);
	}
	// Currently this is only used in tests.
	iterateFiles() {
		return this.visited.values();
	}
}


================================================
FILE: packages/tscc/src/graph/source_node_factory.ts
================================================
import {ISourceNode} from './ISourceNode';
import fs = require('fs');
import readline = require('readline');

/**
 * Uses fast regex search instead of parsing AST, as done in
 * https://github.com/google/closure-library/blob/master/closure/bin/build/source.py
 */
export async function sourceNodeFactory(closureSourcePath: string): Promise<ISourceNode> {
	const rl = readline.createInterface({
		input: fs.createReadStream(closureSourcePath),
		crlfDelay: Infinity
	});
	const parser = new ClosureSourceLineParser(closureSourcePath);
	for await (const line of rl) {
		if (parser.consumeLine(line)) break;
	}
	return parser.getSourceNode();
}

export function sourceNodeFactoryFromContent(fileName: string, content: string): ISourceNode {
	const lines = content.split('\n');
	const parser = new ClosureSourceLineParser(fileName);
	for (const line of lines) {
		if (parser.consumeLine(line)) break;
	}
	return parser.getSourceNode();
}

class ClosureSourceLineParser {
	private isInComment = false;
	private moduleSymbol: string | undefined;
	private providedSymbols = new Set<string>();
	private requiredSymbols = new Set<string>();
	private forwardDeclaredSymbols = new Set<string>();
	constructor(
		private closureSourcePath: string
	) {}
	// Looking for top-level goog.require,provide,module,forwardDeclare,requireType calls on each line.
	// Tsickle now emits goog.requireType instead of forwardDeclare as of Feb 3 2019.
	// Returns truthy value when no more line needs to be consumed.
	consumeLine(line: string): boolean {
		// Heuristic for searching provideGoog in comments
		if (!this.isInComment && reStartPureComment.test(line)) this.isInComment = true;
		if (this.isInComment) {
			if (reProvideGoog.test(line)) {
				this.providedSymbols.add('goog');
				return true;
			}
			if (reEndComment.test(line)) this.isInComment = false;
		}

		if (reGoogModule.exec(line)) {
			if (this.moduleSymbol) {
				throw new ClosureSourceError(`Duplicate module symbols in ${this.closureSourcePath}`);
			}
			this.moduleSymbol = RegExp.$1;
		} else if (reGoogProvide.exec(line)) {
			this.providedSymbols.add(RegExp.$1);
		} else if (reGoogRequire.exec(line)) {
			this.requiredSymbols.add(RegExp.$1);
		} else if (reGoogForwardDeclare.exec(line)) {
			this.forwardDeclaredSymbols.add(RegExp.$1);
		} else if (reGoogRequireType.exec(line)) {
			this.forwardDeclaredSymbols.add(RegExp.$1);
		}
		return false;
	}
	getSourceNode(): ISourceNode {
		if (this.moduleSymbol && this.providedSymbols.size) {
			throw new ClosureSourceError(
				`goog.provide call in goog module ${this.closureSourcePath}`
			);
		}
		if (!this.moduleSymbol && this.providedSymbols.size === 0) {
			// Such files can occur naturally while providing bulk of files via glob
			throw new ClosureSourceError(
				`File ${this.closureSourcePath} is not a goog module nor provides anything.`,
				false /* not harmful */
			);
		}
		return {
			fileName: this.closureSourcePath,
			provides: this.moduleSymbol ? [this.moduleSymbol] : [...this.providedSymbols],
			// goog is implicitly required by every module
			required: this.providedSymbols.has('goog') ? [] : ['goog', ...this.requiredSymbols],
			forwardDeclared: [...this.forwardDeclaredSymbols]
		}
	}
}

function toGoogPrimitiveRegex(name: string, assignment: boolean = false) {
	let src = `goog\\.${name}\\(['"](.*)['"]\\)`
	if (assignment) {
		src = `(?:(?:var|let|const)\\s+[a-zA-Z0-9$_,:\\{\\}\\s]*\\s*=\\s*)?` + src;
	}
	return new RegExp(`^\\s*` + src);
}

const reGoogProvide = toGoogPrimitiveRegex('provide');
const reGoogModule = toGoogPrimitiveRegex('module');
const reGoogRequire = toGoogPrimitiveRegex('require', true);
const reGoogForwardDeclare = toGoogPrimitiveRegex('forwardDeclared', true);
const reGoogRequireType = toGoogPrimitiveRegex('requireType', true);
// base.js of closure library goog.provide's "goog", even though it's not declared in it,
// and is implicitly required by any module/library that access "goog" namespace.
// Such a file is marked by /** @provideGoog */ comment.
const reProvideGoog = /@provideGoog/;
const reStartPureComment = /^\s*\/\*\*/;
const reEndComment = /\*\//;

export class ClosureSourceError extends Error {
	constructor(msg: string, public fatal = true) {
		super(msg);
	}
}



================================================
FILE: packages/tscc/src/log/Logger.ts
================================================
/**
 * @fileoverview Creates a logger instance, which provides the following functionalities:
 *  - Adding prefix
 *  - Adding a spinner that sticks at the bottom
 * It should be okay to have multiple instances that are writing to the same tty.
 */
import ora = require('ora');
import readline = require('readline');
import console = require('console');
import { hasSpinner } from './spinner'

export default class Logger {
	private console: Console
	constructor(
		private prefix: string,
		private out: NodeJS.WritableStream = process.stderr
	) {
		this.console = new console.Console(this.out);
	}
	/**
	 * Analogous to console.log - applies basic formatting, adds a newline at the end.
	 */
	@Logger.eraseSpinner
	log(msg: string, ...args: any[]) {
		this.console.log(this.prefix + msg, ...args);
	}
	/**
	 * Analogous to process.stdout.write() - no formatting
	 */
	@Logger.eraseSpinner
	write(msg: string) {
		this.out.write(msg);
	}
	private static eraseSpinner(target: Object, prop: string, desc: PropertyDescriptor) {
		let origMethod = desc.value;
		desc.value = function (this: Logger) {
			if (hasSpinner()) {
				readline.clearLine(this.out, 0);
				/*
				 * Restore cursor position
				 * {@link https://stackoverflow.com/questions/10585683/how-do-you-edit-existing-text-and-move-the-cursor-around-in-the-terminal}
				 */
				this.out.write('\x1b[u');
			}
			Reflect.apply(origMethod, this, arguments);
			// store cursor position & move to the newline
			this.out.write('\x1b[s');
			if (hasSpinner()) {
				this.out.write('\n');
			}
		}
	}
}



================================================
FILE: packages/tscc/src/log/spinner.ts
================================================
import ora = require('ora');

let spinner: ora.Ora | undefined;
let timer: NodeJS.Timer | undefined;

/**
 * Attach a spinner that sticks at the bottom of the stream,
 * indicating that a task is running.
 */
export function startTask(text: string) {
	if (hasSpinner()) unstick();
	spinner = ora({
		text,
		stream: process.stderr,
		spinner: "dots12",
		// See https://github.com/theseanl/tscc/issues/70
		// If this option is not set, it can lead to very strange behaviors.
		// 'discarding stdin' does it by overriding globals and it is badly done.
		discardStdin: false
	});
	spinner.start();
	const start = Date.now();
	timer = setInterval(() => {
		spinner!.text = text + " " + toDDHHMMSS(Date.now() - start);
	}, 1000);
}

export function succeed(text?: string) {
	if (!hasSpinner()) return;
	spinner!.succeed(text);
	clearInterval(timer!);
	timer = undefined;
}

export function fail(text?: string) {
	if (!hasSpinner()) return;
	spinner!.fail(text);
	clearInterval(timer!);
	timer = undefined;
}

/**
 * Even if a task might have ended (via succeed or fail) the spinner will
 * still stick at the bottom. After calling this method, all subsequent
 * writes will happen below the spinner.
 */
export function unstick() {
	if (!hasSpinner()) return;
	if (spinner!.isSpinning) spinner!.stop();
	spinner = undefined;
	if (timer) {
		clearInterval(timer);
		timer = undefined;
	}
}

export function hasSpinner() {
	return typeof spinner !== 'undefined';
}

function toDDHHMMSS(milliseconds: number) {
	let sec_num = Math.floor(milliseconds / 1000);
	let days = Math.floor(sec_num / 86400);
	let hours = Math.floor(sec_num / 3600);
	let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
	let seconds = sec_num - (hours * 3600) - (minutes * 60);

	let out = '';
	if (days > 0) out += String(days) + ":";
	if (days > 0 || hours > 0) out += String(hours) + ":";
	out += String(minutes).padStart(2, "0");
	out += ":";
	out += String(seconds).padStart(2, "0");
	return out;
}



================================================
FILE: packages/tscc/src/main.ts
================================================
#!/usr/bin/env node

import yargs = require('yargs/yargs');
import chalk = require('chalk');
import tscc, {TEMP_DIR, CcError, TsccError} from './tscc';
import {TsError} from './spec/TsccSpecWithTS'
import {IInputTsccSpecJSON, INamedModuleSpecs, TsccSpecError, primitives} from '@tscc/tscc-spec'
import {ClosureDepsError} from './graph/ClosureDependencyGraph'
import Logger from './log/Logger';
import console = require('console');

/**
 * example: tscc -s src/tscc.spec.json -- --experimentalDecorators -- --assume_function_wrapper
 */
async function main(args: any) {
	if (args.clean) {
		require('rimraf').sync(TEMP_DIR);
		console.log(`Removed ${TEMP_DIR}.`);
		return 0;
	}

	if (args['module'] === undefined && args['spec'] === undefined) {
		// Assumes that --spec was set to the current working directory implicitly.
		args['spec'] = '.';
	}

	const {tsccSpecJSON, tsArgs} = buildTsccSpecJSONAndTsArgsFromArgs(args);
	await tscc(<IInputTsccSpecJSON>tsccSpecJSON, tsArgs);

	return 0;
}

export function parseTsccCommandLineArgs(args: string[], strict = true): {[key: string]: primitives | primitives[]} {
	return <any>yargs()
		.scriptName('tscc')
		.usage(`tscc [--help] [--clean] [--spec <spec_file_path>] [-- <typescript_flags> [-- <closure_compiler_flags>]]`)
		.describe(
			'spec',
			`Perform compilation with tscc spec file at the specified path. ` +
			`Defaults to the current working directory.`
		)
		.string('spec')
		.describe(
			'module',
			`Module spec descriptions. ` +
			`Format: <name>:<entry_file>[:<dependency_name>[,<dependency2_name>[...]][:<extra_source>[,...]]]`
		)
		.string('module')
		.array('module')
		.describe(
			'external',
			'External module descriptions. Format: <module_name>:<global_name>'
		)
		.string('external')
		.array('external')
		.describe(
			'prefix',
			`Directory names to emit outputs in, or prefixes for output file names. ` +
			`It will just be prepended to module names, so if its last character is not a path separator, ` +
			`it will modify the output file's name. Sub-flags --prefix.cc and --prefix.rollup are available.`
		)
		.describe(
			'prefix.cc',
			`Prefix to be used only by closure compiler build.`
		)
		.describe(
			'prefix.rollup',
			`Prefix to be used only by rollup build.`
		)
		.describe(
			'debug',
			`A namespace for debugging options.`
		)
		.describe(
			'debug.persistArtifacts',
			`Writes intermediate tsickle outputs to .tscc_temp directory.`
		)
		.describe(
			'debug.ignoreWarningsPath',
			`Prevents tsickle warnings for files whose path contains substrings provided by this flag.`
		)
		.array('debug.ignoreWarningsPath')
		.describe(
			'clean',
			`Clear temporary files in .tscc_temp directory.`
		)
		.describe(
			'-',
			`Any flags after the first "--" and before the second "--" (if exists) ` +
			`will be provided to the typescript compiler.`
		)
		.describe(
			'{2}',
			`Any flags after the second "--" will be provided to the closure compiler.`
		)
		.epilogue(
			`For more information or bug reports, please visit https://github.com/theseanl/tscc.`
		)
		.alias({
			"spec": "s",
			"h": "help",
			"v": "version",
		})
		.parserConfiguration({
			'populate--': true,
			'camel-case-expansion': false
		})
		.strict(strict)
		.help('h')
		.version()
		.parse(args);
}

export function buildTsccSpecJSONAndTsArgsFromArgs(args: any) {
	const tsArgs = <string[]>args["--"] || [];
	const closureCompilerArgs: string[] = (<any>yargs()
		.parserConfiguration({'populate--': true})
		.parse(tsArgs))["--"] || [];

	let i = tsArgs.indexOf('--');
	if (i !== -1) {
		tsArgs.splice(i);
	}

	const out: Partial<IInputTsccSpecJSON> = {};

	// module flags
	// Using "--module" instead of "--modules" looks more natural for a command line interface.
	let moduleFlags: string[] = args["module"];
	if (moduleFlags) {
		const moduleFlagValue: INamedModuleSpecs[] = [];
		for (let moduleFlag of moduleFlags) {
			// --modules chunk2:./src/chunk2.ts:chunk0,chunk1:css_renaming_map.js
			let [moduleName, entry, dependenciesStr, extraSourcesStr] = moduleFlag.split(':');
			let dependencies: string[] | undefined, extraSources: string[] | undefined;
			if (dependenciesStr) dependencies = dependenciesStr.split(',');
			if (extraSourcesStr) extraSources = extraSourcesStr.split(',');
			moduleFlagValue.push({moduleName, entry, dependencies, extraSources})
		}
		out.modules = moduleFlagValue;
	}

	// external flags
	// --external react-dom:ReactDOM
	let external: string[] = args["external"]
	if (external) {
		const externalValue: {[moduleName: string]: string} = {};
		for (let externalEntry of external) {
			let [moduleName, globalName] = externalEntry.split(':');
			externalValue[moduleName] = globalName;
		}
		out.external = externalValue;
	}

	// prefix flags
	if (args["prefix"]) {
		out.prefix = args["prefix"];
	}

	// compilerFlags flags
	if (closureCompilerArgs.length) {
		let compilerFlags: any = yargs().parse(closureCompilerArgs);
		// delete special args produced by yargs
		delete compilerFlags["_"];
		delete compilerFlags["$0"];
		out.compilerFlags = <any>compilerFlags;
	}

	// debug flags
	let debugArgs = args["debug"];
	if (debugArgs && typeof debugArgs === 'object') {
		out.debug = debugArgs;
	}

	// spec file
	if (args["spec"]) {
		out.specFile = args["spec"];
	}

	return {tsccSpecJSON: <IInputTsccSpecJSON>out, tsArgs}
}

if (require.main === module) {
	const tsccWarning = new Logger(chalk.green('TSCC: '));
	const tsWarning = new Logger(chalk.blue('TS: '));

	const parsedArgs = parseTsccCommandLineArgs(process.argv.slice(2));

	main(parsedArgs)
		.then(code => process.exit(code))
		.catch(e => {
			if (e instanceof TsccSpecError || e instanceof TsccError) {
				tsccWarning.log(chalk.red(e.message));
			} else if (e instanceof TsError) {
				tsWarning.log(chalk.red(e.message));
			} else if (e instanceof ClosureDepsError) {
				tsccWarning.log(chalk.red(e.message));
			} else if (e instanceof CcError) {
				tsccWarning.log(chalk.red(e.message));
			} else {
				tsccWarning.log(chalk.red(`The compilation has terminated with an unexpected error.`));
				tsccWarning.log(e.stack);
				return process.exit(1);
			}
			tsccWarning.log(`The compilation has terminated with an error.`)
			return process.exit(1);
		});
}



================================================
FILE: packages/tscc/src/shared/PartialMap.ts
================================================
export default class PartialMap<K, V extends {}> extends Map<K, Partial<V>> {
	set(key: K, value: Partial<V>) {
		if (!this.has(key)) {
			super.set(key, value);
		} else {
			let prevValue = this.get(key)!;
			Object.assign(prevValue, value);
		}
		return this;
	}
}


================================================
FILE: packages/tscc/src/shared/array_utils.ts
================================================
export function riffle<T>(x: T, array: T[]): T[] {
	let out: T[] = [];
	for (let i = 0, l = array.length; i < l; i++) {
		out.push(x, array[i]);
	}
	return out;
}

export function flatten<T>(array: T[][]): T[] {
	let out: T[] = [];
	for (let i = 0, l = array.length; i < l; i++) {
		out.push(...array[i]);
	}
	return out;
}

export function union<T>(array1: T[], array2: T[]): T[] {
	let out: T[] = array1.slice();
	for (let i = 0, l = array2.length; i < l; i++) {
		let el = array2[i];
		if (out.includes(el)) continue;
		out.push(el);
	}
	return out;
}


================================================
FILE: packages/tscc/src/shared/escape_goog_identifier.ts
================================================
/**
 * @fileoverview A valid goog.module name is a dot-separated sequence of legal property. Legal
 * property is a name that consists only of [a-zA-Z0-9._$]. Trailing, leading dots, or consecutive
 * dots are not allowed. Source: com.google.javascript.jscomp.GatherModuleMetadata.java error
 * message for JSC_INVALID_NAMESPACE_OR_MODULE_ID.
 *
 * This file provides an analogue of Javascript escape/unescape function pair for string identifiers
 * for goog.module, goog.provide, etc. One does not lose information after escaping so that we can
 * faithfully map converted module names to the original TS source file's name.
 */
import path = require('path');

function codePoint(char: string) {return char.codePointAt(0)!;}
/**************************************************************************************************/
const LOWERCASE_A_CODE_POINT = codePoint('a');
const LOWERCASE_Z_CODE_POINT = codePoint('z');
const UPPERCASE_A_CODE_POINT = codePoint('A');
const UPPERCASE_Z_CODE_POINT = codePoint('Z');
const PERIOD_CODE_POINT = codePoint('.');
const LOWER_DASH_CODE_POINT = codePoint('_');
const DOLLAR_SIGN_CODE_POINT = codePoint('$');
const ZERO_CODE_POINT = codePoint('0');
const NINE_CODE_POINT = codePoint('9');
const SEP = path.sep;
/**************************************************************************************************/
function isLatin(code: number) {
	return ((LOWERCASE_A_CODE_POINT <= code && code <= LOWERCASE_Z_CODE_POINT) ||
		(UPPERCASE_A_CODE_POINT <= code && code <= UPPERCASE_Z_CODE_POINT));
}
function isNumber(code: number) {
	return ZERO_CODE_POINT <= code && code <= NINE_CODE_POINT;
}
function isLowerDash(code: number) {
	return code === LOWER_DASH_CODE_POINT;
}
function isPeriod(code: number) {
	return code === PERIOD_CODE_POINT;
}
function isDollarSign(code: number) {
	return code === DOLLAR_SIGN_CODE_POINT;
}
/**************************************************************************************************/
/**
 *                   Latin  ⟹  Latin
 *                  number  ⟹  number
 *                     "_"  ⟹  "_"
 *          path separator  ⟹  "." (for ergonomical reason)
 *                     "."  ⟹  "$_"
 *     Any other character  ⟹  "$" followed by length 4 base36 representation of its code point,
 *                              left-padded with 0.
 *
 * This requires that the first character is not a path separator, in order to make sure that
 * the resulting escaped name does not start with ".", which is disallowed in goog.module. One should
 * always feed relative paths.
 */
export function escapeGoogAdmissibleName(name: string): string {
	let out = "";
	if (name[0] === SEP) throw new TypeError("Name cannot start with a path separator");
	for (let char of name) {
		let code = codePoint(char);
		if (isLatin(code) || isNumber(code) || isLowerDash(code)) {
			out += char;
		} else if (char === SEP) {
			out += ".";
		} else if (isPeriod(code)) {
			out += "$_";
		} else {
			out += "$" + code.toString(36).padStart(4, "0");
		}
	}
	return out;
}
export function unescapeGoogAdmissibleName(escapedName: string): string {
	let out = "";
	let i = 0;
	let code: number;
	// charCodeAt returns NaN when an index is out of range.
	while (!isNaN(code = escapedName.charCodeAt(i))) {
		if (isLatin(code) || isNumber(code) || isLowerDash(code)) {
			out += escapedName[i];
			i++;
		} else if (isPeriod(code)) {
			out += SEP;
			i++;
		} else if (isDollarSign(code)) {
			// If the next character is "_", add "."
			if (isLowerDash(escapedName.charCodeAt(i + 1))) {
				out += ".";
				i += 2;
			} else {
				// Read next 4 chars
				try {
					let base32Codes = parseInt(escapedName.substr(i + 1, 4), 36);
					out += String.fromCodePoint(base32Codes);
					i += 5;
				} catch (e) {
					throw new RangeError(`Invalid characters between position ${i + 1} and ${i + 4}`);
				}
			}
		} else {
			throw new RangeError(`Invalid character at position ${i}`);
		}
	}
	return out;
}
export function escapedGoogNameIsDts(escapedName: string) {
	return escapedName.endsWith("$_d$_ts");
}


================================================
FILE: packages/tscc/src/shared/sourcemap_splice.ts
================================================
import {SourceMapConsumer, SourceMapGenerator, Mapping, RawSourceMap} from 'source-map';

/**
 * From a file with sourcemap, splice intervals specified with the third argument
 * and translate sourcemaps accordingly.
 * @param content
 * @param map
 * @param spliceIntervals sorted, non-overlapping intervals to splice.
 */
export default async function spliceSourceMap(content: string, map: RawSourceMap, spliceIntervals: [number, number][]): Promise<RawSourceMap> {
	const consumer = await new SourceMapConsumer(map);
	const generator = new SourceMapGenerator({file: map.file});

	const seeker = new Seeker(content, spliceIntervals);

	consumer.eachMapping(({source, generatedLine, generatedColumn, originalLine, originalColumn, name}) => {
		// line numbers in mozilla/source-map are 1-based. column numbers are 0-based.
		seeker.seek(generatedLine - 1, generatedColumn);
		if (seeker.isInInterval()) return;
		let transformedLine = seeker.getTransformedLine();
		let transformedColumn = seeker.getTransformedColumn();
		const mapping = getMapping(
			source, transformedLine + 1, transformedColumn,
			originalLine, originalColumn, name
		);
		generator.addMapping(mapping);
	});

	return generator.toJSON();
}

const placeholderString = undefined as any as string;
const placeholderNumber = undefined as any as number;

const mapping = {
	source: placeholderString,
	generated: {
		line: placeholderNumber,
		column: placeholderNumber
	},
	original: {
		line: placeholderNumber,
		column: placeholderNumber
	},
	name: placeholderString
};

const mappingWithoutOriginal = {
	source: placeholderString,
	generated: {
		line: placeholderNumber,
		column: placeholderNumber
	}
};

function getMapping(
	source: string, generatedLine: number, generatedColumn: number,
	originalLine: number, originalColumn: number, name: string
): Mapping {
	if (typeof originalLine !== 'number' && typeof originalLine !== 'number') {
		mappingWithoutOriginal.source = source;
		mappingWithoutOriginal.generated.line = generatedLine;
		mappingWithoutOriginal.generated.column = generatedColumn;
		return mappingWithoutOriginal as Mapping;
	}
	mapping.source = source;
	mapping.generated.line = generatedLine;
	mapping.generated.column = generatedColumn;
	mapping.original.line = originalLine;
	mapping.original.column = originalColumn;
	mapping.name = name;
	return mapping;
}

export function splitWithRegex(contents: string, regex: RegExp) {
	const intervals: [number, number][] = [];
	let prevEnd = 0;
	let replacedContent = '';
	let execRes: RegExpExecArray | null
	while ((execRes = regex.exec(contents)) !== null) {
		let removeStart = execRes.index;
		let removeEnd = removeStart + execRes[0].length;
		replacedContent += contents.substring(prevEnd, removeStart);
		prevEnd = removeEnd;
		intervals.push([removeStart, removeEnd])
	}
	replacedContent += contents.substring(prevEnd);
	return {contents: replacedContent, intervals}
}

export class Seeker {
	constructor(
		private contents: string,
		private intervals: [number, number][]
	) {}
	/*************** State machine state *****************/
	// Current cursor position descriptors
	private line = 0;
	private column = 0;
	private index = 0;
	private lineStart = 0; // Index of current line's start
	private intervalIndex = -1; // Index of last interval whose start comes before then or at the same point with the current index
	private accLine = 0;
	private accColumn = 0;
	/************* State machine state end ***************/

	/**
	 * Seeks the last interval that intersects with the interval [0, index], starting from the current interval.
	 * Returns a contribution of lengths occupied by intervals in [this.Index, index).
	 * (Beware the parentheses)
	 */
	private seekInterval(index: number) {
		let {intervalIndex, index: prevIndex} = this;
		let occupied = 0;
		if (intervalIndex === -1) intervalIndex = 0;
		let interval = this.getInterval(intervalIndex);
		while (interval && interval[0] <= index) {
			if (interval[1] > prevIndex) {
				occupied += min(interval[1], index) - max(interval[0], prevIndex);
			}
			interval = this.getInterval(++intervalIndex);
		}
		this.intervalIndex = intervalIndex - 1;
		return occupied;
	}
	private seekWithinLine(nextColumn: number) {
		let increment = nextColumn - this.column;
		let nextIndex = this.index + increment;

		// Update column (line and lineStart stays the same)
		let lineEnd = this.nextLineBreak();
		if (lineEnd !== -1 && nextIndex > lineEnd)
			throw new Error('EOL');
		if (nextIndex >= this.contents.length) throw new Error('EOF');

		this.column = nextColumn;

		// Update intervalIndex, accColumn (accLine stays the same)
		let occupied = this.seekInterval(nextIndex);
		this.accColumn += increment - occupied;
		this.index = nextIndex;
	}
	private nextLine() {
		// Update line,column,lineStart
		let lineStart = this.nextLineBreak() + 1;
		if (lineStart > 0 && this.contents.length <= lineStart)
			throw new Error(`EOF`);

		this.lineStart = lineStart;
		this.line++;
		this.column = 0;
		let increment = lineStart - this.index;

		// Update interavlIndex, accLine, accColumn
		// Check if there is an interval containing lineStart - 1 (index of '\n')
		let occupied = this.seekInterval(lineStart - 1);
		let interval = this.getInterval(this.intervalIndex);

		this.index = lineStart; // Setting it after seekInterval call, as it requires prev index.

		if (!interval || interval[1] <= lineStart - 1) {
			// No interval contains the previous line break character - accLine will be increased.
			this.accLine++;
			this.accColumn = 0;
			// intervalIndex may need to proceed one step further,
			// as we are looking for the latest interval s.t. interval[0] <= lineStart
			// See test "when interval ends with \n".
			let nextInterval = this.getInterval(this.intervalIndex + 1);
			if (nextInterval && nextInterval[0] === lineStart) this.intervalIndex++;
		} else {
			// This interval contains the line break character.
			// In order to get # of occupied positions before the lineStart, we need to increase
			// occupied by 1, since the line break character is occupied by the current interval.
			this.accColumn += increment - occupied - 1;
		}
	}
	seek(nextLine: number, nextColumn: number) {
		while (nextLine > this.line) {
			this.nextLine();
		}
		this.seekWithinLine(nextColumn);
	}

	// Querying methods
	isInInterval(): boolean {
		let currentInterval = this.getInterval(this.intervalIndex);
		return currentInterval && currentInterval[1] > this.index;
	}
	getTransformedLine(): number {
		return this.accLine;
	}
	getTransformedColumn(): number {
		return this.accColumn;
	}

	private nextLineBreak(): number {
		return this.contents.indexOf('\n', this.index) || this.contents.length;
	}
	private getInterval(intervalIndex: number): [number, number] {
		return this.intervals[intervalIndex];
	}
}

function max(a: number, b: number) {
	return a > b ? a : b;
}

function min(a: number, b: number) {
	return a > b ? b : a;
}


================================================
FILE: packages/tscc/src/shared/vinyl_utils.ts
================================================
import stream = require('stream')
import Vinyl = require('vinyl');
import Logger from '../log/Logger';
import chalk = require('chalk');
import spliceSourceMap, {splitWithRegex} from './sourcemap_splice';

import {RawSourceMap} from 'source-map';

// Custom property augmenting Vinyl interface used by gulp-sourcemaps
const SOURCE_MAP = 'sourceMap'

/**
 * JSON file format that Closure Compiler accepts.
 * See `AbstractCommandLineRunner#JsonFileSpec`
 */
export declare interface IClosureCompilerInputJson {
	path: string,
	src: string,
	sourceMap?: string
}

/**
 * JSON file format that Closure Compiler produces.
 * See `AbstractCommandLineRunner#outputJsonStream`
 * {@link https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/AbstractCommandLineRunner.java#L1517}
 * It is extremely weird that it accepts `sourceMap` as input but produces `source_map` as output.
 */
export declare interface IClosureCompilerOutputJson {
	path: string,
	src: string,
	source_map?: string
}

/**
 * Object produced by stream-json package
 */
interface ArrayStreamItem<T> {
	key: number,
	value: T
}

abstract class LoggingTransformStream extends stream.Transform {
	abstract _rawTransform(data: any, encoding: BufferEncoding): any
	constructor(
		protected logger: Logger
	) {super({objectMode: true});}
	async _transform(data: any, encoding: BufferEncoding, callback: stream.TransformCallback) {
		let transformed: any;
		try {
			transformed = await this._rawTransform(data, encoding);
		} catch (e) {
			const error = e instanceof Error ? e : new Error(String(e));
			this.logger.log(chalk.red('Error during post-transformation: '));
			this.logger.log(error.stack!);
			callback(error);
			return;
		}
		callback(null, transformed);
	}
}

export class ClosureJsonToVinyl extends LoggingTransformStream {
	constructor(
		private applySourceMap: boolean | undefined,
		logger: Logger
	) {super(logger)}
	_rawTransform(data: ArrayStreamItem<IClosureCompilerOutputJson>, encoding: BufferEncoding) {
		if (!data) return data;
		const json = data.value;
		const vinyl = new Vinyl({
			path: json.path,
			contents: Buffer.from(json.src)
		});
		if (this.applySourceMap && json.source_map) {
			// Custom property used by gulp-sourcemaps and plugins supporting it
			vinyl[SOURCE_MAP] = JSON.parse(json.source_map);
		}
		return vinyl;
	}
}

export class RemoveTempGlobalAssignments extends LoggingTransformStream {
	async _rawTransform(data: Vinyl, encoding: BufferEncoding) {
		if (data.isNull()) return data;
		const origContents = data.contents!.toString(encoding);
		// Fast path
		if (!origContents.includes('__tscc_export_start__')) return data;
		if (!data[SOURCE_MAP]) { // Simple regex replace
			data.contents = Buffer.from(origContents.replace(RemoveTempGlobalAssignments.reCcExport, ''));
		} else { // Perform sourcemap-aware replace
			const origMap: RawSourceMap = data[SOURCE_MAP];
			const {contents: replacedContents, intervals}
				= splitWithRegex(origContents, RemoveTempGlobalAssignments.reCcExport);
			const replacedMap = await spliceSourceMap(origContents, origMap, intervals);
			// Modify data
			data.contents = Buffer.from(replacedContents);
			data[SOURCE_MAP] = replacedMap;
		}
		return data;
	}
	private static reCcExport = /;?\s*["']__tscc_export_start__["'][\s\S]*["']__tscc_export_end__["']\s*/g;
}



================================================
FILE: packages/tscc/src/spawn_compiler.ts
================================================
import Logger from './log/Logger';
import chalk = require('chalk');
import childProcess = require('child_process');

export default function spawnCompiler(providedArgs: string[], logger: Logger, debug?: boolean) {
	const {bin, args} = getSupportedCompiler();
	args.push(...providedArgs);

	if (debug) logger.log(`args: ${bin} ` + args.join(' '));

	const compilerProcess = childProcess.spawn(bin, args);

	// TODO consider moving this to tscc.ts.
	compilerProcess.stderr.on('data', (data) => {
		logger.log(data);
	})
	compilerProcess.on('error', (err) => {
		logger.log(chalk.red(`Closure compiler spawn error, Is java in your path?\n${err.message}`));
		//	onClose(1);
	});
	return compilerProcess;
}

function getSupportedCompiler(): {bin: string, args: string[]} {
	const pkgName = PlatformToCompilerPackageName[process.platform];
	if (pkgName) {
		try {
			// Try resolving optional dependencies
			return {bin: require(pkgName), args: []};
		} catch (e) {}
	}
	// Not found, defaults to JAVA version.
	return {bin: 'java', args: ['-jar', require('google-closure-compiler-java')]};
}

enum PlatformToCompilerPackageName {
	'darwin' = 'google-closure-compiler-osx',
	'win32' = 'google-closure-compiler-windows',
	'linux' = 'google-closure-compiler-linux',
	'aix' = '',
	'android' = '',
	'freebsd' = '',
	'openbsd' = '',
	'sunos' = '',
	'cygwin' = '',
	'netbsd' = '',
	'haiku' = '',
}


================================================
FILE: packages/tscc/src/spec/ITsccSpecWithTS.ts
================================================
import {ITsccSpec} from '@tscc/tscc-spec';
import * as ts from 'typescript'

export default interface ITsccSpecWithTS extends ITsccSpec {
	getTSRoot(): string
	getCompilerOptions(): Readonly<ts.CompilerOptions>
	getCompilerHost(): ts.CompilerHost
	getOutputFileNames(): string[]
	/**
	 * --compilation_level: defaults to ADVANCED
	 * --language_in: Derived from tsconfig's `target`
	 * --language_out: defaults to ECMASCRIPT_NEXT
	 * --chunk_output_prefix: determined from `prefix` key of tscc spec.
	 */
	getBaseCompilerFlags(): string[]
	/**
	 * Returns a list of file names included in the TS project.
	 */
	getAbsoluteFileNamesSet(): Set<string>
	/**
	 * For a given module name as used in import ... from ${moduleName}, returns a type reference file's
	 * file name. Returns null if it cannot find a type definition for a module's name.
	 */
	resolveExternalModuleTypeReference(moduleName: string): string | null;
	/**
	 * Create a unique hash for a project, consisting of the absolute path of tsconfig,
	 * absolute path of tsccspec, and their contents.
	 */
	getProjectHash(): string
}



================================================
FILE: packages/tscc/src/spec/TsccSpecWithTS.ts
================================================
import {IInputTsccSpecJSON, ITsccSpecJSON, closureCompilerFlags, TsccSpec, TsccSpecError} from '@tscc/tscc-spec';
import * as ts from 'typescript';
import ITsccSpecWithTS from './ITsccSpecWithTS';
import path = require('path');


export class TsError extends Error {
	constructor(
		public diagnostics: ReadonlyArray<ts.Diagnostic>
	) {
		super(ts.formatDiagnostics(diagnostics, ts.createCompilerHost({})));
	}
}

type TWarningCallback = (msg: string) => void;

export default class TsccSpecWithTS extends TsccSpec implements ITsccSpecWithTS {
	static loadTsConfigFromArgs(tsArgs: string[], specRoot: string, onWarning: TWarningCallback) {
		const {options, fileNames, errors} = ts.parseCommandLine(tsArgs);
		if (errors.length) {
			throw new TsError(errors);
		}
		if (fileNames.length) {
			onWarning(`Files provided via TS args are ignored.`);
		}
		// If "--project" argument is supplied - load tsconfig from there, merge things with this.
		// Otherwise, we lookup from tsccSpecPath - this is what is different to "tsc" (which looks up
		// the current working directory).
		// I think this is a more reasonable behavior, since many users will just put spec.json and
		// tsconfig.json at the same directory, they will otherwise have to provide the same information
		// twice, once for tscc and once for tsc.
		const configFileName = TsccSpecWithTS.findConfigFileAndThrow(options.project, specRoot);
		return TsccSpecWithTS.loadTsConfigFromResolvedPath(configFileName, options);
	}
	// compilerOptions is a JSON object in the form of tsconfig.json's compilerOption value.
	// Its value will override compiler options.
	static loadTsConfigFromPath(tsConfigPath?: string, specRoot?: string, compilerOptions?: object) {
		const configFileName = TsccSpecWithTS.findConfigFileAndThrow(tsConfigPath, specRoot);
		let options: ts.CompilerOptions = {}, errors: ts.Diagnostic[];
		if (compilerOptions) {
			({options, errors} = ts.convertCompilerOptionsFromJson(
				compilerOptions, path.dirname(configFileName)
			));
			if (errors.length) {
				throw new TsError(errors);
			}
		}
		return TsccSpecWithTS.loadTsConfigFromResolvedPath(configFileName, options);
	}
	// At least one among searchPath and defaultLocation must be non-null.
	private static findConfigFileAndThrow(searchPath?: string, defaultLocation?: string) {
		const configFileName =
			TsccSpecWithTS.resolveSpecFile(searchPath, 'tsconfig.json', defaultLocation);
		if (configFileName === undefined) {
			throw new TsccSpecError(
				`Cannot find tsconfig at ${TsccSpecWithTS.toDisplayedPath(searchPath ?? defaultLocation!)}.`
			)
		}
		return configFileName;
	}
	private static loadTsConfigFromResolvedPath(configFileName: string, options: ts.CompilerOptions) {
		const compilerHost: ts.ParseConfigFileHost = Object.create(ts.sys);
		compilerHost.onUnRecoverableConfigFileDiagnostic = (diagnostic) => {throw new TsError([diagnostic]);}
		const parsedConfig = ts.getParsedCommandLineOfConfigFile(configFileName, options, compilerHost)!;
		if (parsedConfig.errors.length) {
			throw new TsError(parsedConfig!.errors);
		}
		const projectRoot = path.dirname(configFileName);
		return {projectRoot, parsedConfig};
	}
	static loadSpecWithTS(
		tsccSpecJSONOrItsPath: string | IInputTsccSpecJSON,
		tsConfigPathOrTsArgs?: string | string[],
		compilerOptionsOverride?: object,
		onTsccWarning: (msg: string) => void = noop
	) {
		// When TS project root is not provided, it will be assumed to be the location of tscc spec file.
		let {tsccSpecJSON, tsccSpecJSONPath} = TsccSpecWithTS.loadSpecRaw(tsccSpecJSONOrItsPath);
		let specRoot = path.dirname(tsccSpecJSONPath);
		let {projectRoot, parsedConfig} = Array.isArray(tsConfigPathOrTsArgs) ?
			TsccSpecWithTS.loadTsConfigFromArgs(tsConfigPathOrTsArgs, specRoot, onTsccWarning) :
			TsccSpecWithTS.loadTsConfigFromPath(tsConfigPathOrTsArgs, specRoot, compilerOptionsOverride);

		TsccSpecWithTS.pruneCompilerOptions(parsedConfig.options, onTsccWarning);
		return new TsccSpecWithTS(tsccSpecJSON, tsccSpecJSONPath, parsedConfig, projectRoot);
	}
	/**
	 * Prune compiler options
	 *  - "module" to "commonjs"
	 *  - Warn when rootDir or outDir is used - these options are about `tsc` output directory structure,
	 *    which is of no use with tscc.
	 *  - Warn when target language is ES3 – Tsickle does not assume that the output can be lower than ES5,
	 */
	static pruneCompilerOptions(options: ts.CompilerOptions, onWarning: TWarningCallback) {
		if (options.module !== ts.ModuleKind.CommonJS) {
			if (typeof options.module !== 'undefined') {
				onWarning(`Module option is set. tsickle converts TypeScript modules to Closure modules`
					+ `via CommonJS internally, so it will be overridden to "commonjs".`);
			}
			options.module = ts.ModuleKind.CommonJS;
		}
		if (options.outDir) {
			onWarning(`--outDir option is set, but it is no-op for tscc.` +
				`Use prefix option in spec file to control output directory.`);
			options.outDir = undefined;
		}
		/**
		 * {@link https://github.com/angular/tsickle/commit/2050e902ea0fa59aa36f414cab192155167a9b06}
		 * tsickle throws if `rootDir` is not provided, for presumably "internal" reasons. In tscc,
		 * it normalizes paths to absolute paths, so the presence of `rootDir` does not have any
		 * visible effect. If it is not supplied, we provide a default value of the config file's
		 * containing root directory. Note that ts.CompilerOptions.configFilePath is an internal
		 * property.
		 */
		const {configFilePath} = options;
		const rootDir = configFilePath ? path.parse(configFilePath as string).root : '/';
		if (options.rootDir) {
			onWarning(`--rootDir is set, but it is no-op for tscc. It will internally set to ${rootDir}.`);
		}
		options.rootDir = rootDir;

		// See https://github.com/angular/tsickle/commit/c0123da31e2924ad45c3f0a02d536e750028de7b,
		// where a check to emit `const` declaration is done by target === ScriptTarget.ES5.
		if (options.target === ts.ScriptTarget.ES3) {
			onWarning(`tsickle does not support targetting ES3, and it will be overridden to ES5`
				+ `Consider setting compilationFlags.language_out to ECMASCRIPT3`);
			options.target = ts.ScriptTarget.ES5;
		} else if (typeof options.target === 'undefined') {
			// Prevent TS from treating unspecified target as a default value ES3.
			options.target = ts.ScriptTarget.ES5;
		}
		if (!options.importHelpers) {
			onWarning(`tsickle uses a custom tslib optimized for closure compiler. importHelpers flag is set.`);
			options.importHelpers = true;
		}
		if (options.removeComments) {
			onWarning(`Closure compiler relies on type annotations, removeComments flag is unset.`);
			options.removeComments = false;
		}
		if (options.inlineSourceMap) {
			onWarning(`Inlining sourcemap is not supported. inlineSourceMap flag is unset.`);
			options.inlineSourceMap = false;
			// inlineSource option depends on sourceMap or inlineSourceMap being enabled
			// so enabling sourceMap in order not to break tsc.
			options.sourceMap = true;
		}
		if (options.incremental) {
			// Incremental compilation produces an additional .tsbuildinfo file. This triggers
			// unrecognized file extension error, so we disable it.
			// Currently I'm not sure that among typescript and closure compiler, which impacts the
			// compilation time more. If it is closure compiler, there would not be much sense to
			// support incremental compilation, for closure compiler does not support it. Otherwise,
			// I may try to attempt implementing it. To do so, we have to write intermediate output
			// like what we do with --debug.persistArtifacts.
			onWarning(`Incremental compilation is not supported. incremental flag is unset.`);
			options.incremental = false;
		}
		// Silently unset flags related to declaration
		options.declaration &&= false;
		options.declarationMap &&= false;
	}
	private tsCompilerHost: ts.CompilerHost = ts.createCompilerHost(this.parsedConfig.options);
	private constructor(
		tsccSpec: ITsccSpecJSON,
		basePath: string,
		private parsedConfig: ts.ParsedCommandLine,
		private projectRoot: string
	) {
		super(tsccSpec, basePath);
		this.validateSpecWithTS();
	}
	private validateSpecWithTS() {
		// Checks that each of entry files is provided in tsConfig.
		const fileNames = this.getAbsoluteFileNamesSet();
		const modules = this.getOrderedModuleSpecs();
		for (let module of modules) {
			if (!fileNames.has(module.entry)) {
				throw new TsccSpecError(
					`An entry file ${module.entry} is not provided ` +
					`in a typescript project ${this.projectRoot}.`
				)
			}
		}
	}
	getTSRoot() {
		return this.projectRoot;
	}
	getCompilerOptions() {
		return this.parsedConfig.options;
	}
	getCompilerHost() {
		return this.tsCompilerHost;
	}
	private static readonly tsTargetToCcTarget = {
		[ts.ScriptTarget.ES5]: "ECMASCRIPT5_STRICT",
		[ts.ScriptTarget.ES2015]: "ECMASCRIPT_2015",
		[ts.ScriptTarget.ES2016]: "ECMASCRIPT_2016",
		[ts.ScriptTarget.ES2017]: "ECMASCRIPT_2017",
		[ts.ScriptTarget.ES2018]: "ECMASCRIPT_2018",
		[ts.ScriptTarget.ES2019]: "ECMASCRIPT_2019",
		[ts.ScriptTarget.ES2020]: "ECMASCRIPT_2020",
		[ts.ScriptTarget.ES2021]: "ECMASCRIPT_2021",
		[ts.ScriptTarget.ES2022]: "ECMASCRIPT_NEXT",
		[ts.ScriptTarget.ESNext]: "ECMASCRIPT_NEXT"
	}
	private static readonly chunkFormatToCcType = {
		['global']: "GLOBAL_NAMESPACE",
		['module']: "ES_MODULES"
	}
	getOutputFileNames(): string[] {
		return this.getOrderedModuleSpecs()
			.map(moduleSpec => {
				const {moduleName} = moduleSpec;
				return this.absolute(this.getOutputPrefix('cc')) + moduleName + '.js';
			});
	}
	private getDefaultFlags(): closureCompilerFlags {
		// Certain compiler options are guarded in pruneCompilerOptions method.
		type PrunedCompilerOptions = ts.CompilerOptions & {
			// Typescript accepts an undocumented compilation target "json".
			target: Exclude<Exclude<ts.ScriptTarget, ts.ScriptTarget.JSON>, ts.ScriptTarget.ES3>
		}
		let {target, sourceMap, inlineSources} = this.parsedConfig.options as PrunedCompilerOptions;

		const defaultFlags: closureCompilerFlags = {};
		defaultFlags["language_in"] = TsccSpecWithTS.tsTargetToCcTarget[target];
		// Closure compiler's default behavior is to output ECMASCRIPT_NEXT so that transpilation is
		// applied only when users explicitly request it. See:
		// https://github.com/google/closure-compiler/wiki/Releases#november-7-2021-v20211107
		// In version <=0.7.5, we had this set to ECMASCRIPT5.
		defaultFlags["language_out"] = "ECMASCRIPT_NEXT";
		defaultFlags["compilation_level"] = "ADVANCED";
		if (this.getOrderedModuleSpecs().length > 1) {
			// Multi-chunk build uses --chunk and --chunk_output_path_prefix.
			// This path will appear in a sourcemap that closure compiler generates - need to use
			// relative path in order not to leak global directory structure.
			defaultFlags["chunk_output_path_prefix"] = this.relativeFromCwd(this.getOutputPrefix('cc'));
		} else {
			// Single-chunk build uses --js_output_file.
			defaultFlags["js_output_file"] =
				this.relativeFromCwd(this.getOutputPrefix('cc')) +
				this.getOrderedModuleSpecs()[0].moduleName + '.js';
		}
		defaultFlags["chunk_output_type"] =
			this.tsccSpec.chunkFormat && TsccSpecWithTS.chunkFormatToCcType[this.tsccSpec.chunkFormat] ||
			"GLOBAL_NAMESPACE";
		defaultFlags["generate_exports"] = true;
		defaultFlags["export_local_property_definitions"] = true;

		if (sourceMap) {
			defaultFlags["create_source_map"] = "%outname%.map";
			defaultFlags["apply_input_source_maps"] = true;
		}
		if (inlineSources) {
			defaultFlags["source_map_include_content"] = true;
		}

		return defaultFlags;
	}
	getBaseCompilerFlags() {
		const baseFlags = this.tsccSpec.compilerFlags || {};
		const defaultFlags = this.getDefaultFlags();
		const flagsMap = Object.assign(defaultFlags, baseFlags);

		const outFlags: string[] = [];
		const pushFlag = (key: string, value: string | number | boolean) => {
			if (typeof value === 'boolean') {
				if (value === true) outFlags.push('--' + key);
			} else {
				outFlags.push('--' + key, String(value));
			}
		}
		for (let [key, value] of Object.entries(flagsMap)) {
			if (Array.isArray(value)) {
				for (let val of value) {
					pushFlag(key, val);
				}
			} else {
				pushFlag(key, value);
			}
		}
		return outFlags;
	}
	getAbsoluteFileNamesSet() {
		return new Set(
			this.parsedConfig.fileNames
				.map(fileName => path.resolve(this.projectRoot, fileName))
		);
	}
	resolveExternalModuleTypeReference(moduleName: string) {
		const resolved = ts.resolveTypeReferenceDirective(
			moduleName,
			// Following convention of Typescript source code
			path.join(this.projectRoot, '__inferred type names__.ts'),
			this.getCompilerOptions(),
			this.getCompilerHost()
		);
		if (resolved && resolved.resolvedTypeReferenceDirective &&
			resolved.resolvedTypeReferenceDirective.isExternalLibraryImport) {
			return resolved.resolvedTypeReferenceDirective.resolvedFileName ?? null;
		}
		return null;
	}
	getProjectHash(): string {
		return require('crypto').createHash('sha256')
			.update(
				this.basePath + JSON.stringify(this.tsccSpec) +
				this.projectRoot + JSON.stringify(this.parsedConfig.options)
			)
			.digest('hex');
	}
}

function noop() {}



================================================
FILE: packages/tscc/src/transformer/decorator_property_transformer.ts
================================================
/**
 * @fileoverview Decorators in TS is not compatible with Closure Compiler, as it generates
 * code that access a class' prototype property by string literals.
 * decoratorPropertyTransformer lookup occurence of such string literal property names,
 * and replaces it with appropriate `goog.reflect.objectProperty(<prop_name>, <target>)` call.
 *
 * Tsickle may at some point implement a similar feature. Currently it only implements some
 * other kinds of tranformation that is only made to make Angular work.
 *
 * Usage of goog.reflect.objectProperty is based on the following article:
 * {@link http://closuretools.blogspot.com/2016/06/using-polymer-with-closure-compiler-part-2.html}.
 *
 * In addition, we have to prevent this DevirtualizeMethods pass of closure compiler. However, there is
 * seem to be no stable way; see
 * nocollapse does not work - {@link https://github.com/google/closure-compiler/issues/2420}
 * sinkValue prevents inlining but does not prevent devirtualization
 * {@link https://github.com/google/closure-compiler/issues/2599}
 *
 * The pass is prevented when the property is accessed in a global scope, so we are creating
 * aaccesses of those and remove those via regex replace after the compilation. This is hacky and
 * not guaranteed to work but was the only way to make this work. Also has to be careful about
 * accessor decorators.
 */
import * as ts from 'typescript';
import {TsickleHost} from 'tsickle';
import TsHelperTransformer from './ts_helper_transformer';

export default function decoratorPropertyTransformer(tsickleHost: TsickleHost):
	(context: ts.TransformationContext) => ts.Transformer<ts.SourceFile> {
	return (context: ts.TransformationContext) => {
		return (sf: ts.SourceFile) => {
			return new DecoratorTransformer(tsickleHost, context, sf).transformSourceFile();
		};
	};
}

class DecoratorTransformer extends TsHelperTransformer {
	protected HELPER_NAME = "__decorate";

	private tempGlobalAssignments: ts.Statement[] = [];
	private getId() {
		return `tscc_global_access_name_${this.counter++}`;
	}
	private counter = 1;

	protected onHelperCall(node: ts.CallExpression, googReflectImport: ts.Identifier) {
		// Found a candidate. Decorator helper call signature:
		// __decorate([decoratorsArray], <target>, <propertyName>, <desc>)
		// Note that class decorator only has 2 arguments.
		let propNameLiteral = node.arguments[2];
		if (!propNameLiteral || !ts.isStringLiteral(propNameLiteral)) return;
		let propName = propNameLiteral.text;

		// Create goog.reflect.objectProperty
		const target = node.arguments[1];
		const googReflectObjectProperty = ts.setTextRange(
			this.factory.createCallExpression(
				this.factory.createPropertyAccessExpression(
					googReflectImport,
					this.factory.createIdentifier('objectProperty')
				),
				undefined,
				[
					this.factory.createStringLiteral(propName),
					ts.getMutableClone(target)
				]
			),
			propNameLiteral
		);
		// Replace third argument of __decorate call to goog.reflect.objectProperty.
		// If TS output is in ES3 mode, there will be 3 arguments in __decorate call.
		// if its higher than or equal to ES5 mode, there will be 4 arguments.
		// The number of arguments must be preserved.
		const caller = node.expression;
		const decorateArgs = node.arguments.slice();
		decorateArgs.splice(2, 1, googReflectObjectProperty);
		const newCallExpression = this.factory.createCallExpression(caller, undefined, decorateArgs);
		const globalAssignment = this.factory.createBinaryExpression(
			this.factory.createElementAccessExpression(
				this.factory.createIdentifier("self"),
				this.factory.createStringLiteral(this.getId())
			),
			this.factory.createToken(ts.SyntaxKind.FirstAssignment),
			this.factory.createPropertyAccessExpression(
				this.factory.createParenthesizedExpression(ts.getMutableClone(target)),
				this.factory.createIdentifier(propName)
			)
		);
		this.tempGlobalAssignments.push(
			ts.setEmitFlags(
				this.factory.createExpressionStatement(globalAssignment),
				ts.EmitFlags.NoSourceMap | ts.EmitFlags.NoTokenSourceMaps | ts.EmitFlags.NoNestedSourceMaps
			)
		);
		return newCallExpression;
	}

	protected combineStatements(stmts: ts.Statement[], googReflectImport: ts.Identifier) {
		super.combineStatements(stmts, googReflectImport);
		stmts.push(
			this.factory.createExpressionStatement(this.factory.createStringLiteral("__tscc_export_start__")),
			this.factory.createBlock(this.tempGlobalAssignments),
			this.factory.createExpressionStatement(this.factory.createStringLiteral('__tscc_export_end__'))
		);
		return stmts;
	}
}


================================================
FILE: packages/tscc/src/transformer/dts_requiretype_transformer.ts
================================================
/**
 * @fileoverview Transforms `const tsickle_aaaa = goog.requireType(.....)` calls to external modules
 * into const tsickle_aaaa = mangled$namespace$declared$in$externs. When certain external module's
 * main type declaration file merely reexports some other file,
 *
 * (details to be tested, some other file or some other file in another module?)
 *
 * tsickle inserts such requireType statements referencing that file directly.
 *
 * Type declarations in such files are already declared in externs, so we can just alias that variable
 * with a namespace on which the file's declarations are written.
 *
 * This code was mostly same as the one we've used to transform goog.require("a-external_module")
 * before we've switched to gluing module method.
 *
 * Codes are copied from commit
 * 1c9824461fcb71814466729b9c1424c4a60ef4ce (feat: use gluing modules for external module support)
 *
 * TODO: improve comment here and documentation.
 */
import * as ts from 'typescript';
import ITsccSpecWithTS from '../spec/ITsccSpecWithTS';
import {TsickleHost} from 'tsickle';
import {moduleNameAsIdentifier} from 'tsickle/out/src/annotator_host';
import {isGoogRequireLikeStatement, topLevelStatementTransformerFactory} from './transformer_utils';
import {escapedGoogNameIsDts, unescapeGoogAdmissibleName} from '../shared/escape_goog_identifier';
import path = require('path');

/**
 * This is a transformer run after ts transformation, before googmodule transformation.
 *
 * In order to wire imports of external modules to their global symbols, we replace
 * top-level `require`s of external modules to an assignment of a local variable to
 * a global symbol. This results in no `goog.require` or `goog.requireType` emit.
 */
export default function dtsRequireTypeTransformer(spec: ITsccSpecWithTS, tsickleHost: TsickleHost)
	: (context: ts.TransformationContext) => ts.Transformer<ts.SourceFile> {
	const externalModuleNames = spec.getExternalModuleNames();

	return topLevelStatementTransformerFactory((node, fh) => {
		let _ = isGoogRequireLikeStatement(node, "requireType");
		if (!_) return node;
		let {importedUrl, newIdent} = _;

		// We are only interested in `requireType`ing .d.ts files.
		if (!escapedGoogNameIsDts(importedUrl)) return node;
		// If imported url is external module, no need to handle it further.
		if (externalModuleNames.includes(importedUrl)) return node;
		// origUrl will be a file path relative to the ts project root.
		let origUrl = unescapeGoogAdmissibleName(importedUrl);
		let absoluteOrigUrl = path.resolve(spec.getTSRoot(), origUrl);
		// We must figure out on what namespace the extern for this module is defined.
		// See tsickle/src/externs.js for precise logic. In our case, goog.requireType(....d.ts)
		// will be emitted for "module .d.ts", in which case a mangled name derived from a
		// .d.ts file's path is used. See how `moduleNamespace`, `rootNamespace` is constructed
		// in tsickle/src/externs.js.
		// This relies on the heuristic of tsickle, so must be carefully validated whenever tsickle updates.
		let mangledNamespace = moduleNameAsIdentifier(tsickleHost, absoluteOrigUrl);
		if (newIdent.escapedText === mangledNamespace) {
			// Name of the introduced identifier coincides with the global identifier,
			// no need to emit things.
			return setOriginalNode(fh.factory.createEmptyStatement(), node);
		}
		// Convert `const importedName = goog.requireType("module d.ts")` to:
		// `const importedName = mangledNamespace;`
		return setOriginalNode(
			fh.createVariableAssignment(
				newIdent, fh.namespaceToQualifiedName(mangledNamespace),
				/* useConst */ tsickleHost.options.target !== ts.ScriptTarget.ES5
			),
			node
		);
	});
}

function setOriginalNode<T extends ts.Node>(range: T, node: ts.Statement): T {
	return ts.setOriginalNode<T>(ts.setTextRange(range, node), node);
}


================================================
FILE: packages/tscc/src/transformer/goog_namespace_transformer.ts
================================================
import {isVariableRequireStatement, isGoogRequireLikeStatement, topLevelStatementTransformerFactory} from './transformer_utils';

export const googNamespaceTransformer = topLevelStatementTransformerFactory((stmt, fh) => {
	// Before googmodule transformer of tsickle, import statements we are looking for looks like
	// var goog = require('goog:goog').
	let _ = isVariableRequireStatement(stmt);
	if (_) {
		let {importedUrl, newIdent} = _;
		if (importedUrl === "goog:goog" && newIdent.text === "goog") {
			return fh.factory.createNotEmittedStatement(stmt);
		}
	} else {
		_ = isGoogRequireLikeStatement(stmt, "requireType");
		if (_) {
			let {importedUrl, newIdent} = _;
			if (importedUrl === "goog") {
				return fh.createVariableAssignment(newIdent, fh.factory.createIdentifier("goog"));
			}
		}
	}
});


================================================
FILE: packages/tscc/src/transformer/rest_property_transformer.ts
================================================
import * as ts from 'typescript';
import {TsickleHost} from 'tsickle';
import TsHelperTransformer from './ts_helper_transformer';

export default function decoratorPropertyTransformer(tsickleHost: TsickleHost):
	(context: ts.TransformationContext) => ts.Transformer<ts.SourceFile> {
	return (context: ts.TransformationContext) => {
		return (sf: ts.SourceFile) => {
			return new RestHelperTransformer(tsickleHost, context, sf).transformSourceFile();
		};
	};
}

class RestHelperTransformer extends TsHelperTransformer {
	protected HELPER_NAME = "__rest";
	/**
	 * Rest helper call signature:
	 * __rest(<target>, [propertiesArray])
	 */
	protected onHelperCall(node: ts.CallExpression, googReflectImport: ts.Identifier) {
		let caller = node.expression;
		let target = node.arguments[0];
		let propertiesArray = <ts.ArrayLiteralExpression>node.arguments[1];

		// Create new array with goog.reflect.objectProperty
		// Note that for computed properties, Typescript creates a temp variable
		// that stores the computed value (_p), and put
		// ```
		// typeof _p === 'symbol' ? _c : _c + ""
		// ```
		const convertedArray = ts.setTextRange(
			this.factory.createArrayLiteralExpression(
				propertiesArray.elements.map((propNameLiteral: ts.Expression) => {
					if (!ts.isStringLiteral(propNameLiteral)) return propNameLiteral;
					const googReflectObjectProperty = ts.setTextRange(
						this.factory.createCallExpression(
							this.factory.createPropertyAccessExpression(
								googReflectImport,
								this.factory.createIdentifier('objectProperty')
							),
							undefined,
							[
								this.factory.createStringLiteral(propNameLiteral.text),
								ts.getMutableClone(target)
							]
						),
						propNameLiteral
					);
					return googReflectObjectProperty;
				})
			),
			propertiesArray
		);
		const restArgs = node.arguments.slice();
		restArgs.splice(1, 1, convertedArray);
		const newCallExpression = this.factory.createCallExpression(caller, undefined, restArgs);
		return newCallExpression;
	}
}


================================================
FILE: packages/tscc/src/transformer/transformer_utils.ts
================================================
import * as ts from 'typescript';

/**
 * Returns the string argument if call is of the form
 * require('foo')
 */
function extractRequire(call: ts.CallExpression): string | null {
	// Verify that the call is a call of a form require(...).
	const ident = call.expression;
	if (!ts.isIdentifier(ident)) return null;
	if (ident.escapedText !== 'require') return null;

	return getRequiredModuleName(call);
}

type TGoogRequireLike = "require" | "requireType";

/**
 * Verify that the call is a call of a form goog.require(...).
 * @param requireLike require, requireType, provides, ...
 */
function extractGoogRequireLike(call: ts.CallExpression, requireLike: TGoogRequireLike): string | null {
	let exp = call.expression;
	if (!ts.isPropertyAccessExpression(exp)) return null;
	if (!ts.isIdentifier(exp.expression) || exp.expression.escapedText !== 'goog') return null;
	if (exp.name.escapedText !== requireLike) return null;

	return getRequiredModuleName(call);
}

function getRequiredModuleName(call: ts.CallExpression): string | null {
	if (call.arguments.length !== 1) return null;

	// Verify the call takes a single string argument and grab it.
	const arg = call.arguments[0];
	if (!ts.isStringLiteral(arg)) return null;
	return arg.text;
}

interface IImportedVariable {
	importedUrl: string,
	newIdent: ts.Identifier
}

export function isVariableRequireStatement(stmt: ts.Statement): IImportedVariable | undefined {
	if (!ts.isVariableStatement(stmt)) return;
	// Verify it's a single decl (and not "var x = ..., y = ...;").
	if (stmt.declarationList.declarations.length !== 1) return;
	const decl = stmt.declarationList.declarations[0];

	// Grab the variable name (avoiding things like destructuring binds).
	if (decl.name.kind !== ts.SyntaxKind.Identifier) return;
	if (!decl.initializer || !ts.isCallExpression(decl.initializer)) {
		return;
	}
	const importedUrl = extractRequire(decl.initializer);
	if (!importedUrl) return;
	return {importedUrl, newIdent: decl.name};
}

export function isGoogRequireLikeStatement(stmt: ts.Statement, requireLike: TGoogRequireLike): IImportedVariable | undefined {
	if (!ts.isVariableStatement(stmt)) return;
	// Verify it's a single decl (and not "var x = ..., y = ...;").
	if (stmt.declarationList.declarations.length !== 1) return;
	const decl = stmt.declarationList.declarations[0];

	// Grab the variable name (avoiding things like destructuring binds).
	if (decl.name.kind !== ts.SyntaxKind.Identifier) return;
	if (!decl.initializer || !ts.isCallExpression(decl.initializer)) {
		return;
	}
	const importedUrl = extractGoogRequireLike(decl.initializer, requireLike);
	if (!importedUrl) return;
	return {importedUrl, newIdent: decl.name};
}

export function findImportedVariable(sf: ts.SourceFile, moduleName: string): ts.Identifier | undefined {
	for (let stmt of sf.statements) {
		let _ = isVariableRequireStatement(stmt);
		if (!_) continue;
		if (_.importedUrl !== moduleName) continue;
		return _.newIdent
	}
}

export function findGoogRequiredVariable(sf: ts.SourceFile, moduleName: string): ts.Identifier | undefined {
	for (let stmt of sf.statements) {
		let _ = isGoogRequireLikeStatement(stmt, "require");
		if (!_) continue;
		if (_.importedUrl !== moduleName) continue;
		return _.newIdent;
	}
}

/**
 * The transformer needs to discern "tslib" function calls (called EmitHelpers in TS),
 * but they are simply identifiers of name `__decorate` and such, all the difference
 * lies in their `emitNode` internal property. Any functionality related to this is
 * under internal and is not available in public API.
 * This function currently access Node.emitNode.flags to achieve this
 */
export function identifierIsEmitHelper(ident: ts.Identifier): boolean {
	let emitNode = (ident as any)["emitNode"];
	if (emitNode === undefined) return false;
	let flags = emitNode["flags"];
	if (typeof flags !== "number") return false;
	return (flags & ts.EmitFlags.HelperName) !== 0;
}

/**
 * A helper class that provides methods related to TS node factory functions. In body of TS
 * transformers, TS recommends to use ts.Factory object available as a property of a transformer
 * context object.
 */
export class NodeFactoryHelper {
	constructor(
		public readonly factory: ts.NodeFactory
	) {}
	/** Creates a call expression corresponding to `goog.${methodName}(${literal})`. */
	createGoogCall(methodName: string, literal: ts.StringLiteral): ts.CallExpression {
		return this.factory.createCallExpression(
			this.factory.createPropertyAccessExpression(
				this.factory.createIdentifier('goog'), methodName
			),
			undefined,
			[literal]
		);
	}
	// Creates a variable assignment var ${newIdent} = ${initializer}. Set constant = true to have
	// const instead of var.
	createVariableAssignment(newIdent: ts.Identifier, initializer: ts.Expression, useConst: boolean = false) {
		return this.factory.createVariableStatement(
			undefined,
			this.factory.createVariableDeclarationList(
				[
					this.factory.createVariableDeclaration(
						newIdent,
						undefined,
						undefined,
						initializer
					)
				],
				useConst ? ts.NodeFlags.Const : undefined
			)
		)
	}
	createSingleQuoteStringLiteral(text: string): ts.StringLiteral {
		const stringLiteral = this.factory.createStringLiteral(text);
		(stringLiteral as any)['singleQuote'] = true;
		return stringLiteral;
	}
	namespaceToQualifiedName(namespace: string): ts.Expression {
		let names = namespace.split('.');
		let l = names.length;
		let qualifiedName: ts.Expression = this.factory.createIdentifier(names[0]);
		for (let i = 1; i < l; i++) {
			qualifiedName = this.factory.createPropertyAccessExpression(
				qualifiedName, this.factory.createIdentifier(names[i])
			);
		}
		return qualifiedName;
	}
}

/**
 * A factory function that produces ts.TransformerFactory which iterates over a ts.SourceFile's
 * statements and replacing it if needed.
 */
export function topLevelStatementTransformerFactory(
	transformStatement: (stmt: ts.Statement, fh: NodeFactoryHelper) => ts.Statement | void
): ts.TransformerFactory<ts.SourceFile> {
	return (context) => {
		const factoryHelper = new NodeFactoryHelper(context.factory);
		return (sf) => {
			const stmts: ts.Statement[] = [];
			for (const stmt of sf.statements) {
				let newStmt = transformStatement(stmt, factoryHelper);
				stmts.push((newStmt ?? stmt) as ts.Statement);
			}
			return context.factory.updateSourceFile(
				sf,
				ts.setTextRange(
					context.factory.createNodeArray(stmts),
					sf.statements
				)
			);
		}
	}
}


================================================
FILE: packages/tscc/src/transformer/ts_helper_transformer.ts
================================================
/**
 * @fileoverview Contains a common logic that is used to typescript transformers that transforms
 * ts helper (those in tslib) emits.
 */
import * as ts from 'typescript';
import {TsickleHost} from 'tsickle';
import {findImportedVariable, findGoogRequiredVariable, identifierIsEmitHelper, NodeFactoryHelper} from './transformer_utils'

export default abstract class TsHelperTransformer {
	constructor(
		private tsickleHost: TsickleHost,
		private context: ts.TransformationContext,
		private sf: ts.SourceFile
	) {}
	protected factory = this.context.factory;
	protected abstract readonly HELPER_NAME: string;

	/**
	 * Determines whether the given node is a tslib helper call. Such a call expression looks similar
	 * to usual `__decorate(...)` function calls, except that the identifier node __decorate has
	 * a hidden emitNode property. This is encoded in `identifierIsEmitHelper` call and this method
	 * uses it.
	 */
	protected isTsGeneratedHelperCall(node: ts.Node): node is ts.CallExpression {
		if (!ts.isCallExpression(node)) return false;
		const caller = node.expression;
		if (!ts.isIdentifier(caller)) return false;
		if (caller.escapedText !== ts.escapeLeadingUnderscores(this.HELPER_NAME)) return false;
		if (!identifierIsEmitHelper(caller)) return false;
		return true;
	}

	/**
	 * Queries whether a visiting node is a call to tslib helper functions, such as
	 * `tslib_1.__decorate(...)` that is generated by the TS compiler, and if so, returns a new node.
	 * Otherwise, return undefined.
	 */
	protected abstract onHelperCall(node: ts.CallExpression, googReflectImport: ts.Identifier): ts.CallExpression | undefined

	private maybeTsGeneratedHelperCall(node: ts.Node, googReflectImport: ts.Identifier): ts.Node | undefined {
		if (!this.isTsGeneratedHelperCall(node)) return;
		return this.onHelperCall(node, googReflectImport);
	}

	transformSourceFile(): ts.SourceFile {
		const sf = this.sf;
		// There's nothing to do when tslib was not imported to the module.
		if (!findImportedVariable(sf, 'tslib')) return sf;
		const existingGoogReflectImport =
			findImportedVariable(sf, 'goog:goog.reflect') ||
			findGoogRequiredVariable(sf, 'goog.reflect');
		const googReflectImport =
			existingGoogReflectImport ||
			this.factory.createIdentifier(`tscc_goog_reflect_injected`);

		let foundTransformedDecorateCall = false;
		const visitor = (node: ts.Node): ts.Node => {
			let transformed = this.maybeTsGeneratedHelperCall(node, googReflectImport);
			if (transformed) {
				foundTransformedDecorateCall = true;
				return transformed;
			}
			return ts.visitEachChild(node, visitor, this.context);
		};

		const newSf = visitor(sf) as ts.SourceFile;
		if (!foundTransformedDecorateCall) return newSf;
		const stmts = this.combineStatements(
			newSf.statements.slice(),
			existingGoogReflectImport ? undefined : googReflectImport
		);

		return this.factory.updateSourceFile(
			newSf, ts.setTextRange(this.factory.createNodeArray(stmts), newSf.statements)
		);
	}

	protected combineStatements(stmts: ts.Statement[], googReflectImport?: ts.Identifier) {
		if (!googReflectImport) return stmts;
		const requireReflect = this.createGoogReflectRequire(googReflectImport);
		stmts.unshift(requireReflect);
		return stmts;
	}

	private createGoogReflectRequire(ident: ts.Identifier) {
		const fh = new NodeFactoryHelper(this.factory);
		return fh.createVariableAssignment(
			ident,
			fh.createGoogCall("require", this.factory.createStringLiteral('goog.reflect')),
			this.tsickleHost.options.target !== ts.ScriptTarget.ES5
		);
	}
}


================================================
FILE: packages/tscc/src/tscc.ts
================================================
import {IInputTsccSpecJSON} from '@tscc/tscc-spec';
import * as StreamArray from 'stream-json/streamers/StreamArray';
import * as tsickle from "tsickle";
import * as ts from "typescript";
import getDefaultLibs from './default_libs';
import ClosureDependencyGraph from './graph/ClosureDependencyGraph';
import TypescriptDependencyGraph from './graph/TypescriptDependencyGraph';
import Logger from './log/Logger';
import * as spinner from './log/spinner';
import {applyPatches, restorePatches} from './tsickle_patches/facade'
import {riffle, union} from './shared/array_utils';
import PartialMap from './shared/PartialMap';
import {ClosureJsonToVinyl, IClosureCompilerInputJson, RemoveTempGlobalAssignments} from './shared/vinyl_utils';
import {escapeGoogAdmissibleName} from './shared/escape_goog_identifier'
import spawnCompiler from './spawn_compiler';
import ITsccSpecWithTS from "./spec/ITsccSpecWithTS";
import TsccSpecWithTS, {TsError} from "./spec/TsccSpecWithTS";
import decoratorPropertyTransformer from './transformer/decorator_property_transformer';
import restPropertyTransformer from './transformer/rest_property_transformer';
import dtsRequireTypeTransformer from './transformer/dts_requiretype_transformer';
import {googNamespaceTransformer} from './transformer/goog_namespace_transformer';
import {getExternsForExternalModules, getGluingModules} from './external_module_support';
import fs = require('fs');
import path = require('path');
import stream = require('stream');
import {promisify} from 'util';
import fsExtra = require('fs-extra');
import vfs = require('vinyl-fs');
import upath = require('upath');
import chalk = require('chalk');


export const TEMP_DIR = ".tscc_temp";

/**
 * If the first argument is a string, it will try to lookup tscc.spec.json with the following priority:
 *  - The path itself
 *  - Files named tscc.spec.json or tscc.spec.js in a directory, regarding the path as a directory
 * If it is an object, it will treated as a JSON format object of the spec from a file located in
 * the current working directory. If no argument was passed, it will lookup the spec file on the
 * current working directory.
 * The second argument indicates the path to the tsconfig.json file.
 * The third argument is what would you put in tsconfig.json's compilerOptions. Options specified there
 * will override those of tsconfig.json.
 */
export default async function tscc(
	tsccSpecJSONOrItsPath: string | IInputTsccSpecJSON,
	tsConfigPathOrTsArgs?: string,
	compilerOptionsOverride?: object
): Promise<void>
/** @internal */
export default async function tscc(
	tsccSpecJSONOrItsPath: string | IInputTsccSpecJSON,
	tsConfigPathOrTsArgs: string[],
	compilerOptionsOverride?: object
): Promise<void>
/** @internal */
export default async function tscc(
	tsccSpecJSONOrItsPath: string | IInputTsccSpecJSON,
	tsConfigPathOrTsArgs?: string | string[],
	compilerOptionsOverride?: object
): Promise<void> {
	const tsccLogger = new Logger(chalk.green("TSCC: "), process.stderr);
	const tsLogger = new Logger(chalk.blue("TS: "), process.stderr);

	const tsccSpec = TsccSpecWithTS.loadSpecWithTS(
		tsccSpecJSONOrItsPath,
		tsConfigPathOrTsArgs,
		compilerOptionsOverride,
		(msg: string) => {tsccLogger.log(msg)}
	);

	const program = ts.createProgram(
		[...tsccSpec.getAbsoluteFileNamesSet()],
		tsccSpec.getCompilerOptions(),
		tsccSpec.getCompilerHost()
	);
	const diagnostics = ts.getPreEmitDiagnostics(program);
	if (diagnostics.length) throw new TsError(diagnostics);

	const tsDepsGraph = new TypescriptDependencyGraph(program)
	tsccSpec.getOrderedModuleSpecs().forEach(moduleSpec => tsDepsGraph.addRootFile(moduleSpec.entry));
	union(tsccSpec.getExternalModuleNames(), tsccSpec.getCompilerOptions().types ?? [])
		.map(tsccSpec.resolveExternalModuleTypeReference, tsccSpec)
		.map(tsDepsGraph.addRootFile, tsDepsGraph);
	// If user explicitly provided `types` compiler option, it is more likely that its type is actually
	// used in user code.

	const transformerHost = getTsickleHost(tsccSpec, tsDepsGraph, tsLogger);

	/**
	 * Ideally, the dependency graph should be determined from ts sourceFiles, and the compiler
	 * process can be spawned asynchronously before calling tsickle.
	 * Then, we will be able to set `tsickleHost.shouldSkipTsickleProcessing` and the order of
	 * files that are transpiled by tsickle. This has an advantage in that we can stream JSONs
	 * in order that they came out from tsickle, cuz Closure compiler requires JSON files to be
	 * sorted exactly as how js files would be sorted.
	 *
	 * As I recall, it was unsafe to use ModuleManifest returned from tsickle, cuz it does
	 * not include forwardDeclares or something.
	 * For now, we are computing the graph from the tsickle output in order to reuse
	 * codes from closure-tools-helper.
	 */
	const closureDepsGraph = new ClosureDependencyGraph();
	const tsickleOutput: PartialMap<string, IClosureCompilerInputJson> = new PartialMap();

	const {writeFile, writeExterns, externPath} =
		getWriteFileImpl(tsccSpec, tsickleOutput, closureDepsGraph);

	const stdInStream = new stream.Readable({read: function () {}});
	const pushImmediately = (arg: string | null) => setImmediate(pushToStream, stdInStream, arg);

	// ----- start tsickle call -----
	pushImmediately("[")

	// Manually push tslib, goog(base.js), goog.reflect, which are required in compilation
	const defaultLibsProvider = getDefaultLibs(tsccSpec.getTSRoot());
	defaultLibsProvider.libs.forEach(({path, id}) => {
		// ..only when user-provided sources do not provide such modules
		if (closureDepsGraph.hasModule(id)) return;
		writeFile(path, fs.readFileSync(path, 'utf8'))
	})

	// Manually push gluing modules
	getGluingModules(tsccSpec, transformerHost).forEach(({path, content}) => {
		writeFile(path, content)
	})

	// Manually push jsFiles, if there are any
	const jsFiles = tsccSpec.getJsFiles();
	if (jsFiles.length) {
		jsFiles.forEach(path => {
			writeFile(path, fs.readFileSync(path, 'utf8'));
		})
	}

	let result: tsickle.EmitResult;
	try {
		applyPatches();
		result = tsickle.emit(program, transformerHost, writeFile, undefined, undefined, false, {
			afterTs: [
				googNamespaceTransformer,
				dtsRequireTypeTransformer(tsccSpec, transformerHost),
				decoratorPropertyTransformer(transformerHost),
				restPropertyTransformer(transformerHost)
			]
		});
	} finally {
		restorePatches(); // Make sure that our patches are removed even if tsickle.emit throws.
	}

	// If tsickle errors, print diagnostics and exit.
	if (result.diagnostics.length) throw new TsError(result.diagnostics);

	const {src, flags} = closureDepsGraph.getSortedFilesAndFlags(
		tsccSpec.getOrderedModuleSpecs().map(entry => ({
			moduleId: transformerHost.pathToModuleName('', entry.entry),
			...entry
		}))
	);

	pushTsickleOutputToStream(src, tsccSpec, tsickleOutput, stdInStream, tsccLogger);

	// Write externs to a temp file.
	// ..only after attaching tscc's generated externs
	const externs = tsickle.getGeneratedExterns(result.externs, tsccSpec.getTSRoot()) +
		getExternsForExternalModules(tsccSpec, transformerHost);
	writeExterns(externs);

	pushImmediately("]");
	pushImmediately(null);
	/// ----- end tsickle call -----

	/**
	 * Spawn compiler process with module dependency information
	 */
	const ccLogger = new Logger(chalk.redBright("ClosureCompiler: "), process.stderr);
	spinner.startTask("Closure Compiler");

	const compilerProcess = spawnCompiler([
		...tsccSpec.getBaseCompilerFlags(),
		...flags,
		'--json_streams', "BOTH",
		'--externs', externPath,
		...riffle('--externs', defaultLibsProvider.externs)
	], ccLogger, tsccSpec.debug().persistArtifacts);

	const compilerProcessClose = new Promise<void>((resolve, reject) => {
		function onCompilerProcessClose(code: number) {
			if (code === 0) {
				spinner.succeed();
				spinner.unstick();
				tsccLogger.log(`Compilation success.`)
				if (tsccSpec.debug().persistArtifacts) {
					tsccLogger.log(tsccSpec.getOutputFileNames().join('\n'));
				}
				resolve();
			} else {
				spinner.fail(`Closure compiler error`);
				spinner.unstick();
				reject(new CcError(`Closure compiler has exited with code ${code}`));
			}
		}
		compilerProcess.on("close", onCompilerProcessClose);
	});

	stdInStream
		.pipe(compilerProcess.stdin);

	// Use gulp-style transform streams to post-process cc output - see shared/vinyl_utils.ts.
	// TODO support returning gulp stream directly
	const useSourceMap: boolean | undefined = tsccSpec.getCompilerOptions().sourceMap;

	const writeCompilationOutput = promisify(stream.pipeline)(
		compilerProcess.stdout,
		// jsonStreaming: true option makes the Parser of the stream-json package to fail gracefully
		// when no data is streamed. Currently this is not included in @types/stream-json. TODO make a
		// PR in Definitelytyped about this.
		StreamArray.withParser(<any>{jsonStreaming: true}),
		new ClosureJsonToVinyl(useSourceMap, tsccLogger),
		new RemoveTempGlobalAssignments(tsccLogger),
		vfs.dest('.', {sourcemaps: '.'})
	);

	await Promise.all([compilerProcessClose, writeCompilationOutput])
}

export class CcError extends Error {}
export class TsccError extends Error {}
class UnexpectedFileError extends TsccError {}

/**
 * Remove `//# sourceMappingURL=...` from source TS output which typescript generates when
 * sourceMap is enabled. Closure Compiler does not recognize attached sourcemaps in Vinyl
 * if this comment is present.
 * TODO if closure is actually looking for sourcemaps within that url, check that if we can provide
 * sourcemap in such a way that closure can find it, and remove this workaround.
 */
function removeSourceMappingUrl(tsOutput: string): string {
	return tsOutput.replace(reSourceMappingURL, '');
}
const reSourceMappingURL = /^\/\/[#@]\s*sourceMappingURL\s*=\s*.*?\s*$/mi;

function getWriteFileImpl(spec: ITsccSpecWithTS, tsickleVinylOutput: PartialMap<string, IClosureCompilerInputJson>, closureDepsGraph: ClosureDependencyGraph) {
	const tempFileDir = path.join(process.cwd(), TEMP_DIR, spec.getProjectHash());
	fsExtra.mkdirpSync(tempFileDir);
	// Closure compiler produces an error if output file's name is the same as one of
	// input files, which are in this case .js files. However, if such a file is an intermediate file
	// generated by TS, it is a legitimate usage. So we make file paths coming from TS virtual by
	// appending '.tsickle' to it.
	// See GH issue #82: When Windows-style path is used as a 'path' property of input, the Compiler
	// does not recognize path separators and fails to resolve paths in sourcemaps. Hence we replace
	// paths to unix-style paths just before we add it to input JSON object.
	const toVirtualPath = (filePath: string) => {
		if (tsOutputs.includes(filePath)) filePath += '.tsickle';
		let relPath = path.relative(spec.getTSRoot(), filePath);
		if (process.platform === 'win32') {
			// Convert to unix-style path only on Windows; on Unix, Windows-style path separator
			// is a valid directory/file name.
			relPath = upath.normalize(relPath);
		}
		return relPath;
	};
	const tsOutputs = [...spec.getAbsoluteFileNamesSet()].map(fileName => {
		let ext = path.extname(fileName);
		return fileName.slice(0, -ext.length) + '.js';
	});
	const writeFile = (filePath: string, contents: string) => {
		// Typescript calls writeFile with not normalized path. 'spec.getAbsoluteFileNamesSet' returns
		// normalized paths. Fixes GH issue #81.
		filePath = path.normalize(filePath);
		// Typescript calls writeFileCallback with absolute path.
		// On the contrary, "file" property of sourcemaps are relative path from ts project root.
		// For consistency, we convert absolute paths here to path relative to ts project root.
		if (spec.debug().persistArtifacts) {
			// filePath may contain colons which are not allowed in the middle of a path
			// such colons are a part of 'root', we are merely stripping it out.
			let filePathMinusRoot = filePath.substring(path.parse(filePath).root.length);
			fsExtra.outputFileSync(path.join(tempFileDir, filePathMinusRoot), contents);
		}
		switch (path.extname(filePath)) {
			case '.js': {
				if (spec.getCompilerOptions().sourceMap) {
					contents = removeSourceMappingUrl(contents)
				}
				closureDepsGraph.addSourceByContent(filePath, contents);
				tsickleVinylOutput.set(filePath, {
					src: contents,
					path: toVirtualPath(filePath)
				})
				return;
			}
			case '.map': {
				let sourceFilePath = filePath.slice(0
Download .txt
gitextract_d855frd2/

├── .circleci/
│   └── config.yml
├── .editorconfig
├── .github/
│   └── dependabot.yml
├── .gitignore
├── .vscode/
│   └── settings.json
├── LICENSE
├── README.md
├── jest.config.js
├── lerna.json
├── package.json
├── packages/
│   ├── rollup-plugin-tscc/
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── MultiMap.ts
│   │   │   ├── goog_shim_mixin.ts
│   │   │   ├── index.ts
│   │   │   ├── merge_chunks.ts
│   │   │   ├── sort_chunks.ts
│   │   │   └── spec/
│   │   │       ├── ITsccSpecRollupFacade.ts
│   │   │       └── TsccSpecRollupFacade.ts
│   │   ├── test/
│   │   │   ├── __snapshots__/
│   │   │   │   └── golden_test.ts.snap
│   │   │   ├── golden_test.ts
│   │   │   ├── merge_chunks.ts
│   │   │   ├── sample/
│   │   │   │   ├── external-modules/
│   │   │   │   │   ├── entry.js
│   │   │   │   │   └── tscc.spec.json
│   │   │   │   ├── external-modules-in-many-module-build/
│   │   │   │   │   ├── common/
│   │   │   │   │   │   └── index.js
│   │   │   │   │   ├── dependent.js
│   │   │   │   │   ├── entry.js
│   │   │   │   │   └── tscc.spec.json
│   │   │   │   ├── goog-shim/
│   │   │   │   │   ├── dependent.js
│   │   │   │   │   ├── entry.js
│   │   │   │   │   ├── tscc.spec.json
│   │   │   │   │   └── tscc.spec.module.json
│   │   │   │   └── many-module-build/
│   │   │   │       ├── common.js
│   │   │   │       ├── dir/
│   │   │   │       │   └── dependency.js
│   │   │   │       ├── entry.js
│   │   │   │       ├── tscc.spec.json
│   │   │   │       └── tscc.spec.module.json
│   │   │   └── sort_chunks.ts
│   │   ├── third_party/
│   │   │   └── closure_library/
│   │   │       ├── README.md
│   │   │       ├── goog_shim.js
│   │   │       └── reflect_shim.js
│   │   └── tsconfig.json
│   ├── tscc/
│   │   ├── .npmignore
│   │   ├── Makefile
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── default_libs.ts
│   │   │   ├── external_module_support.ts
│   │   │   ├── graph/
│   │   │   │   ├── Cache.ts
│   │   │   │   ├── ClosureDependencyGraph.ts
│   │   │   │   ├── ISourceNode.ts
│   │   │   │   ├── TypescriptDependencyGraph.ts
│   │   │   │   └── source_node_factory.ts
│   │   │   ├── log/
│   │   │   │   ├── Logger.ts
│   │   │   │   └── spinner.ts
│   │   │   ├── main.ts
│   │   │   ├── shared/
│   │   │   │   ├── PartialMap.ts
│   │   │   │   ├── array_utils.ts
│   │   │   │   ├── escape_goog_identifier.ts
│   │   │   │   ├── sourcemap_splice.ts
│   │   │   │   └── vinyl_utils.ts
│   │   │   ├── spawn_compiler.ts
│   │   │   ├── spec/
│   │   │   │   ├── ITsccSpecWithTS.ts
│   │   │   │   └── TsccSpecWithTS.ts
│   │   │   ├── transformer/
│   │   │   │   ├── decorator_property_transformer.ts
│   │   │   │   ├── dts_requiretype_transformer.ts
│   │   │   │   ├── goog_namespace_transformer.ts
│   │   │   │   ├── rest_property_transformer.ts
│   │   │   │   ├── transformer_utils.ts
│   │   │   │   └── ts_helper_transformer.ts
│   │   │   ├── tscc.ts
│   │   │   └── tsickle_patches/
│   │   │       ├── facade.ts
│   │   │       ├── patch_tsickle_decorator_transformer.ts
│   │   │       └── patch_tsickle_module_resolver.ts
│   │   ├── test/
│   │   │   ├── e2e/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── golden_test.ts.snap
│   │   │   │   ├── golden_test.ts
│   │   │   │   └── sample/
│   │   │   │       ├── case_1/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── ab.ts
│   │   │   │       │   ├── b.ts
│   │   │   │       │   ├── bb.ts
│   │   │   │       │   ├── bc.ts
│   │   │   │       │   ├── c.ts
│   │   │   │       │   ├── cc.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_10_unsafe_module_name_and_script_dts/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── script_dts.d.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_11_referencing_goog/
│   │   │   │       │   ├── dependent.ts
│   │   │   │       │   ├── entry.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_12_using_jsFiles/
│   │   │   │       │   ├── entry.ts
│   │   │   │       │   ├── jsfile.d.ts
│   │   │   │       │   ├── jsfile.js
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_13_chunk_format_global/
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_14_chunk_format_module/
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_2_sourcemaps/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_3_sourcemaps_with_decorators/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_4_external/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_5_object_spread/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_6_type_only_references/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── b.ts
│   │   │   │       │   ├── c.ts
│   │   │   │       │   ├── d.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_7_lodash_style_external_module_declaration/
│   │   │   │       │   ├── a.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       ├── case_8_dts_requiretype/
│   │   │   │       │   ├── imported.d.ts
│   │   │   │       │   ├── module.ts
│   │   │   │       │   ├── transtively_imported.d.ts
│   │   │   │       │   ├── tscc.spec.json
│   │   │   │       │   └── tsconfig.json
│   │   │   │       └── case_9_ts_in_node_modules/
│   │   │   │           ├── index.ts
│   │   │   │           ├── tscc.spec.json
│   │   │   │           └── tsconfig.json
│   │   │   ├── graph/
│   │   │   │   ├── ClosureDependencyGraph.ts
│   │   │   │   ├── TypescriptDependencyGraph.ts
│   │   │   │   └── source_node_factory.ts
│   │   │   ├── main.ts
│   │   │   ├── sample/
│   │   │   │   ├── decorator/
│   │   │   │   │   └── decorates.ts
│   │   │   │   ├── dts_requiretype/
│   │   │   │   │   ├── entry.ts
│   │   │   │   │   └── required.d.ts
│   │   │   │   ├── goog_module.js
│   │   │   │   ├── rest/
│   │   │   │   │   ├── case_1.ts
│   │   │   │   │   └── combined_with_decorators.ts
│   │   │   │   ├── tsconfig.json
│   │   │   │   └── tsdepsgraph/
│   │   │   │       ├── a.ts
│   │   │   │       ├── ab.d.ts
│   │   │   │       ├── b.d.ts
│   │   │   │       ├── bb.d.ts
│   │   │   │       ├── entry.ts
│   │   │   │       └── tsconfig.json
│   │   │   ├── shared/
│   │   │   │   ├── escape_goog_identifier.ts
│   │   │   │   └── sourcemap_splice.ts
│   │   │   ├── spec/
│   │   │   │   ├── TsccSpecWithTS.ts
│   │   │   │   └── sample/
│   │   │   │       ├── empty.ts
│   │   │   │       ├── nested_directory/
│   │   │   │       │   ├── empty.ts
│   │   │   │       │   └── tsconfig.json
│   │   │   │       └── tsconfig.1.json
│   │   │   ├── transformer/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── transformers.ts.snap
│   │   │   │   └── transformers.ts
│   │   │   ├── tsconfig.test_files.json
│   │   │   └── tsickle_patches/
│   │   │       └── patch_tsickle_module_resolver.ts
│   │   ├── third_party/
│   │   │   ├── closure_library/
│   │   │   │   ├── base.d.ts
│   │   │   │   ├── base.js
│   │   │   │   ├── reflect.d.ts
│   │   │   │   └── reflect.js
│   │   │   └── tsickle/
│   │   │       ├── closure_externs.js
│   │   │       └── third_party/
│   │   │           └── tslib/
│   │   │               ├── LICENSE.txt
│   │   │               ├── README.google
│   │   │               ├── externs.js
│   │   │               └── tslib.js
│   │   └── tsconfig.json
│   └── tscc-spec/
│       ├── .npmignore
│       ├── index.ts
│       ├── package.json
│       ├── src/
│       │   ├── ITsccSpec.ts
│       │   ├── ITsccSpecJSON.ts
│       │   ├── TsccSpec.ts
│       │   └── shared/
│       │       └── Graph.ts
│       ├── test/
│       │   ├── TsccSpec.ts
│       │   ├── sample/
│       │   │   ├── invalid_json.json
│       │   │   ├── spec_with_relative_external.json
│       │   │   ├── tscc.spec.json
│       │   │   └── unsupported_spec.json
│       │   └── shared/
│       │       └── Graph.ts
│       └── tsconfig.json
└── tsconfig.json
Download .txt
SYMBOL INDEX (449 symbols across 73 files)

FILE: packages/rollup-plugin-tscc/src/MultiMap.ts
  class MultiMap (line 1) | class MultiMap<K, V> {
    method add (line 3) | add(key: K, value?: V) {
    method find (line 15) | find(key: K, value: V): boolean {
    method findKey (line 20) | findKey(key: K): boolean {
    method findValue (line 23) | findValue(value: V): K | undefined {
    method get (line 28) | get(key: K): V[] {
    method putAll (line 32) | putAll(key: K, values: Iterable<V>) {
    method iterateValues (line 43) | iterateValues(key: K): IterableIterator<V> | undefined {
    method keys (line 47) | keys() {
    method size (line 50) | get size() {
    method fromObject (line 53) | static fromObject<V>(object: {[key: string]: V[]}): MultiMap<string, V> {
    method toObject (line 63) | static toObject<K, V>(
  method [Symbol.iterator] (line 36) | *[Symbol.iterator]() {

FILE: packages/rollup-plugin-tscc/src/goog_shim_mixin.ts
  constant SHIM_ROOT (line 10) | const SHIM_ROOT = path.resolve(__dirname, "../third_party/closure_librar...
  constant PREFIX (line 18) | const PREFIX = "\0tscc\0";
  function googShimMixin (line 21) | function googShimMixin<T extends {resolveId: FunctionPluginHooks["resolv...

FILE: packages/rollup-plugin-tscc/src/index.ts
  function isChunk (line 132) | function isChunk(output: rollup.OutputChunk | rollup.OutputAsset): outpu...
  function handleError (line 136) | function handleError<H extends (this: rollup.PluginContext, ..._: any[])...

FILE: packages/rollup-plugin-tscc/src/merge_chunks.ts
  type CodeSplittableModuleFormat (line 7) | type CodeSplittableModuleFormat = Exclude<rollup.ModuleFormat, 'iife' | ...
  class ChunkMerger (line 15) | class ChunkMerger {
    method constructor (line 19) | constructor(
    method resolveGlobalForPrimaryBuild (line 27) | private resolveGlobalForPrimaryBuild(id: string) {
    method populateEntryModuleNamespaces (line 32) | private populateEntryModuleNamespaces() {
    method populateChunkNamespaces (line 40) | private populateChunkNamespaces() {
    method populateUnresolveChunk (line 55) | private populateUnresolveChunk() {
    method createFacadeModuleCode (line 62) | private createFacadeModuleCode(entry: string): string {
    method createFacadeModuleLoaderPlugin (line 76) | private createFacadeModuleLoaderPlugin(entry: string): rollup.Plugin {
    method createLoaderPlugin (line 86) | private createLoaderPlugin(shouldLoadID: (id: string) => boolean): rol...
    method resolveGlobalForSecondaryBuild (line 115) | private resolveGlobalForSecondaryBuild(id: string): string {
    method performSingleEntryBuild (line 136) | async performSingleEntryBuild(entry: string, format: rollup.ModuleForm...
    method performCodeSplittingBuild (line 177) | async performCodeSplittingBuild(format: CodeSplittableModuleFormat) {
    method throwUnexpectedModuleError (line 218) | private static throwUnexpectedModuleError(id: string, importer = ""): ...
    method throwUnexpectedChunkInSecondaryBundleError (line 221) | private static throwUnexpectedChunkInSecondaryBundleError(output: (rol...
  class ChunkMergeError (line 226) | class ChunkMergeError extends Error {}
  function toInputSourceMap (line 231) | function toInputSourceMap(sourcemap: rollup.SourceMap | undefined): roll...
  function trimExtension (line 236) | function trimExtension(name: string) {

FILE: packages/rollup-plugin-tscc/src/sort_chunks.ts
  function computeChunkAllocation (line 13) | function computeChunkAllocation(
  class ChunkSortError (line 60) | class ChunkSortError extends Error {}

FILE: packages/rollup-plugin-tscc/src/spec/ITsccSpecRollupFacade.ts
  type ITsccSpecRollupFacade (line 5) | interface ITsccSpecRollupFacade extends ITsccSpec {

FILE: packages/rollup-plugin-tscc/src/spec/TsccSpecRollupFacade.ts
  class TsccSpecRollupFacade (line 6) | class TsccSpecRollupFacade extends TsccSpec implements ITsccSpecRollupFa...
    method resolveRollupExternalDeps (line 7) | resolveRollupExternalDeps(moduleId: string) {
    method getOutputPrefix (line 10) | protected getOutputPrefix(target: "cc" | "rollup"): string {
    method getResolvedRollupPrefix (line 16) | private getResolvedRollupPrefix() {
    method addPrefix (line 27) | private addPrefix(name: string) {
    method addPrefixAndExtension (line 30) | private addPrefixAndExtension(name: string) {
    method getRollupOutputNameToEntryFileMap (line 33) | getRollupOutputNameToEntryFileMap() {
    method getRollupOutputNameDependencyMap (line 41) | getRollupOutputNameDependencyMap() {
    method getRollupExternalModuleNamesToGlobalMap (line 52) | getRollupExternalModuleNamesToGlobalMap() {
    method getRollupOutputModuleFormat (line 60) | getRollupOutputModuleFormat(): ModuleFormat {

FILE: packages/rollup-plugin-tscc/test/golden_test.ts
  function upathGlob (line 12) | function upathGlob(glob: string): string[] {
  function testBundle (line 25) | async function testBundle(specPath: string) {

FILE: packages/rollup-plugin-tscc/test/merge_chunks.ts
  function mergeIIFE (line 7) | async function mergeIIFE(
  function mergeES (line 16) | async function mergeES(
  function mockChunk (line 550) | function mockChunk(chunk: Partial<rollup.OutputChunk>): rollup.OutputChu...

FILE: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/common/index.js
  function common (line 3) | function common(n) {

FILE: packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/entry.js
  function entry (line 4) | function entry() {

FILE: packages/rollup-plugin-tscc/test/sample/goog-shim/entry.js
  function isDebugging (line 3) | function isDebugging() {

FILE: packages/rollup-plugin-tscc/test/sample/many-module-build/common.js
  function swap (line 1) | function swap([a, b]) {
  function sort (line 5) | function sort([a, b]) {

FILE: packages/rollup-plugin-tscc/third_party/closure_library/goog_shim.js
  function define (line 7) | function define(name, value) {
  constant DEBUG (line 15) | let DEBUG = true;
  function typeOf (line 17) | function typeOf(value) {
  function isArrayLike (line 24) | function isArrayLike(val) {
  function isObject (line 28) | function isObject(val) {
  function getCssName (line 32) | function getCssName(className, opt_modifier) {
  function getMsg (line 35) | function getMsg(str, opt_values, opt_options) {
  function exportSymbol (line 57) | function exportSymbol(publicPath, object, objectToExportTo) {
  function exportProperty (line 70) | function exportProperty(object, publicName, symbol) {

FILE: packages/rollup-plugin-tscc/third_party/closure_library/reflect_shim.js
  function object (line 6) | function object(type, object) {
  function objectProperty (line 10) | function objectProperty(prop, object) {
  function sinkValue (line 14) | function sinkValue(x) {
  function canAccessProperty (line 20) | function canAccessProperty(obj, prop) {
  function cache (line 28) | function cache(cacheObj, key, valueFn, opt_keyFn) {

FILE: packages/tscc-spec/src/ITsccSpec.ts
  type INamedModuleSpecsWithId (line 3) | interface INamedModuleSpecsWithId extends INamedModuleSpecs {
  type ITsccSpec (line 12) | interface ITsccSpec {
  type ExternalModuleData (line 32) | interface ExternalModuleData {

FILE: packages/tscc-spec/src/ITsccSpecJSON.ts
  type IModule (line 4) | interface IModule {
  type INamedModuleSpecs (line 20) | interface INamedModuleSpecs extends IModule {
  type ITsccSpecJSON (line 28) | interface ITsccSpecJSON {
  type IDebugOptions (line 85) | interface IDebugOptions {
  type primitives (line 96) | type primitives = string | boolean | number;
  type closureCompilerFlags (line 97) | type closureCompilerFlags = {[flag: string]: primitives | primitives[]}

FILE: packages/tscc-spec/src/TsccSpec.ts
  type IInputTsccSpecJSONWithSpecFile (line 12) | interface IInputTsccSpecJSONWithSpecFile extends Partial<ITsccSpecJSON> {
  type IInputTsccSpecJSONWithOptionalSpecFile (line 20) | interface IInputTsccSpecJSONWithOptionalSpecFile extends ITsccSpecJSON {
  type IInputTsccSpecJSON (line 24) | type IInputTsccSpecJSON = IInputTsccSpecJSONWithOptionalSpecFile | IInpu...
  function hasSpecFileKey (line 26) | function hasSpecFileKey(json: IInputTsccSpecJSON): json is IInputTsccSpe...
  class TsccSpec (line 30) | class TsccSpec implements ITsccSpec {
    method isDotPath (line 38) | private static isDotPath(p: string) {return TsccSpec.RE_DOT_PATH.test(...
    method endsWithSep (line 39) | private static endsWithSep(p: string) {return TsccSpec.RE_ENDS_WITH_SE...
    method resolveSpecFile (line 55) | protected static resolveSpecFile(
    method toDisplayedPath (line 86) | protected static toDisplayedPath(p: string): string {
    method findTsccSpecAndThrow (line 92) | private static findTsccSpecAndThrow(root: string | undefined): string {
    method loadSpecRaw (line 100) | protected static loadSpecRaw(
    method loadSpec (line 131) | static loadSpec<T extends typeof TsccSpec>(
    method constructor (line 138) | constructor(
    method validateSpec (line 146) | private validateSpec() {
    method computeOrderedModuleSpecs (line 163) | private computeOrderedModuleSpecs() {
    method getOrderedModuleSpecs (line 198) | getOrderedModuleSpecs() {
    method interopModuleSpecs (line 201) | private interopModuleSpecs(moduleName: string, moduleSpec: IModule | s...
    method absolute (line 220) | protected absolute(filePath: string): string {
    method relativeFromCwd (line 233) | protected relativeFromCwd(filePath: string): string {
    method getOutputPrefix (line 240) | protected getOutputPrefix(target: "cc" | "rollup"): string {
    method resolveRelativeExternalModuleNames (line 247) | private resolveRelativeExternalModuleNames() {
    method getExternalModuleNames (line 257) | getExternalModuleNames() {
    method getExternalModuleDataMap (line 260) | getExternalModuleDataMap(): ReadonlyMap<string, Readonly<ExternalModul...
    method getJsFiles (line 263) | getJsFiles() {
    method debug (line 277) | debug(): Readonly<IDebugOptions> {
  class TsccSpecError (line 282) | class TsccSpecError extends Error {}

FILE: packages/tscc-spec/src/shared/Graph.ts
  class AssociativeArrayLink (line 1) | class AssociativeArrayLink<V> {
    method constructor (line 4) | constructor(
    method insertBefore (line 10) | insertBefore(item: this) {
    method remove (line 16) | remove() {
  class AssociativeArray (line 24) | class AssociativeArray<K, V> {
    method hasKey (line 28) | hasKey(key: K): boolean {
    method hasValue (line 31) | hasValue(value: V): boolean {
    method getValue (line 34) | getValue(key: K): V | null {
    method getKey (line 39) | getKey(value: V): K | null {
    method deleteKey (line 44) | deleteKey(key: K): this {
    method deleteValue (line 52) | deleteValue(value: V): this {
    method set (line 60) | set(key: K, value: V) {
    method size (line 68) | get size() {
    method keys (line 71) | keys() {
    method values (line 74) | values() {
    method reversedKeys (line 77) | *reversedKeys() {
    method reversedValues (line 84) | *reversedValues() {
    method clear (line 91) | clear() {
  class Node (line 98) | class Node {
    method addInbound (line 101) | addInbound(edge: DirectedEdge) {
    method addOutbound (line 104) | addOutbound(edge: DirectedEdge) {
    method deleteInbound (line 107) | deleteInbound(edge: DirectedEdge) {
    method deleteOutbound (line 112) | deleteOutbound(edge: DirectedEdge) {
    method isRoot (line 117) | isRoot(): boolean {
    method isLeaf (line 120) | isLeaf(): boolean {
    method iterateInboundEdges (line 123) | iterateInboundEdges() {
    method iterateOutboundEdges (line 126) | iterateOutboundEdges() {
    method iterateAncestors (line 129) | *iterateAncestors<T extends Node>(this: T): Iterable<T> {
  class DirectedEdge (line 139) | class DirectedEdge {
    method constructor (line 140) | constructor(
  class NodeToVisit (line 149) | class NodeToVisit extends Node {
    method setAsVisited (line 153) | setAsVisited(edge: EdgeToVisit) {
    method resetVisited (line 160) | resetVisited() {
    method isDecendent (line 165) | isDecendent(node: NodeToVisit | null) {
    method collectDecendentsFromVisitedEdges (line 169) | collectDecendentsFromVisitedEdges() {
  class EdgeToVisit (line 180) | class EdgeToVisit extends DirectedEdge {
    method setAsVisited (line 183) | setAsVisited() {
  class NodeWithLeaf (line 188) | class NodeWithLeaf extends Node {
    method addLeaf (line 190) | addLeaf(leaf: NodeWithLeaf) {
    method getLeafs (line 193) | getLeafs(): ReadonlyArray<NodeWithLeaf> {
  class CycleError (line 198) | class CycleError<I> extends Error {
    method constructor (line 199) | constructor(
  method iterateNodes (line 206) | protected iterateNodes() {
  method reverseIterateNodes (line 209) | protected reverseIterateNodes() {
  method addNodeById (line 214) | addNodeById(id: I) {
  method addEdgeById (line 220) | addEdgeById(source: I, target: I) {
  method getNodeById (line 226) | getNodeById(id: I): N | null {
  method getIdOfNode (line 230) | getIdOfNode(node: N): I | null {
  method filterLeafs (line 233) | protected static filterLeafs<N extends Node>(node: N): boolean {
  method getALeaf (line 236) | private getALeaf() {
  method getARoot (line 241) | private getARoot() {
  method sort (line 247) | sort() {
  class DirectedTree (line 275) | class DirectedTree<I> extends DirectedTreeBase<I, Node, DirectedEdge> {
    method createNode (line 276) | protected createNode() {
    method createEdge (line 279) | protected createEdge(source: Node, target: Node) {
  class DirectedTreeWithOrdering (line 286) | class DirectedTreeWithOrdering<I> extends DirectedTreeBase<I, NodeToVisi...
    method createNode (line 287) | protected createNode() {
    method createEdge (line 290) | protected createEdge(source: NodeToVisit, target: NodeToVisit) {
    method populateDecendents (line 293) | populateDecendents() {
    method getInfimum (line 306) | getInfimum(idArray: I[]): I | null {
  class DirectedTreeWithLeafs (line 318) | class DirectedTreeWithLeafs<I> extends DirectedTreeBase<I, NodeWithLeaf,...
    method createNode (line 319) | protected createNode() {
    method createEdge (line 322) | protected createEdge(source: NodeWithLeaf, target: NodeWithLeaf) {
    method iterateLeafs (line 325) | private *iterateLeafs() {
    method populateLeafs (line 330) | populateLeafs() {
    method getLeafsOfNode (line 337) | getLeafsOfNode(id: I): I[] {

FILE: packages/tscc-spec/test/TsccSpec.ts
  function mockCurrentWorkingDirectory (line 89) | function mockCurrentWorkingDirectory(mockValue: string) {

FILE: packages/tscc-spec/test/shared/Graph.ts
  function compareGraphStructure (line 4) | function compareGraphStructure(nodes, edges, poset) {
  function posetFromEdges (line 20) | function posetFromEdges<I>(poset: DirectedTreeBase<I, any, any>, edges: ...
  function secondArgIsADescendentOfFirstArg (line 99) | function secondArgIsADescendentOfFirstArg(a: number, b: number) {

FILE: packages/tscc/src/default_libs.ts
  function resolveTSCCAssets (line 13) | function resolveTSCCAssets(relPath: string, projectRoot: string): string {

FILE: packages/tscc/src/external_module_support.ts
  function getExternsForExternalModules (line 10) | function getExternsForExternalModules(tsccSpec: ITsccSpecWithTS, tsickle...
  function getGluingModules (line 29) | function getGluingModules(tsccSpec: ITsccSpecWithTS, tsickleHost: Tsickl...

FILE: packages/tscc/src/graph/Cache.ts
  class Cache (line 5) | class Cache<T> {
    method constructor (line 13) | constructor(
    method get (line 23) | get(key: string): T {
    method getMtime (line 26) | getMtime(key: string): number {
    method put (line 29) | put(key: string, content: T, mtime: number) {
    method remove (line 33) | remove(key: string) {
    method commit (line 36) | async commit() {
  class FSCacheAccessor (line 42) | class FSCacheAccessor<T> {
    method constructor (line 43) | constructor(
    method getFileData (line 47) | async getFileData(path: string) {
    method updateCache (line 67) | async updateCache() {
  class FSCacheAccessError (line 72) | class FSCacheAccessError extends Error {}

FILE: packages/tscc/src/graph/ClosureDependencyGraph.ts
  type IEntryPoint (line 8) | interface IEntryPoint {
  class ClosureDependencyGraph (line 13) | class ClosureDependencyGraph {
    method addSourceByFileNames (line 14) | async addSourceByFileNames(fileNames: string[], fsCacheAccessor: FSCac...
    method addSourceByContent (line 25) | addSourceByContent(fileName: string, content: string) {
    method addSourceNode (line 34) | addSourceNode(sourceNode: ISourceNode) {
    method hasModule (line 50) | hasModule(moduleName: string): boolean {
    method clear (line 59) | clear() {
    method getSourceNode (line 63) | private getSourceNode(moduleName: string) {
    method getRequiredNodes (line 78) | private *getRequiredNodes(node: string | ISourceNode): IterableIterato...
    method walkTypeRequiredNodes (line 106) | private walkTypeRequiredNodes(node: ISourceNode) {
    method getFileName (line 117) | private static getFileName(sourceNode: ISourceNode) {
    method getSortedFilesAndFlags (line 120) | getSortedFilesAndFlags(entryPoints: Omit<INamedModuleSpecsWithId, 'ent...
  type IFilesAndFlags (line 156) | interface IFilesAndFlags {
  class ClosureDepsError (line 161) | class ClosureDepsError extends Error {}

FILE: packages/tscc/src/graph/ISourceNode.ts
  type ISourceNode (line 1) | interface ISourceNode {

FILE: packages/tscc/src/graph/TypescriptDependencyGraph.ts
  type SourceFileWithInternalAPIs (line 47) | interface SourceFileWithInternalAPIs extends ts.SourceFile {
  class TypescriptDependencyGraph (line 54) | class TypescriptDependencyGraph {
    method constructor (line 55) | constructor(
    method isDefaultLib (line 62) | private isDefaultLib(fileName: string) {
    method isTslib (line 65) | private isTslib(fileName: string) {
    method isTsccAsset (line 68) | private isTsccAsset(fileName: string) {
    method walk (line 71) | private walk(fileName: string | undefined | null) {
    method addRootFile (line 118) | addRootFile(fileName: string | undefined | null) {
    method hasFile (line 121) | hasFile(fileName: string) {
    method iterateFiles (line 125) | iterateFiles() {

FILE: packages/tscc/src/graph/source_node_factory.ts
  function sourceNodeFactory (line 9) | async function sourceNodeFactory(closureSourcePath: string): Promise<ISo...
  function sourceNodeFactoryFromContent (line 21) | function sourceNodeFactoryFromContent(fileName: string, content: string)...
  class ClosureSourceLineParser (line 30) | class ClosureSourceLineParser {
    method constructor (line 36) | constructor(
    method consumeLine (line 42) | consumeLine(line: string): boolean {
    method getSourceNode (line 69) | getSourceNode(): ISourceNode {
  function toGoogPrimitiveRegex (line 92) | function toGoogPrimitiveRegex(name: string, assignment: boolean = false) {
  class ClosureSourceError (line 112) | class ClosureSourceError extends Error {
    method constructor (line 113) | constructor(msg: string, public fatal = true) {

FILE: packages/tscc/src/log/Logger.ts
  class Logger (line 12) | class Logger {
    method constructor (line 14) | constructor(
    method log (line 24) | log(msg: string, ...args: any[]) {
    method write (line 31) | write(msg: string) {
    method eraseSpinner (line 34) | private static eraseSpinner(target: Object, prop: string, desc: Proper...

FILE: packages/tscc/src/log/spinner.ts
  function startTask (line 10) | function startTask(text: string) {
  function succeed (line 28) | function succeed(text?: string) {
  function fail (line 35) | function fail(text?: string) {
  function unstick (line 47) | function unstick() {
  function hasSpinner (line 57) | function hasSpinner() {
  function toDDHHMMSS (line 61) | function toDDHHMMSS(milliseconds: number) {

FILE: packages/tscc/src/main.ts
  function main (line 15) | async function main(args: any) {
  function parseTsccCommandLineArgs (line 33) | function parseTsccCommandLineArgs(args: string[], strict = true): {[key:...
  function buildTsccSpecJSONAndTsArgsFromArgs (line 114) | function buildTsccSpecJSONAndTsArgsFromArgs(args: any) {

FILE: packages/tscc/src/shared/PartialMap.ts
  class PartialMap (line 1) | class PartialMap<K, V extends {}> extends Map<K, Partial<V>> {
    method set (line 2) | set(key: K, value: Partial<V>) {

FILE: packages/tscc/src/shared/array_utils.ts
  function riffle (line 1) | function riffle<T>(x: T, array: T[]): T[] {
  function flatten (line 9) | function flatten<T>(array: T[][]): T[] {
  function union (line 17) | function union<T>(array1: T[], array2: T[]): T[] {

FILE: packages/tscc/src/shared/escape_goog_identifier.ts
  function codePoint (line 13) | function codePoint(char: string) {return char.codePointAt(0)!;}
  constant LOWERCASE_A_CODE_POINT (line 15) | const LOWERCASE_A_CODE_POINT = codePoint('a');
  constant LOWERCASE_Z_CODE_POINT (line 16) | const LOWERCASE_Z_CODE_POINT = codePoint('z');
  constant UPPERCASE_A_CODE_POINT (line 17) | const UPPERCASE_A_CODE_POINT = codePoint('A');
  constant UPPERCASE_Z_CODE_POINT (line 18) | const UPPERCASE_Z_CODE_POINT = codePoint('Z');
  constant PERIOD_CODE_POINT (line 19) | const PERIOD_CODE_POINT = codePoint('.');
  constant LOWER_DASH_CODE_POINT (line 20) | const LOWER_DASH_CODE_POINT = codePoint('_');
  constant DOLLAR_SIGN_CODE_POINT (line 21) | const DOLLAR_SIGN_CODE_POINT = codePoint('$');
  constant ZERO_CODE_POINT (line 22) | const ZERO_CODE_POINT = codePoint('0');
  constant NINE_CODE_POINT (line 23) | const NINE_CODE_POINT = codePoint('9');
  constant SEP (line 24) | const SEP = path.sep;
  function isLatin (line 26) | function isLatin(code: number) {
  function isNumber (line 30) | function isNumber(code: number) {
  function isLowerDash (line 33) | function isLowerDash(code: number) {
  function isPeriod (line 36) | function isPeriod(code: number) {
  function isDollarSign (line 39) | function isDollarSign(code: number) {
  function escapeGoogAdmissibleName (line 56) | function escapeGoogAdmissibleName(name: string): string {
  function unescapeGoogAdmissibleName (line 73) | function unescapeGoogAdmissibleName(escapedName: string): string {
  function escapedGoogNameIsDts (line 106) | function escapedGoogNameIsDts(escapedName: string) {

FILE: packages/tscc/src/shared/sourcemap_splice.ts
  function spliceSourceMap (line 10) | async function spliceSourceMap(content: string, map: RawSourceMap, splic...
  function getMapping (line 56) | function getMapping(
  function splitWithRegex (line 75) | function splitWithRegex(contents: string, regex: RegExp) {
  class Seeker (line 91) | class Seeker {
    method constructor (line 92) | constructor(
    method seekInterval (line 112) | private seekInterval(index: number) {
    method seekWithinLine (line 126) | private seekWithinLine(nextColumn: number) {
    method nextLine (line 143) | private nextLine() {
    method seek (line 177) | seek(nextLine: number, nextColumn: number) {
    method isInInterval (line 185) | isInInterval(): boolean {
    method getTransformedLine (line 189) | getTransformedLine(): number {
    method getTransformedColumn (line 192) | getTransformedColumn(): number {
    method nextLineBreak (line 196) | private nextLineBreak(): number {
    method getInterval (line 199) | private getInterval(intervalIndex: number): [number, number] {
  function max (line 204) | function max(a: number, b: number) {
  function min (line 208) | function min(a: number, b: number) {

FILE: packages/tscc/src/shared/vinyl_utils.ts
  constant SOURCE_MAP (line 10) | const SOURCE_MAP = 'sourceMap'
  type IClosureCompilerInputJson (line 16) | interface IClosureCompilerInputJson {
  type IClosureCompilerOutputJson (line 28) | interface IClosureCompilerOutputJson {
  type ArrayStreamItem (line 37) | interface ArrayStreamItem<T> {
  method constructor (line 44) | constructor(
  method _transform (line 47) | async _transform(data: any, encoding: BufferEncoding, callback: stream.T...
  class ClosureJsonToVinyl (line 62) | class ClosureJsonToVinyl extends LoggingTransformStream {
    method constructor (line 63) | constructor(
    method _rawTransform (line 67) | _rawTransform(data: ArrayStreamItem<IClosureCompilerOutputJson>, encod...
  class RemoveTempGlobalAssignments (line 82) | class RemoveTempGlobalAssignments extends LoggingTransformStream {
    method _rawTransform (line 83) | async _rawTransform(data: Vinyl, encoding: BufferEncoding) {

FILE: packages/tscc/src/spawn_compiler.ts
  function spawnCompiler (line 5) | function spawnCompiler(providedArgs: string[], logger: Logger, debug?: b...
  function getSupportedCompiler (line 24) | function getSupportedCompiler(): {bin: string, args: string[]} {
  type PlatformToCompilerPackageName (line 36) | enum PlatformToCompilerPackageName {

FILE: packages/tscc/src/spec/ITsccSpecWithTS.ts
  type ITsccSpecWithTS (line 4) | interface ITsccSpecWithTS extends ITsccSpec {

FILE: packages/tscc/src/spec/TsccSpecWithTS.ts
  class TsError (line 7) | class TsError extends Error {
    method constructor (line 8) | constructor(
  type TWarningCallback (line 15) | type TWarningCallback = (msg: string) => void;
  class TsccSpecWithTS (line 17) | class TsccSpecWithTS extends TsccSpec implements ITsccSpecWithTS {
    method loadTsConfigFromArgs (line 18) | static loadTsConfigFromArgs(tsArgs: string[], specRoot: string, onWarn...
    method loadTsConfigFromPath (line 37) | static loadTsConfigFromPath(tsConfigPath?: string, specRoot?: string, ...
    method findConfigFileAndThrow (line 51) | private static findConfigFileAndThrow(searchPath?: string, defaultLoca...
    method loadTsConfigFromResolvedPath (line 61) | private static loadTsConfigFromResolvedPath(configFileName: string, op...
    method loadSpecWithTS (line 71) | static loadSpecWithTS(
    method pruneCompilerOptions (line 94) | static pruneCompilerOptions(options: ts.CompilerOptions, onWarning: TW...
    method constructor (line 163) | private constructor(
    method validateSpecWithTS (line 172) | private validateSpecWithTS() {
    method getTSRoot (line 185) | getTSRoot() {
    method getCompilerOptions (line 188) | getCompilerOptions() {
    method getCompilerHost (line 191) | getCompilerHost() {
    method getOutputFileNames (line 210) | getOutputFileNames(): string[] {
    method getDefaultFlags (line 217) | private getDefaultFlags(): closureCompilerFlags {
    method getBaseCompilerFlags (line 260) | getBaseCompilerFlags() {
    method getAbsoluteFileNamesSet (line 284) | getAbsoluteFileNamesSet() {
    method resolveExternalModuleTypeReference (line 290) | resolveExternalModuleTypeReference(moduleName: string) {
    method getProjectHash (line 304) | getProjectHash(): string {
  function noop (line 314) | function noop() {}

FILE: packages/tscc/src/transformer/decorator_property_transformer.ts
  function decoratorPropertyTransformer (line 28) | function decoratorPropertyTransformer(tsickleHost: TsickleHost):
  class DecoratorTransformer (line 37) | class DecoratorTransformer extends TsHelperTransformer {
    method getId (line 41) | private getId() {
    method onHelperCall (line 46) | protected onHelperCall(node: ts.CallExpression, googReflectImport: ts....
    method combineStatements (line 98) | protected combineStatements(stmts: ts.Statement[], googReflectImport: ...

FILE: packages/tscc/src/transformer/dts_requiretype_transformer.ts
  function dtsRequireTypeTransformer (line 36) | function dtsRequireTypeTransformer(spec: ITsccSpecWithTS, tsickleHost: T...
  function setOriginalNode (line 76) | function setOriginalNode<T extends ts.Node>(range: T, node: ts.Statement...

FILE: packages/tscc/src/transformer/rest_property_transformer.ts
  function decoratorPropertyTransformer (line 5) | function decoratorPropertyTransformer(tsickleHost: TsickleHost):
  class RestHelperTransformer (line 14) | class RestHelperTransformer extends TsHelperTransformer {
    method onHelperCall (line 20) | protected onHelperCall(node: ts.CallExpression, googReflectImport: ts....

FILE: packages/tscc/src/transformer/transformer_utils.ts
  function extractRequire (line 7) | function extractRequire(call: ts.CallExpression): string | null {
  type TGoogRequireLike (line 16) | type TGoogRequireLike = "require" | "requireType";
  function extractGoogRequireLike (line 22) | function extractGoogRequireLike(call: ts.CallExpression, requireLike: TG...
  function getRequiredModuleName (line 31) | function getRequiredModuleName(call: ts.CallExpression): string | null {
  type IImportedVariable (line 40) | interface IImportedVariable {
  function isVariableRequireStatement (line 45) | function isVariableRequireStatement(stmt: ts.Statement): IImportedVariab...
  function isGoogRequireLikeStatement (line 61) | function isGoogRequireLikeStatement(stmt: ts.Statement, requireLike: TGo...
  function findImportedVariable (line 77) | function findImportedVariable(sf: ts.SourceFile, moduleName: string): ts...
  function findGoogRequiredVariable (line 86) | function findGoogRequiredVariable(sf: ts.SourceFile, moduleName: string)...
  function identifierIsEmitHelper (line 102) | function identifierIsEmitHelper(ident: ts.Identifier): boolean {
  class NodeFactoryHelper (line 115) | class NodeFactoryHelper {
    method constructor (line 116) | constructor(
    method createGoogCall (line 120) | createGoogCall(methodName: string, literal: ts.StringLiteral): ts.Call...
    method createVariableAssignment (line 131) | createVariableAssignment(newIdent: ts.Identifier, initializer: ts.Expr...
    method createSingleQuoteStringLiteral (line 147) | createSingleQuoteStringLiteral(text: string): ts.StringLiteral {
    method namespaceToQualifiedName (line 152) | namespaceToQualifiedName(namespace: string): ts.Expression {
  function topLevelStatementTransformerFactory (line 169) | function topLevelStatementTransformerFactory(

FILE: packages/tscc/src/transformer/ts_helper_transformer.ts
  method constructor (line 10) | constructor(
  method isTsGeneratedHelperCall (line 24) | protected isTsGeneratedHelperCall(node: ts.Node): node is ts.CallExpress...
  method maybeTsGeneratedHelperCall (line 40) | private maybeTsGeneratedHelperCall(node: ts.Node, googReflectImport: ts....
  method transformSourceFile (line 45) | transformSourceFile(): ts.SourceFile {
  method combineStatements (line 78) | protected combineStatements(stmts: ts.Statement[], googReflectImport?: t...
  method createGoogReflectRequire (line 85) | private createGoogReflectRequire(ident: ts.Identifier) {

FILE: packages/tscc/src/tscc.ts
  constant TEMP_DIR (line 33) | const TEMP_DIR = ".tscc_temp";
  function tscc (line 58) | async function tscc(
  class CcError (line 228) | class CcError extends Error {}
  class TsccError (line 229) | class TsccError extends Error {}
  class UnexpectedFileError (line 230) | class UnexpectedFileError extends TsccError {}
  function removeSourceMappingUrl (line 239) | function removeSourceMappingUrl(tsOutput: string): string {
  function getWriteFileImpl (line 244) | function getWriteFileImpl(spec: ITsccSpecWithTS, tsickleVinylOutput: Par...
  function pushToStream (line 312) | function pushToStream(stream: stream.Readable, ...args: (string | null)[...
  function pushTsickleOutputToStream (line 316) | function pushTsickleOutputToStream(
  function getTsickleHost (line 348) | function getTsickleHost(tsccSpec: ITsccSpecWithTS, tsDependencyGraph: Ty...

FILE: packages/tscc/src/tsickle_patches/facade.ts
  function applyPatches (line 9) | function applyPatches() {
  function restorePatches (line 14) | function restorePatches() {

FILE: packages/tscc/src/tsickle_patches/patch_tsickle_decorator_transformer.ts
  function patchTsickleDecoratorTransformer (line 15) | function patchTsickleDecoratorTransformer() {
  function restoreTsickleDecoratorTransformer (line 25) | function restoreTsickleDecoratorTransformer() {

FILE: packages/tscc/src/tsickle_patches/patch_tsickle_module_resolver.ts
  function getPackageBoundary (line 16) | function getPackageBoundary(fileName: string): string {
  function resolveModuleName (line 31) | function resolveModuleName(
  function patchTsickleResolveModule (line 60) | function patchTsickleResolveModule() {
  function restoreTsickleResolveModule (line 68) | function restoreTsickleResolveModule() {

FILE: packages/tscc/test/e2e/sample/case_1/a.ts
  class ClassUsedByAandB (line 3) | class ClassUsedByAandB implements IAmUsedByAandB {
    method methodUsedByA (line 4) | methodUsedByA() {
    method methodUsedByB (line 7) | methodUsedByB() {
  function callA (line 13) | function callA(a: IAmUsedByAandB) {
  function ac (line 19) | function ac() {

FILE: packages/tscc/test/e2e/sample/case_1/ab.ts
  type IAmUsedByAandB (line 1) | interface IAmUsedByAandB {

FILE: packages/tscc/test/e2e/sample/case_1/bc.ts
  function bc (line 1) | function bc() {

FILE: packages/tscc/test/e2e/sample/case_1/cc.ts
  function cc (line 1) | function cc() {

FILE: packages/tscc/test/e2e/sample/case_10_unsafe_module_name_and_script_dts/script_dts.d.ts
  type interfaceName (line 2) | interface interfaceName {

FILE: packages/tscc/test/e2e/sample/case_11_referencing_goog/entry.ts
  function isDebugging (line 4) | function isDebugging() {

FILE: packages/tscc/test/e2e/sample/case_2_sourcemaps/a.ts
  function a (line 1) | function a(b) {

FILE: packages/tscc/test/e2e/sample/case_3_sourcemaps_with_decorators/a.ts
  function decorator (line 1) | function decorator(target, prop:PropertyKey, desc:PropertyDescriptor) {
  class A (line 5) | class A {
    method b (line 7) | b() {console.log('a')}

FILE: packages/tscc/test/e2e/sample/case_5_object_spread/a.ts
  function myDecorator (line 1) | function myDecorator(target, prop, desc) {
  class A (line 7) | class A {
    method myMethod (line 9) | public myMethod(a, {b, ...c}) {

FILE: packages/tscc/test/e2e/sample/case_6_type_only_references/a.ts
  type a (line 1) | interface a {
  class b (line 5) | class b implements a {
    method b (line 6) | b() {

FILE: packages/tscc/test/e2e/sample/case_6_type_only_references/b.ts
  type b (line 3) | type b = (x:a)=>void;

FILE: packages/tscc/test/e2e/sample/case_6_type_only_references/c.ts
  method b (line 4) | b() {}

FILE: packages/tscc/test/e2e/sample/case_8_dts_requiretype/transtively_imported.d.ts
  type a (line 3) | type a = ()=>number;

FILE: packages/tscc/test/graph/TypescriptDependencyGraph.ts
  function createProgramFromConfigFile (line 34) | function createProgramFromConfigFile(configFilePath: string): ts.Program {

FILE: packages/tscc/test/graph/source_node_factory.ts
  function sample (line 40) | function sample(name: string) {
  function readSample (line 44) | function readSample(name: string) {

FILE: packages/tscc/test/sample/decorator/decorates.ts
  class A (line 6) | @adornClass
    method aMethod (line 9) | aMethod() {
    method anAccessor (line 17) | get anAccessor() {
    method anAccessor (line 20) | set anAccessor(v: number) {
    method aMethodWithParams (line 23) | aMethodWithParams(@adornParameter param) {

FILE: packages/tscc/test/sample/dts_requiretype/required.d.ts
  type I (line 1) | interface I {

FILE: packages/tscc/test/sample/rest/case_1.ts
  function A (line 12) | function A(a, {b, c, ...d}) {

FILE: packages/tscc/test/sample/rest/combined_with_decorators.ts
  function myDecorator (line 1) | function myDecorator(target, prop, desc) {
  class A (line 7) | class A {
    method myMethod (line 9) | public myMethod() {}

FILE: packages/tscc/test/shared/sourcemap_splice.ts
  class TestSupport (line 126) | class TestSupport {
    method constructor (line 127) | constructor(
    method pos (line 130) | pos(line: number, column: number) {
  function splitTestString (line 140) | function splitTestString(string: string, regex: RegExp = /(?:#[#\s]+|%[%...

FILE: packages/tscc/test/spec/TsccSpecWithTS.ts
  function noop (line 106) | function noop() {}

FILE: packages/tscc/test/transformer/transformers.ts
  method getTSRoot (line 94) | getTSRoot() {
  method getExternalModuleNames (line 97) | getExternalModuleNames() {
  method pathToModuleName (line 104) | pathToModuleName(context, fileName) {
  type EmitTransformerFactory (line 126) | type EmitTransformerFactory = (host: tsickle.TsickleHost) => tsickle.Emi...
  function emit (line 128) | function emit(

FILE: packages/tscc/third_party/closure_library/base.js
  function tempCtor (line 2168) | function tempCtor() {}
  function addNewerLanguageTranspilationCheck (line 2637) | function addNewerLanguageTranspilationCheck(modeName, isSupported) {
  function evalCheck (line 2653) | function /** boolean */ evalCheck(/** string */ code) {
  function resolve (line 2811) | function resolve() {
  function write (line 3562) | function write(src, contents) {
  function append (line 3580) | function append(src, contents) {
  function fetch (line 3700) | function fetch() {
  function load (line 3730) | function load() {
  function fetchInOwnScriptThenLoad (line 3779) | function fetchInOwnScriptThenLoad() {

FILE: packages/tscc/third_party/tsickle/closure_externs.js
  function PromiseLike (line 66) | function PromiseLike() {}
  function CanvasDrawImage (line 88) | function CanvasDrawImage() {}
  function CryptoKey (line 91) | function CryptoKey() {}
  function CryptoKeyPair (line 93) | function CryptoKeyPair() {}
  function ImportMeta (line 105) | function ImportMeta() {}
  function HTMLElementEventMap (line 116) | function HTMLElementEventMap() {}
  function ElementEventMap (line 118) | function ElementEventMap() {}
  function DocumentEventMap (line 120) | function DocumentEventMap() {}
  function WindowEventMap (line 122) | function WindowEventMap() {}
  function GlobalEventHandlersEventMap (line 124) | function GlobalEventHandlersEventMap() {}
  function DocumentAndElementEventHandlersEventMap (line 126) | function DocumentAndElementEventHandlersEventMap() {}
  function EventSourceEventMap (line 128) | function EventSourceEventMap() {}

FILE: packages/tscc/third_party/tsickle/third_party/tslib/tslib.js
  function __ (line 22) | function __() {
  function fulfilled (line 100) | function fulfilled(value) { try { step((/** @type {?} */ (generator)).ne...
  function rejected (line 101) | function rejected(value) { try { step(generator["throw"](value)); } catc...
  function step (line 102) | function step(result) { result.done ? resolve(result.value) : new P(func...
  function verb (line 129) | function verb(n) {
  function step (line 134) | function step(op) {
  function verb (line 289) | function verb(n) {
  function resume (line 297) | function resume(n, v) {
  function step (line 304) | function step(r) {
  function fulfill (line 309) | function fulfill(value) {
  function reject (line 312) | function reject(value) {
  function settle (line 315) | function settle(f, v) {
  function verb (line 335) | function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? ...
Condensed preview — 185 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (515K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 1094,
    "preview": "cache_key: &cache_key tscc-{{ checksum \"yarn.lock\" }}\nsave_cache: &save_cache\n  save_cache:\n    key: *cache_key\n    path"
  },
  {
    "path": ".editorconfig",
    "chars": 244,
    "preview": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n[*.{js,jsx,ts,tsx,css,html,json}]\ncharset = utf-8\nindent_"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 251,
    "preview": "version: 2\nupdates:\n- package-ecosystem: npm\n  directory: \"/\"\n  schedule:\n    interval: weekly\n  open-pull-requests-limi"
  },
  {
    "path": ".gitignore",
    "chars": 113,
    "preview": "/node_modules\n/packages/*/node_modules\ndist\nlerna-debug.log\njunit.xml\n.tscc_temp\nyarn-error.log\n.vscode/**/*.log\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 422,
    "preview": "{\n\t\"editor.rulers\": [\n\t\t100\n\t],\n\t\"editor.formatOnSave\": true,\n\t\"javascript.format.insertSpaceAfterOpeningAndBeforeClosin"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2019 Sean Lee\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "README.md",
    "chars": 24529,
    "preview": "# TSCC\n\n[![tscc npm version](https://img.shields.io/npm/v/@tscc/tscc.svg?style=popout&color=blue&label=%40tscc%2Ftscc)]("
  },
  {
    "path": "jest.config.js",
    "chars": 420,
    "preview": "const {compilerOptions} = require('./tsconfig.json');\ncompilerOptions.strict = false;\n\nmodule.exports = {\n\tpreset: 'ts-j"
  },
  {
    "path": "lerna.json",
    "chars": 103,
    "preview": "{\n  \"packages\": [\"packages/*\"],\n  \"version\": \"0.9.4\",\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": true\n}\n"
  },
  {
    "path": "package.json",
    "chars": 605,
    "preview": "{\n\t\"name\": \"tscc\",\n\t\"version\": \"1.0.0\",\n\t\"private\": true,\n\t\"workspaces\": [\n\t\t\"packages/*\"\n\t],\n\t\"license\": \"MIT\",\n\t\"scrip"
  },
  {
    "path": "packages/rollup-plugin-tscc/.npmignore",
    "chars": 72,
    "preview": "index.ts\n/src\ntest\nnode_modules\ntsconfig.json\nyarn.lock\nyarn-error.log\n\n"
  },
  {
    "path": "packages/rollup-plugin-tscc/README.md",
    "chars": 2919,
    "preview": "# rollup-plugin-tscc\n\nThis is a companion plugin for tscc which lets you perform an isomorphic build with rollup.\nThe co"
  },
  {
    "path": "packages/rollup-plugin-tscc/package.json",
    "chars": 833,
    "preview": "{\n  \"name\": \"@tscc/rollup-plugin-tscc\",\n  \"author\": \"theseanl\",\n  \"description\": \"A rollup plugin to use tscc module spe"
  },
  {
    "path": "packages/rollup-plugin-tscc/src/MultiMap.ts",
    "chars": 1738,
    "preview": "export default class MultiMap<K, V> {\n\tprivate map: Map<K, Set<V>> = new Map();\n\tadd(key: K, value?: V) {\n\t\tlet ar: Set<"
  },
  {
    "path": "packages/rollup-plugin-tscc/src/goog_shim_mixin.ts",
    "chars": 1285,
    "preview": "/**\n * @fileoverview Provides a mixin for Rollup plugins that loads shim files for default libraries.\n * These are goog."
  },
  {
    "path": "packages/rollup-plugin-tscc/src/index.ts",
    "chars": 6684,
    "preview": "import {IInputTsccSpecJSON} from '@tscc/tscc-spec';\nimport * as rollup from 'rollup';\nimport {googShimMixin} from './goo"
  },
  {
    "path": "packages/rollup-plugin-tscc/src/merge_chunks.ts",
    "chars": 10013,
    "preview": "import * as rollup from 'rollup';\nimport {googShimMixin} from './goog_shim_mixin';\nimport MultiMap from './MultiMap';\nim"
  },
  {
    "path": "packages/rollup-plugin-tscc/src/sort_chunks.ts",
    "chars": 2428,
    "preview": "/**\n * @fileoverview Rollup generates at most one chunk per each combination of entry points. In our case\n * of emulatin"
  },
  {
    "path": "packages/rollup-plugin-tscc/src/spec/ITsccSpecRollupFacade.ts",
    "chars": 1029,
    "preview": "import {ITsccSpec} from '@tscc/tscc-spec'\nimport MultiMap from '../MultiMap';\nimport {ModuleFormat} from 'rollup';\n\nexpo"
  },
  {
    "path": "packages/rollup-plugin-tscc/src/spec/TsccSpecRollupFacade.ts",
    "chars": 2297,
    "preview": "import {TsccSpec, TsccSpecError} from '@tscc/tscc-spec';\nimport ITsccSpecRollupFacade from './ITsccSpecRollupFacade'\nimp"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/__snapshots__/golden_test.ts.snap",
    "chars": 4911,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Golden Tests: external-modules/tscc.spec.json: packages/rollup-plug"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/golden_test.ts",
    "chars": 1594,
    "preview": "///<reference types=\"jest\"/>\nimport tsccPlugin from '../src/index';\nimport * as rollup from 'rollup';\nimport fg = requir"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/merge_chunks.ts",
    "chars": 14485,
    "preview": "///<reference types=\"jest\"/>\nimport {ChunkMerger} from \"../src/merge_chunks\";\nimport MultiMap from \"../src/MultiMap\";\nim"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/external-modules/entry.js",
    "chars": 222,
    "preview": "import * as externalInNodeModules from 'external';\nimport * as externalWithFilePaths from './external_with_file_paths';\n"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/external-modules/tscc.spec.json",
    "chars": 223,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.js\"\n\t},\n\t\"external\": {\n\t\t\"external\": \"externalInNodeModules\",\n\t\t\"./external_with_fil"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/common/index.js",
    "chars": 149,
    "preview": "import * as c from './external/from/common';\nlet counter = 0;\nexport function common(n) {\n\tconsole.log(\"common\");\n\tcount"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/dependent.js",
    "chars": 149,
    "preview": "import {common} from './common/index';\nimport {entry} from './entry';\nimport * as b from './external-dependent';\ncommon("
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/entry.js",
    "chars": 168,
    "preview": "import {common} from './common/index';\nimport * as a from './external-entry';\n\nexport function entry() {\n\tcommon(0);\n\tco"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/external-modules-in-many-module-build/tscc.spec.json",
    "chars": 315,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.js\",\n\t\t\"dependent\": {\n\t\t\t\"entry\": \"./dependent.js\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"entry\""
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/goog-shim/dependent.js",
    "chars": 450,
    "preview": "import * as entry from './entry';\n\nimport * as goog from 'goog:goog';\n\n// This module is only used in \"dependent\" module"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/goog-shim/entry.js",
    "chars": 141,
    "preview": "import * as goog from 'goog:goog';\n\nexport function isDebugging() {\n\treturn goog.DEBUG;\n}\n\nif (isDebugging()) {\n\tconsole"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/goog-shim/tscc.spec.json",
    "chars": 199,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.js\",\n\t\t\"dependent\": {\n\t\t\t\"entry\": \"./dependent.js\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"entry\""
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/goog-shim/tscc.spec.module.json",
    "chars": 225,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.js\",\n\t\t\"dependent\": {\n\t\t\t\"entry\": \"./dependent.js\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"entry\""
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/many-module-build/common.js",
    "chars": 123,
    "preview": "export function swap([a, b]) {\n\treturn [b, a];\n}\n\nexport function sort([a, b]) {\n\treturn a > b ? [a, b] : swap([a, b]);\n"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/many-module-build/dir/dependency.js",
    "chars": 99,
    "preview": "import * as utils from '../common';\nimport {b} from '../entry';\n\nconsole.log(utils.sort([1, b]));\n\n"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/many-module-build/entry.js",
    "chars": 102,
    "preview": "import {swap} from './common';\n\nconst a = [1, 2];\nconst b = swap(a);\n\nconsole.log(b);\n\nexport { b };\n\n"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/many-module-build/tscc.spec.json",
    "chars": 204,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.js\",\n\t\t\"dependent\": {\n\t\t\t\"entry\": \"./dir/dependency.js\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"e"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sample/many-module-build/tscc.spec.module.json",
    "chars": 230,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.js\",\n\t\t\"dependent\": {\n\t\t\t\"entry\": \"./dir/dependency.js\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"e"
  },
  {
    "path": "packages/rollup-plugin-tscc/test/sort_chunks.ts",
    "chars": 3665,
    "preview": "///<reference types=\"jest\"/>\nimport computeChunkAllocation from '../src/sort_chunks';\nimport MultiMap from '../src/Multi"
  },
  {
    "path": "packages/rollup-plugin-tscc/third_party/closure_library/README.md",
    "chars": 294,
    "preview": "Original source: https://github.com/google/closure-library\nLicense: Apache 2.0\nDescription:\nWhen `rollup-plugin-tscc` bu"
  },
  {
    "path": "packages/rollup-plugin-tscc/third_party/closure_library/goog_shim.js",
    "chars": 2215,
    "preview": "/**\n * @fileoverview Hand-modified shim file for Closure Library `goog/goog.js`. References to the\n * global `goog` vari"
  },
  {
    "path": "packages/rollup-plugin-tscc/third_party/closure_library/reflect_shim.js",
    "chars": 762,
    "preview": "/**\n * @fileoverview Hand-modified shim file for Closure Library `goog/reflect.js`. References to the\n * global `goog` v"
  },
  {
    "path": "packages/rollup-plugin-tscc/tsconfig.json",
    "chars": 137,
    "preview": "{\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist\",\n\t\t\"rootDir\": \"src\"\n\t},\n\t\"include\": [\n\t\t\"s"
  },
  {
    "path": "packages/tscc/.npmignore",
    "chars": 81,
    "preview": "index.ts\n/src\ntest\nnode_modules\ntsconfig.json\nyarn.lock\nyarn-error.log\nMakefile\n\n"
  },
  {
    "path": "packages/tscc/Makefile",
    "chars": 1003,
    "preview": ".PHONY: fetch_tslib clean fetch_closure_lib fetch_tsickle_externs\n\nall: $(shell find dist) fetch_tslib\n\ndist/%.js: src/%"
  },
  {
    "path": "packages/tscc/README.md",
    "chars": 88,
    "preview": "# TSCC\n\nWe refer to the [README of the main package](https://github.com/theseanl/tscc).\n"
  },
  {
    "path": "packages/tscc/package.json",
    "chars": 1694,
    "preview": "{\n  \"name\": \"@tscc/tscc\",\n  \"author\": \"theseanl\",\n  \"description\": \"A typescript transpiler and bundler that wires up ts"
  },
  {
    "path": "packages/tscc/src/default_libs.ts",
    "chars": 1831,
    "preview": "/**\n * @fileoverview Files described here are provided to closure compiler by default.\n */\nimport fs = require('fs');\nim"
  },
  {
    "path": "packages/tscc/src/external_module_support.ts",
    "chars": 2063,
    "preview": "/**\n * @fileoverview Transforms `import localName from \"external_module\"` to\n * `const localName = global_name_for_the_e"
  },
  {
    "path": "packages/tscc/src/graph/Cache.ts",
    "chars": 1667,
    "preview": "import fs = require('fs');\n\nconst fsp = fs.promises;\n\nexport class Cache<T> {\n\tprivate cache: {\n\t\t[key: string]: {\n\t\t\tco"
  },
  {
    "path": "packages/tscc/src/graph/ClosureDependencyGraph.ts",
    "chars": 5390,
    "preview": "import {FSCacheAccessor} from './Cache';\nimport {ISourceNode} from './ISourceNode';\nimport {sourceNodeFactoryFromContent"
  },
  {
    "path": "packages/tscc/src/graph/ISourceNode.ts",
    "chars": 194,
    "preview": "export interface ISourceNode {\n\treadonly fileName: string\n\treadonly provides: ReadonlyArray<string>\n\treadonly required: "
  },
  {
    "path": "packages/tscc/src/graph/TypescriptDependencyGraph.ts",
    "chars": 6957,
    "preview": "/**\n * @fileoverview Starting from a provided set of files, it walks Typescript SourceFiles that are\n * referenced from "
  },
  {
    "path": "packages/tscc/src/graph/source_node_factory.ts",
    "chars": 4258,
    "preview": "import {ISourceNode} from './ISourceNode';\nimport fs = require('fs');\nimport readline = require('readline');\n\n/**\n * Use"
  },
  {
    "path": "packages/tscc/src/log/Logger.ts",
    "chars": 1562,
    "preview": "/**\n * @fileoverview Creates a logger instance, which provides the following functionalities:\n *  - Adding prefix\n *  - "
  },
  {
    "path": "packages/tscc/src/log/spinner.ts",
    "chars": 1980,
    "preview": "import ora = require('ora');\n\nlet spinner: ora.Ora | undefined;\nlet timer: NodeJS.Timer | undefined;\n\n/**\n * Attach a sp"
  },
  {
    "path": "packages/tscc/src/main.ts",
    "chars": 6264,
    "preview": "#!/usr/bin/env node\n\nimport yargs = require('yargs/yargs');\nimport chalk = require('chalk');\nimport tscc, {TEMP_DIR, CcE"
  },
  {
    "path": "packages/tscc/src/shared/PartialMap.ts",
    "chars": 268,
    "preview": "export default class PartialMap<K, V extends {}> extends Map<K, Partial<V>> {\n\tset(key: K, value: Partial<V>) {\n\t\tif (!t"
  },
  {
    "path": "packages/tscc/src/shared/array_utils.ts",
    "chars": 555,
    "preview": "export function riffle<T>(x: T, array: T[]): T[] {\n\tlet out: T[] = [];\n\tfor (let i = 0, l = array.length; i < l; i++) {\n"
  },
  {
    "path": "packages/tscc/src/shared/escape_goog_identifier.ts",
    "chars": 4066,
    "preview": "/**\n * @fileoverview A valid goog.module name is a dot-separated sequence of legal property. Legal\n * property is a name"
  },
  {
    "path": "packages/tscc/src/shared/sourcemap_splice.ts",
    "chars": 6961,
    "preview": "import {SourceMapConsumer, SourceMapGenerator, Mapping, RawSourceMap} from 'source-map';\n\n/**\n * From a file with source"
  },
  {
    "path": "packages/tscc/src/shared/vinyl_utils.ts",
    "chars": 3357,
    "preview": "import stream = require('stream')\nimport Vinyl = require('vinyl');\nimport Logger from '../log/Logger';\nimport chalk = re"
  },
  {
    "path": "packages/tscc/src/spawn_compiler.ts",
    "chars": 1388,
    "preview": "import Logger from './log/Logger';\nimport chalk = require('chalk');\nimport childProcess = require('child_process');\n\nexp"
  },
  {
    "path": "packages/tscc/src/spec/ITsccSpecWithTS.ts",
    "chars": 1094,
    "preview": "import {ITsccSpec} from '@tscc/tscc-spec';\nimport * as ts from 'typescript'\n\nexport default interface ITsccSpecWithTS ex"
  },
  {
    "path": "packages/tscc/src/spec/TsccSpecWithTS.ts",
    "chars": 13212,
    "preview": "import {IInputTsccSpecJSON, ITsccSpecJSON, closureCompilerFlags, TsccSpec, TsccSpecError} from '@tscc/tscc-spec';\nimport"
  },
  {
    "path": "packages/tscc/src/transformer/decorator_property_transformer.ts",
    "chars": 4601,
    "preview": "/**\n * @fileoverview Decorators in TS is not compatible with Closure Compiler, as it generates\n * code that access a cla"
  },
  {
    "path": "packages/tscc/src/transformer/dts_requiretype_transformer.ts",
    "chars": 3848,
    "preview": "/**\n * @fileoverview Transforms `const tsickle_aaaa = goog.requireType(.....)` calls to external modules\n * into const t"
  },
  {
    "path": "packages/tscc/src/transformer/goog_namespace_transformer.ts",
    "chars": 812,
    "preview": "import {isVariableRequireStatement, isGoogRequireLikeStatement, topLevelStatementTransformerFactory} from './transformer"
  },
  {
    "path": "packages/tscc/src/transformer/rest_property_transformer.ts",
    "chars": 2032,
    "preview": "import * as ts from 'typescript';\nimport {TsickleHost} from 'tsickle';\nimport TsHelperTransformer from './ts_helper_tran"
  },
  {
    "path": "packages/tscc/src/transformer/transformer_utils.ts",
    "chars": 6521,
    "preview": "import * as ts from 'typescript';\n\n/**\n * Returns the string argument if call is of the form\n * require('foo')\n */\nfunct"
  },
  {
    "path": "packages/tscc/src/transformer/ts_helper_transformer.ts",
    "chars": 3562,
    "preview": "/**\n * @fileoverview Contains a common logic that is used to typescript transformers that transforms\n * ts helper (those"
  },
  {
    "path": "packages/tscc/src/tscc.ts",
    "chars": 17967,
    "preview": "import {IInputTsccSpecJSON} from '@tscc/tscc-spec';\nimport * as StreamArray from 'stream-json/streamers/StreamArray';\nim"
  },
  {
    "path": "packages/tscc/src/tsickle_patches/facade.ts",
    "chars": 645,
    "preview": "/**\n * @fileoverview This contains functions to apply various patches to tsickle. For more details, see\n * each modules."
  },
  {
    "path": "packages/tscc/src/tsickle_patches/patch_tsickle_decorator_transformer.ts",
    "chars": 1496,
    "preview": "/**\n * @fileoverview This patches tsickle's decorator transformer exported from `decorator.ts` module\n * into a no-op tr"
  },
  {
    "path": "packages/tscc/src/tsickle_patches/patch_tsickle_module_resolver.ts",
    "chars": 2631,
    "preview": "/**\n * @fileoverview This patches tsickle's `resolveModuleName` function exported from `googmodule.ts`\n * in order to wo"
  },
  {
    "path": "packages/tscc/test/e2e/__snapshots__/golden_test.ts.snap",
    "chars": 8718,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`tscc e2e case_1: case_1 1`] = `\nArray [\n  \"a.js\",\n  \"b.js\",\n  \"c.js"
  },
  {
    "path": "packages/tscc/test/e2e/golden_test.ts",
    "chars": 1535,
    "preview": "///<reference types=\"jest\"/>\nimport tscc, {TEMP_DIR} from '../../src/tscc';\nimport path = require('path');\nimport upath "
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/a.ts",
    "chars": 379,
    "preview": "import {IAmUsedByAandB} from './ab'\n\nclass ClassUsedByAandB implements IAmUsedByAandB {\n\tmethodUsedByA() {\n\t\tconsole.log"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/ab.ts",
    "chars": 82,
    "preview": "export interface IAmUsedByAandB {\n\tmethodUsedByA(): void\n\tmethodUsedByB(): void\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/b.ts",
    "chars": 118,
    "preview": "import {a, callA} from './a';\nimport {bb} from './bb';\nimport {bc} from './bc';\n\na.methodUsedByB();\ncallA(bb);\nbc();\n\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/bb.ts",
    "chars": 186,
    "preview": "import {IAmUsedByAandB} from './ab'\nexport const bb: IAmUsedByAandB = {\n\tmethodUsedByA: function () {\n\t\tconsole.log('bba"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/bc.ts",
    "chars": 46,
    "preview": "export function bc() {\n\tconsole.log('bc');\n}\n\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/c.ts",
    "chars": 95,
    "preview": "import {ac} from './a'\nimport {bc} from './bc';\nimport { cc } from './cc';\n\nac();\nbc();\ncc();\n\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/cc.ts",
    "chars": 46,
    "preview": "export function cc() {\n\tconsole.log('cc');\n}\n\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/tscc.spec.json",
    "chars": 210,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"./a.ts\",\n\t\t\"b\": {\n\t\t\t\"entry\": \"./b.ts\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"a\"\n\t\t\t]\n\t\t},\n\t\t\"c\": {\n\t\t\t\"entr"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_1/tsconfig.json",
    "chars": 125,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\"\n\t},\n\t\"include\": [\n\t\t\"./*.ts\"\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_10_unsafe_module_name_and_script_dts/index.ts",
    "chars": 137,
    "preview": "import * as unsafe from '@unsafe/module-name';\n\nconsole.log(unsafe.variableNameThatShouldntBeMangled.propertyNameThatSho"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_10_unsafe_module_name_and_script_dts/script_dts.d.ts",
    "chars": 173,
    "preview": "declare module \"@unsafe/module-name\" {\n\tinterface interfaceName {\n\t\tpropertyNameThatShouldntBeMangled: number;\n\t}\n\tconst"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_10_unsafe_module_name_and_script_dts/tscc.spec.json",
    "chars": 176,
    "preview": "{\n\t\"modules\": {\n\t\t\"index\": \"./index.ts\"\n\t},\n\t\"external\": {\n\t\t\"@unsafe/module-name\": \"unsafeModuleName\"\n\t},\n\t\"prefix\": \"."
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_10_unsafe_module_name_and_script_dts/tsconfig.json",
    "chars": 81,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\"\n\t]\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_11_referencing_goog/dependent.ts",
    "chars": 616,
    "preview": "///<reference path=\"../../../../third_party/closure_library/base.d.ts\"/>\n///<reference path=\"../../../../third_party/clo"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_11_referencing_goog/entry.ts",
    "chars": 214,
    "preview": "///<reference path=\"../../../../third_party/closure_library/base.d.ts\"/>\nimport * as goog from 'goog:goog';\n\nexport func"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_11_referencing_goog/tscc.spec.json",
    "chars": 185,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.ts\",\n\t\t\"dependent\": {\n\t\t\t\"entry\": \"./dependent.ts\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"entry\""
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_11_referencing_goog/tsconfig.json",
    "chars": 81,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\"\n\t]\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_12_using_jsFiles/entry.ts",
    "chars": 70,
    "preview": "import {someVariable} from 'goog:manual';\n\nconsole.log(someVariable);\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_12_using_jsFiles/jsfile.d.ts",
    "chars": 67,
    "preview": "declare module 'goog:manual' {\n\texport var someVariable: number;\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_12_using_jsFiles/jsfile.js",
    "chars": 72,
    "preview": "goog.module(\"manual\");\n\n/** @type {number} */\nexports.someVariable = 1;\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_12_using_jsFiles/tscc.spec.json",
    "chars": 122,
    "preview": "{\n\t\"modules\": {\n\t\t\"entry\": \"./entry.ts\"\n\t},\n\t\"prefix\": \".tscc_temp/case_12_using_jsFiles/\",\n\t\"jsFiles\": [\n\t\t\"./*.js\"\n\t]\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_12_using_jsFiles/tsconfig.json",
    "chars": 81,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\"\n\t]\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_13_chunk_format_global/tscc.spec.json",
    "chars": 281,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"../case_1/a.ts\",\n\t\t\"b\": {\n\t\t\t\"entry\": \"../case_1/b.ts\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"a\"\n\t\t\t]\n\t\t},\n\t"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_13_chunk_format_global/tsconfig.json",
    "chars": 133,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\"\n\t},\n\t\"include\": [\n\t\t\"../case_"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_14_chunk_format_module/tscc.spec.json",
    "chars": 281,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"../case_1/a.ts\",\n\t\t\"b\": {\n\t\t\t\"entry\": \"../case_1/b.ts\",\n\t\t\t\"dependencies\": [\n\t\t\t\t\"a\"\n\t\t\t]\n\t\t},\n\t"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_14_chunk_format_module/tsconfig.json",
    "chars": 133,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\"\n\t},\n\t\"include\": [\n\t\t\"../case_"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_2_sourcemaps/a.ts",
    "chars": 67,
    "preview": "function a(b) {\n\tconsole.log(b);\n}\na(\"Hello world!\");\n\nexport {};\n\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_2_sourcemaps/tscc.spec.json",
    "chars": 81,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"./a.ts\"\n\t},\n\t\"prefix\": \".tscc_temp/case_2_sourcemaps/\"\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_2_sourcemaps/tsconfig.json",
    "chars": 98,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"sourceMap\": true\n\t}\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_3_sourcemaps_with_decorators/a.ts",
    "chars": 163,
    "preview": "function decorator(target, prop:PropertyKey, desc:PropertyDescriptor) {\n\treturn desc;\n}\n\nclass A {\n\t@decorator\n\tb() {con"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_3_sourcemaps_with_decorators/tscc.spec.json",
    "chars": 97,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"./a.ts\"\n\t},\n\t\"prefix\": \".tscc_temp/case_3_sourcemaps_with_decorators/\"\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_3_sourcemaps_with_decorators/tsconfig.json",
    "chars": 155,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"experimentalDecorators\": true,\n\t\t\"target\": \""
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_4_external/a.ts",
    "chars": 299,
    "preview": "import * as thing from 'an-external-module'\nimport * as CollidesWithGlobalName from 'another-external-module';\n\nthing.a("
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_4_external/tscc.spec.json",
    "chars": 196,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"./a.ts\"\n\t},\n\t\"external\": {\n\t\t\"an-external-module\": \"anExternalModule\",\n\t\t\"another-external-modul"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_4_external/tsconfig.json",
    "chars": 81,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\"\n\t]\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_5_object_spread/a.ts",
    "chars": 370,
    "preview": "function myDecorator(target, prop, desc) {\n\tlet {value, ...rest} = desc;\n\tconsole.log(rest);\n\tdesc.value = {};\n}\n\nclass "
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_5_object_spread/tscc.spec.json",
    "chars": 84,
    "preview": "{\n\t\"modules\": {\n\t\t\"a\": \"./a.ts\"\n\t},\n\t\"prefix\": \".tscc_temp/case_5_object_spread/\"\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_5_object_spread/tsconfig.json",
    "chars": 133,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"experimentalDecorators\": true,\n\t\t\"target\": \""
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_6_type_only_references/a.ts",
    "chars": 98,
    "preview": "export interface a {\n\tb():void\n}\n\nexport class b implements a {\n\tb() {\n\t\tconsole.log('boo');\n\t}\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_6_type_only_references/b.ts",
    "chars": 75,
    "preview": "import { a } from './a' // type-only import\n\nexport type b = (x:a)=>void;\n\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_6_type_only_references/c.ts",
    "chars": 88,
    "preview": "import * as b from './b' // type-only import\n\n\nwindow['b'] = (x: b.b) => {x({b() {} })}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_6_type_only_references/d.ts",
    "chars": 37,
    "preview": "import {b} from './a';\n\nnew b().b();\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_6_type_only_references/tscc.spec.json",
    "chars": 152,
    "preview": "{\n\t\"modules\": {\n\t\t\"1\": \"./c.ts\",\n\t\t\"2\": {\n\t\t\t\"entry\": \"./d.ts\",\n\t\t\t\"dependencies\": [\"1\"]\n\t\t}\n\t},\n\t\"prefix\": \".tscc_temp/"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_6_type_only_references/tsconfig.json",
    "chars": 52,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\"\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_7_lodash_style_external_module_declaration/a.ts",
    "chars": 940,
    "preview": "/**\n * @fileoverview This test case makes sure that module names appearing in external module type\n * declarations are c"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_7_lodash_style_external_module_declaration/tscc.spec.json",
    "chars": 191,
    "preview": "{\n    \"modules\": {\n        \"a\": \"./a.ts\"\n    },\n    \"external\": {\n        \"lodash_style_module\": \"lodash\"\n    },\n    \"pr"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_7_lodash_style_external_module_declaration/tsconfig.json",
    "chars": 81,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\"\n\t]\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_8_dts_requiretype/imported.d.ts",
    "chars": 65,
    "preview": "import {a} from './transtively_imported';\nexport function b():a;\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_8_dts_requiretype/module.ts",
    "chars": 104,
    "preview": "import * as i from './imported';\nimport * as e from 'external';\nwindow[\"a\"] = i.b();\nwindow[\"b\"] = e.a;\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_8_dts_requiretype/transtively_imported.d.ts",
    "chars": 58,
    "preview": "import {number} from \"yargs\"\n\nexport type a = ()=>number;\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_8_dts_requiretype/tscc.spec.json",
    "chars": 201,
    "preview": "{\n    \"modules\": {\n        \"module\": \"./module.ts\"\n    },\n    \"external\": {\n        \"external\": \"external\",\n        \"./i"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_8_dts_requiretype/tsconfig.json",
    "chars": 81,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\"\n\t]\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_9_ts_in_node_modules/index.ts",
    "chars": 69,
    "preview": "import {a} from './node_modules/non-external/index';\nconsole.log(a);\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_9_ts_in_node_modules/tscc.spec.json",
    "chars": 97,
    "preview": "{\n\t\"modules\": {\n\t\t\"index\": \"./index.ts\"\n\t},\n\t\"prefix\": \".tscc_temp/case_9_ts_in_node_modules/\"\n}\n"
  },
  {
    "path": "packages/tscc/test/e2e/sample/case_9_ts_in_node_modules/tsconfig.json",
    "chars": 123,
    "preview": "{\n\t\"extends\": \"../../../tsconfig.test_files.json\",\n\t\"include\": [\n\t\t\"./*.ts\",\n\t\t\"./node_modules/non-external/index.ts\"\n\t]"
  },
  {
    "path": "packages/tscc/test/graph/ClosureDependencyGraph.ts",
    "chars": 1058,
    "preview": "///<reference types=\"jest\"/>\nimport ClosureDependencyGraph from '../../src/graph/ClosureDependencyGraph'\nimport {ISource"
  },
  {
    "path": "packages/tscc/test/graph/TypescriptDependencyGraph.ts",
    "chars": 1511,
    "preview": "///<reference types=\"jest\"/>\nimport TypescriptDependencyGraph from '../../src/graph/TypescriptDependencyGraph';\nimport *"
  },
  {
    "path": "packages/tscc/test/graph/source_node_factory.ts",
    "chars": 1843,
    "preview": "///<reference types=\"jest\" />\nimport {sourceNodeFactory, sourceNodeFactoryFromContent} from '../../src/graph/source_node"
  },
  {
    "path": "packages/tscc/test/main.ts",
    "chars": 3116,
    "preview": "///<reference types=\"jest\" />\nimport {parseTsccCommandLineArgs, buildTsccSpecJSONAndTsArgsFromArgs} from '../src/main'\n\n"
  },
  {
    "path": "packages/tscc/test/sample/decorator/decorates.ts",
    "chars": 510,
    "preview": "const adornClass: ClassDecorator = (target) => target\nconst adornProperty: PropertyDecorator = (target, prop) => {}\ncons"
  },
  {
    "path": "packages/tscc/test/sample/dts_requiretype/entry.ts",
    "chars": 66,
    "preview": "import * as required from './required';\n\nvar a = required.func();\n"
  },
  {
    "path": "packages/tscc/test/sample/dts_requiretype/required.d.ts",
    "chars": 85,
    "preview": "interface I {\n\tproperty: SVGPathSegCurvetoQuadraticAbs\n}\n\nexport function func(): I;\n"
  },
  {
    "path": "packages/tscc/test/sample/goog_module.js",
    "chars": 190,
    "preview": "goog.module(\"this.is.a.goog.module\");\n\nconst a_type = goog.requireType(\"another.module\");\nconst a = goog.require(\"anothe"
  },
  {
    "path": "packages/tscc/test/sample/rest/case_1.ts",
    "chars": 694,
    "preview": "var o = {\n\ta: {},\n\tb: {},\n\t\"c\": {},\n\t[\"d\"]: {},\n\t[Symbol('foo')]: {},\n\t[Math.random() > .5 ? \"foo\" : \"bar\"]: {}\n};\n\nvar "
  },
  {
    "path": "packages/tscc/test/sample/rest/combined_with_decorators.ts",
    "chars": 279,
    "preview": "function myDecorator(target, prop, desc) {\n\tlet {value, ...rest} = desc;\n\tconsole.log(rest);\n\tdesc.value = {};\n}\n\nclass "
  },
  {
    "path": "packages/tscc/test/sample/tsconfig.json",
    "chars": 123,
    "preview": "{\n\t\"extends\": \"../tsconfig.test_files.json\",\n\t\"compilerOptions\": {\n\t\t\"experimentalDecorators\": true,\n\t\t\"rootDir\": \".\"\n\t}"
  },
  {
    "path": "packages/tscc/test/sample/tsdepsgraph/a.ts",
    "chars": 100,
    "preview": "///<reference path=\"./ab.d.ts\"/>\n///<reference types=\"ac\"/>\nexport * from 'aa';\nexport const a = 1;\n"
  },
  {
    "path": "packages/tscc/test/sample/tsdepsgraph/ab.d.ts",
    "chars": 33,
    "preview": "declare var ab:PromiseLike<any>;\n"
  },
  {
    "path": "packages/tscc/test/sample/tsdepsgraph/b.d.ts",
    "chars": 112,
    "preview": "///<reference path=\"./bb.d.ts\"/>\n///<reference types=\"bc\"/>\ndeclare const b:WeakSet<WindowOrWorkerGlobalScope>;\n"
  },
  {
    "path": "packages/tscc/test/sample/tsdepsgraph/bb.d.ts",
    "chars": 44,
    "preview": "declare namespace bb {\n\tconst $: Atomics;\n}\n"
  },
  {
    "path": "packages/tscc/test/sample/tsdepsgraph/entry.ts",
    "chars": 125,
    "preview": "/// <reference path=\"./b.d.ts\" />\n/// <reference types=\"c\"/>\nimport * as a from './a';\n\na.a;\na.aa;\nab;\nac;\n\nb;\nbb.$;\nbc;"
  },
  {
    "path": "packages/tscc/test/sample/tsdepsgraph/tsconfig.json",
    "chars": 145,
    "preview": "{\n    \"compilerOptions\": {\n        \"moduleResolution\": \"node\",\n        \"importHelpers\": true\n    },\n    \"includes\": [\n  "
  },
  {
    "path": "packages/tscc/test/shared/escape_goog_identifier.ts",
    "chars": 1325,
    "preview": "///<reference types=\"jest\"/>\nimport {escapedGoogNameIsDts, escapeGoogAdmissibleName, unescapeGoogAdmissibleName} from '."
  },
  {
    "path": "packages/tscc/test/shared/sourcemap_splice.ts",
    "chars": 5173,
    "preview": "///<reference types=\"jest\" />\r\nimport spliceSourceMap, {Seeker, splitWithRegex} from '../../src/shared/sourcemap_splice'"
  },
  {
    "path": "packages/tscc/test/spec/TsccSpecWithTS.ts",
    "chars": 3512,
    "preview": "///<reference types=\"jest\"/>\nimport TsccSpecWithTS from '../../src/spec/TsccSpecWithTS';\nimport * as ts from 'typescript"
  },
  {
    "path": "packages/tscc/test/spec/sample/empty.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/tscc/test/spec/sample/nested_directory/empty.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/tscc/test/spec/sample/nested_directory/tsconfig.json",
    "chars": 107,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"ES5\",\n\t\t\"moduleResolution\": \"Node\",\n\t\t\"downlevelIteration\": true\n\t}\n}\n"
  },
  {
    "path": "packages/tscc/test/spec/sample/tsconfig.1.json",
    "chars": 107,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"ES5\",\n\t\t\"moduleResolution\": \"Node\",\n\t\t\"downlevelIteration\": true\n\t}\n}\n"
  },
  {
    "path": "packages/tscc/test/transformer/__snapshots__/transformers.ts.snap",
    "chars": 9761,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`decoratorPropertyTransformer modifies property name access to goog."
  },
  {
    "path": "packages/tscc/test/transformer/transformers.ts",
    "chars": 5714,
    "preview": "///<reference types=\"jest\" />\nimport * as ts from 'typescript';\nimport * as tsickle from 'tsickle';\nimport TsccSpecWithT"
  },
  {
    "path": "packages/tscc/test/tsconfig.test_files.json",
    "chars": 209,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"types\": [],\n\t\t\"target\": \"es6\",\n\t\t\"module\": \"commonjs\",\n\t\t\"declaration\": false,\n\t\t\"importHelpe"
  },
  {
    "path": "packages/tscc/test/tsickle_patches/patch_tsickle_module_resolver.ts",
    "chars": 650,
    "preview": "///<reference types=\"jest\" />\nimport {getPackageBoundary} from '../../src/tsickle_patches/patch_tsickle_module_resolver'"
  },
  {
    "path": "packages/tscc/third_party/closure_library/base.d.ts",
    "chars": 11504,
    "preview": "/**\n * @fileoverview this is a hand-written, non-exhaustive d.ts file for closure library's base.js.\n * Instead of autom"
  },
  {
    "path": "packages/tscc/third_party/closure_library/base.js",
    "chars": 139336,
    "preview": "// Copyright 2006 The Closure Library Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "packages/tscc/third_party/closure_library/reflect.d.ts",
    "chars": 3812,
    "preview": "/**\n * @fileoverview this is a hand-written d.ts file for goog.reflect.\n */\ndeclare module \"goog:goog.reflect\" {\n\tnamesp"
  },
  {
    "path": "packages/tscc/third_party/closure_library/reflect.js",
    "chars": 4541,
    "preview": "// Copyright 2009 The Closure Library Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "packages/tscc/third_party/tsickle/closure_externs.js",
    "chars": 2968,
    "preview": "/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style "
  },
  {
    "path": "packages/tscc/third_party/tsickle/third_party/tslib/LICENSE.txt",
    "chars": 9197,
    "preview": "Apache License\r\n\r\nVersion 2.0, January 2004\r\n\r\nhttp://www.apache.org/licenses/ \r\n\r\nTERMS AND CONDITIONS FOR USE, REPRODU"
  },
  {
    "path": "packages/tscc/third_party/tsickle/third_party/tslib/README.google",
    "chars": 282,
    "preview": "URL: https://github.com/Microsoft/tslib\nLicense: Apache 2.0\nDescription:\ntslib.js contains a version of the 'tslib' libr"
  },
  {
    "path": "packages/tscc/third_party/tsickle/third_party/tslib/externs.js",
    "chars": 39,
    "preview": "/** @externs */\n\nSymbol.asyncIterator;\n"
  },
  {
    "path": "packages/tscc/third_party/tsickle/third_party/tslib/tslib.js",
    "chars": 10969,
    "preview": "/**\n * @fileoverview\n * Hand-modified Closure version of tslib.js.\n * These use the literal space optimized code from Ty"
  },
  {
    "path": "packages/tscc/tsconfig.json",
    "chars": 137,
    "preview": "{\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist\",\n\t\t\"rootDir\": \"src\"\n\t},\n\t\"include\": [\n\t\t\"s"
  },
  {
    "path": "packages/tscc-spec/.npmignore",
    "chars": 71,
    "preview": "index.ts\n/src\ntest\nnode_modules\ntsconfig.json\nyarn.lock\nyarn-error.log\n"
  },
  {
    "path": "packages/tscc-spec/index.ts",
    "chars": 314,
    "preview": "export * from './src/TsccSpec';\nexport * from './src/ITsccSpec';\nexport * from './src/ITsccSpecJSON';\nexport * from './s"
  },
  {
    "path": "packages/tscc-spec/package.json",
    "chars": 274,
    "preview": "{\n  \"name\": \"@tscc/tscc-spec\",\n  \"author\": \"theseanl\",\n  \"version\": \"0.9.4\",\n  \"main\": \"dist/index.js\",\n  \"license\": \"MI"
  },
  {
    "path": "packages/tscc-spec/src/ITsccSpec.ts",
    "chars": 960,
    "preview": "import {INamedModuleSpecs, IDebugOptions} from './ITsccSpecJSON';\n\nexport interface INamedModuleSpecsWithId extends INam"
  },
  {
    "path": "packages/tscc-spec/src/ITsccSpecJSON.ts",
    "chars": 3373,
    "preview": "/**\n * @fileoverview All paths in values are resolved from the parent directory of the JSON file.\n */\nexport declare int"
  },
  {
    "path": "packages/tscc-spec/src/TsccSpec.ts",
    "chars": 11066,
    "preview": "import ITsccSpec, {ExternalModuleData} from './ITsccSpec';\nimport ITsccSpecJSON, {IModule, INamedModuleSpecs, IDebugOpti"
  },
  {
    "path": "packages/tscc-spec/src/shared/Graph.ts",
    "chars": 8702,
    "preview": "class AssociativeArrayLink<V> {\n\tpublic prev: this\n\tpublic next: this\n\tconstructor(\n\t\tpublic value: V\n\t) {\n\t\tthis.prev ="
  },
  {
    "path": "packages/tscc-spec/test/TsccSpec.ts",
    "chars": 3211,
    "preview": "///<reference types=\"jest\"/>\nimport TsccSpec, {TsccSpecError} from '../src/TsccSpec';\nimport path = require('path');\nimp"
  },
  {
    "path": "packages/tscc-spec/test/sample/invalid_json.json",
    "chars": 40,
    "preview": "{\n\t\"module\": {\n\t\t\"out : \"index.ts\"\n\t}\n}\n"
  },
  {
    "path": "packages/tscc-spec/test/sample/spec_with_relative_external.json",
    "chars": 175,
    "preview": "{\n    \"modules\": {\n        \"out\": \"index.ts\"\n    },\n    \"external\": {\n        \"non-relative\": \"nonRelative\",\n        \"./"
  },
  {
    "path": "packages/tscc-spec/test/sample/tscc.spec.json",
    "chars": 41,
    "preview": "{\n\t\"modules\": {\n\t\t\"out\": \"index.ts\"\n\t}\n}\n"
  },
  {
    "path": "packages/tscc-spec/test/sample/unsupported_spec.json",
    "chars": 107,
    "preview": "{\n\t\"modules\": {\n\t\t\"out\": \"index.ts\"\n\t},\n\t\"external\": {\n\t\t\"vendor\": \"vendor\"\n\t},\n\t\"chunkFormat\": \"module\"\n}\n"
  },
  {
    "path": "packages/tscc-spec/test/shared/Graph.ts",
    "chars": 4415,
    "preview": "///<reference types=\"jest\"/>\nimport {DirectedTreeBase, DirectedTree, DirectedTreeWithOrdering, DirectedTreeWithLeafs} fr"
  },
  {
    "path": "packages/tscc-spec/tsconfig.json",
    "chars": 131,
    "preview": "{\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist\"\n\t},\n\t\"include\": [\n\t\t\"index.ts\",\n\t\t\"src/**/"
  },
  {
    "path": "tsconfig.json",
    "chars": 290,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"lib\": [\n\t\t\t\"es7\"\n\t\t],\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t],\n\t\t\"target\": \"es2017\",\n\t\t\"module\": \"commonjs"
  }
]

About this extraction

This page contains the full source code of the theseanl/tscc GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 185 files (459.6 KB), approximately 129.2k tokens, and a symbol index with 449 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!