add: dépendances jest

master
Mathilde JEAN 2 years ago
parent 6e97479586
commit bf35a216d1

@ -1,6 +1,6 @@
{ {
"expoServerPort": 19000, "expoServerPort": null,
"packagerPort": 19000, "packagerPort": null,
"packagerPid": null, "packagerPid": null,
"expoServerNgrokUrl": null, "expoServerNgrokUrl": null,
"packagerNgrokUrl": null, "packagerNgrokUrl": null,

@ -0,0 +1,7 @@
import { getCityList } from 'redux/actions/getFavoriteCity';
describe("Actions tests", () => {
it('should create an action with FETCH_FAVORITE_CITY type', () => {
expect(getFavoriteCity().toEqual({type: 'FETCH_FAVORITE_CITY'}));
})
})

@ -0,0 +1 @@
../escodegen/bin/escodegen.js

@ -0,0 +1 @@
../escodegen/bin/esgenerate.js

@ -0,0 +1 @@
../jest/bin/jest.js

@ -0,0 +1 @@
../resolve/bin/resolve

@ -0,0 +1 @@
../which/bin/which

File diff suppressed because it is too large Load Diff

@ -0,0 +1,19 @@
# @babel/plugin-syntax-bigint
> Allow parsing of BigInt literals
See our website [@babel/plugin-syntax-bigint](https://babeljs.io/docs/en/next/babel-plugin-syntax-bigint.html) for more information.
## Install
Using npm:
```sh
npm install --save-dev @babel/plugin-syntax-bigint
```
or using yarn:
```sh
yarn add @babel/plugin-syntax-bigint --dev
```

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _helperPluginUtils = require("@babel/helper-plugin-utils");
var _default = (0, _helperPluginUtils.declare)(api => {
api.assertVersion(7);
return {
name: "syntax-bigint",
manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("bigInt");
}
};
});
exports.default = _default;

@ -0,0 +1,23 @@
{
"name": "@babel/plugin-syntax-bigint",
"version": "7.8.3",
"description": "Allow parsing of BigInt literals",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-bigint",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "lib/index.js",
"keywords": [
"babel-plugin"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
},
"devDependencies": {
"@babel/core": "^7.8.0"
}
}

@ -0,0 +1,19 @@
# @babel/plugin-syntax-import-meta
> Allow parsing of import.meta
See our website [@babel/plugin-syntax-import-meta](https://babeljs.io/docs/en/next/babel-plugin-syntax-import-meta.html) for more information.
## Install
Using npm:
```sh
npm install --save-dev @babel/plugin-syntax-import-meta
```
or using yarn:
```sh
yarn add @babel/plugin-syntax-import-meta --dev
```

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _helperPluginUtils = require("@babel/helper-plugin-utils");
var _default = (0, _helperPluginUtils.declare)(api => {
api.assertVersion(7);
return {
name: "syntax-import-meta",
manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("importMeta");
}
};
});
exports.default = _default;

@ -0,0 +1,28 @@
{
"name": "@babel/plugin-syntax-import-meta",
"version": "7.10.4",
"description": "Allow parsing of import.meta",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-plugin-syntax-import-meta"
},
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "lib/index.js",
"keywords": [
"babel-plugin"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.10.4"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
},
"devDependencies": {
"@babel/core": "^7.10.4"
},
"gitHead": "7fd40d86a0d03ff0e9c3ea16b29689945433d4df"
}

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

@ -0,0 +1,2 @@
# Enforce `lf` for text files (even on Windows)
text eol=lf

@ -0,0 +1,250 @@
## Next
- **[Breaking change]** Replace `OutModules` enum by custom compiler option `mjsModule`.
- **[Breaking change]** Drop support for Pug, Sass, Angular & Webpack.
- **[Feature]** Expose custom registries for each target.
- **[Feature]** Add `dist.tscOptions` for `lib` target to override options for
distribution builds.
- **[Feature]** Native ESM tests with mocha.
- **[Fix]** Disable deprecated TsLint rules from the default config
- **[Fix]** Remove use of experimental `fs/promises` module.
- **[Internal]** Fix continuous deployment script (stop confusing PRs to master
with push to master)
- **[Internal]** Update dependencies
- **[Internal]** Fix deprecated Mocha types.
## 0.17.1 (2017-05-03)
- **[Fix]** Update dependencies, remove `std/esm` warning.
## 0.17.0 (2017-04-22)
- **[Breaking change]** Update dependencies. Use `esm` instead of `@std/esm`, update Typescript to `2.8.3`.
- **[Fix]** Fix Node processes spawn on Windows (Mocha, Nyc)
## 0.16.2 (2017-02-07)
- **[Fix]** Fix Typedoc generation: use `tsconfig.json` generated for the lib.
- **[Fix]** Write source map for `.mjs` files
- **[Fix]** Copy sources to `_src` when publishing a lib (#87).
- **[Internal]** Restore continuous deployment of documentation.
## 0.16.1 (2017-01-20)
- **[Feature]** Support `mocha` tests on `.mjs` files (using `@std/esm`). Enabled by default
if `outModules` is configured to emit `.mjs`. **You currently need to add
`"@std/esm": {"esm": "cjs"}` to your `package.json`.**
## 0.16.0 (2017-01-09)
- **[Breaking change]** Enable `allowSyntheticDefaultImports` and `esModuleInterop` by default
- **[Fix]** Allow deep module imports in default Tslint rules
- **[Fix]** Drop dependency on deprecated `gulp-util`
- **[Internal]** Replace most custom typings by types from `@types`
## 0.15.8 (2017-12-05)
- **[Fix]** Exit with non-zero code if command tested with coverage fails
- **[Fix]** Solve duplicated error message when using the `run` mocha task.
- **[Fix]** Exit with non-zero code when building scripts fails.
## 0.15.7 (2017-11-29)
- **[Feature]** Add `coverage` task to `mocha` target, use it for the default task
## 0.15.6 (2017-11-29)
- **[Fix]** Fix path to source in source maps.
- **[Fix]** Disable `number-literal-format` in default Tslint rules. It enforced uppercase for hex.
- **[Internal]** Enable integration with Greenkeeper.
- **[Internal]** Enable integration with Codecov
- **[Internal]** Enable code coverage
## 0.15.5 (2017-11-10)
- **[Feature]** Enable the following TsLint rules: `no-duplicate-switch-case`, `no-implicit-dependencies`,
`no-return-await`
- **[Internal]** Update self-dependency `0.15.4`, this restores the README on _npm_
- **[Internal]** Add homepage and author fields to package.json
## 0.15.4 (2017-11-10)
- **[Fix]** Add support for custom additional copy for distribution builds. [#49](https://github.com/demurgos/turbo-gulp/issues/49)
- **[Internal]** Update self-dependency to `turbo-gulp`
- **[Internal]** Add link to license in `README.md`
## 0.15.3 (2017-11-09)
**Rename to `turbo-gulp`**. This package was previously named `demurgos-web-build-tools`.
This version is fully compatible: you can just change the name of your dependency.
## 0.15.2 (2017-11-09)
**The package is prepared to be renamed `turbo-gulp`.**
This is the last version released as `demurgos-web-build-tools`.
- **[Feature]** Add support for watch mode for library targets.
- **[Fix]** Disable experimental support for `*.mjs` by default.
- **[Fix]** Do not emit duplicate TS errors
## 0.15.1 (2017-10-19)
- **[Feature]** Add experimental support for `*.mjs` files
- **[Fix]** Fix support of releases from Continuous Deployment using Travis.
## 0.15.0 (2017-10-18)
- **[Fix]** Add error handling for git deployment.
- **[Internal]** Enable continuous deployment of the `master` branch.
## 0.15.0-beta.11 (2017-08-29)
- **[Feature]** Add `LibTarget.dist.copySrc` option to disable copy of source files to the dist directory.
This allows to prevent issues with missing custom typings.
- **[Fix]** Mark `deploy` property of `LibTarget.typedoc` as optional.
- **[Internal]** Update self-dependency to `v0.15.0-beta.10`.
## 0.15.0-beta.10 (2017-08-28)
- **[Breaking]** Update Tslint rules to use `tslint@5.7.0`.
- **[Fix]** Set `allowJs` to false in default TSC options.
- **[Fix]** Do not pipe output of git commands to stdout.
- **[Internal]** Update self-dependency to `v0.15.0-beta.9`.
## 0.15.0-beta.9 (2017-08-28)
- **[Breaking]** Drop old-style `test` target.
- **[Breaking]** Drop old-style `node` target.
- **[Feature]** Add `mocha` target to run tests in `spec.ts` files.
- **[Feature]** Add `node` target to build and run top-level Node applications.
- **[Feature]** Provide `generateNodeTasks`, `generateLibTasks` and `generateMochaTasks` functions.
They create the tasks but do not register them.
- **[Fix]** Run `clean` before `dist`, if defined.
- **[Fix]** Run `dist` before `publish`.
## 0.15.0-beta.8 (2017-08-26)
- **[Fix]** Remove auth token and registry options for `<lib>:dist:publish`. It is better served
by configuring the environment appropriately.
## 0.15.0-beta.7 (2017-08-26)
- **[Feature]** Add `clean` task to `lib` targets.
- **[Fix]** Ensure that `gitHead` is defined when publishing a package to npm.
## 0.15.0-beta.6 (2017-08-22)
- **[Feature]** Add support for Typedoc deployment to a remote git branch (such as `gh-pages`)
- **[Feature]** Add support for `copy` tasks in new library target.
- **[Fix]** Resolve absolute paths when compiling scripts with custom typings.
## 0.15.0-beta.5 (2017-08-14)
- **[Fix]** Fix package entry for the main module.
## 0.15.0-beta.4 (2017-08-14)
- **[Breaking]** Drop ES5 build exposed to browsers with the `browser` field in `package.json`.
- **[Feature]** Introduce first new-style target (`LibTarget`). it supports typedoc generation, dev builds and
simple distribution.
## 0.15.0-beta.3 (2017-08-11)
- **[Breaking]** Update default lib target to use target-specific `srcDir`.
- **[Feature]** Allow to complete `srcDir` in target.
- **[Feature]** Add experimental library distribution supporting deep requires.
## 0.15.0-beta.2 (2017-08-10)
- **[Fix]** Default to CommonJS for project tsconfig.json
- **[Fix]** Add Typescript configuration for default project.
- **[Internal]** Update self-dependency to `0.15.0-beta.1`.
## 0.15.0-beta.1 (2017-08-09)
- **[Feature]** Support typed TSLint rules.
- **[Internal]** Update gulpfile.ts to use build tools `0.15.0-beta.0`.
- **[Fix]** Fix regressions caused by `0.15.0-beta.0` (missing type definition).
## 0.15.0-beta.0 (2017-08-09)
- **[Breaking]** Expose option interfaces directly in the main module instead of the `config` namespace.
- **[Breaking]** Rename `DEFAULT_PROJECT_OPTIONS` to `DEFAULT_PROJECT`.
- **[Feature]** Emit project-wide `tsconfig.json`.
- **[Internal]** Convert gulpfile to Typescript, use `ts-node` to run it.
- **[Internal]** Update dependencies
## 0.14.3 (2017-07-16)
- **[Feature]** Add `:lint:fix` project task to fix some lint errors.
## 0.14.2 (2017-07-10)
- **[Internal]** Update dependencies: add `package-lock.json` and update `tslint`.
## 0.14.1 (2017-06-17)
- **[Internal]** Update dependencies.
- **[Internal]** Drop dependency on _Bluebird_.
- **[Internal]** Drop dependency on _typings_.
## 0.14.0 (2017-05-10)
- **[Breaking]** Enforce trailing commas by default for multiline objects
- **[Feature]** Allow bump from either `master` or a branch with the same name as the tag (exampel: `v1.2.3`)
- **[Feature]** Support TSLint 8, allow to extend the default rules
- **[Patch]** Allow mergeable namespaces
# 0.13.1
- **[Patch]** Allow namespaces in the default TS-Lint config
# 0.13.0
- **[Breaking]** Major overhaul of the angular target. The server build no longer depends on the client.
- **[Breaking]** Update to `gulp@4` (from `gulp@3`)
- **[Breaking]** Update to `tslint@7` (from `tslint@6`), add stricter default rules
- **[Breaking]** Update signature of targetGenerators and project tasks: it only uses
`ProjectOptions` and `Target` now, the additional options are embedded in those two objects.
- **[Breaking]** Remove `:install`, `:instal:npm` and `:install:typings`. Use the `prepare` script in
your `package.json` file instead.
- Add `:tslint.json` project task to generate configuration for `tslint`
- Add first class support for processing of `pug` and `sass` files, similar to `copy`
- Implement end-to-end tests
- Enable `emitDecoratorMetadata` in default typescript options.
- Allow configuration of `:lint` with the `tslintOptions` property of the project configuration.
- Add `<target>:watch` tasks for incremental builds.
# 0.12.3
- Support `templateUrl` and `styleUrls` in angular modules.
# 0.12.2
- Add `<target>:build:copy` task. It copies user-defined files.
# 0.12.1
- Fix `<target>:watch` task.
# 0.12.0
- **[Breaking]**: Change naming convention for tasks. The names primary part is
the target, then the action (`lib:build` instead of `build:lib`) to group
the tasks per target.
- **[Breaking]**: Use `typeRoots` instead of `definitions` in configuration to
specify Typescript definition files.
- Generate `tsconfig.json` file (mainly for editors)
- Implement the `test` target to run unit-tests with `mocha`.
# 0.11.2
- Target `angular`: Add `build:<target>:assets:sass` for `.scss` files (Sassy CSS)
# 0.11.1
- Rename project to `web-build-tools` (`demurgos-web-build-tools` on _npm_)
- Target `angular`: Add `build:<target>:assets`, `build:<target>:pug` and `build:<target>:static`.
- Update `gulp-typescript`: solve error message during compilation
- Targets `node` and `angular`: `build:<target>:scripts` now include in-lined source maps
- Target `node`: `watch:<target>` to support incremental builds

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2015-2017 Charles Samborski
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.

@ -0,0 +1,14 @@
Copyright (c) 2017, Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

@ -0,0 +1,11 @@
# V8 Coverage
[![npm](https://img.shields.io/npm/v/@c88/v8-coverage.svg?maxAge=2592000)](https://www.npmjs.com/package/@c88/v8-coverage)
[![GitHub repository](https://img.shields.io/badge/Github-demurgos%2Fv8--coverage-blue.svg)](https://github.com/demurgos/v8-coverage)
[![Build status (Travis)](https://img.shields.io/travis/demurgos/v8-coverage/master.svg?maxAge=2592000)](https://travis-ci.org/demurgos/v8-coverage)
[![Build status (AppVeyor)](https://ci.appveyor.com/api/projects/status/qgcbdffyb9e09d0e?svg=true)](https://ci.appveyor.com/project/demurgos/v8-coverage)
[![Codecov](https://codecov.io/gh/demurgos/v8-coverage/branch/master/graph/badge.svg)](https://codecov.io/gh/demurgos/v8-coverage)
## License
[MIT License](./LICENSE.md)

@ -0,0 +1,250 @@
## Next
- **[Breaking change]** Replace `OutModules` enum by custom compiler option `mjsModule`.
- **[Breaking change]** Drop support for Pug, Sass, Angular & Webpack.
- **[Feature]** Expose custom registries for each target.
- **[Feature]** Add `dist.tscOptions` for `lib` target to override options for
distribution builds.
- **[Feature]** Native ESM tests with mocha.
- **[Fix]** Disable deprecated TsLint rules from the default config
- **[Fix]** Remove use of experimental `fs/promises` module.
- **[Internal]** Fix continuous deployment script (stop confusing PRs to master
with push to master)
- **[Internal]** Update dependencies
- **[Internal]** Fix deprecated Mocha types.
## 0.17.1 (2017-05-03)
- **[Fix]** Update dependencies, remove `std/esm` warning.
## 0.17.0 (2017-04-22)
- **[Breaking change]** Update dependencies. Use `esm` instead of `@std/esm`, update Typescript to `2.8.3`.
- **[Fix]** Fix Node processes spawn on Windows (Mocha, Nyc)
## 0.16.2 (2017-02-07)
- **[Fix]** Fix Typedoc generation: use `tsconfig.json` generated for the lib.
- **[Fix]** Write source map for `.mjs` files
- **[Fix]** Copy sources to `_src` when publishing a lib (#87).
- **[Internal]** Restore continuous deployment of documentation.
## 0.16.1 (2017-01-20)
- **[Feature]** Support `mocha` tests on `.mjs` files (using `@std/esm`). Enabled by default
if `outModules` is configured to emit `.mjs`. **You currently need to add
`"@std/esm": {"esm": "cjs"}` to your `package.json`.**
## 0.16.0 (2017-01-09)
- **[Breaking change]** Enable `allowSyntheticDefaultImports` and `esModuleInterop` by default
- **[Fix]** Allow deep module imports in default Tslint rules
- **[Fix]** Drop dependency on deprecated `gulp-util`
- **[Internal]** Replace most custom typings by types from `@types`
## 0.15.8 (2017-12-05)
- **[Fix]** Exit with non-zero code if command tested with coverage fails
- **[Fix]** Solve duplicated error message when using the `run` mocha task.
- **[Fix]** Exit with non-zero code when building scripts fails.
## 0.15.7 (2017-11-29)
- **[Feature]** Add `coverage` task to `mocha` target, use it for the default task
## 0.15.6 (2017-11-29)
- **[Fix]** Fix path to source in source maps.
- **[Fix]** Disable `number-literal-format` in default Tslint rules. It enforced uppercase for hex.
- **[Internal]** Enable integration with Greenkeeper.
- **[Internal]** Enable integration with Codecov
- **[Internal]** Enable code coverage
## 0.15.5 (2017-11-10)
- **[Feature]** Enable the following TsLint rules: `no-duplicate-switch-case`, `no-implicit-dependencies`,
`no-return-await`
- **[Internal]** Update self-dependency `0.15.4`, this restores the README on _npm_
- **[Internal]** Add homepage and author fields to package.json
## 0.15.4 (2017-11-10)
- **[Fix]** Add support for custom additional copy for distribution builds. [#49](https://github.com/demurgos/turbo-gulp/issues/49)
- **[Internal]** Update self-dependency to `turbo-gulp`
- **[Internal]** Add link to license in `README.md`
## 0.15.3 (2017-11-09)
**Rename to `turbo-gulp`**. This package was previously named `demurgos-web-build-tools`.
This version is fully compatible: you can just change the name of your dependency.
## 0.15.2 (2017-11-09)
**The package is prepared to be renamed `turbo-gulp`.**
This is the last version released as `demurgos-web-build-tools`.
- **[Feature]** Add support for watch mode for library targets.
- **[Fix]** Disable experimental support for `*.mjs` by default.
- **[Fix]** Do not emit duplicate TS errors
## 0.15.1 (2017-10-19)
- **[Feature]** Add experimental support for `*.mjs` files
- **[Fix]** Fix support of releases from Continuous Deployment using Travis.
## 0.15.0 (2017-10-18)
- **[Fix]** Add error handling for git deployment.
- **[Internal]** Enable continuous deployment of the `master` branch.
## 0.15.0-beta.11 (2017-08-29)
- **[Feature]** Add `LibTarget.dist.copySrc` option to disable copy of source files to the dist directory.
This allows to prevent issues with missing custom typings.
- **[Fix]** Mark `deploy` property of `LibTarget.typedoc` as optional.
- **[Internal]** Update self-dependency to `v0.15.0-beta.10`.
## 0.15.0-beta.10 (2017-08-28)
- **[Breaking]** Update Tslint rules to use `tslint@5.7.0`.
- **[Fix]** Set `allowJs` to false in default TSC options.
- **[Fix]** Do not pipe output of git commands to stdout.
- **[Internal]** Update self-dependency to `v0.15.0-beta.9`.
## 0.15.0-beta.9 (2017-08-28)
- **[Breaking]** Drop old-style `test` target.
- **[Breaking]** Drop old-style `node` target.
- **[Feature]** Add `mocha` target to run tests in `spec.ts` files.
- **[Feature]** Add `node` target to build and run top-level Node applications.
- **[Feature]** Provide `generateNodeTasks`, `generateLibTasks` and `generateMochaTasks` functions.
They create the tasks but do not register them.
- **[Fix]** Run `clean` before `dist`, if defined.
- **[Fix]** Run `dist` before `publish`.
## 0.15.0-beta.8 (2017-08-26)
- **[Fix]** Remove auth token and registry options for `<lib>:dist:publish`. It is better served
by configuring the environment appropriately.
## 0.15.0-beta.7 (2017-08-26)
- **[Feature]** Add `clean` task to `lib` targets.
- **[Fix]** Ensure that `gitHead` is defined when publishing a package to npm.
## 0.15.0-beta.6 (2017-08-22)
- **[Feature]** Add support for Typedoc deployment to a remote git branch (such as `gh-pages`)
- **[Feature]** Add support for `copy` tasks in new library target.
- **[Fix]** Resolve absolute paths when compiling scripts with custom typings.
## 0.15.0-beta.5 (2017-08-14)
- **[Fix]** Fix package entry for the main module.
## 0.15.0-beta.4 (2017-08-14)
- **[Breaking]** Drop ES5 build exposed to browsers with the `browser` field in `package.json`.
- **[Feature]** Introduce first new-style target (`LibTarget`). it supports typedoc generation, dev builds and
simple distribution.
## 0.15.0-beta.3 (2017-08-11)
- **[Breaking]** Update default lib target to use target-specific `srcDir`.
- **[Feature]** Allow to complete `srcDir` in target.
- **[Feature]** Add experimental library distribution supporting deep requires.
## 0.15.0-beta.2 (2017-08-10)
- **[Fix]** Default to CommonJS for project tsconfig.json
- **[Fix]** Add Typescript configuration for default project.
- **[Internal]** Update self-dependency to `0.15.0-beta.1`.
## 0.15.0-beta.1 (2017-08-09)
- **[Feature]** Support typed TSLint rules.
- **[Internal]** Update gulpfile.ts to use build tools `0.15.0-beta.0`.
- **[Fix]** Fix regressions caused by `0.15.0-beta.0` (missing type definition).
## 0.15.0-beta.0 (2017-08-09)
- **[Breaking]** Expose option interfaces directly in the main module instead of the `config` namespace.
- **[Breaking]** Rename `DEFAULT_PROJECT_OPTIONS` to `DEFAULT_PROJECT`.
- **[Feature]** Emit project-wide `tsconfig.json`.
- **[Internal]** Convert gulpfile to Typescript, use `ts-node` to run it.
- **[Internal]** Update dependencies
## 0.14.3 (2017-07-16)
- **[Feature]** Add `:lint:fix` project task to fix some lint errors.
## 0.14.2 (2017-07-10)
- **[Internal]** Update dependencies: add `package-lock.json` and update `tslint`.
## 0.14.1 (2017-06-17)
- **[Internal]** Update dependencies.
- **[Internal]** Drop dependency on _Bluebird_.
- **[Internal]** Drop dependency on _typings_.
## 0.14.0 (2017-05-10)
- **[Breaking]** Enforce trailing commas by default for multiline objects
- **[Feature]** Allow bump from either `master` or a branch with the same name as the tag (exampel: `v1.2.3`)
- **[Feature]** Support TSLint 8, allow to extend the default rules
- **[Patch]** Allow mergeable namespaces
# 0.13.1
- **[Patch]** Allow namespaces in the default TS-Lint config
# 0.13.0
- **[Breaking]** Major overhaul of the angular target. The server build no longer depends on the client.
- **[Breaking]** Update to `gulp@4` (from `gulp@3`)
- **[Breaking]** Update to `tslint@7` (from `tslint@6`), add stricter default rules
- **[Breaking]** Update signature of targetGenerators and project tasks: it only uses
`ProjectOptions` and `Target` now, the additional options are embedded in those two objects.
- **[Breaking]** Remove `:install`, `:instal:npm` and `:install:typings`. Use the `prepare` script in
your `package.json` file instead.
- Add `:tslint.json` project task to generate configuration for `tslint`
- Add first class support for processing of `pug` and `sass` files, similar to `copy`
- Implement end-to-end tests
- Enable `emitDecoratorMetadata` in default typescript options.
- Allow configuration of `:lint` with the `tslintOptions` property of the project configuration.
- Add `<target>:watch` tasks for incremental builds.
# 0.12.3
- Support `templateUrl` and `styleUrls` in angular modules.
# 0.12.2
- Add `<target>:build:copy` task. It copies user-defined files.
# 0.12.1
- Fix `<target>:watch` task.
# 0.12.0
- **[Breaking]**: Change naming convention for tasks. The names primary part is
the target, then the action (`lib:build` instead of `build:lib`) to group
the tasks per target.
- **[Breaking]**: Use `typeRoots` instead of `definitions` in configuration to
specify Typescript definition files.
- Generate `tsconfig.json` file (mainly for editors)
- Implement the `test` target to run unit-tests with `mocha`.
# 0.11.2
- Target `angular`: Add `build:<target>:assets:sass` for `.scss` files (Sassy CSS)
# 0.11.1
- Rename project to `web-build-tools` (`demurgos-web-build-tools` on _npm_)
- Target `angular`: Add `build:<target>:assets`, `build:<target>:pug` and `build:<target>:static`.
- Update `gulp-typescript`: solve error message during compilation
- Targets `node` and `angular`: `build:<target>:scripts` now include in-lined source maps
- Target `node`: `watch:<target>` to support incremental builds

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2015-2017 Charles Samborski
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.

@ -0,0 +1,11 @@
# V8 Coverage
[![npm](https://img.shields.io/npm/v/@c88/v8-coverage.svg?maxAge=2592000)](https://www.npmjs.com/package/@c88/v8-coverage)
[![GitHub repository](https://img.shields.io/badge/Github-demurgos%2Fv8--coverage-blue.svg)](https://github.com/demurgos/v8-coverage)
[![Build status (Travis)](https://img.shields.io/travis/demurgos/v8-coverage/master.svg?maxAge=2592000)](https://travis-ci.org/demurgos/v8-coverage)
[![Build status (AppVeyor)](https://ci.appveyor.com/api/projects/status/qgcbdffyb9e09d0e?svg=true)](https://ci.appveyor.com/project/demurgos/v8-coverage)
[![Codecov](https://codecov.io/gh/demurgos/v8-coverage/branch/master/graph/badge.svg)](https://codecov.io/gh/demurgos/v8-coverage)
## License
[MIT License](./LICENSE.md)

@ -0,0 +1,146 @@
import { compareRangeCovs } from "./compare";
import { RangeCov } from "./types";
interface ReadonlyRangeTree {
readonly start: number;
readonly end: number;
readonly count: number;
readonly children: ReadonlyRangeTree[];
}
export function emitForest(trees: ReadonlyArray<ReadonlyRangeTree>): string {
return emitForestLines(trees).join("\n");
}
export function emitForestLines(trees: ReadonlyArray<ReadonlyRangeTree>): string[] {
const colMap: Map<number, number> = getColMap(trees);
const header: string = emitOffsets(colMap);
return [header, ...trees.map(tree => emitTree(tree, colMap).join("\n"))];
}
function getColMap(trees: Iterable<ReadonlyRangeTree>): Map<number, number> {
const eventSet: Set<number> = new Set();
for (const tree of trees) {
const stack: ReadonlyRangeTree[] = [tree];
while (stack.length > 0) {
const cur: ReadonlyRangeTree = stack.pop()!;
eventSet.add(cur.start);
eventSet.add(cur.end);
for (const child of cur.children) {
stack.push(child);
}
}
}
const events: number[] = [...eventSet];
events.sort((a, b) => a - b);
let maxDigits: number = 1;
for (const event of events) {
maxDigits = Math.max(maxDigits, event.toString(10).length);
}
const colWidth: number = maxDigits + 3;
const colMap: Map<number, number> = new Map();
for (const [i, event] of events.entries()) {
colMap.set(event, i * colWidth);
}
return colMap;
}
function emitTree(tree: ReadonlyRangeTree, colMap: Map<number, number>): string[] {
const layers: ReadonlyRangeTree[][] = [];
let nextLayer: ReadonlyRangeTree[] = [tree];
while (nextLayer.length > 0) {
const layer: ReadonlyRangeTree[] = nextLayer;
layers.push(layer);
nextLayer = [];
for (const node of layer) {
for (const child of node.children) {
nextLayer.push(child);
}
}
}
return layers.map(layer => emitTreeLayer(layer, colMap));
}
export function parseFunctionRanges(text: string, offsetMap: Map<number, number>): RangeCov[] {
const result: RangeCov[] = [];
for (const line of text.split("\n")) {
for (const range of parseTreeLayer(line, offsetMap)) {
result.push(range);
}
}
result.sort(compareRangeCovs);
return result;
}
/**
*
* @param layer Sorted list of disjoint trees.
* @param colMap
*/
function emitTreeLayer(layer: ReadonlyRangeTree[], colMap: Map<number, number>): string {
const line: string[] = [];
let curIdx: number = 0;
for (const {start, end, count} of layer) {
const startIdx: number = colMap.get(start)!;
const endIdx: number = colMap.get(end)!;
if (startIdx > curIdx) {
line.push(" ".repeat(startIdx - curIdx));
}
line.push(emitRange(count, endIdx - startIdx));
curIdx = endIdx;
}
return line.join("");
}
function parseTreeLayer(text: string, offsetMap: Map<number, number>): RangeCov[] {
const result: RangeCov[] = [];
const regex: RegExp = /\[(\d+)-*\)/gs;
while (true) {
const match: RegExpMatchArray | null = regex.exec(text);
if (match === null) {
break;
}
const startIdx: number = match.index!;
const endIdx: number = startIdx + match[0].length;
const count: number = parseInt(match[1], 10);
const startOffset: number | undefined = offsetMap.get(startIdx);
const endOffset: number | undefined = offsetMap.get(endIdx);
if (startOffset === undefined || endOffset === undefined) {
throw new Error(`Invalid offsets for: ${JSON.stringify(text)}`);
}
result.push({startOffset, endOffset, count});
}
return result;
}
function emitRange(count: number, len: number): string {
const rangeStart: string = `[${count.toString(10)}`;
const rangeEnd: string = ")";
const hyphensLen: number = len - (rangeStart.length + rangeEnd.length);
const hyphens: string = "-".repeat(Math.max(0, hyphensLen));
return `${rangeStart}${hyphens}${rangeEnd}`;
}
function emitOffsets(colMap: Map<number, number>): string {
let line: string = "";
for (const [event, col] of colMap) {
if (line.length < col) {
line += " ".repeat(col - line.length);
}
line += event.toString(10);
}
return line;
}
export function parseOffsets(text: string): Map<number, number> {
const result: Map<number, number> = new Map();
const regex: RegExp = /\d+/gs;
while (true) {
const match: RegExpExecArray | null = regex.exec(text);
if (match === null) {
break;
}
result.set(match.index, parseInt(match[0], 10));
}
return result;
}

@ -0,0 +1,70 @@
import { FunctionCov, ProcessCov, RangeCov, ScriptCov } from "./types";
/**
* Creates a deep copy of a process coverage.
*
* @param processCov Process coverage to clone.
* @return Cloned process coverage.
*/
export function cloneProcessCov(processCov: Readonly<ProcessCov>): ProcessCov {
const result: ScriptCov[] = [];
for (const scriptCov of processCov.result) {
result.push(cloneScriptCov(scriptCov));
}
return {
result,
};
}
/**
* Creates a deep copy of a script coverage.
*
* @param scriptCov Script coverage to clone.
* @return Cloned script coverage.
*/
export function cloneScriptCov(scriptCov: Readonly<ScriptCov>): ScriptCov {
const functions: FunctionCov[] = [];
for (const functionCov of scriptCov.functions) {
functions.push(cloneFunctionCov(functionCov));
}
return {
scriptId: scriptCov.scriptId,
url: scriptCov.url,
functions,
};
}
/**
* Creates a deep copy of a function coverage.
*
* @param functionCov Function coverage to clone.
* @return Cloned function coverage.
*/
export function cloneFunctionCov(functionCov: Readonly<FunctionCov>): FunctionCov {
const ranges: RangeCov[] = [];
for (const rangeCov of functionCov.ranges) {
ranges.push(cloneRangeCov(rangeCov));
}
return {
functionName: functionCov.functionName,
ranges,
isBlockCoverage: functionCov.isBlockCoverage,
};
}
/**
* Creates a deep copy of a function coverage.
*
* @param rangeCov Range coverage to clone.
* @return Cloned range coverage.
*/
export function cloneRangeCov(rangeCov: Readonly<RangeCov>): RangeCov {
return {
startOffset: rangeCov.startOffset,
endOffset: rangeCov.endOffset,
count: rangeCov.count,
};
}

@ -0,0 +1,40 @@
import { FunctionCov, RangeCov, ScriptCov } from "./types";
/**
* Compares two script coverages.
*
* The result corresponds to the comparison of their `url` value (alphabetical sort).
*/
export function compareScriptCovs(a: Readonly<ScriptCov>, b: Readonly<ScriptCov>): number {
if (a.url === b.url) {
return 0;
} else if (a.url < b.url) {
return -1;
} else {
return 1;
}
}
/**
* Compares two function coverages.
*
* The result corresponds to the comparison of the root ranges.
*/
export function compareFunctionCovs(a: Readonly<FunctionCov>, b: Readonly<FunctionCov>): number {
return compareRangeCovs(a.ranges[0], b.ranges[0]);
}
/**
* Compares two range coverages.
*
* The ranges are first ordered by ascending `startOffset` and then by
* descending `endOffset`.
* This corresponds to a pre-order tree traversal.
*/
export function compareRangeCovs(a: Readonly<RangeCov>, b: Readonly<RangeCov>): number {
if (a.startOffset !== b.startOffset) {
return a.startOffset - b.startOffset;
} else {
return b.endOffset - a.endOffset;
}
}

@ -0,0 +1,6 @@
export { emitForest, emitForestLines, parseFunctionRanges, parseOffsets } from "./ascii";
export { cloneFunctionCov, cloneProcessCov, cloneScriptCov, cloneRangeCov } from "./clone";
export { compareScriptCovs, compareFunctionCovs, compareRangeCovs } from "./compare";
export { mergeFunctionCovs, mergeProcessCovs, mergeScriptCovs } from "./merge";
export { RangeTree } from "./range-tree";
export { ProcessCov, ScriptCov, FunctionCov, RangeCov } from "./types";

@ -0,0 +1,343 @@
import {
deepNormalizeScriptCov,
normalizeFunctionCov,
normalizeProcessCov,
normalizeRangeTree,
normalizeScriptCov,
} from "./normalize";
import { RangeTree } from "./range-tree";
import { FunctionCov, ProcessCov, Range, RangeCov, ScriptCov } from "./types";
/**
* Merges a list of process coverages.
*
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param processCovs Process coverages to merge.
* @return Merged process coverage.
*/
export function mergeProcessCovs(processCovs: ReadonlyArray<ProcessCov>): ProcessCov {
if (processCovs.length === 0) {
return {result: []};
}
const urlToScripts: Map<string, ScriptCov[]> = new Map();
for (const processCov of processCovs) {
for (const scriptCov of processCov.result) {
let scriptCovs: ScriptCov[] | undefined = urlToScripts.get(scriptCov.url);
if (scriptCovs === undefined) {
scriptCovs = [];
urlToScripts.set(scriptCov.url, scriptCovs);
}
scriptCovs.push(scriptCov);
}
}
const result: ScriptCov[] = [];
for (const scripts of urlToScripts.values()) {
// assert: `scripts.length > 0`
result.push(mergeScriptCovs(scripts)!);
}
const merged: ProcessCov = {result};
normalizeProcessCov(merged);
return merged;
}
/**
* Merges a list of matching script coverages.
*
* Scripts are matching if they have the same `url`.
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param scriptCovs Process coverages to merge.
* @return Merged script coverage, or `undefined` if the input list was empty.
*/
export function mergeScriptCovs(scriptCovs: ReadonlyArray<ScriptCov>): ScriptCov | undefined {
if (scriptCovs.length === 0) {
return undefined;
} else if (scriptCovs.length === 1) {
const merged: ScriptCov = scriptCovs[0];
deepNormalizeScriptCov(merged);
return merged;
}
const first: ScriptCov = scriptCovs[0];
const scriptId: string = first.scriptId;
const url: string = first.url;
const rangeToFuncs: Map<string, FunctionCov[]> = new Map();
for (const scriptCov of scriptCovs) {
for (const funcCov of scriptCov.functions) {
const rootRange: string = stringifyFunctionRootRange(funcCov);
let funcCovs: FunctionCov[] | undefined = rangeToFuncs.get(rootRange);
if (funcCovs === undefined ||
// if the entry in rangeToFuncs is function-level granularity and
// the new coverage is block-level, prefer block-level.
(!funcCovs[0].isBlockCoverage && funcCov.isBlockCoverage)) {
funcCovs = [];
rangeToFuncs.set(rootRange, funcCovs);
} else if (funcCovs[0].isBlockCoverage && !funcCov.isBlockCoverage) {
// if the entry in rangeToFuncs is block-level granularity, we should
// not append function level granularity.
continue;
}
funcCovs.push(funcCov);
}
}
const functions: FunctionCov[] = [];
for (const funcCovs of rangeToFuncs.values()) {
// assert: `funcCovs.length > 0`
functions.push(mergeFunctionCovs(funcCovs)!);
}
const merged: ScriptCov = {scriptId, url, functions};
normalizeScriptCov(merged);
return merged;
}
/**
* Returns a string representation of the root range of the function.
*
* This string can be used to match function with same root range.
* The string is derived from the start and end offsets of the root range of
* the function.
* This assumes that `ranges` is non-empty (true for valid function coverages).
*
* @param funcCov Function coverage with the range to stringify
* @internal
*/
function stringifyFunctionRootRange(funcCov: Readonly<FunctionCov>): string {
const rootRange: RangeCov = funcCov.ranges[0];
return `${rootRange.startOffset.toString(10)};${rootRange.endOffset.toString(10)}`;
}
/**
* Merges a list of matching function coverages.
*
* Functions are matching if their root ranges have the same span.
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param funcCovs Function coverages to merge.
* @return Merged function coverage, or `undefined` if the input list was empty.
*/
export function mergeFunctionCovs(funcCovs: ReadonlyArray<FunctionCov>): FunctionCov | undefined {
if (funcCovs.length === 0) {
return undefined;
} else if (funcCovs.length === 1) {
const merged: FunctionCov = funcCovs[0];
normalizeFunctionCov(merged);
return merged;
}
const functionName: string = funcCovs[0].functionName;
const trees: RangeTree[] = [];
for (const funcCov of funcCovs) {
// assert: `fn.ranges.length > 0`
// assert: `fn.ranges` is sorted
trees.push(RangeTree.fromSortedRanges(funcCov.ranges)!);
}
// assert: `trees.length > 0`
const mergedTree: RangeTree = mergeRangeTrees(trees)!;
normalizeRangeTree(mergedTree);
const ranges: RangeCov[] = mergedTree.toRanges();
const isBlockCoverage: boolean = !(ranges.length === 1 && ranges[0].count === 0);
const merged: FunctionCov = {functionName, ranges, isBlockCoverage};
// assert: `merged` is normalized
return merged;
}
/**
* @precondition Same `start` and `end` for all the trees
*/
function mergeRangeTrees(trees: ReadonlyArray<RangeTree>): RangeTree | undefined {
if (trees.length <= 1) {
return trees[0];
}
const first: RangeTree = trees[0];
let delta: number = 0;
for (const tree of trees) {
delta += tree.delta;
}
const children: RangeTree[] = mergeRangeTreeChildren(trees);
return new RangeTree(first.start, first.end, delta, children);
}
class RangeTreeWithParent {
readonly parentIndex: number;
readonly tree: RangeTree;
constructor(parentIndex: number, tree: RangeTree) {
this.parentIndex = parentIndex;
this.tree = tree;
}
}
class StartEvent {
readonly offset: number;
readonly trees: RangeTreeWithParent[];
constructor(offset: number, trees: RangeTreeWithParent[]) {
this.offset = offset;
this.trees = trees;
}
static compare(a: StartEvent, b: StartEvent): number {
return a.offset - b.offset;
}
}
class StartEventQueue {
private readonly queue: StartEvent[];
private nextIndex: number;
private pendingOffset: number;
private pendingTrees: RangeTreeWithParent[] | undefined;
private constructor(queue: StartEvent[]) {
this.queue = queue;
this.nextIndex = 0;
this.pendingOffset = 0;
this.pendingTrees = undefined;
}
static fromParentTrees(parentTrees: ReadonlyArray<RangeTree>): StartEventQueue {
const startToTrees: Map<number, RangeTreeWithParent[]> = new Map();
for (const [parentIndex, parentTree] of parentTrees.entries()) {
for (const child of parentTree.children) {
let trees: RangeTreeWithParent[] | undefined = startToTrees.get(child.start);
if (trees === undefined) {
trees = [];
startToTrees.set(child.start, trees);
}
trees.push(new RangeTreeWithParent(parentIndex, child));
}
}
const queue: StartEvent[] = [];
for (const [startOffset, trees] of startToTrees) {
queue.push(new StartEvent(startOffset, trees));
}
queue.sort(StartEvent.compare);
return new StartEventQueue(queue);
}
setPendingOffset(offset: number): void {
this.pendingOffset = offset;
}
pushPendingTree(tree: RangeTreeWithParent): void {
if (this.pendingTrees === undefined) {
this.pendingTrees = [];
}
this.pendingTrees.push(tree);
}
next(): StartEvent | undefined {
const pendingTrees: RangeTreeWithParent[] | undefined = this.pendingTrees;
const nextEvent: StartEvent | undefined = this.queue[this.nextIndex];
if (pendingTrees === undefined) {
this.nextIndex++;
return nextEvent;
} else if (nextEvent === undefined) {
this.pendingTrees = undefined;
return new StartEvent(this.pendingOffset, pendingTrees);
} else {
if (this.pendingOffset < nextEvent.offset) {
this.pendingTrees = undefined;
return new StartEvent(this.pendingOffset, pendingTrees);
} else {
if (this.pendingOffset === nextEvent.offset) {
this.pendingTrees = undefined;
for (const tree of pendingTrees) {
nextEvent.trees.push(tree);
}
}
this.nextIndex++;
return nextEvent;
}
}
}
}
function mergeRangeTreeChildren(parentTrees: ReadonlyArray<RangeTree>): RangeTree[] {
const result: RangeTree[] = [];
const startEventQueue: StartEventQueue = StartEventQueue.fromParentTrees(parentTrees);
const parentToNested: Map<number, RangeTree[]> = new Map();
let openRange: Range | undefined;
while (true) {
const event: StartEvent | undefined = startEventQueue.next();
if (event === undefined) {
break;
}
if (openRange !== undefined && openRange.end <= event.offset) {
result.push(nextChild(openRange, parentToNested));
openRange = undefined;
}
if (openRange === undefined) {
let openRangeEnd: number = event.offset + 1;
for (const {parentIndex, tree} of event.trees) {
openRangeEnd = Math.max(openRangeEnd, tree.end);
insertChild(parentToNested, parentIndex, tree);
}
startEventQueue.setPendingOffset(openRangeEnd);
openRange = {start: event.offset, end: openRangeEnd};
} else {
for (const {parentIndex, tree} of event.trees) {
if (tree.end > openRange.end) {
const right: RangeTree = tree.split(openRange.end);
startEventQueue.pushPendingTree(new RangeTreeWithParent(parentIndex, right));
}
insertChild(parentToNested, parentIndex, tree);
}
}
}
if (openRange !== undefined) {
result.push(nextChild(openRange, parentToNested));
}
return result;
}
function insertChild(parentToNested: Map<number, RangeTree[]>, parentIndex: number, tree: RangeTree): void {
let nested: RangeTree[] | undefined = parentToNested.get(parentIndex);
if (nested === undefined) {
nested = [];
parentToNested.set(parentIndex, nested);
}
nested.push(tree);
}
function nextChild(openRange: Range, parentToNested: Map<number, RangeTree[]>): RangeTree {
const matchingTrees: RangeTree[] = [];
for (const nested of parentToNested.values()) {
if (nested.length === 1 && nested[0].start === openRange.start && nested[0].end === openRange.end) {
matchingTrees.push(nested[0]);
} else {
matchingTrees.push(new RangeTree(
openRange.start,
openRange.end,
0,
nested,
));
}
}
parentToNested.clear();
return mergeRangeTrees(matchingTrees)!;
}

@ -0,0 +1,84 @@
import { compareFunctionCovs, compareRangeCovs, compareScriptCovs } from "./compare";
import { RangeTree } from "./range-tree";
import { FunctionCov, ProcessCov, ScriptCov } from "./types";
/**
* Normalizes a process coverage.
*
* Sorts the scripts alphabetically by `url`.
* Reassigns script ids: the script at index `0` receives `"0"`, the script at
* index `1` receives `"1"` etc.
* This does not normalize the script coverages.
*
* @param processCov Process coverage to normalize.
*/
export function normalizeProcessCov(processCov: ProcessCov): void {
processCov.result.sort(compareScriptCovs);
for (const [scriptId, scriptCov] of processCov.result.entries()) {
scriptCov.scriptId = scriptId.toString(10);
}
}
/**
* Normalizes a process coverage deeply.
*
* Normalizes the script coverages deeply, then normalizes the process coverage
* itself.
*
* @param processCov Process coverage to normalize.
*/
export function deepNormalizeProcessCov(processCov: ProcessCov): void {
for (const scriptCov of processCov.result) {
deepNormalizeScriptCov(scriptCov);
}
normalizeProcessCov(processCov);
}
/**
* Normalizes a script coverage.
*
* Sorts the function by root range (pre-order sort).
* This does not normalize the function coverages.
*
* @param scriptCov Script coverage to normalize.
*/
export function normalizeScriptCov(scriptCov: ScriptCov): void {
scriptCov.functions.sort(compareFunctionCovs);
}
/**
* Normalizes a script coverage deeply.
*
* Normalizes the function coverages deeply, then normalizes the script coverage
* itself.
*
* @param scriptCov Script coverage to normalize.
*/
export function deepNormalizeScriptCov(scriptCov: ScriptCov): void {
for (const funcCov of scriptCov.functions) {
normalizeFunctionCov(funcCov);
}
normalizeScriptCov(scriptCov);
}
/**
* Normalizes a function coverage.
*
* Sorts the ranges (pre-order sort).
* TODO: Tree-based normalization of the ranges.
*
* @param funcCov Function coverage to normalize.
*/
export function normalizeFunctionCov(funcCov: FunctionCov): void {
funcCov.ranges.sort(compareRangeCovs);
const tree: RangeTree = RangeTree.fromSortedRanges(funcCov.ranges)!;
normalizeRangeTree(tree);
funcCov.ranges = tree.toRanges();
}
/**
* @internal
*/
export function normalizeRangeTree(tree: RangeTree): void {
tree.normalize();
}

@ -0,0 +1,156 @@
import { RangeCov } from "./types";
export class RangeTree {
start: number;
end: number;
delta: number;
children: RangeTree[];
constructor(
start: number,
end: number,
delta: number,
children: RangeTree[],
) {
this.start = start;
this.end = end;
this.delta = delta;
this.children = children;
}
/**
* @precodition `ranges` are well-formed and pre-order sorted
*/
static fromSortedRanges(ranges: ReadonlyArray<RangeCov>): RangeTree | undefined {
let root: RangeTree | undefined;
// Stack of parent trees and parent counts.
const stack: [RangeTree, number][] = [];
for (const range of ranges) {
const node: RangeTree = new RangeTree(range.startOffset, range.endOffset, range.count, []);
if (root === undefined) {
root = node;
stack.push([node, range.count]);
continue;
}
let parent: RangeTree;
let parentCount: number;
while (true) {
[parent, parentCount] = stack[stack.length - 1];
// assert: `top !== undefined` (the ranges are sorted)
if (range.startOffset < parent.end) {
break;
} else {
stack.pop();
}
}
node.delta -= parentCount;
parent.children.push(node);
stack.push([node, range.count]);
}
return root;
}
normalize(): void {
const children: RangeTree[] = [];
let curEnd: number;
let head: RangeTree | undefined;
const tail: RangeTree[] = [];
for (const child of this.children) {
if (head === undefined) {
head = child;
} else if (child.delta === head.delta && child.start === curEnd!) {
tail.push(child);
} else {
endChain();
head = child;
}
curEnd = child.end;
}
if (head !== undefined) {
endChain();
}
if (children.length === 1) {
const child: RangeTree = children[0];
if (child.start === this.start && child.end === this.end) {
this.delta += child.delta;
this.children = child.children;
// `.lazyCount` is zero for both (both are after normalization)
return;
}
}
this.children = children;
function endChain(): void {
if (tail.length !== 0) {
head!.end = tail[tail.length - 1].end;
for (const tailTree of tail) {
for (const subChild of tailTree.children) {
subChild.delta += tailTree.delta - head!.delta;
head!.children.push(subChild);
}
}
tail.length = 0;
}
head!.normalize();
children.push(head!);
}
}
/**
* @precondition `tree.start < value && value < tree.end`
* @return RangeTree Right part
*/
split(value: number): RangeTree {
let leftChildLen: number = this.children.length;
let mid: RangeTree | undefined;
// TODO(perf): Binary search (check overhead)
for (let i: number = 0; i < this.children.length; i++) {
const child: RangeTree = this.children[i];
if (child.start < value && value < child.end) {
mid = child.split(value);
leftChildLen = i + 1;
break;
} else if (child.start >= value) {
leftChildLen = i;
break;
}
}
const rightLen: number = this.children.length - leftChildLen;
const rightChildren: RangeTree[] = this.children.splice(leftChildLen, rightLen);
if (mid !== undefined) {
rightChildren.unshift(mid);
}
const result: RangeTree = new RangeTree(
value,
this.end,
this.delta,
rightChildren,
);
this.end = value;
return result;
}
/**
* Get the range coverages corresponding to the tree.
*
* The ranges are pre-order sorted.
*/
toRanges(): RangeCov[] {
const ranges: RangeCov[] = [];
// Stack of parent trees and counts.
const stack: [RangeTree, number][] = [[this, 0]];
while (stack.length > 0) {
const [cur, parentCount]: [RangeTree, number] = stack.pop()!;
const count: number = parentCount + cur.delta;
ranges.push({startOffset: cur.start, endOffset: cur.end, count});
for (let i: number = cur.children.length - 1; i >= 0; i--) {
stack.push([cur.children[i], count]);
}
}
return ranges;
}
}

@ -0,0 +1,26 @@
export interface ProcessCov {
result: ScriptCov[];
}
export interface ScriptCov {
scriptId: string;
url: string;
functions: FunctionCov[];
}
export interface FunctionCov {
functionName: string;
ranges: RangeCov[];
isBlockCoverage: boolean;
}
export interface Range {
readonly start: number;
readonly end: number;
}
export interface RangeCov {
startOffset: number;
endOffset: number;
count: number;
}

@ -0,0 +1,12 @@
import { RangeCov } from "./types";
interface ReadonlyRangeTree {
readonly start: number;
readonly end: number;
readonly count: number;
readonly children: ReadonlyRangeTree[];
}
export declare function emitForest(trees: ReadonlyArray<ReadonlyRangeTree>): string;
export declare function emitForestLines(trees: ReadonlyArray<ReadonlyRangeTree>): string[];
export declare function parseFunctionRanges(text: string, offsetMap: Map<number, number>): RangeCov[];
export declare function parseOffsets(text: string): Map<number, number>;
export {};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,29 @@
import { FunctionCov, ProcessCov, RangeCov, ScriptCov } from "./types";
/**
* Creates a deep copy of a process coverage.
*
* @param processCov Process coverage to clone.
* @return Cloned process coverage.
*/
export declare function cloneProcessCov(processCov: Readonly<ProcessCov>): ProcessCov;
/**
* Creates a deep copy of a script coverage.
*
* @param scriptCov Script coverage to clone.
* @return Cloned script coverage.
*/
export declare function cloneScriptCov(scriptCov: Readonly<ScriptCov>): ScriptCov;
/**
* Creates a deep copy of a function coverage.
*
* @param functionCov Function coverage to clone.
* @return Cloned function coverage.
*/
export declare function cloneFunctionCov(functionCov: Readonly<FunctionCov>): FunctionCov;
/**
* Creates a deep copy of a function coverage.
*
* @param rangeCov Range coverage to clone.
* @return Cloned range coverage.
*/
export declare function cloneRangeCov(rangeCov: Readonly<RangeCov>): RangeCov;

@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Creates a deep copy of a process coverage.
*
* @param processCov Process coverage to clone.
* @return Cloned process coverage.
*/
function cloneProcessCov(processCov) {
const result = [];
for (const scriptCov of processCov.result) {
result.push(cloneScriptCov(scriptCov));
}
return {
result,
};
}
exports.cloneProcessCov = cloneProcessCov;
/**
* Creates a deep copy of a script coverage.
*
* @param scriptCov Script coverage to clone.
* @return Cloned script coverage.
*/
function cloneScriptCov(scriptCov) {
const functions = [];
for (const functionCov of scriptCov.functions) {
functions.push(cloneFunctionCov(functionCov));
}
return {
scriptId: scriptCov.scriptId,
url: scriptCov.url,
functions,
};
}
exports.cloneScriptCov = cloneScriptCov;
/**
* Creates a deep copy of a function coverage.
*
* @param functionCov Function coverage to clone.
* @return Cloned function coverage.
*/
function cloneFunctionCov(functionCov) {
const ranges = [];
for (const rangeCov of functionCov.ranges) {
ranges.push(cloneRangeCov(rangeCov));
}
return {
functionName: functionCov.functionName,
ranges,
isBlockCoverage: functionCov.isBlockCoverage,
};
}
exports.cloneFunctionCov = cloneFunctionCov;
/**
* Creates a deep copy of a function coverage.
*
* @param rangeCov Range coverage to clone.
* @return Cloned range coverage.
*/
function cloneRangeCov(rangeCov) {
return {
startOffset: rangeCov.startOffset,
endOffset: rangeCov.endOffset,
count: rangeCov.count,
};
}
exports.cloneRangeCov = cloneRangeCov;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvY2xvbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQTs7Ozs7R0FLRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxVQUFnQztJQUM5RCxNQUFNLE1BQU0sR0FBZ0IsRUFBRSxDQUFDO0lBQy9CLEtBQUssTUFBTSxTQUFTLElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRTtRQUN6QyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0tBQ3hDO0lBRUQsT0FBTztRQUNMLE1BQU07S0FDUCxDQUFDO0FBQ0osQ0FBQztBQVRELDBDQVNDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixjQUFjLENBQUMsU0FBOEI7SUFDM0QsTUFBTSxTQUFTLEdBQWtCLEVBQUUsQ0FBQztJQUNwQyxLQUFLLE1BQU0sV0FBVyxJQUFJLFNBQVMsQ0FBQyxTQUFTLEVBQUU7UUFDN0MsU0FBUyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0tBQy9DO0lBRUQsT0FBTztRQUNMLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUTtRQUM1QixHQUFHLEVBQUUsU0FBUyxDQUFDLEdBQUc7UUFDbEIsU0FBUztLQUNWLENBQUM7QUFDSixDQUFDO0FBWEQsd0NBV0M7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLFdBQWtDO0lBQ2pFLE1BQU0sTUFBTSxHQUFlLEVBQUUsQ0FBQztJQUM5QixLQUFLLE1BQU0sUUFBUSxJQUFJLFdBQVcsQ0FBQyxNQUFNLEVBQUU7UUFDekMsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztLQUN0QztJQUVELE9BQU87UUFDTCxZQUFZLEVBQUUsV0FBVyxDQUFDLFlBQVk7UUFDdEMsTUFBTTtRQUNOLGVBQWUsRUFBRSxXQUFXLENBQUMsZUFBZTtLQUM3QyxDQUFDO0FBQ0osQ0FBQztBQVhELDRDQVdDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixhQUFhLENBQUMsUUFBNEI7SUFDeEQsT0FBTztRQUNMLFdBQVcsRUFBRSxRQUFRLENBQUMsV0FBVztRQUNqQyxTQUFTLEVBQUUsUUFBUSxDQUFDLFNBQVM7UUFDN0IsS0FBSyxFQUFFLFFBQVEsQ0FBQyxLQUFLO0tBQ3RCLENBQUM7QUFDSixDQUFDO0FBTkQsc0NBTUMiLCJmaWxlIjoiY2xvbmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGdW5jdGlvbkNvdiwgUHJvY2Vzc0NvdiwgUmFuZ2VDb3YsIFNjcmlwdENvdiB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiBhIHByb2Nlc3MgY292ZXJhZ2UuXG4gKlxuICogQHBhcmFtIHByb2Nlc3NDb3YgUHJvY2VzcyBjb3ZlcmFnZSB0byBjbG9uZS5cbiAqIEByZXR1cm4gQ2xvbmVkIHByb2Nlc3MgY292ZXJhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbG9uZVByb2Nlc3NDb3YocHJvY2Vzc0NvdjogUmVhZG9ubHk8UHJvY2Vzc0Nvdj4pOiBQcm9jZXNzQ292IHtcbiAgY29uc3QgcmVzdWx0OiBTY3JpcHRDb3ZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHNjcmlwdENvdiBvZiBwcm9jZXNzQ292LnJlc3VsdCkge1xuICAgIHJlc3VsdC5wdXNoKGNsb25lU2NyaXB0Q292KHNjcmlwdENvdikpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZXN1bHQsXG4gIH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiBhIHNjcmlwdCBjb3ZlcmFnZS5cbiAqXG4gKiBAcGFyYW0gc2NyaXB0Q292IFNjcmlwdCBjb3ZlcmFnZSB0byBjbG9uZS5cbiAqIEByZXR1cm4gQ2xvbmVkIHNjcmlwdCBjb3ZlcmFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsb25lU2NyaXB0Q292KHNjcmlwdENvdjogUmVhZG9ubHk8U2NyaXB0Q292Pik6IFNjcmlwdENvdiB7XG4gIGNvbnN0IGZ1bmN0aW9uczogRnVuY3Rpb25Db3ZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGZ1bmN0aW9uQ292IG9mIHNjcmlwdENvdi5mdW5jdGlvbnMpIHtcbiAgICBmdW5jdGlvbnMucHVzaChjbG9uZUZ1bmN0aW9uQ292KGZ1bmN0aW9uQ292KSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHNjcmlwdElkOiBzY3JpcHRDb3Yuc2NyaXB0SWQsXG4gICAgdXJsOiBzY3JpcHRDb3YudXJsLFxuICAgIGZ1bmN0aW9ucyxcbiAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIGEgZnVuY3Rpb24gY292ZXJhZ2UuXG4gKlxuICogQHBhcmFtIGZ1bmN0aW9uQ292IEZ1bmN0aW9uIGNvdmVyYWdlIHRvIGNsb25lLlxuICogQHJldHVybiBDbG9uZWQgZnVuY3Rpb24gY292ZXJhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbG9uZUZ1bmN0aW9uQ292KGZ1bmN0aW9uQ292OiBSZWFkb25seTxGdW5jdGlvbkNvdj4pOiBGdW5jdGlvbkNvdiB7XG4gIGNvbnN0IHJhbmdlczogUmFuZ2VDb3ZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHJhbmdlQ292IG9mIGZ1bmN0aW9uQ292LnJhbmdlcykge1xuICAgIHJhbmdlcy5wdXNoKGNsb25lUmFuZ2VDb3YocmFuZ2VDb3YpKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZnVuY3Rpb25OYW1lOiBmdW5jdGlvbkNvdi5mdW5jdGlvbk5hbWUsXG4gICAgcmFuZ2VzLFxuICAgIGlzQmxvY2tDb3ZlcmFnZTogZnVuY3Rpb25Db3YuaXNCbG9ja0NvdmVyYWdlLFxuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgYSBmdW5jdGlvbiBjb3ZlcmFnZS5cbiAqXG4gKiBAcGFyYW0gcmFuZ2VDb3YgUmFuZ2UgY292ZXJhZ2UgdG8gY2xvbmUuXG4gKiBAcmV0dXJuIENsb25lZCByYW5nZSBjb3ZlcmFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsb25lUmFuZ2VDb3YocmFuZ2VDb3Y6IFJlYWRvbmx5PFJhbmdlQ292Pik6IFJhbmdlQ292IHtcbiAgcmV0dXJuIHtcbiAgICBzdGFydE9mZnNldDogcmFuZ2VDb3Yuc3RhcnRPZmZzZXQsXG4gICAgZW5kT2Zmc2V0OiByYW5nZUNvdi5lbmRPZmZzZXQsXG4gICAgY291bnQ6IHJhbmdlQ292LmNvdW50LFxuICB9O1xufVxuIl0sInNvdXJjZVJvb3QiOiIifQ==

@ -0,0 +1,64 @@
/**
* Creates a deep copy of a process coverage.
*
* @param processCov Process coverage to clone.
* @return Cloned process coverage.
*/
export function cloneProcessCov(processCov) {
const result = [];
for (const scriptCov of processCov.result) {
result.push(cloneScriptCov(scriptCov));
}
return {
result,
};
}
/**
* Creates a deep copy of a script coverage.
*
* @param scriptCov Script coverage to clone.
* @return Cloned script coverage.
*/
export function cloneScriptCov(scriptCov) {
const functions = [];
for (const functionCov of scriptCov.functions) {
functions.push(cloneFunctionCov(functionCov));
}
return {
scriptId: scriptCov.scriptId,
url: scriptCov.url,
functions,
};
}
/**
* Creates a deep copy of a function coverage.
*
* @param functionCov Function coverage to clone.
* @return Cloned function coverage.
*/
export function cloneFunctionCov(functionCov) {
const ranges = [];
for (const rangeCov of functionCov.ranges) {
ranges.push(cloneRangeCov(rangeCov));
}
return {
functionName: functionCov.functionName,
ranges,
isBlockCoverage: functionCov.isBlockCoverage,
};
}
/**
* Creates a deep copy of a function coverage.
*
* @param rangeCov Range coverage to clone.
* @return Cloned range coverage.
*/
export function cloneRangeCov(rangeCov) {
return {
startOffset: rangeCov.startOffset,
endOffset: rangeCov.endOffset,
count: rangeCov.count,
};
}
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvY2xvbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLFVBQWdDO0lBQzlELE1BQU0sTUFBTSxHQUFnQixFQUFFLENBQUM7SUFDL0IsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLENBQUMsTUFBTSxFQUFFO1FBQ3pDLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7S0FDeEM7SUFFRCxPQUFPO1FBQ0wsTUFBTTtLQUNQLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUFDLFNBQThCO0lBQzNELE1BQU0sU0FBUyxHQUFrQixFQUFFLENBQUM7SUFDcEMsS0FBSyxNQUFNLFdBQVcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFO1FBQzdDLFNBQVMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztLQUMvQztJQUVELE9BQU87UUFDTCxRQUFRLEVBQUUsU0FBUyxDQUFDLFFBQVE7UUFDNUIsR0FBRyxFQUFFLFNBQVMsQ0FBQyxHQUFHO1FBQ2xCLFNBQVM7S0FDVixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLFdBQWtDO0lBQ2pFLE1BQU0sTUFBTSxHQUFlLEVBQUUsQ0FBQztJQUM5QixLQUFLLE1BQU0sUUFBUSxJQUFJLFdBQVcsQ0FBQyxNQUFNLEVBQUU7UUFDekMsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztLQUN0QztJQUVELE9BQU87UUFDTCxZQUFZLEVBQUUsV0FBVyxDQUFDLFlBQVk7UUFDdEMsTUFBTTtRQUNOLGVBQWUsRUFBRSxXQUFXLENBQUMsZUFBZTtLQUM3QyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxRQUE0QjtJQUN4RCxPQUFPO1FBQ0wsV0FBVyxFQUFFLFFBQVEsQ0FBQyxXQUFXO1FBQ2pDLFNBQVMsRUFBRSxRQUFRLENBQUMsU0FBUztRQUM3QixLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUs7S0FDdEIsQ0FBQztBQUNKLENBQUMiLCJmaWxlIjoiY2xvbmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGdW5jdGlvbkNvdiwgUHJvY2Vzc0NvdiwgUmFuZ2VDb3YsIFNjcmlwdENvdiB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiBhIHByb2Nlc3MgY292ZXJhZ2UuXG4gKlxuICogQHBhcmFtIHByb2Nlc3NDb3YgUHJvY2VzcyBjb3ZlcmFnZSB0byBjbG9uZS5cbiAqIEByZXR1cm4gQ2xvbmVkIHByb2Nlc3MgY292ZXJhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbG9uZVByb2Nlc3NDb3YocHJvY2Vzc0NvdjogUmVhZG9ubHk8UHJvY2Vzc0Nvdj4pOiBQcm9jZXNzQ292IHtcbiAgY29uc3QgcmVzdWx0OiBTY3JpcHRDb3ZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHNjcmlwdENvdiBvZiBwcm9jZXNzQ292LnJlc3VsdCkge1xuICAgIHJlc3VsdC5wdXNoKGNsb25lU2NyaXB0Q292KHNjcmlwdENvdikpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZXN1bHQsXG4gIH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiBhIHNjcmlwdCBjb3ZlcmFnZS5cbiAqXG4gKiBAcGFyYW0gc2NyaXB0Q292IFNjcmlwdCBjb3ZlcmFnZSB0byBjbG9uZS5cbiAqIEByZXR1cm4gQ2xvbmVkIHNjcmlwdCBjb3ZlcmFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsb25lU2NyaXB0Q292KHNjcmlwdENvdjogUmVhZG9ubHk8U2NyaXB0Q292Pik6IFNjcmlwdENvdiB7XG4gIGNvbnN0IGZ1bmN0aW9uczogRnVuY3Rpb25Db3ZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGZ1bmN0aW9uQ292IG9mIHNjcmlwdENvdi5mdW5jdGlvbnMpIHtcbiAgICBmdW5jdGlvbnMucHVzaChjbG9uZUZ1bmN0aW9uQ292KGZ1bmN0aW9uQ292KSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHNjcmlwdElkOiBzY3JpcHRDb3Yuc2NyaXB0SWQsXG4gICAgdXJsOiBzY3JpcHRDb3YudXJsLFxuICAgIGZ1bmN0aW9ucyxcbiAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIGEgZnVuY3Rpb24gY292ZXJhZ2UuXG4gKlxuICogQHBhcmFtIGZ1bmN0aW9uQ292IEZ1bmN0aW9uIGNvdmVyYWdlIHRvIGNsb25lLlxuICogQHJldHVybiBDbG9uZWQgZnVuY3Rpb24gY292ZXJhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbG9uZUZ1bmN0aW9uQ292KGZ1bmN0aW9uQ292OiBSZWFkb25seTxGdW5jdGlvbkNvdj4pOiBGdW5jdGlvbkNvdiB7XG4gIGNvbnN0IHJhbmdlczogUmFuZ2VDb3ZbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHJhbmdlQ292IG9mIGZ1bmN0aW9uQ292LnJhbmdlcykge1xuICAgIHJhbmdlcy5wdXNoKGNsb25lUmFuZ2VDb3YocmFuZ2VDb3YpKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZnVuY3Rpb25OYW1lOiBmdW5jdGlvbkNvdi5mdW5jdGlvbk5hbWUsXG4gICAgcmFuZ2VzLFxuICAgIGlzQmxvY2tDb3ZlcmFnZTogZnVuY3Rpb25Db3YuaXNCbG9ja0NvdmVyYWdlLFxuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgYSBmdW5jdGlvbiBjb3ZlcmFnZS5cbiAqXG4gKiBAcGFyYW0gcmFuZ2VDb3YgUmFuZ2UgY292ZXJhZ2UgdG8gY2xvbmUuXG4gKiBAcmV0dXJuIENsb25lZCByYW5nZSBjb3ZlcmFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsb25lUmFuZ2VDb3YocmFuZ2VDb3Y6IFJlYWRvbmx5PFJhbmdlQ292Pik6IFJhbmdlQ292IHtcbiAgcmV0dXJuIHtcbiAgICBzdGFydE9mZnNldDogcmFuZ2VDb3Yuc3RhcnRPZmZzZXQsXG4gICAgZW5kT2Zmc2V0OiByYW5nZUNvdi5lbmRPZmZzZXQsXG4gICAgY291bnQ6IHJhbmdlQ292LmNvdW50LFxuICB9O1xufVxuIl0sInNvdXJjZVJvb3QiOiIifQ==

@ -0,0 +1,21 @@
import { FunctionCov, RangeCov, ScriptCov } from "./types";
/**
* Compares two script coverages.
*
* The result corresponds to the comparison of their `url` value (alphabetical sort).
*/
export declare function compareScriptCovs(a: Readonly<ScriptCov>, b: Readonly<ScriptCov>): number;
/**
* Compares two function coverages.
*
* The result corresponds to the comparison of the root ranges.
*/
export declare function compareFunctionCovs(a: Readonly<FunctionCov>, b: Readonly<FunctionCov>): number;
/**
* Compares two range coverages.
*
* The ranges are first ordered by ascending `startOffset` and then by
* descending `endOffset`.
* This corresponds to a pre-order tree traversal.
*/
export declare function compareRangeCovs(a: Readonly<RangeCov>, b: Readonly<RangeCov>): number;

@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Compares two script coverages.
*
* The result corresponds to the comparison of their `url` value (alphabetical sort).
*/
function compareScriptCovs(a, b) {
if (a.url === b.url) {
return 0;
}
else if (a.url < b.url) {
return -1;
}
else {
return 1;
}
}
exports.compareScriptCovs = compareScriptCovs;
/**
* Compares two function coverages.
*
* The result corresponds to the comparison of the root ranges.
*/
function compareFunctionCovs(a, b) {
return compareRangeCovs(a.ranges[0], b.ranges[0]);
}
exports.compareFunctionCovs = compareFunctionCovs;
/**
* Compares two range coverages.
*
* The ranges are first ordered by ascending `startOffset` and then by
* descending `endOffset`.
* This corresponds to a pre-order tree traversal.
*/
function compareRangeCovs(a, b) {
if (a.startOffset !== b.startOffset) {
return a.startOffset - b.startOffset;
}
else {
return b.endOffset - a.endOffset;
}
}
exports.compareRangeCovs = compareRangeCovs;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvY29tcGFyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUVBOzs7O0dBSUc7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxDQUFzQixFQUFFLENBQXNCO0lBQzlFLElBQUksQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFFO1FBQ25CLE9BQU8sQ0FBQyxDQUFDO0tBQ1Y7U0FBTSxJQUFJLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRTtRQUN4QixPQUFPLENBQUMsQ0FBQyxDQUFDO0tBQ1g7U0FBTTtRQUNMLE9BQU8sQ0FBQyxDQUFDO0tBQ1Y7QUFDSCxDQUFDO0FBUkQsOENBUUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQUMsQ0FBd0IsRUFBRSxDQUF3QjtJQUNwRixPQUFPLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3BELENBQUM7QUFGRCxrREFFQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLENBQXFCLEVBQUUsQ0FBcUI7SUFDM0UsSUFBSSxDQUFDLENBQUMsV0FBVyxLQUFLLENBQUMsQ0FBQyxXQUFXLEVBQUU7UUFDbkMsT0FBTyxDQUFDLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUM7S0FDdEM7U0FBTTtRQUNMLE9BQU8sQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDO0tBQ2xDO0FBQ0gsQ0FBQztBQU5ELDRDQU1DIiwiZmlsZSI6ImNvbXBhcmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGdW5jdGlvbkNvdiwgUmFuZ2VDb3YsIFNjcmlwdENvdiB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQ29tcGFyZXMgdHdvIHNjcmlwdCBjb3ZlcmFnZXMuXG4gKlxuICogVGhlIHJlc3VsdCBjb3JyZXNwb25kcyB0byB0aGUgY29tcGFyaXNvbiBvZiB0aGVpciBgdXJsYCB2YWx1ZSAoYWxwaGFiZXRpY2FsIHNvcnQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZVNjcmlwdENvdnMoYTogUmVhZG9ubHk8U2NyaXB0Q292PiwgYjogUmVhZG9ubHk8U2NyaXB0Q292Pik6IG51bWJlciB7XG4gIGlmIChhLnVybCA9PT0gYi51cmwpIHtcbiAgICByZXR1cm4gMDtcbiAgfSBlbHNlIGlmIChhLnVybCA8IGIudXJsKSB7XG4gICAgcmV0dXJuIC0xO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiAxO1xuICB9XG59XG5cbi8qKlxuICogQ29tcGFyZXMgdHdvIGZ1bmN0aW9uIGNvdmVyYWdlcy5cbiAqXG4gKiBUaGUgcmVzdWx0IGNvcnJlc3BvbmRzIHRvIHRoZSBjb21wYXJpc29uIG9mIHRoZSByb290IHJhbmdlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBhcmVGdW5jdGlvbkNvdnMoYTogUmVhZG9ubHk8RnVuY3Rpb25Db3Y+LCBiOiBSZWFkb25seTxGdW5jdGlvbkNvdj4pOiBudW1iZXIge1xuICByZXR1cm4gY29tcGFyZVJhbmdlQ292cyhhLnJhbmdlc1swXSwgYi5yYW5nZXNbMF0pO1xufVxuXG4vKipcbiAqIENvbXBhcmVzIHR3byByYW5nZSBjb3ZlcmFnZXMuXG4gKlxuICogVGhlIHJhbmdlcyBhcmUgZmlyc3Qgb3JkZXJlZCBieSBhc2NlbmRpbmcgYHN0YXJ0T2Zmc2V0YCBhbmQgdGhlbiBieVxuICogZGVzY2VuZGluZyBgZW5kT2Zmc2V0YC5cbiAqIFRoaXMgY29ycmVzcG9uZHMgdG8gYSBwcmUtb3JkZXIgdHJlZSB0cmF2ZXJzYWwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wYXJlUmFuZ2VDb3ZzKGE6IFJlYWRvbmx5PFJhbmdlQ292PiwgYjogUmVhZG9ubHk8UmFuZ2VDb3Y+KTogbnVtYmVyIHtcbiAgaWYgKGEuc3RhcnRPZmZzZXQgIT09IGIuc3RhcnRPZmZzZXQpIHtcbiAgICByZXR1cm4gYS5zdGFydE9mZnNldCAtIGIuc3RhcnRPZmZzZXQ7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGIuZW5kT2Zmc2V0IC0gYS5lbmRPZmZzZXQ7XG4gIH1cbn1cbiJdLCJzb3VyY2VSb290IjoiIn0=

@ -0,0 +1,41 @@
/**
* Compares two script coverages.
*
* The result corresponds to the comparison of their `url` value (alphabetical sort).
*/
export function compareScriptCovs(a, b) {
if (a.url === b.url) {
return 0;
}
else if (a.url < b.url) {
return -1;
}
else {
return 1;
}
}
/**
* Compares two function coverages.
*
* The result corresponds to the comparison of the root ranges.
*/
export function compareFunctionCovs(a, b) {
return compareRangeCovs(a.ranges[0], b.ranges[0]);
}
/**
* Compares two range coverages.
*
* The ranges are first ordered by ascending `startOffset` and then by
* descending `endOffset`.
* This corresponds to a pre-order tree traversal.
*/
export function compareRangeCovs(a, b) {
if (a.startOffset !== b.startOffset) {
return a.startOffset - b.startOffset;
}
else {
return b.endOffset - a.endOffset;
}
}
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvY29tcGFyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQTs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUFDLENBQXNCLEVBQUUsQ0FBc0I7SUFDOUUsSUFBSSxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUU7UUFDbkIsT0FBTyxDQUFDLENBQUM7S0FDVjtTQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFO1FBQ3hCLE9BQU8sQ0FBQyxDQUFDLENBQUM7S0FDWDtTQUFNO1FBQ0wsT0FBTyxDQUFDLENBQUM7S0FDVjtBQUNILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLENBQXdCLEVBQUUsQ0FBd0I7SUFDcEYsT0FBTyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNwRCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLENBQXFCLEVBQUUsQ0FBcUI7SUFDM0UsSUFBSSxDQUFDLENBQUMsV0FBVyxLQUFLLENBQUMsQ0FBQyxXQUFXLEVBQUU7UUFDbkMsT0FBTyxDQUFDLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUM7S0FDdEM7U0FBTTtRQUNMLE9BQU8sQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDO0tBQ2xDO0FBQ0gsQ0FBQyIsImZpbGUiOiJjb21wYXJlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRnVuY3Rpb25Db3YsIFJhbmdlQ292LCBTY3JpcHRDb3YgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIENvbXBhcmVzIHR3byBzY3JpcHQgY292ZXJhZ2VzLlxuICpcbiAqIFRoZSByZXN1bHQgY29ycmVzcG9uZHMgdG8gdGhlIGNvbXBhcmlzb24gb2YgdGhlaXIgYHVybGAgdmFsdWUgKGFscGhhYmV0aWNhbCBzb3J0KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBhcmVTY3JpcHRDb3ZzKGE6IFJlYWRvbmx5PFNjcmlwdENvdj4sIGI6IFJlYWRvbmx5PFNjcmlwdENvdj4pOiBudW1iZXIge1xuICBpZiAoYS51cmwgPT09IGIudXJsKSB7XG4gICAgcmV0dXJuIDA7XG4gIH0gZWxzZSBpZiAoYS51cmwgPCBiLnVybCkge1xuICAgIHJldHVybiAtMTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gMTtcbiAgfVxufVxuXG4vKipcbiAqIENvbXBhcmVzIHR3byBmdW5jdGlvbiBjb3ZlcmFnZXMuXG4gKlxuICogVGhlIHJlc3VsdCBjb3JyZXNwb25kcyB0byB0aGUgY29tcGFyaXNvbiBvZiB0aGUgcm9vdCByYW5nZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wYXJlRnVuY3Rpb25Db3ZzKGE6IFJlYWRvbmx5PEZ1bmN0aW9uQ292PiwgYjogUmVhZG9ubHk8RnVuY3Rpb25Db3Y+KTogbnVtYmVyIHtcbiAgcmV0dXJuIGNvbXBhcmVSYW5nZUNvdnMoYS5yYW5nZXNbMF0sIGIucmFuZ2VzWzBdKTtcbn1cblxuLyoqXG4gKiBDb21wYXJlcyB0d28gcmFuZ2UgY292ZXJhZ2VzLlxuICpcbiAqIFRoZSByYW5nZXMgYXJlIGZpcnN0IG9yZGVyZWQgYnkgYXNjZW5kaW5nIGBzdGFydE9mZnNldGAgYW5kIHRoZW4gYnlcbiAqIGRlc2NlbmRpbmcgYGVuZE9mZnNldGAuXG4gKiBUaGlzIGNvcnJlc3BvbmRzIHRvIGEgcHJlLW9yZGVyIHRyZWUgdHJhdmVyc2FsLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZVJhbmdlQ292cyhhOiBSZWFkb25seTxSYW5nZUNvdj4sIGI6IFJlYWRvbmx5PFJhbmdlQ292Pik6IG51bWJlciB7XG4gIGlmIChhLnN0YXJ0T2Zmc2V0ICE9PSBiLnN0YXJ0T2Zmc2V0KSB7XG4gICAgcmV0dXJuIGEuc3RhcnRPZmZzZXQgLSBiLnN0YXJ0T2Zmc2V0O1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBiLmVuZE9mZnNldCAtIGEuZW5kT2Zmc2V0O1xuICB9XG59XG4iXSwic291cmNlUm9vdCI6IiJ9

@ -0,0 +1,6 @@
export { emitForest, emitForestLines, parseFunctionRanges, parseOffsets } from "./ascii";
export { cloneFunctionCov, cloneProcessCov, cloneScriptCov, cloneRangeCov } from "./clone";
export { compareScriptCovs, compareFunctionCovs, compareRangeCovs } from "./compare";
export { mergeFunctionCovs, mergeProcessCovs, mergeScriptCovs } from "./merge";
export { RangeTree } from "./range-tree";
export { ProcessCov, ScriptCov, FunctionCov, RangeCov } from "./types";

@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ascii_1 = require("./ascii");
exports.emitForest = ascii_1.emitForest;
exports.emitForestLines = ascii_1.emitForestLines;
exports.parseFunctionRanges = ascii_1.parseFunctionRanges;
exports.parseOffsets = ascii_1.parseOffsets;
var clone_1 = require("./clone");
exports.cloneFunctionCov = clone_1.cloneFunctionCov;
exports.cloneProcessCov = clone_1.cloneProcessCov;
exports.cloneScriptCov = clone_1.cloneScriptCov;
exports.cloneRangeCov = clone_1.cloneRangeCov;
var compare_1 = require("./compare");
exports.compareScriptCovs = compare_1.compareScriptCovs;
exports.compareFunctionCovs = compare_1.compareFunctionCovs;
exports.compareRangeCovs = compare_1.compareRangeCovs;
var merge_1 = require("./merge");
exports.mergeFunctionCovs = merge_1.mergeFunctionCovs;
exports.mergeProcessCovs = merge_1.mergeProcessCovs;
exports.mergeScriptCovs = merge_1.mergeScriptCovs;
var range_tree_1 = require("./range-tree");
exports.RangeTree = range_tree_1.RangeTree;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxpQ0FBeUY7QUFBaEYsNkJBQUEsVUFBVSxDQUFBO0FBQUUsa0NBQUEsZUFBZSxDQUFBO0FBQUUsc0NBQUEsbUJBQW1CLENBQUE7QUFBRSwrQkFBQSxZQUFZLENBQUE7QUFDdkUsaUNBQTJGO0FBQWxGLG1DQUFBLGdCQUFnQixDQUFBO0FBQUUsa0NBQUEsZUFBZSxDQUFBO0FBQUUsaUNBQUEsY0FBYyxDQUFBO0FBQUUsZ0NBQUEsYUFBYSxDQUFBO0FBQ3pFLHFDQUFxRjtBQUE1RSxzQ0FBQSxpQkFBaUIsQ0FBQTtBQUFFLHdDQUFBLG1CQUFtQixDQUFBO0FBQUUscUNBQUEsZ0JBQWdCLENBQUE7QUFDakUsaUNBQStFO0FBQXRFLG9DQUFBLGlCQUFpQixDQUFBO0FBQUUsbUNBQUEsZ0JBQWdCLENBQUE7QUFBRSxrQ0FBQSxlQUFlLENBQUE7QUFDN0QsMkNBQXlDO0FBQWhDLGlDQUFBLFNBQVMsQ0FBQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IGVtaXRGb3Jlc3QsIGVtaXRGb3Jlc3RMaW5lcywgcGFyc2VGdW5jdGlvblJhbmdlcywgcGFyc2VPZmZzZXRzIH0gZnJvbSBcIi4vYXNjaWlcIjtcbmV4cG9ydCB7IGNsb25lRnVuY3Rpb25Db3YsIGNsb25lUHJvY2Vzc0NvdiwgY2xvbmVTY3JpcHRDb3YsIGNsb25lUmFuZ2VDb3YgfSBmcm9tIFwiLi9jbG9uZVwiO1xuZXhwb3J0IHsgY29tcGFyZVNjcmlwdENvdnMsIGNvbXBhcmVGdW5jdGlvbkNvdnMsIGNvbXBhcmVSYW5nZUNvdnMgfSBmcm9tIFwiLi9jb21wYXJlXCI7XG5leHBvcnQgeyBtZXJnZUZ1bmN0aW9uQ292cywgbWVyZ2VQcm9jZXNzQ292cywgbWVyZ2VTY3JpcHRDb3ZzIH0gZnJvbSBcIi4vbWVyZ2VcIjtcbmV4cG9ydCB7IFJhbmdlVHJlZSB9IGZyb20gXCIuL3JhbmdlLXRyZWVcIjtcbmV4cG9ydCB7IFByb2Nlc3NDb3YsIFNjcmlwdENvdiwgRnVuY3Rpb25Db3YsIFJhbmdlQ292IH0gZnJvbSBcIi4vdHlwZXNcIjtcbiJdLCJzb3VyY2VSb290IjoiIn0=

@ -0,0 +1,7 @@
export { emitForest, emitForestLines, parseFunctionRanges, parseOffsets } from "./ascii";
export { cloneFunctionCov, cloneProcessCov, cloneScriptCov, cloneRangeCov } from "./clone";
export { compareScriptCovs, compareFunctionCovs, compareRangeCovs } from "./compare";
export { mergeFunctionCovs, mergeProcessCovs, mergeScriptCovs } from "./merge";
export { RangeTree } from "./range-tree";
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxlQUFlLEVBQUUsbUJBQW1CLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUMzRixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsbUJBQW1CLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUMvRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sY0FBYyxDQUFDIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgZW1pdEZvcmVzdCwgZW1pdEZvcmVzdExpbmVzLCBwYXJzZUZ1bmN0aW9uUmFuZ2VzLCBwYXJzZU9mZnNldHMgfSBmcm9tIFwiLi9hc2NpaVwiO1xuZXhwb3J0IHsgY2xvbmVGdW5jdGlvbkNvdiwgY2xvbmVQcm9jZXNzQ292LCBjbG9uZVNjcmlwdENvdiwgY2xvbmVSYW5nZUNvdiB9IGZyb20gXCIuL2Nsb25lXCI7XG5leHBvcnQgeyBjb21wYXJlU2NyaXB0Q292cywgY29tcGFyZUZ1bmN0aW9uQ292cywgY29tcGFyZVJhbmdlQ292cyB9IGZyb20gXCIuL2NvbXBhcmVcIjtcbmV4cG9ydCB7IG1lcmdlRnVuY3Rpb25Db3ZzLCBtZXJnZVByb2Nlc3NDb3ZzLCBtZXJnZVNjcmlwdENvdnMgfSBmcm9tIFwiLi9tZXJnZVwiO1xuZXhwb3J0IHsgUmFuZ2VUcmVlIH0gZnJvbSBcIi4vcmFuZ2UtdHJlZVwiO1xuZXhwb3J0IHsgUHJvY2Vzc0NvdiwgU2NyaXB0Q292LCBGdW5jdGlvbkNvdiwgUmFuZ2VDb3YgfSBmcm9tIFwiLi90eXBlc1wiO1xuIl0sInNvdXJjZVJvb3QiOiIifQ==

@ -0,0 +1,39 @@
import { FunctionCov, ProcessCov, ScriptCov } from "./types";
/**
* Merges a list of process coverages.
*
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param processCovs Process coverages to merge.
* @return Merged process coverage.
*/
export declare function mergeProcessCovs(processCovs: ReadonlyArray<ProcessCov>): ProcessCov;
/**
* Merges a list of matching script coverages.
*
* Scripts are matching if they have the same `url`.
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param scriptCovs Process coverages to merge.
* @return Merged script coverage, or `undefined` if the input list was empty.
*/
export declare function mergeScriptCovs(scriptCovs: ReadonlyArray<ScriptCov>): ScriptCov | undefined;
/**
* Merges a list of matching function coverages.
*
* Functions are matching if their root ranges have the same span.
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param funcCovs Function coverages to merge.
* @return Merged function coverage, or `undefined` if the input list was empty.
*/
export declare function mergeFunctionCovs(funcCovs: ReadonlyArray<FunctionCov>): FunctionCov | undefined;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,53 @@
import { RangeTree } from "./range-tree";
import { FunctionCov, ProcessCov, ScriptCov } from "./types";
/**
* Normalizes a process coverage.
*
* Sorts the scripts alphabetically by `url`.
* Reassigns script ids: the script at index `0` receives `"0"`, the script at
* index `1` receives `"1"` etc.
* This does not normalize the script coverages.
*
* @param processCov Process coverage to normalize.
*/
export declare function normalizeProcessCov(processCov: ProcessCov): void;
/**
* Normalizes a process coverage deeply.
*
* Normalizes the script coverages deeply, then normalizes the process coverage
* itself.
*
* @param processCov Process coverage to normalize.
*/
export declare function deepNormalizeProcessCov(processCov: ProcessCov): void;
/**
* Normalizes a script coverage.
*
* Sorts the function by root range (pre-order sort).
* This does not normalize the function coverages.
*
* @param scriptCov Script coverage to normalize.
*/
export declare function normalizeScriptCov(scriptCov: ScriptCov): void;
/**
* Normalizes a script coverage deeply.
*
* Normalizes the function coverages deeply, then normalizes the script coverage
* itself.
*
* @param scriptCov Script coverage to normalize.
*/
export declare function deepNormalizeScriptCov(scriptCov: ScriptCov): void;
/**
* Normalizes a function coverage.
*
* Sorts the ranges (pre-order sort).
* TODO: Tree-based normalization of the ranges.
*
* @param funcCov Function coverage to normalize.
*/
export declare function normalizeFunctionCov(funcCov: FunctionCov): void;
/**
* @internal
*/
export declare function normalizeRangeTree(tree: RangeTree): void;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,44 @@
{
"name": "@bcoe/v8-coverage",
"version": "0.2.3",
"description": "Helper functions for V8 coverage files.",
"author": "Charles Samborski <demurgos@demurgos.net> (https://demurgos.net)",
"license": "MIT",
"main": "index",
"types": "index.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/demurgos/v8-coverage.git"
},
"homepage": "https://demurgos.github.io/v8-coverage",
"devDependencies": {
"@types/chai": "^4.1.4",
"@types/gulp": "^4.0.5",
"@types/minimist": "^1.2.0",
"@types/mocha": "^5.2.2",
"@types/node": "^10.5.4",
"chai": "^4.1.2",
"codecov": "^3.0.2",
"gulp": "^4.0.0",
"gulp-cli": "^2.0.1",
"minimist": "^1.2.0",
"pre-commit": "^1.2.2",
"ts-node": "^8.3.0",
"turbo-gulp": "^0.20.1"
},
"nyc": {
"include": [
"build/test/lib/**/*.js",
"build/test/lib/**/*.mjs"
],
"reporter": [
"text",
"html"
],
"extension": [
".mjs"
]
},
"gitHead": "529387e2bd3e0ba0b9336d80ec563aee593331e1",
"private": false
}

@ -0,0 +1,24 @@
import { RangeCov } from "./types";
export declare class RangeTree {
start: number;
end: number;
delta: number;
children: RangeTree[];
constructor(start: number, end: number, delta: number, children: RangeTree[]);
/**
* @precodition `ranges` are well-formed and pre-order sorted
*/
static fromSortedRanges(ranges: ReadonlyArray<RangeCov>): RangeTree | undefined;
normalize(): void;
/**
* @precondition `tree.start < value && value < tree.end`
* @return RangeTree Right part
*/
split(value: number): RangeTree;
/**
* Get the range coverages corresponding to the tree.
*
* The ranges are pre-order sorted.
*/
toRanges(): RangeCov[];
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,62 @@
{
"compilerOptions": {
"allowJs": false,
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"alwaysStrict": true,
"charset": "utf8",
"checkJs": false,
"declaration": true,
"disableSizeLimit": false,
"downlevelIteration": false,
"emitBOM": false,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"importHelpers": false,
"inlineSourceMap": false,
"inlineSources": false,
"isolatedModules": false,
"lib": [
"es2017",
"esnext.asynciterable"
],
"locale": "en-us",
"module": "commonjs",
"moduleResolution": "node",
"newLine": "lf",
"noEmit": false,
"noEmitHelpers": false,
"noEmitOnError": true,
"noErrorTruncation": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noStrictGenericChecks": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitUseStrict": false,
"noLib": false,
"noResolve": false,
"preserveConstEnums": true,
"removeComments": false,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictNullChecks": true,
"suppressExcessPropertyErrors": false,
"suppressImplicitAnyIndexErrors": false,
"target": "es2017",
"traceResolution": false,
"rootDir": "",
"outDir": "../../build/lib",
"typeRoots": []
},
"include": [
"**/*.ts"
],
"exclude": []
}

@ -0,0 +1,22 @@
export interface ProcessCov {
result: ScriptCov[];
}
export interface ScriptCov {
scriptId: string;
url: string;
functions: FunctionCov[];
}
export interface FunctionCov {
functionName: string;
ranges: RangeCov[];
isBlockCoverage: boolean;
}
export interface Range {
readonly start: number;
readonly end: number;
}
export interface RangeCov {
startOffset: number;
endOffset: number;
count: number;
}

@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJ0eXBlcy5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBpbnRlcmZhY2UgUHJvY2Vzc0NvdiB7XG4gIHJlc3VsdDogU2NyaXB0Q292W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NyaXB0Q292IHtcbiAgc2NyaXB0SWQ6IHN0cmluZztcbiAgdXJsOiBzdHJpbmc7XG4gIGZ1bmN0aW9uczogRnVuY3Rpb25Db3ZbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGdW5jdGlvbkNvdiB7XG4gIGZ1bmN0aW9uTmFtZTogc3RyaW5nO1xuICByYW5nZXM6IFJhbmdlQ292W107XG4gIGlzQmxvY2tDb3ZlcmFnZTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSYW5nZSB7XG4gIHJlYWRvbmx5IHN0YXJ0OiBudW1iZXI7XG4gIHJlYWRvbmx5IGVuZDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJhbmdlQ292IHtcbiAgc3RhcnRPZmZzZXQ6IG51bWJlcjtcbiAgZW5kT2Zmc2V0OiBudW1iZXI7XG4gIGNvdW50OiBudW1iZXI7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9

@ -0,0 +1,3 @@
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJ0eXBlcy5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBpbnRlcmZhY2UgUHJvY2Vzc0NvdiB7XG4gIHJlc3VsdDogU2NyaXB0Q292W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NyaXB0Q292IHtcbiAgc2NyaXB0SWQ6IHN0cmluZztcbiAgdXJsOiBzdHJpbmc7XG4gIGZ1bmN0aW9uczogRnVuY3Rpb25Db3ZbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGdW5jdGlvbkNvdiB7XG4gIGZ1bmN0aW9uTmFtZTogc3RyaW5nO1xuICByYW5nZXM6IFJhbmdlQ292W107XG4gIGlzQmxvY2tDb3ZlcmFnZTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSYW5nZSB7XG4gIHJlYWRvbmx5IHN0YXJ0OiBudW1iZXI7XG4gIHJlYWRvbmx5IGVuZDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJhbmdlQ292IHtcbiAgc3RhcnRPZmZzZXQ6IG51bWJlcjtcbiAgZW5kT2Zmc2V0OiBudW1iZXI7XG4gIGNvdW50OiBudW1iZXI7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9

@ -0,0 +1,95 @@
import * as buildTools from "turbo-gulp";
import { LibTarget, registerLibTasks } from "turbo-gulp/targets/lib";
import { MochaTarget, registerMochaTasks } from "turbo-gulp/targets/mocha";
import gulp from "gulp";
import minimist from "minimist";
interface Options {
devDist?: string;
}
const options: Options & minimist.ParsedArgs = minimist(process.argv.slice(2), {
string: ["devDist"],
default: {devDist: undefined},
alias: {devDist: "dev-dist"},
});
const project: buildTools.Project = {
root: __dirname,
packageJson: "package.json",
buildDir: "build",
distDir: "dist",
srcDir: "src",
typescript: {}
};
const lib: LibTarget = {
project,
name: "lib",
srcDir: "src/lib",
scripts: ["**/*.ts"],
mainModule: "index",
dist: {
packageJsonMap: (old: buildTools.PackageJson): buildTools.PackageJson => {
const version: string = options.devDist !== undefined ? `${old.version}-build.${options.devDist}` : old.version;
return <any> {...old, version, scripts: undefined, private: false};
},
npmPublish: {
tag: options.devDist !== undefined ? "next" : "latest",
},
},
tscOptions: {
declaration: true,
skipLibCheck: true,
},
typedoc: {
dir: "typedoc",
name: "Helpers for V8 coverage files",
deploy: {
repository: "git@github.com:demurgos/v8-coverage.git",
branch: "gh-pages",
},
},
copy: [
{
files: ["**/*.json"],
},
],
clean: {
dirs: ["build/lib", "dist/lib"],
},
};
const test: MochaTarget = {
project,
name: "test",
srcDir: "src",
scripts: ["test/**/*.ts", "lib/**/*.ts", "e2e/*/*.ts"],
customTypingsDir: "src/custom-typings",
tscOptions: {
allowSyntheticDefaultImports: true,
esModuleInterop: true,
skipLibCheck: true,
},
// generateTestMain: true,
copy: [
{
src: "e2e",
// <project-name>/(project|test-resources)/<any>
files: ["*/project/**/*", "*/test-resources/**/*"],
dest: "e2e",
},
],
clean: {
dirs: ["build/test"],
},
};
const libTasks: any = registerLibTasks(gulp, lib);
registerMochaTasks(gulp, test);
buildTools.projectTasks.registerAll(gulp, project);
gulp.task("all:tsconfig.json", gulp.parallel("lib:tsconfig.json", "test:tsconfig.json"));
gulp.task("dist", libTasks.dist);
gulp.task("default", libTasks.dist);

@ -0,0 +1,48 @@
{
"name": "@bcoe/v8-coverage",
"version": "0.2.3",
"description": "Helper functions for V8 coverage files.",
"author": "Charles Samborski <demurgos@demurgos.net> (https://demurgos.net)",
"license": "MIT",
"main": "dist/lib/index",
"types": "dist/lib/index.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/demurgos/v8-coverage.git"
},
"homepage": "https://demurgos.github.io/v8-coverage",
"scripts": {
"prepare": "gulp all:tsconfig.json && gulp dist",
"pretest": "gulp lib:build",
"test": "gulp test",
"lint": "gulp :lint:fix"
},
"devDependencies": {
"@types/chai": "^4.1.4",
"@types/gulp": "^4.0.5",
"@types/minimist": "^1.2.0",
"@types/mocha": "^5.2.2",
"@types/node": "^10.5.4",
"chai": "^4.1.2",
"codecov": "^3.0.2",
"gulp": "^4.0.0",
"gulp-cli": "^2.0.1",
"minimist": "^1.2.0",
"pre-commit": "^1.2.2",
"ts-node": "^8.3.0",
"turbo-gulp": "^0.20.1"
},
"nyc": {
"include": [
"build/test/lib/**/*.js",
"build/test/lib/**/*.mjs"
],
"reporter": [
"text",
"html"
],
"extension": [
".mjs"
]
}
}

@ -0,0 +1,146 @@
import { compareRangeCovs } from "./compare";
import { RangeCov } from "./types";
interface ReadonlyRangeTree {
readonly start: number;
readonly end: number;
readonly count: number;
readonly children: ReadonlyRangeTree[];
}
export function emitForest(trees: ReadonlyArray<ReadonlyRangeTree>): string {
return emitForestLines(trees).join("\n");
}
export function emitForestLines(trees: ReadonlyArray<ReadonlyRangeTree>): string[] {
const colMap: Map<number, number> = getColMap(trees);
const header: string = emitOffsets(colMap);
return [header, ...trees.map(tree => emitTree(tree, colMap).join("\n"))];
}
function getColMap(trees: Iterable<ReadonlyRangeTree>): Map<number, number> {
const eventSet: Set<number> = new Set();
for (const tree of trees) {
const stack: ReadonlyRangeTree[] = [tree];
while (stack.length > 0) {
const cur: ReadonlyRangeTree = stack.pop()!;
eventSet.add(cur.start);
eventSet.add(cur.end);
for (const child of cur.children) {
stack.push(child);
}
}
}
const events: number[] = [...eventSet];
events.sort((a, b) => a - b);
let maxDigits: number = 1;
for (const event of events) {
maxDigits = Math.max(maxDigits, event.toString(10).length);
}
const colWidth: number = maxDigits + 3;
const colMap: Map<number, number> = new Map();
for (const [i, event] of events.entries()) {
colMap.set(event, i * colWidth);
}
return colMap;
}
function emitTree(tree: ReadonlyRangeTree, colMap: Map<number, number>): string[] {
const layers: ReadonlyRangeTree[][] = [];
let nextLayer: ReadonlyRangeTree[] = [tree];
while (nextLayer.length > 0) {
const layer: ReadonlyRangeTree[] = nextLayer;
layers.push(layer);
nextLayer = [];
for (const node of layer) {
for (const child of node.children) {
nextLayer.push(child);
}
}
}
return layers.map(layer => emitTreeLayer(layer, colMap));
}
export function parseFunctionRanges(text: string, offsetMap: Map<number, number>): RangeCov[] {
const result: RangeCov[] = [];
for (const line of text.split("\n")) {
for (const range of parseTreeLayer(line, offsetMap)) {
result.push(range);
}
}
result.sort(compareRangeCovs);
return result;
}
/**
*
* @param layer Sorted list of disjoint trees.
* @param colMap
*/
function emitTreeLayer(layer: ReadonlyRangeTree[], colMap: Map<number, number>): string {
const line: string[] = [];
let curIdx: number = 0;
for (const {start, end, count} of layer) {
const startIdx: number = colMap.get(start)!;
const endIdx: number = colMap.get(end)!;
if (startIdx > curIdx) {
line.push(" ".repeat(startIdx - curIdx));
}
line.push(emitRange(count, endIdx - startIdx));
curIdx = endIdx;
}
return line.join("");
}
function parseTreeLayer(text: string, offsetMap: Map<number, number>): RangeCov[] {
const result: RangeCov[] = [];
const regex: RegExp = /\[(\d+)-*\)/gs;
while (true) {
const match: RegExpMatchArray | null = regex.exec(text);
if (match === null) {
break;
}
const startIdx: number = match.index!;
const endIdx: number = startIdx + match[0].length;
const count: number = parseInt(match[1], 10);
const startOffset: number | undefined = offsetMap.get(startIdx);
const endOffset: number | undefined = offsetMap.get(endIdx);
if (startOffset === undefined || endOffset === undefined) {
throw new Error(`Invalid offsets for: ${JSON.stringify(text)}`);
}
result.push({startOffset, endOffset, count});
}
return result;
}
function emitRange(count: number, len: number): string {
const rangeStart: string = `[${count.toString(10)}`;
const rangeEnd: string = ")";
const hyphensLen: number = len - (rangeStart.length + rangeEnd.length);
const hyphens: string = "-".repeat(Math.max(0, hyphensLen));
return `${rangeStart}${hyphens}${rangeEnd}`;
}
function emitOffsets(colMap: Map<number, number>): string {
let line: string = "";
for (const [event, col] of colMap) {
if (line.length < col) {
line += " ".repeat(col - line.length);
}
line += event.toString(10);
}
return line;
}
export function parseOffsets(text: string): Map<number, number> {
const result: Map<number, number> = new Map();
const regex: RegExp = /\d+/gs;
while (true) {
const match: RegExpExecArray | null = regex.exec(text);
if (match === null) {
break;
}
result.set(match.index, parseInt(match[0], 10));
}
return result;
}

@ -0,0 +1,70 @@
import { FunctionCov, ProcessCov, RangeCov, ScriptCov } from "./types";
/**
* Creates a deep copy of a process coverage.
*
* @param processCov Process coverage to clone.
* @return Cloned process coverage.
*/
export function cloneProcessCov(processCov: Readonly<ProcessCov>): ProcessCov {
const result: ScriptCov[] = [];
for (const scriptCov of processCov.result) {
result.push(cloneScriptCov(scriptCov));
}
return {
result,
};
}
/**
* Creates a deep copy of a script coverage.
*
* @param scriptCov Script coverage to clone.
* @return Cloned script coverage.
*/
export function cloneScriptCov(scriptCov: Readonly<ScriptCov>): ScriptCov {
const functions: FunctionCov[] = [];
for (const functionCov of scriptCov.functions) {
functions.push(cloneFunctionCov(functionCov));
}
return {
scriptId: scriptCov.scriptId,
url: scriptCov.url,
functions,
};
}
/**
* Creates a deep copy of a function coverage.
*
* @param functionCov Function coverage to clone.
* @return Cloned function coverage.
*/
export function cloneFunctionCov(functionCov: Readonly<FunctionCov>): FunctionCov {
const ranges: RangeCov[] = [];
for (const rangeCov of functionCov.ranges) {
ranges.push(cloneRangeCov(rangeCov));
}
return {
functionName: functionCov.functionName,
ranges,
isBlockCoverage: functionCov.isBlockCoverage,
};
}
/**
* Creates a deep copy of a function coverage.
*
* @param rangeCov Range coverage to clone.
* @return Cloned range coverage.
*/
export function cloneRangeCov(rangeCov: Readonly<RangeCov>): RangeCov {
return {
startOffset: rangeCov.startOffset,
endOffset: rangeCov.endOffset,
count: rangeCov.count,
};
}

@ -0,0 +1,40 @@
import { FunctionCov, RangeCov, ScriptCov } from "./types";
/**
* Compares two script coverages.
*
* The result corresponds to the comparison of their `url` value (alphabetical sort).
*/
export function compareScriptCovs(a: Readonly<ScriptCov>, b: Readonly<ScriptCov>): number {
if (a.url === b.url) {
return 0;
} else if (a.url < b.url) {
return -1;
} else {
return 1;
}
}
/**
* Compares two function coverages.
*
* The result corresponds to the comparison of the root ranges.
*/
export function compareFunctionCovs(a: Readonly<FunctionCov>, b: Readonly<FunctionCov>): number {
return compareRangeCovs(a.ranges[0], b.ranges[0]);
}
/**
* Compares two range coverages.
*
* The ranges are first ordered by ascending `startOffset` and then by
* descending `endOffset`.
* This corresponds to a pre-order tree traversal.
*/
export function compareRangeCovs(a: Readonly<RangeCov>, b: Readonly<RangeCov>): number {
if (a.startOffset !== b.startOffset) {
return a.startOffset - b.startOffset;
} else {
return b.endOffset - a.endOffset;
}
}

@ -0,0 +1,6 @@
export { emitForest, emitForestLines, parseFunctionRanges, parseOffsets } from "./ascii";
export { cloneFunctionCov, cloneProcessCov, cloneScriptCov, cloneRangeCov } from "./clone";
export { compareScriptCovs, compareFunctionCovs, compareRangeCovs } from "./compare";
export { mergeFunctionCovs, mergeProcessCovs, mergeScriptCovs } from "./merge";
export { RangeTree } from "./range-tree";
export { ProcessCov, ScriptCov, FunctionCov, RangeCov } from "./types";

@ -0,0 +1,343 @@
import {
deepNormalizeScriptCov,
normalizeFunctionCov,
normalizeProcessCov,
normalizeRangeTree,
normalizeScriptCov,
} from "./normalize";
import { RangeTree } from "./range-tree";
import { FunctionCov, ProcessCov, Range, RangeCov, ScriptCov } from "./types";
/**
* Merges a list of process coverages.
*
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param processCovs Process coverages to merge.
* @return Merged process coverage.
*/
export function mergeProcessCovs(processCovs: ReadonlyArray<ProcessCov>): ProcessCov {
if (processCovs.length === 0) {
return {result: []};
}
const urlToScripts: Map<string, ScriptCov[]> = new Map();
for (const processCov of processCovs) {
for (const scriptCov of processCov.result) {
let scriptCovs: ScriptCov[] | undefined = urlToScripts.get(scriptCov.url);
if (scriptCovs === undefined) {
scriptCovs = [];
urlToScripts.set(scriptCov.url, scriptCovs);
}
scriptCovs.push(scriptCov);
}
}
const result: ScriptCov[] = [];
for (const scripts of urlToScripts.values()) {
// assert: `scripts.length > 0`
result.push(mergeScriptCovs(scripts)!);
}
const merged: ProcessCov = {result};
normalizeProcessCov(merged);
return merged;
}
/**
* Merges a list of matching script coverages.
*
* Scripts are matching if they have the same `url`.
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param scriptCovs Process coverages to merge.
* @return Merged script coverage, or `undefined` if the input list was empty.
*/
export function mergeScriptCovs(scriptCovs: ReadonlyArray<ScriptCov>): ScriptCov | undefined {
if (scriptCovs.length === 0) {
return undefined;
} else if (scriptCovs.length === 1) {
const merged: ScriptCov = scriptCovs[0];
deepNormalizeScriptCov(merged);
return merged;
}
const first: ScriptCov = scriptCovs[0];
const scriptId: string = first.scriptId;
const url: string = first.url;
const rangeToFuncs: Map<string, FunctionCov[]> = new Map();
for (const scriptCov of scriptCovs) {
for (const funcCov of scriptCov.functions) {
const rootRange: string = stringifyFunctionRootRange(funcCov);
let funcCovs: FunctionCov[] | undefined = rangeToFuncs.get(rootRange);
if (funcCovs === undefined ||
// if the entry in rangeToFuncs is function-level granularity and
// the new coverage is block-level, prefer block-level.
(!funcCovs[0].isBlockCoverage && funcCov.isBlockCoverage)) {
funcCovs = [];
rangeToFuncs.set(rootRange, funcCovs);
} else if (funcCovs[0].isBlockCoverage && !funcCov.isBlockCoverage) {
// if the entry in rangeToFuncs is block-level granularity, we should
// not append function level granularity.
continue;
}
funcCovs.push(funcCov);
}
}
const functions: FunctionCov[] = [];
for (const funcCovs of rangeToFuncs.values()) {
// assert: `funcCovs.length > 0`
functions.push(mergeFunctionCovs(funcCovs)!);
}
const merged: ScriptCov = {scriptId, url, functions};
normalizeScriptCov(merged);
return merged;
}
/**
* Returns a string representation of the root range of the function.
*
* This string can be used to match function with same root range.
* The string is derived from the start and end offsets of the root range of
* the function.
* This assumes that `ranges` is non-empty (true for valid function coverages).
*
* @param funcCov Function coverage with the range to stringify
* @internal
*/
function stringifyFunctionRootRange(funcCov: Readonly<FunctionCov>): string {
const rootRange: RangeCov = funcCov.ranges[0];
return `${rootRange.startOffset.toString(10)};${rootRange.endOffset.toString(10)}`;
}
/**
* Merges a list of matching function coverages.
*
* Functions are matching if their root ranges have the same span.
* The result is normalized.
* The input values may be mutated, it is not safe to use them after passing
* them to this function.
* The computation is synchronous.
*
* @param funcCovs Function coverages to merge.
* @return Merged function coverage, or `undefined` if the input list was empty.
*/
export function mergeFunctionCovs(funcCovs: ReadonlyArray<FunctionCov>): FunctionCov | undefined {
if (funcCovs.length === 0) {
return undefined;
} else if (funcCovs.length === 1) {
const merged: FunctionCov = funcCovs[0];
normalizeFunctionCov(merged);
return merged;
}
const functionName: string = funcCovs[0].functionName;
const trees: RangeTree[] = [];
for (const funcCov of funcCovs) {
// assert: `fn.ranges.length > 0`
// assert: `fn.ranges` is sorted
trees.push(RangeTree.fromSortedRanges(funcCov.ranges)!);
}
// assert: `trees.length > 0`
const mergedTree: RangeTree = mergeRangeTrees(trees)!;
normalizeRangeTree(mergedTree);
const ranges: RangeCov[] = mergedTree.toRanges();
const isBlockCoverage: boolean = !(ranges.length === 1 && ranges[0].count === 0);
const merged: FunctionCov = {functionName, ranges, isBlockCoverage};
// assert: `merged` is normalized
return merged;
}
/**
* @precondition Same `start` and `end` for all the trees
*/
function mergeRangeTrees(trees: ReadonlyArray<RangeTree>): RangeTree | undefined {
if (trees.length <= 1) {
return trees[0];
}
const first: RangeTree = trees[0];
let delta: number = 0;
for (const tree of trees) {
delta += tree.delta;
}
const children: RangeTree[] = mergeRangeTreeChildren(trees);
return new RangeTree(first.start, first.end, delta, children);
}
class RangeTreeWithParent {
readonly parentIndex: number;
readonly tree: RangeTree;
constructor(parentIndex: number, tree: RangeTree) {
this.parentIndex = parentIndex;
this.tree = tree;
}
}
class StartEvent {
readonly offset: number;
readonly trees: RangeTreeWithParent[];
constructor(offset: number, trees: RangeTreeWithParent[]) {
this.offset = offset;
this.trees = trees;
}
static compare(a: StartEvent, b: StartEvent): number {
return a.offset - b.offset;
}
}
class StartEventQueue {
private readonly queue: StartEvent[];
private nextIndex: number;
private pendingOffset: number;
private pendingTrees: RangeTreeWithParent[] | undefined;
private constructor(queue: StartEvent[]) {
this.queue = queue;
this.nextIndex = 0;
this.pendingOffset = 0;
this.pendingTrees = undefined;
}
static fromParentTrees(parentTrees: ReadonlyArray<RangeTree>): StartEventQueue {
const startToTrees: Map<number, RangeTreeWithParent[]> = new Map();
for (const [parentIndex, parentTree] of parentTrees.entries()) {
for (const child of parentTree.children) {
let trees: RangeTreeWithParent[] | undefined = startToTrees.get(child.start);
if (trees === undefined) {
trees = [];
startToTrees.set(child.start, trees);
}
trees.push(new RangeTreeWithParent(parentIndex, child));
}
}
const queue: StartEvent[] = [];
for (const [startOffset, trees] of startToTrees) {
queue.push(new StartEvent(startOffset, trees));
}
queue.sort(StartEvent.compare);
return new StartEventQueue(queue);
}
setPendingOffset(offset: number): void {
this.pendingOffset = offset;
}
pushPendingTree(tree: RangeTreeWithParent): void {
if (this.pendingTrees === undefined) {
this.pendingTrees = [];
}
this.pendingTrees.push(tree);
}
next(): StartEvent | undefined {
const pendingTrees: RangeTreeWithParent[] | undefined = this.pendingTrees;
const nextEvent: StartEvent | undefined = this.queue[this.nextIndex];
if (pendingTrees === undefined) {
this.nextIndex++;
return nextEvent;
} else if (nextEvent === undefined) {
this.pendingTrees = undefined;
return new StartEvent(this.pendingOffset, pendingTrees);
} else {
if (this.pendingOffset < nextEvent.offset) {
this.pendingTrees = undefined;
return new StartEvent(this.pendingOffset, pendingTrees);
} else {
if (this.pendingOffset === nextEvent.offset) {
this.pendingTrees = undefined;
for (const tree of pendingTrees) {
nextEvent.trees.push(tree);
}
}
this.nextIndex++;
return nextEvent;
}
}
}
}
function mergeRangeTreeChildren(parentTrees: ReadonlyArray<RangeTree>): RangeTree[] {
const result: RangeTree[] = [];
const startEventQueue: StartEventQueue = StartEventQueue.fromParentTrees(parentTrees);
const parentToNested: Map<number, RangeTree[]> = new Map();
let openRange: Range | undefined;
while (true) {
const event: StartEvent | undefined = startEventQueue.next();
if (event === undefined) {
break;
}
if (openRange !== undefined && openRange.end <= event.offset) {
result.push(nextChild(openRange, parentToNested));
openRange = undefined;
}
if (openRange === undefined) {
let openRangeEnd: number = event.offset + 1;
for (const {parentIndex, tree} of event.trees) {
openRangeEnd = Math.max(openRangeEnd, tree.end);
insertChild(parentToNested, parentIndex, tree);
}
startEventQueue.setPendingOffset(openRangeEnd);
openRange = {start: event.offset, end: openRangeEnd};
} else {
for (const {parentIndex, tree} of event.trees) {
if (tree.end > openRange.end) {
const right: RangeTree = tree.split(openRange.end);
startEventQueue.pushPendingTree(new RangeTreeWithParent(parentIndex, right));
}
insertChild(parentToNested, parentIndex, tree);
}
}
}
if (openRange !== undefined) {
result.push(nextChild(openRange, parentToNested));
}
return result;
}
function insertChild(parentToNested: Map<number, RangeTree[]>, parentIndex: number, tree: RangeTree): void {
let nested: RangeTree[] | undefined = parentToNested.get(parentIndex);
if (nested === undefined) {
nested = [];
parentToNested.set(parentIndex, nested);
}
nested.push(tree);
}
function nextChild(openRange: Range, parentToNested: Map<number, RangeTree[]>): RangeTree {
const matchingTrees: RangeTree[] = [];
for (const nested of parentToNested.values()) {
if (nested.length === 1 && nested[0].start === openRange.start && nested[0].end === openRange.end) {
matchingTrees.push(nested[0]);
} else {
matchingTrees.push(new RangeTree(
openRange.start,
openRange.end,
0,
nested,
));
}
}
parentToNested.clear();
return mergeRangeTrees(matchingTrees)!;
}

@ -0,0 +1,84 @@
import { compareFunctionCovs, compareRangeCovs, compareScriptCovs } from "./compare";
import { RangeTree } from "./range-tree";
import { FunctionCov, ProcessCov, ScriptCov } from "./types";
/**
* Normalizes a process coverage.
*
* Sorts the scripts alphabetically by `url`.
* Reassigns script ids: the script at index `0` receives `"0"`, the script at
* index `1` receives `"1"` etc.
* This does not normalize the script coverages.
*
* @param processCov Process coverage to normalize.
*/
export function normalizeProcessCov(processCov: ProcessCov): void {
processCov.result.sort(compareScriptCovs);
for (const [scriptId, scriptCov] of processCov.result.entries()) {
scriptCov.scriptId = scriptId.toString(10);
}
}
/**
* Normalizes a process coverage deeply.
*
* Normalizes the script coverages deeply, then normalizes the process coverage
* itself.
*
* @param processCov Process coverage to normalize.
*/
export function deepNormalizeProcessCov(processCov: ProcessCov): void {
for (const scriptCov of processCov.result) {
deepNormalizeScriptCov(scriptCov);
}
normalizeProcessCov(processCov);
}
/**
* Normalizes a script coverage.
*
* Sorts the function by root range (pre-order sort).
* This does not normalize the function coverages.
*
* @param scriptCov Script coverage to normalize.
*/
export function normalizeScriptCov(scriptCov: ScriptCov): void {
scriptCov.functions.sort(compareFunctionCovs);
}
/**
* Normalizes a script coverage deeply.
*
* Normalizes the function coverages deeply, then normalizes the script coverage
* itself.
*
* @param scriptCov Script coverage to normalize.
*/
export function deepNormalizeScriptCov(scriptCov: ScriptCov): void {
for (const funcCov of scriptCov.functions) {
normalizeFunctionCov(funcCov);
}
normalizeScriptCov(scriptCov);
}
/**
* Normalizes a function coverage.
*
* Sorts the ranges (pre-order sort).
* TODO: Tree-based normalization of the ranges.
*
* @param funcCov Function coverage to normalize.
*/
export function normalizeFunctionCov(funcCov: FunctionCov): void {
funcCov.ranges.sort(compareRangeCovs);
const tree: RangeTree = RangeTree.fromSortedRanges(funcCov.ranges)!;
normalizeRangeTree(tree);
funcCov.ranges = tree.toRanges();
}
/**
* @internal
*/
export function normalizeRangeTree(tree: RangeTree): void {
tree.normalize();
}

@ -0,0 +1,156 @@
import { RangeCov } from "./types";
export class RangeTree {
start: number;
end: number;
delta: number;
children: RangeTree[];
constructor(
start: number,
end: number,
delta: number,
children: RangeTree[],
) {
this.start = start;
this.end = end;
this.delta = delta;
this.children = children;
}
/**
* @precodition `ranges` are well-formed and pre-order sorted
*/
static fromSortedRanges(ranges: ReadonlyArray<RangeCov>): RangeTree | undefined {
let root: RangeTree | undefined;
// Stack of parent trees and parent counts.
const stack: [RangeTree, number][] = [];
for (const range of ranges) {
const node: RangeTree = new RangeTree(range.startOffset, range.endOffset, range.count, []);
if (root === undefined) {
root = node;
stack.push([node, range.count]);
continue;
}
let parent: RangeTree;
let parentCount: number;
while (true) {
[parent, parentCount] = stack[stack.length - 1];
// assert: `top !== undefined` (the ranges are sorted)
if (range.startOffset < parent.end) {
break;
} else {
stack.pop();
}
}
node.delta -= parentCount;
parent.children.push(node);
stack.push([node, range.count]);
}
return root;
}
normalize(): void {
const children: RangeTree[] = [];
let curEnd: number;
let head: RangeTree | undefined;
const tail: RangeTree[] = [];
for (const child of this.children) {
if (head === undefined) {
head = child;
} else if (child.delta === head.delta && child.start === curEnd!) {
tail.push(child);
} else {
endChain();
head = child;
}
curEnd = child.end;
}
if (head !== undefined) {
endChain();
}
if (children.length === 1) {
const child: RangeTree = children[0];
if (child.start === this.start && child.end === this.end) {
this.delta += child.delta;
this.children = child.children;
// `.lazyCount` is zero for both (both are after normalization)
return;
}
}
this.children = children;
function endChain(): void {
if (tail.length !== 0) {
head!.end = tail[tail.length - 1].end;
for (const tailTree of tail) {
for (const subChild of tailTree.children) {
subChild.delta += tailTree.delta - head!.delta;
head!.children.push(subChild);
}
}
tail.length = 0;
}
head!.normalize();
children.push(head!);
}
}
/**
* @precondition `tree.start < value && value < tree.end`
* @return RangeTree Right part
*/
split(value: number): RangeTree {
let leftChildLen: number = this.children.length;
let mid: RangeTree | undefined;
// TODO(perf): Binary search (check overhead)
for (let i: number = 0; i < this.children.length; i++) {
const child: RangeTree = this.children[i];
if (child.start < value && value < child.end) {
mid = child.split(value);
leftChildLen = i + 1;
break;
} else if (child.start >= value) {
leftChildLen = i;
break;
}
}
const rightLen: number = this.children.length - leftChildLen;
const rightChildren: RangeTree[] = this.children.splice(leftChildLen, rightLen);
if (mid !== undefined) {
rightChildren.unshift(mid);
}
const result: RangeTree = new RangeTree(
value,
this.end,
this.delta,
rightChildren,
);
this.end = value;
return result;
}
/**
* Get the range coverages corresponding to the tree.
*
* The ranges are pre-order sorted.
*/
toRanges(): RangeCov[] {
const ranges: RangeCov[] = [];
// Stack of parent trees and counts.
const stack: [RangeTree, number][] = [[this, 0]];
while (stack.length > 0) {
const [cur, parentCount]: [RangeTree, number] = stack.pop()!;
const count: number = parentCount + cur.delta;
ranges.push({startOffset: cur.start, endOffset: cur.end, count});
for (let i: number = cur.children.length - 1; i >= 0; i--) {
stack.push([cur.children[i], count]);
}
}
return ranges;
}
}

@ -0,0 +1,26 @@
export interface ProcessCov {
result: ScriptCov[];
}
export interface ScriptCov {
scriptId: string;
url: string;
functions: FunctionCov[];
}
export interface FunctionCov {
functionName: string;
ranges: RangeCov[];
isBlockCoverage: boolean;
}
export interface Range {
readonly start: number;
readonly end: number;
}
export interface RangeCov {
startOffset: number;
endOffset: number;
count: number;
}

@ -0,0 +1,280 @@
import chai from "chai";
import fs from "fs";
import path from "path";
import { FunctionCov, mergeFunctionCovs, mergeProcessCovs, mergeScriptCovs, ProcessCov, ScriptCov } from "../lib";
const REPO_ROOT: string = path.join(__dirname, "..", "..", "..", "..");
const BENCHES_INPUT_DIR: string = path.join(REPO_ROOT, "benches");
const BENCHES_DIR: string = path.join(REPO_ROOT, "test-data", "merge", "benches");
const RANGES_DIR: string = path.join(REPO_ROOT, "test-data", "merge", "ranges");
const BENCHES_TIMEOUT: number = 20000; // 20sec
interface MergeRangeItem {
name: string;
status: "run" | "skip" | "only";
inputs: ProcessCov[];
expected: ProcessCov;
}
const FIXTURES_DIR: string = path.join(REPO_ROOT, "test-data", "bugs");
function loadFixture(name: string) {
const content: string = fs.readFileSync(
path.resolve(FIXTURES_DIR, `${name}.json`),
{encoding: "UTF-8"},
);
return JSON.parse(content);
}
describe("merge", () => {
describe("Various", () => {
it("accepts empty arrays for `mergeProcessCovs`", () => {
const inputs: ProcessCov[] = [];
const expected: ProcessCov = {result: []};
const actual: ProcessCov = mergeProcessCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
it("accepts empty arrays for `mergeScriptCovs`", () => {
const inputs: ScriptCov[] = [];
const expected: ScriptCov | undefined = undefined;
const actual: ScriptCov | undefined = mergeScriptCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
it("accepts empty arrays for `mergeFunctionCovs`", () => {
const inputs: FunctionCov[] = [];
const expected: FunctionCov | undefined = undefined;
const actual: FunctionCov | undefined = mergeFunctionCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
it("accepts arrays with a single item for `mergeProcessCovs`", () => {
const inputs: ProcessCov[] = [
{
result: [
{
scriptId: "123",
url: "/lib.js",
functions: [
{
functionName: "test",
isBlockCoverage: true,
ranges: [
{startOffset: 0, endOffset: 4, count: 2},
{startOffset: 1, endOffset: 2, count: 1},
{startOffset: 2, endOffset: 3, count: 1},
],
},
],
},
],
},
];
const expected: ProcessCov = {
result: [
{
scriptId: "0",
url: "/lib.js",
functions: [
{
functionName: "test",
isBlockCoverage: true,
ranges: [
{startOffset: 0, endOffset: 4, count: 2},
{startOffset: 1, endOffset: 3, count: 1},
],
},
],
},
],
};
const actual: ProcessCov = mergeProcessCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
describe("mergeProcessCovs", () => {
// see: https://github.com/demurgos/v8-coverage/issues/2
it("handles function coverage merged into block coverage", () => {
const blockCoverage: ProcessCov = loadFixture("issue-2-block-coverage");
const functionCoverage: ProcessCov = loadFixture("issue-2-func-coverage");
const inputs: ProcessCov[] = [
functionCoverage,
blockCoverage,
];
const expected: ProcessCov = loadFixture("issue-2-expected");
const actual: ProcessCov = mergeProcessCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
// see: https://github.com/demurgos/v8-coverage/issues/2
it("handles block coverage merged into function coverage", () => {
const blockCoverage: ProcessCov = loadFixture("issue-2-block-coverage");
const functionCoverage: ProcessCov = loadFixture("issue-2-func-coverage");
const inputs: ProcessCov[] = [
blockCoverage,
functionCoverage,
];
const expected: ProcessCov = loadFixture("issue-2-expected");
const actual: ProcessCov = mergeProcessCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
});
it("accepts arrays with a single item for `mergeScriptCovs`", () => {
const inputs: ScriptCov[] = [
{
scriptId: "123",
url: "/lib.js",
functions: [
{
functionName: "test",
isBlockCoverage: true,
ranges: [
{startOffset: 0, endOffset: 4, count: 2},
{startOffset: 1, endOffset: 2, count: 1},
{startOffset: 2, endOffset: 3, count: 1},
],
},
],
},
];
const expected: ScriptCov | undefined = {
scriptId: "123",
url: "/lib.js",
functions: [
{
functionName: "test",
isBlockCoverage: true,
ranges: [
{startOffset: 0, endOffset: 4, count: 2},
{startOffset: 1, endOffset: 3, count: 1},
],
},
],
};
const actual: ScriptCov | undefined = mergeScriptCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
it("accepts arrays with a single item for `mergeFunctionCovs`", () => {
const inputs: FunctionCov[] = [
{
functionName: "test",
isBlockCoverage: true,
ranges: [
{startOffset: 0, endOffset: 4, count: 2},
{startOffset: 1, endOffset: 2, count: 1},
{startOffset: 2, endOffset: 3, count: 1},
],
},
];
const expected: FunctionCov = {
functionName: "test",
isBlockCoverage: true,
ranges: [
{startOffset: 0, endOffset: 4, count: 2},
{startOffset: 1, endOffset: 3, count: 1},
],
};
const actual: FunctionCov | undefined = mergeFunctionCovs(inputs);
chai.assert.deepEqual(actual, expected);
});
});
describe("ranges", () => {
for (const sourceFile of getSourceFiles()) {
const relPath: string = path.relative(RANGES_DIR, sourceFile);
describe(relPath, () => {
const content: string = fs.readFileSync(sourceFile, {encoding: "UTF-8"});
const items: MergeRangeItem[] = JSON.parse(content);
for (const item of items) {
const test: () => void = () => {
const actual: ProcessCov | undefined = mergeProcessCovs(item.inputs);
chai.assert.deepEqual(actual, item.expected);
};
switch (item.status) {
case "run":
it(item.name, test);
break;
case "only":
it.only(item.name, test);
break;
case "skip":
it.skip(item.name, test);
break;
default:
throw new Error(`Unexpected status: ${item.status}`);
}
}
});
}
});
describe("benches", () => {
for (const bench of getBenches()) {
const BENCHES_TO_SKIP: Set<string> = new Set();
if (process.env.CI === "true") {
// Skip very large benchmarks when running continuous integration
BENCHES_TO_SKIP.add("node@10.11.0");
BENCHES_TO_SKIP.add("npm@6.4.1");
}
const name: string = path.basename(bench);
if (BENCHES_TO_SKIP.has(name)) {
it.skip(`${name} (skipped: too large for CI)`, testBench);
} else {
it(name, testBench);
}
async function testBench(this: Mocha.Context) {
this.timeout(BENCHES_TIMEOUT);
const inputFileNames: string[] = await fs.promises.readdir(bench);
const inputPromises: Promise<ProcessCov>[] = [];
for (const inputFileName of inputFileNames) {
const resolved: string = path.join(bench, inputFileName);
inputPromises.push(fs.promises.readFile(resolved).then(buffer => JSON.parse(buffer.toString("UTF-8"))));
}
const inputs: ProcessCov[] = await Promise.all(inputPromises);
const expectedPath: string = path.join(BENCHES_DIR, `${name}.json`);
const expectedContent: string = await fs.promises.readFile(expectedPath, {encoding: "UTF-8"}) as string;
const expected: ProcessCov = JSON.parse(expectedContent);
const startTime: number = Date.now();
const actual: ProcessCov | undefined = mergeProcessCovs(inputs);
const endTime: number = Date.now();
console.error(`Time (${name}): ${(endTime - startTime) / 1000}`);
chai.assert.deepEqual(actual, expected);
console.error(`OK: ${name}`);
}
}
});
});
function getSourceFiles() {
return getSourcesFrom(RANGES_DIR);
function* getSourcesFrom(dir: string): Iterable<string> {
const names: string[] = fs.readdirSync(dir);
for (const name of names) {
const resolved: string = path.join(dir, name);
const stat: fs.Stats = fs.statSync(resolved);
if (stat.isDirectory()) {
yield* getSourcesFrom(dir);
} else {
yield resolved;
}
}
}
}
function* getBenches(): Iterable<string> {
const names: string[] = fs.readdirSync(BENCHES_INPUT_DIR);
for (const name of names) {
const resolved: string = path.join(BENCHES_INPUT_DIR, name);
const stat: fs.Stats = fs.statSync(resolved);
if (stat.isDirectory()) {
yield resolved;
}
}
}

@ -0,0 +1,59 @@
{
"compilerOptions": {
"allowJs": false,
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"alwaysStrict": true,
"charset": "utf8",
"checkJs": false,
"declaration": false,
"disableSizeLimit": false,
"downlevelIteration": false,
"emitBOM": false,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"importHelpers": false,
"inlineSourceMap": false,
"inlineSources": false,
"isolatedModules": false,
"lib": [
"es2017",
"esnext.asynciterable"
],
"locale": "en-us",
"module": "commonjs",
"moduleResolution": "node",
"newLine": "lf",
"noEmit": false,
"noEmitHelpers": false,
"noEmitOnError": true,
"noErrorTruncation": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noStrictGenericChecks": false,
"noUnusedLocals": true,
"noUnusedParameters": false,
"noImplicitUseStrict": false,
"noLib": false,
"noResolve": false,
"preserveConstEnums": false,
"removeComments": false,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictNullChecks": true,
"suppressExcessPropertyErrors": false,
"suppressImplicitAnyIndexErrors": false,
"target": "es2017",
"traceResolution": false,
"typeRoots": [
"src/lib/custom-typings",
"node_modules/@types"
]
}
}

@ -0,0 +1 @@
../which/bin/node-which

@ -0,0 +1,23 @@
MIT License
Copyright (c) 2012-2018 Aseem Kishore, and [others].
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.
[others]: https://github.com/json5/json5/contributors

@ -0,0 +1,234 @@
# JSON5 JSON for Humans
[![Build Status](https://travis-ci.org/json5/json5.svg)][Build Status]
[![Coverage
Status](https://coveralls.io/repos/github/json5/json5/badge.svg)][Coverage
Status]
The JSON5 Data Interchange Format (JSON5) is a superset of [JSON] that aims to
alleviate some of the limitations of JSON by expanding its syntax to include
some productions from [ECMAScript 5.1].
This JavaScript library is the official reference implementation for JSON5
parsing and serialization libraries.
[Build Status]: https://travis-ci.org/json5/json5
[Coverage Status]: https://coveralls.io/github/json5/json5
[JSON]: https://tools.ietf.org/html/rfc7159
[ECMAScript 5.1]: https://www.ecma-international.org/ecma-262/5.1/
## Summary of Features
The following ECMAScript 5.1 features, which are not supported in JSON, have
been extended to JSON5.
### Objects
- Object keys may be an ECMAScript 5.1 _[IdentifierName]_.
- Objects may have a single trailing comma.
### Arrays
- Arrays may have a single trailing comma.
### Strings
- Strings may be single quoted.
- Strings may span multiple lines by escaping new line characters.
- Strings may include character escapes.
### Numbers
- Numbers may be hexadecimal.
- Numbers may have a leading or trailing decimal point.
- Numbers may be [IEEE 754] positive infinity, negative infinity, and NaN.
- Numbers may begin with an explicit plus sign.
### Comments
- Single and multi-line comments are allowed.
### White Space
- Additional white space characters are allowed.
[IdentifierName]: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
[IEEE 754]: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933
## Short Example
```js
{
// comments
unquoted: 'and you can quote me on that',
singleQuotes: 'I can use "double quotes" here',
lineBreaks: "Look, Mom! \
No \\n's!",
hexadecimal: 0xdecaf,
leadingDecimalPoint: .8675309, andTrailing: 8675309.,
positiveSign: +1,
trailingComma: 'in objects', andIn: ['arrays',],
"backwardsCompatible": "with JSON",
}
```
## Specification
For a detailed explanation of the JSON5 format, please read the [official
specification](https://json5.github.io/json5-spec/).
## Installation
### Node.js
```sh
npm install json5
```
```js
const JSON5 = require('json5')
```
### Browsers
```html
<script src="https://unpkg.com/json5@^1.0.0"></script>
```
This will create a global `JSON5` variable.
## API
The JSON5 API is compatible with the [JSON API].
[JSON API]:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
### JSON5.parse()
Parses a JSON5 string, constructing the JavaScript value or object described by
the string. An optional reviver function can be provided to perform a
transformation on the resulting object before it is returned.
#### Syntax
JSON5.parse(text[, reviver])
#### Parameters
- `text`: The string to parse as JSON5.
- `reviver`: If a function, this prescribes how the value originally produced by
parsing is transformed, before being returned.
#### Return value
The object corresponding to the given JSON5 text.
### JSON5.stringify()
Converts a JavaScript value to a JSON5 string, optionally replacing values if a
replacer function is specified, or optionally including only the specified
properties if a replacer array is specified.
#### Syntax
JSON5.stringify(value[, replacer[, space]])
JSON5.stringify(value[, options])
#### Parameters
- `value`: The value to convert to a JSON5 string.
- `replacer`: A function that alters the behavior of the stringification
process, or an array of String and Number objects that serve as a whitelist
for selecting/filtering the properties of the value object to be included in
the JSON5 string. If this value is null or not provided, all properties of the
object are included in the resulting JSON5 string.
- `space`: A String or Number object that's used to insert white space into the
output JSON5 string for readability purposes. If this is a Number, it
indicates the number of space characters to use as white space; this number is
capped at 10 (if it is greater, the value is just 10). Values less than 1
indicate that no space should be used. If this is a String, the string (or the
first 10 characters of the string, if it's longer than that) is used as white
space. If this parameter is not provided (or is null), no white space is used.
If white space is used, trailing commas will be used in objects and arrays.
- `options`: An object with the following properties:
- `replacer`: Same as the `replacer` parameter.
- `space`: Same as the `space` parameter.
- `quote`: A String representing the quote character to use when serializing
strings.
#### Return value
A JSON5 string representing the value.
### Node.js `require()` JSON5 files
When using Node.js, you can `require()` JSON5 files by adding the following
statement.
```js
require('json5/lib/register')
```
Then you can load a JSON5 file with a Node.js `require()` statement. For
example:
```js
const config = require('./config.json5')
```
## CLI
Since JSON is more widely used than JSON5, this package includes a CLI for
converting JSON5 to JSON and for validating the syntax of JSON5 documents.
### Installation
```sh
npm install --global json5
```
### Usage
```sh
json5 [options] <file>
```
If `<file>` is not provided, then STDIN is used.
#### Options:
- `-s`, `--space`: The number of spaces to indent or `t` for tabs
- `-o`, `--out-file [file]`: Output to the specified file, otherwise STDOUT
- `-v`, `--validate`: Validate JSON5 but do not output JSON
- `-V`, `--version`: Output the version number
- `-h`, `--help`: Output usage information
## Contibuting
### Development
```sh
git clone https://github.com/json5/json5
cd json5
npm install
```
When contributing code, please write relevant tests and run `npm test` and `npm
run lint` before submitting pull requests. Please use an editor that supports
[EditorConfig](http://editorconfig.org/).
### Issues
To report bugs or request features regarding the JSON5 data format, please
submit an issue to the [official specification
repository](https://github.com/json5/json5-spec).
To report bugs or request features regarding the JavaScript implentation of
JSON5, please submit an issue to this repository.
## License
MIT. See [LICENSE.md](./LICENSE.md) for details.
## Credits
[Assem Kishore](https://github.com/aseemk) founded this project.
[Michael Bolin](http://bolinfest.com/) independently arrived at and published
some of these same ideas with awesome explanations and detail. Recommended
reading: [Suggested Improvements to JSON](http://bolinfest.com/essays/json.html)
[Douglas Crockford](http://www.crockford.com/) of course designed and built
JSON, but his state machine diagrams on the [JSON website](http://json.org/), as
cheesy as it may sound, gave us motivation and confidence that building a new
parser to implement these ideas was within reach! The original
implementation of JSON5 was also modeled directly off of Dougs open-source
[json_parse.js] parser. Were grateful for that clean and well-documented
code.
[json_parse.js]:
https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
[Max Nanasy](https://github.com/MaxNanasy) has been an early and prolific
supporter, contributing multiple patches and ideas.
[Andrew Eisenberg](https://github.com/aeisenberg) contributed the original
`stringify` method.
[Jordan Tucker](https://github.com/jordanbtucker) has aligned JSON5 more closely
with ES5, wrote the official JSON5 specification, completely rewrote the
codebase from the ground up, and is actively maintaining this project.

File diff suppressed because one or more lines are too long

@ -0,0 +1,2 @@
#!/usr/bin/env node
'use strict';var _fs=require('fs');var _fs2=_interopRequireDefault(_fs);var _path=require('path');var _path2=_interopRequireDefault(_path);var _minimist=require('minimist');var _minimist2=_interopRequireDefault(_minimist);var _package=require('../package.json');var _package2=_interopRequireDefault(_package);var _=require('./');var _2=_interopRequireDefault(_);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}var argv=(0,_minimist2.default)(process.argv.slice(2),{alias:{'convert':'c','space':'s','validate':'v','out-file':'o','version':'V','help':'h'},boolean:['convert','validate','version','help'],string:['space','out-file']});if(argv.version){version()}else if(argv.help){usage()}else{var inFilename=argv._[0];var readStream=void 0;if(inFilename){readStream=_fs2.default.createReadStream(inFilename)}else{readStream=process.stdin}var json5='';readStream.on('data',function(data){json5+=data});readStream.on('end',function(){var space=void 0;if(argv.space==='t'||argv.space==='tab'){space='\t'}else{space=Number(argv.space)}var value=void 0;try{value=_2.default.parse(json5);if(!argv.validate){var json=JSON.stringify(value,null,space);var writeStream=void 0;if(argv.convert&&inFilename&&!argv.o){var parsedFilename=_path2.default.parse(inFilename);var outFilename=_path2.default.format(Object.assign(parsedFilename,{base:_path2.default.basename(parsedFilename.base,parsedFilename.ext)+'.json'}));writeStream=_fs2.default.createWriteStream(outFilename)}else if(argv.o){writeStream=_fs2.default.createWriteStream(argv.o)}else{writeStream=process.stdout}writeStream.write(json)}}catch(err){console.error(err.message);process.exit(1)}})}function version(){console.log(_package2.default.version)}function usage(){console.log('\n Usage: json5 [options] <file>\n\n If <file> is not provided, then STDIN is used.\n\n Options:\n\n -s, --space The number of spaces to indent or \'t\' for tabs\n -o, --out-file [file] Output to the specified file, otherwise STDOUT\n -v, --validate Validate JSON5 but do not output JSON\n -V, --version Output the version number\n -h, --help Output usage information')}

@ -0,0 +1 @@
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _parse=require('./parse');var _parse2=_interopRequireDefault(_parse);var _stringify=require('./stringify');var _stringify2=_interopRequireDefault(_stringify);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}exports.default={parse:_parse2.default,stringify:_stringify2.default};module.exports=exports['default'];

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
'use strict';var _fs=require('fs');var _fs2=_interopRequireDefault(_fs);var _=require('./');var _2=_interopRequireDefault(_);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}require.extensions['.json5']=function(module,filename){var content=_fs2.default.readFileSync(filename,'utf8');try{module.exports=_2.default.parse(content)}catch(err){err.message=filename+': '+err.message;throw err}};

@ -0,0 +1 @@
"use strict";require("./register");console.warn("'json5/require' is deprecated. Please use 'json5/register' instead.");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.isSpaceSeparator=isSpaceSeparator;exports.isIdStartChar=isIdStartChar;exports.isIdContinueChar=isIdContinueChar;exports.isDigit=isDigit;exports.isHexDigit=isHexDigit;var _unicode=require('../lib/unicode');var unicode=_interopRequireWildcard(_unicode);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key]}}newObj.default=obj;return newObj}}function isSpaceSeparator(c){return unicode.Space_Separator.test(c)}function isIdStartChar(c){return c>='a'&&c<='z'||c>='A'&&c<='Z'||c==='$'||c==='_'||unicode.ID_Start.test(c)}function isIdContinueChar(c){return c>='a'&&c<='z'||c>='A'&&c<='Z'||c>='0'&&c<='9'||c==='$'||c==='_'||c==='\u200C'||c==='\u200D'||unicode.ID_Continue.test(c)}function isDigit(c){return /[0-9]/.test(c)}function isHexDigit(c){return /[0-9A-Fa-f]/.test(c)}

@ -0,0 +1,76 @@
{
"name": "json5",
"version": "1.0.2",
"description": "JSON for humans.",
"main": "lib/index.js",
"bin": "lib/cli.js",
"browser": "dist/index.js",
"files": [
"lib/",
"dist/"
],
"scripts": {
"build": "babel-node build/build.js && babel src -d lib && rollup -c",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"lint": "eslint --fix build src",
"prepublishOnly": "npm run lint && npm test && npm run production",
"pretest": "cross-env NODE_ENV=test npm run build",
"preversion": "npm run lint && npm test && npm run production",
"production": "cross-env NODE_ENV=production npm run build",
"test": "nyc --reporter=html --reporter=text mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/json5/json5.git"
},
"keywords": [
"json",
"json5",
"es5",
"es2015",
"ecmascript"
],
"author": "Aseem Kishore <aseem.kishore@gmail.com>",
"contributors": [
"Max Nanasy <max.nanasy@gmail.com>",
"Andrew Eisenberg <andrew@eisenberg.as>",
"Jordan Tucker <jordanbtucker@gmail.com>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/json5/json5/issues"
},
"homepage": "http://json5.org/",
"dependencies": {
"minimist": "^1.2.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-istanbul": "^4.1.5",
"babel-preset-env": "^1.6.1",
"babel-register": "^6.26.0",
"babelrc-rollup": "^3.0.0",
"coveralls": "^3.0.0",
"cross-env": "^5.1.4",
"del": "^3.0.0",
"eslint": "^4.18.2",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.9.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-standard": "^3.0.1",
"mocha": "^5.0.4",
"nyc": "^11.4.1",
"regenerate": "^1.3.3",
"rollup": "^0.56.5",
"rollup-plugin-babel": "^3.0.3",
"rollup-plugin-commonjs": "^9.0.0",
"rollup-plugin-node-resolve": "^3.2.0",
"rollup-plugin-uglify": "^3.0.0",
"sinon": "^4.4.2",
"unicode-9.0.0": "^0.7.5"
}
}

@ -0,0 +1,23 @@
MIT License
Copyright (c) 2012-2018 Aseem Kishore, and [others].
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.
[others]: https://github.com/json5/json5/contributors

@ -0,0 +1,234 @@
# JSON5 JSON for Humans
[![Build Status](https://travis-ci.org/json5/json5.svg)][Build Status]
[![Coverage
Status](https://coveralls.io/repos/github/json5/json5/badge.svg)][Coverage
Status]
The JSON5 Data Interchange Format (JSON5) is a superset of [JSON] that aims to
alleviate some of the limitations of JSON by expanding its syntax to include
some productions from [ECMAScript 5.1].
This JavaScript library is the official reference implementation for JSON5
parsing and serialization libraries.
[Build Status]: https://travis-ci.org/json5/json5
[Coverage Status]: https://coveralls.io/github/json5/json5
[JSON]: https://tools.ietf.org/html/rfc7159
[ECMAScript 5.1]: https://www.ecma-international.org/ecma-262/5.1/
## Summary of Features
The following ECMAScript 5.1 features, which are not supported in JSON, have
been extended to JSON5.
### Objects
- Object keys may be an ECMAScript 5.1 _[IdentifierName]_.
- Objects may have a single trailing comma.
### Arrays
- Arrays may have a single trailing comma.
### Strings
- Strings may be single quoted.
- Strings may span multiple lines by escaping new line characters.
- Strings may include character escapes.
### Numbers
- Numbers may be hexadecimal.
- Numbers may have a leading or trailing decimal point.
- Numbers may be [IEEE 754] positive infinity, negative infinity, and NaN.
- Numbers may begin with an explicit plus sign.
### Comments
- Single and multi-line comments are allowed.
### White Space
- Additional white space characters are allowed.
[IdentifierName]: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
[IEEE 754]: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933
## Short Example
```js
{
// comments
unquoted: 'and you can quote me on that',
singleQuotes: 'I can use "double quotes" here',
lineBreaks: "Look, Mom! \
No \\n's!",
hexadecimal: 0xdecaf,
leadingDecimalPoint: .8675309, andTrailing: 8675309.,
positiveSign: +1,
trailingComma: 'in objects', andIn: ['arrays',],
"backwardsCompatible": "with JSON",
}
```
## Specification
For a detailed explanation of the JSON5 format, please read the [official
specification](https://json5.github.io/json5-spec/).
## Installation
### Node.js
```sh
npm install json5
```
```js
const JSON5 = require('json5')
```
### Browsers
```html
<script src="https://unpkg.com/json5@^1.0.0"></script>
```
This will create a global `JSON5` variable.
## API
The JSON5 API is compatible with the [JSON API].
[JSON API]:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
### JSON5.parse()
Parses a JSON5 string, constructing the JavaScript value or object described by
the string. An optional reviver function can be provided to perform a
transformation on the resulting object before it is returned.
#### Syntax
JSON5.parse(text[, reviver])
#### Parameters
- `text`: The string to parse as JSON5.
- `reviver`: If a function, this prescribes how the value originally produced by
parsing is transformed, before being returned.
#### Return value
The object corresponding to the given JSON5 text.
### JSON5.stringify()
Converts a JavaScript value to a JSON5 string, optionally replacing values if a
replacer function is specified, or optionally including only the specified
properties if a replacer array is specified.
#### Syntax
JSON5.stringify(value[, replacer[, space]])
JSON5.stringify(value[, options])
#### Parameters
- `value`: The value to convert to a JSON5 string.
- `replacer`: A function that alters the behavior of the stringification
process, or an array of String and Number objects that serve as a whitelist
for selecting/filtering the properties of the value object to be included in
the JSON5 string. If this value is null or not provided, all properties of the
object are included in the resulting JSON5 string.
- `space`: A String or Number object that's used to insert white space into the
output JSON5 string for readability purposes. If this is a Number, it
indicates the number of space characters to use as white space; this number is
capped at 10 (if it is greater, the value is just 10). Values less than 1
indicate that no space should be used. If this is a String, the string (or the
first 10 characters of the string, if it's longer than that) is used as white
space. If this parameter is not provided (or is null), no white space is used.
If white space is used, trailing commas will be used in objects and arrays.
- `options`: An object with the following properties:
- `replacer`: Same as the `replacer` parameter.
- `space`: Same as the `space` parameter.
- `quote`: A String representing the quote character to use when serializing
strings.
#### Return value
A JSON5 string representing the value.
### Node.js `require()` JSON5 files
When using Node.js, you can `require()` JSON5 files by adding the following
statement.
```js
require('json5/lib/register')
```
Then you can load a JSON5 file with a Node.js `require()` statement. For
example:
```js
const config = require('./config.json5')
```
## CLI
Since JSON is more widely used than JSON5, this package includes a CLI for
converting JSON5 to JSON and for validating the syntax of JSON5 documents.
### Installation
```sh
npm install --global json5
```
### Usage
```sh
json5 [options] <file>
```
If `<file>` is not provided, then STDIN is used.
#### Options:
- `-s`, `--space`: The number of spaces to indent or `t` for tabs
- `-o`, `--out-file [file]`: Output to the specified file, otherwise STDOUT
- `-v`, `--validate`: Validate JSON5 but do not output JSON
- `-V`, `--version`: Output the version number
- `-h`, `--help`: Output usage information
## Contibuting
### Development
```sh
git clone https://github.com/json5/json5
cd json5
npm install
```
When contributing code, please write relevant tests and run `npm test` and `npm
run lint` before submitting pull requests. Please use an editor that supports
[EditorConfig](http://editorconfig.org/).
### Issues
To report bugs or request features regarding the JSON5 data format, please
submit an issue to the [official specification
repository](https://github.com/json5/json5-spec).
To report bugs or request features regarding the JavaScript implentation of
JSON5, please submit an issue to this repository.
## License
MIT. See [LICENSE.md](./LICENSE.md) for details.
## Credits
[Assem Kishore](https://github.com/aseemk) founded this project.
[Michael Bolin](http://bolinfest.com/) independently arrived at and published
some of these same ideas with awesome explanations and detail. Recommended
reading: [Suggested Improvements to JSON](http://bolinfest.com/essays/json.html)
[Douglas Crockford](http://www.crockford.com/) of course designed and built
JSON, but his state machine diagrams on the [JSON website](http://json.org/), as
cheesy as it may sound, gave us motivation and confidence that building a new
parser to implement these ideas was within reach! The original
implementation of JSON5 was also modeled directly off of Dougs open-source
[json_parse.js] parser. Were grateful for that clean and well-documented
code.
[json_parse.js]:
https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
[Max Nanasy](https://github.com/MaxNanasy) has been an early and prolific
supporter, contributing multiple patches and ideas.
[Andrew Eisenberg](https://github.com/aeisenberg) contributed the original
`stringify` method.
[Jordan Tucker](https://github.com/jordanbtucker) has aligned JSON5 more closely
with ES5, wrote the official JSON5 specification, completely rewrote the
codebase from the ground up, and is actively maintaining this project.

File diff suppressed because one or more lines are too long

@ -0,0 +1,2 @@
#!/usr/bin/env node
'use strict';var _fs=require('fs');var _fs2=_interopRequireDefault(_fs);var _path=require('path');var _path2=_interopRequireDefault(_path);var _minimist=require('minimist');var _minimist2=_interopRequireDefault(_minimist);var _package=require('../package.json');var _package2=_interopRequireDefault(_package);var _=require('./');var _2=_interopRequireDefault(_);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}var argv=(0,_minimist2.default)(process.argv.slice(2),{alias:{'convert':'c','space':'s','validate':'v','out-file':'o','version':'V','help':'h'},boolean:['convert','validate','version','help'],string:['space','out-file']});if(argv.version){version()}else if(argv.help){usage()}else{var inFilename=argv._[0];var readStream=void 0;if(inFilename){readStream=_fs2.default.createReadStream(inFilename)}else{readStream=process.stdin}var json5='';readStream.on('data',function(data){json5+=data});readStream.on('end',function(){var space=void 0;if(argv.space==='t'||argv.space==='tab'){space='\t'}else{space=Number(argv.space)}var value=void 0;try{value=_2.default.parse(json5);if(!argv.validate){var json=JSON.stringify(value,null,space);var writeStream=void 0;if(argv.convert&&inFilename&&!argv.o){var parsedFilename=_path2.default.parse(inFilename);var outFilename=_path2.default.format(Object.assign(parsedFilename,{base:_path2.default.basename(parsedFilename.base,parsedFilename.ext)+'.json'}));writeStream=_fs2.default.createWriteStream(outFilename)}else if(argv.o){writeStream=_fs2.default.createWriteStream(argv.o)}else{writeStream=process.stdout}writeStream.write(json)}}catch(err){console.error(err.message);process.exit(1)}})}function version(){console.log(_package2.default.version)}function usage(){console.log('\n Usage: json5 [options] <file>\n\n If <file> is not provided, then STDIN is used.\n\n Options:\n\n -s, --space The number of spaces to indent or \'t\' for tabs\n -o, --out-file [file] Output to the specified file, otherwise STDOUT\n -v, --validate Validate JSON5 but do not output JSON\n -V, --version Output the version number\n -h, --help Output usage information')}

@ -0,0 +1 @@
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _parse=require('./parse');var _parse2=_interopRequireDefault(_parse);var _stringify=require('./stringify');var _stringify2=_interopRequireDefault(_stringify);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}exports.default={parse:_parse2.default,stringify:_stringify2.default};module.exports=exports['default'];

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
'use strict';var _fs=require('fs');var _fs2=_interopRequireDefault(_fs);var _=require('./');var _2=_interopRequireDefault(_);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}require.extensions['.json5']=function(module,filename){var content=_fs2.default.readFileSync(filename,'utf8');try{module.exports=_2.default.parse(content)}catch(err){err.message=filename+': '+err.message;throw err}};

@ -0,0 +1 @@
"use strict";require("./register");console.warn("'json5/require' is deprecated. Please use 'json5/register' instead.");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.isSpaceSeparator=isSpaceSeparator;exports.isIdStartChar=isIdStartChar;exports.isIdContinueChar=isIdContinueChar;exports.isDigit=isDigit;exports.isHexDigit=isHexDigit;var _unicode=require('../lib/unicode');var unicode=_interopRequireWildcard(_unicode);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key]}}newObj.default=obj;return newObj}}function isSpaceSeparator(c){return unicode.Space_Separator.test(c)}function isIdStartChar(c){return c>='a'&&c<='z'||c>='A'&&c<='Z'||c==='$'||c==='_'||unicode.ID_Start.test(c)}function isIdContinueChar(c){return c>='a'&&c<='z'||c>='A'&&c<='Z'||c>='0'&&c<='9'||c==='$'||c==='_'||c==='\u200C'||c==='\u200D'||unicode.ID_Continue.test(c)}function isDigit(c){return /[0-9]/.test(c)}function isHexDigit(c){return /[0-9A-Fa-f]/.test(c)}

@ -0,0 +1,76 @@
{
"name": "json5",
"version": "1.0.2",
"description": "JSON for humans.",
"main": "lib/index.js",
"bin": "lib/cli.js",
"browser": "dist/index.js",
"files": [
"lib/",
"dist/"
],
"scripts": {
"build": "babel-node build/build.js && babel src -d lib && rollup -c",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"lint": "eslint --fix build src",
"prepublishOnly": "npm run lint && npm test && npm run production",
"pretest": "cross-env NODE_ENV=test npm run build",
"preversion": "npm run lint && npm test && npm run production",
"production": "cross-env NODE_ENV=production npm run build",
"test": "nyc --reporter=html --reporter=text mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/json5/json5.git"
},
"keywords": [
"json",
"json5",
"es5",
"es2015",
"ecmascript"
],
"author": "Aseem Kishore <aseem.kishore@gmail.com>",
"contributors": [
"Max Nanasy <max.nanasy@gmail.com>",
"Andrew Eisenberg <andrew@eisenberg.as>",
"Jordan Tucker <jordanbtucker@gmail.com>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/json5/json5/issues"
},
"homepage": "http://json5.org/",
"dependencies": {
"minimist": "^1.2.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-istanbul": "^4.1.5",
"babel-preset-env": "^1.6.1",
"babel-register": "^6.26.0",
"babelrc-rollup": "^3.0.0",
"coveralls": "^3.0.0",
"cross-env": "^5.1.4",
"del": "^3.0.0",
"eslint": "^4.18.2",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.9.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-standard": "^3.0.1",
"mocha": "^5.0.4",
"nyc": "^11.4.1",
"regenerate": "^1.3.3",
"rollup": "^0.56.5",
"rollup-plugin-babel": "^3.0.3",
"rollup-plugin-commonjs": "^9.0.0",
"rollup-plugin-node-resolve": "^3.2.0",
"rollup-plugin-uglify": "^3.0.0",
"sinon": "^4.4.2",
"unicode-9.0.0": "^0.7.5"
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save