Updated the files.
This commit is contained in:
parent
1553e6b971
commit
753967d4f5
23418 changed files with 3784666 additions and 0 deletions
2570
my-app/node_modules/karma/CHANGELOG.md
generated
vendored
Executable file
2570
my-app/node_modules/karma/CHANGELOG.md
generated
vendored
Executable file
File diff suppressed because it is too large
Load diff
13
my-app/node_modules/karma/CODE_OF_CONDUCT.md
generated
vendored
Executable file
13
my-app/node_modules/karma/CODE_OF_CONDUCT.md
generated
vendored
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
|
||||
|
||||
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.0.0, available at <https://www.contributor-covenant.org/version/1/0/0/code-of-conduct/>
|
||||
14
my-app/node_modules/karma/ISSUE_TEMPLATE.md
generated
vendored
Executable file
14
my-app/node_modules/karma/ISSUE_TEMPLATE.md
generated
vendored
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
### Expected behaviour
|
||||
|
||||
### Actual behaviour
|
||||
|
||||
### Environment Details
|
||||
|
||||
- Karma version (output of `karma --version`):
|
||||
- Relevant part of your `karma.config.js` file
|
||||
|
||||
### Steps to reproduce the behaviour
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
20
my-app/node_modules/karma/LICENSE
generated
vendored
Executable file
20
my-app/node_modules/karma/LICENSE
generated
vendored
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License
|
||||
|
||||
Copyright (C) 2011-2021 Google, Inc.
|
||||
|
||||
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.
|
||||
124
my-app/node_modules/karma/README.md
generated
vendored
Executable file
124
my-app/node_modules/karma/README.md
generated
vendored
Executable file
|
|
@ -0,0 +1,124 @@
|
|||
# Karma
|
||||
[](https://github.com/karma-runner/karma) [](https://www.npmjs.com/package/karma) [](https://npmcharts.com/compare/karma?minimal=true)
|
||||
|
||||
[](https://codeclimate.com/github/karma-runner/karma) [](https://makeapullrequest.com/) [](https://david-dm.org/karma-runner/karma) [](https://david-dm.org/karma-runner/karma#info=devDependencies) [](https://github.com/semantic-release/semantic-release)
|
||||
|
||||
A simple tool that allows you to execute JavaScript code in multiple
|
||||
_real_ browsers.
|
||||
|
||||
> The main purpose of Karma is to make your test-driven development easy,
|
||||
> fast, and fun.
|
||||
|
||||
|
||||
## Help and Support
|
||||
|
||||
> For questions and support please use the mailing list or Gitter.
|
||||
> The issue tracker is for bug reports and feature discussions only.
|
||||
|
||||
* Obligatory [documentation]
|
||||
* Quick questions:
|
||||
[](https://gitter.im/karma-runner/karma)
|
||||
* Longer questions: [Mailing List]
|
||||
* Bug reports [Issue Tracker]
|
||||
* Everything less than 140 characters: [@JsKarma] on Twitter
|
||||
|
||||
|
||||
|
||||
## When should I use Karma?
|
||||
|
||||
* You want to test code in *real* browsers.
|
||||
* You want to test code in multiple browsers (desktop, mobile,
|
||||
tablets, etc.).
|
||||
* You want to execute your tests locally during development.
|
||||
* You want to execute your tests on a continuous integration server.
|
||||
* You want to execute your tests on every save.
|
||||
* You love your terminal.
|
||||
* You don't want your (testing) life to suck.
|
||||
* You want to use [Istanbul] to automagically generate coverage
|
||||
reports.
|
||||
* You want to use [RequireJS] for your source files.
|
||||
|
||||
|
||||
## But I still want to use \_insert testing library\_
|
||||
|
||||
Karma is not a testing framework, nor an assertion library.
|
||||
Karma just launches an HTTP server, and generates the test runner HTML file you probably already know from your favourite testing framework.
|
||||
So for testing purposes you can use pretty much anything you like. There are already plugins for most of the common testing frameworks:
|
||||
|
||||
* [Jasmine]
|
||||
* [Mocha]
|
||||
* [QUnit]
|
||||
* and [many others](https://www.npmjs.com/search?q=keywords:karma-adapter)
|
||||
|
||||
If you can't find an adapter for your favourite framework, don't worry and write your own.
|
||||
It's not that hard and we are here to help.
|
||||
|
||||
|
||||
## Which Browsers can I use?
|
||||
|
||||
All the major browsers are supported, if you want to know more see the
|
||||
[browsers] page.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
See [FAQ](https://karma-runner.github.io/latest/intro/faq.html).
|
||||
|
||||
|
||||
## I want to use it. Where do I sign?
|
||||
|
||||
You don't need to sign anything but here are some resources to help
|
||||
you to get started...
|
||||
|
||||
|
||||
### Obligatory Screencast.
|
||||
|
||||
Every serious project has a screencast, so here is ours. Just click
|
||||
[here] and let the show begin.
|
||||
|
||||
|
||||
### Installation.
|
||||
|
||||
See [installation](https://karma-runner.github.io/latest/intro/installation.html).
|
||||
|
||||
|
||||
### Using it.
|
||||
|
||||
See [configuration](https://karma-runner.github.io/latest/intro/configuration.html).
|
||||
|
||||
|
||||
## This is so great. I want to help.
|
||||
|
||||
Please, see
|
||||
[contributing](https://karma-runner.github.io/latest/dev/contributing.html).
|
||||
|
||||
|
||||
## Why did you create this?
|
||||
|
||||
Throughout the development of [AngularJS], we've been using [JSTD] for
|
||||
testing. I really think that JSTD is a great idea. Unfortunately, we
|
||||
had many problems with JSTD, so we decided to write our own test
|
||||
runner based on the same idea. We wanted a simple tool just for
|
||||
executing JavaScript tests that is both stable and fast. That's why we
|
||||
use the awesome [Socket.io] library and [Node.js].
|
||||
|
||||
|
||||
## My boss wants a license. So where is it?
|
||||
[MIT License](./LICENSE)
|
||||
|
||||
|
||||
[AngularJS]: https://angularjs.org/
|
||||
[JSTD]: https://code.google.com/p/js-test-driver/
|
||||
[Socket.io]: https://socket.io/
|
||||
[Node.js]: https://nodejs.org/
|
||||
[Jasmine]: https://github.com/karma-runner/karma-jasmine
|
||||
[Mocha]: https://github.com/karma-runner/karma-mocha
|
||||
[QUnit]: https://github.com/karma-runner/karma-qunit
|
||||
[here]: https://www.youtube.com/watch?v=MVw8N3hTfCI
|
||||
[Mailing List]: https://groups.google.com/forum/#!forum/karma-users
|
||||
[Issue Tracker]: https://github.com/karma-runner/karma/issues
|
||||
[@JsKarma]: https://twitter.com/JsKarma
|
||||
[RequireJS]: https://requirejs.org/
|
||||
[Istanbul]: https://github.com/gotwarlost/istanbul
|
||||
|
||||
[browsers]: https://karma-runner.github.io/latest/config/browsers.html
|
||||
[documentation]: https://karma-runner.github.io
|
||||
11
my-app/node_modules/karma/SECURITY.md
generated
vendored
Executable file
11
my-app/node_modules/karma/SECURITY.md
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Only the latest version of the project are currently being supported with security updates.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report a security issue, please email karma-runner-eng+security@google.com
|
||||
with a description of the issue, the steps you took to create the issue,
|
||||
affected versions, and if known, mitigations for the issue.
|
||||
3
my-app/node_modules/karma/bin/karma
generated
vendored
Executable file
3
my-app/node_modules/karma/bin/karma
generated
vendored
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/cli').run();
|
||||
1
my-app/node_modules/karma/commitlint.config.js
generated
vendored
Executable file
1
my-app/node_modules/karma/commitlint.config.js
generated
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
module.exports = { extends: ['@commitlint/config-angular'] }
|
||||
100
my-app/node_modules/karma/common/stringify.js
generated
vendored
Executable file
100
my-app/node_modules/karma/common/stringify.js
generated
vendored
Executable file
|
|
@ -0,0 +1,100 @@
|
|||
var serialize = null
|
||||
try {
|
||||
serialize = require('dom-serialize')
|
||||
} catch (e) {
|
||||
// Ignore failure on IE8
|
||||
}
|
||||
|
||||
var instanceOf = require('./util').instanceOf
|
||||
|
||||
function isNode (obj) {
|
||||
return (obj.tagName || obj.nodeName) && obj.nodeType
|
||||
}
|
||||
|
||||
function stringify (obj, depth) {
|
||||
if (depth === 0) {
|
||||
return '...'
|
||||
}
|
||||
|
||||
if (obj === null) {
|
||||
return 'null'
|
||||
}
|
||||
|
||||
switch (typeof obj) {
|
||||
case 'symbol':
|
||||
return obj.toString()
|
||||
case 'string':
|
||||
return "'" + obj + "'"
|
||||
case 'undefined':
|
||||
return 'undefined'
|
||||
case 'function':
|
||||
try {
|
||||
// function abc(a, b, c) { /* code goes here */ }
|
||||
// -> function abc(a, b, c) { ... }
|
||||
return obj.toString().replace(/\{[\s\S]*\}/, '{ ... }')
|
||||
} catch (err) {
|
||||
if (err instanceof TypeError) {
|
||||
// Support older browsers
|
||||
return 'function ' + (obj.name || '') + '() { ... }'
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
case 'boolean':
|
||||
return obj ? 'true' : 'false'
|
||||
case 'object':
|
||||
var strs = []
|
||||
if (instanceOf(obj, 'Array')) {
|
||||
strs.push('[')
|
||||
for (var i = 0, ii = obj.length; i < ii; i++) {
|
||||
if (i) {
|
||||
strs.push(', ')
|
||||
}
|
||||
strs.push(stringify(obj[i], depth - 1))
|
||||
}
|
||||
strs.push(']')
|
||||
} else if (instanceOf(obj, 'Date')) {
|
||||
return obj.toString()
|
||||
} else if (instanceOf(obj, 'Text')) {
|
||||
return obj.nodeValue
|
||||
} else if (instanceOf(obj, 'Comment')) {
|
||||
return '<!--' + obj.nodeValue + '-->'
|
||||
} else if (obj.outerHTML) {
|
||||
return obj.outerHTML
|
||||
} else if (isNode(obj)) {
|
||||
if (serialize) {
|
||||
return serialize(obj)
|
||||
} else {
|
||||
return 'Skipping stringify, no support for dom-serialize'
|
||||
}
|
||||
} else if (instanceOf(obj, 'Error')) {
|
||||
return obj.toString() + '\n' + obj.stack
|
||||
} else {
|
||||
var constructor = 'Object'
|
||||
if (obj.constructor && typeof obj.constructor === 'function') {
|
||||
constructor = obj.constructor.name
|
||||
}
|
||||
|
||||
strs.push(constructor)
|
||||
strs.push('{')
|
||||
var first = true
|
||||
for (var key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
if (first) {
|
||||
first = false
|
||||
} else {
|
||||
strs.push(', ')
|
||||
}
|
||||
|
||||
strs.push(key + ': ' + stringify(obj[key], depth - 1))
|
||||
}
|
||||
}
|
||||
strs.push('}')
|
||||
}
|
||||
return strs.join('')
|
||||
default:
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = stringify
|
||||
32
my-app/node_modules/karma/common/util.js
generated
vendored
Executable file
32
my-app/node_modules/karma/common/util.js
generated
vendored
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
exports.instanceOf = function (value, constructorName) {
|
||||
return Object.prototype.toString.apply(value) === '[object ' + constructorName + ']'
|
||||
}
|
||||
|
||||
exports.elm = function (id) {
|
||||
return document.getElementById(id)
|
||||
}
|
||||
|
||||
exports.generateId = function (prefix) {
|
||||
return prefix + Math.floor(Math.random() * 10000)
|
||||
}
|
||||
|
||||
exports.isUndefined = function (value) {
|
||||
return typeof value === 'undefined'
|
||||
}
|
||||
|
||||
exports.isDefined = function (value) {
|
||||
return !exports.isUndefined(value)
|
||||
}
|
||||
|
||||
exports.parseQueryParams = function (locationSearch) {
|
||||
var params = {}
|
||||
var pairs = locationSearch.slice(1).split('&')
|
||||
var keyValue
|
||||
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
keyValue = pairs[i].split('=')
|
||||
params[decodeURIComponent(keyValue[0])] = decodeURIComponent(keyValue[1])
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
71
my-app/node_modules/karma/config.tpl.coffee
generated
vendored
Executable file
71
my-app/node_modules/karma/config.tpl.coffee
generated
vendored
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
# Karma configuration
|
||||
# Generated on %DATE%
|
||||
|
||||
module.exports = (config) ->
|
||||
config.set
|
||||
|
||||
# base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '%BASE_PATH%'
|
||||
|
||||
|
||||
# frameworks to use
|
||||
# available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
|
||||
frameworks: [%FRAMEWORKS%]
|
||||
|
||||
|
||||
# list of files / patterns to load in the browser
|
||||
files: [%FILES%
|
||||
]
|
||||
|
||||
|
||||
# list of files / patterns to exclude
|
||||
exclude: [%EXCLUDE%
|
||||
]
|
||||
|
||||
|
||||
# preprocess matching files before serving them to the browser
|
||||
# available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
|
||||
preprocessors: {%PREPROCESSORS%
|
||||
}
|
||||
|
||||
|
||||
# test results reporter to use
|
||||
# possible values: 'dots', 'progress'
|
||||
# available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
|
||||
reporters: ['progress']
|
||||
|
||||
|
||||
# web server port
|
||||
port: 9876
|
||||
|
||||
|
||||
# enable / disable colors in the output (reporters and logs)
|
||||
colors: true
|
||||
|
||||
|
||||
# level of logging
|
||||
# possible values:
|
||||
# - config.LOG_DISABLE
|
||||
# - config.LOG_ERROR
|
||||
# - config.LOG_WARN
|
||||
# - config.LOG_INFO
|
||||
# - config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO
|
||||
|
||||
|
||||
# enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: %AUTO_WATCH%
|
||||
|
||||
|
||||
# start these browsers
|
||||
# available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
|
||||
browsers: [%BROWSERS%]
|
||||
|
||||
|
||||
# Continuous Integration mode
|
||||
# if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: false
|
||||
|
||||
# Concurrency level
|
||||
# how many browser instances should be started simultaneously
|
||||
concurrency: Infinity
|
||||
68
my-app/node_modules/karma/config.tpl.js
generated
vendored
Executable file
68
my-app/node_modules/karma/config.tpl.js
generated
vendored
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
// Karma configuration
|
||||
// Generated on %DATE%
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '%BASE_PATH%',
|
||||
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
|
||||
frameworks: [%FRAMEWORKS%],
|
||||
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [%FILES%
|
||||
],
|
||||
|
||||
|
||||
// list of files / patterns to exclude
|
||||
exclude: [%EXCLUDE%
|
||||
],
|
||||
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
|
||||
preprocessors: {%PREPROCESSORS%
|
||||
},
|
||||
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
|
||||
reporters: ['progress'],
|
||||
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: %AUTO_WATCH%,
|
||||
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
|
||||
browsers: [%BROWSERS%],
|
||||
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: false,
|
||||
|
||||
// Concurrency level
|
||||
// how many browser instances should be started simultaneously
|
||||
concurrency: Infinity
|
||||
})
|
||||
}
|
||||
70
my-app/node_modules/karma/config.tpl.ls
generated
vendored
Executable file
70
my-app/node_modules/karma/config.tpl.ls
generated
vendored
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
# Karma configuration
|
||||
# Generated on %DATE%
|
||||
|
||||
module.exports = (config) ->
|
||||
config.set do
|
||||
|
||||
# base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '%BASE_PATH%'
|
||||
|
||||
|
||||
# frameworks to use
|
||||
# available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
|
||||
frameworks: [%FRAMEWORKS%]
|
||||
|
||||
|
||||
# list of files / patterns to load in the browser
|
||||
files: [%FILES%
|
||||
]
|
||||
|
||||
|
||||
# list of files / patterns to exclude
|
||||
exclude: [%EXCLUDE%
|
||||
]
|
||||
|
||||
|
||||
# preprocess matching files before serving them to the browser
|
||||
# available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
|
||||
preprocessors: {%PREPROCESSORS%
|
||||
}
|
||||
|
||||
# test results reporter to use
|
||||
# possible values: 'dots', 'progress'
|
||||
# available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
|
||||
reporters: ['progress']
|
||||
|
||||
|
||||
# web server port
|
||||
port: 9876
|
||||
|
||||
|
||||
# enable / disable colors in the output (reporters and logs)
|
||||
colors: true
|
||||
|
||||
|
||||
# level of logging
|
||||
# possible values:
|
||||
# - config.LOG_DISABLE
|
||||
# - config.LOG_ERROR
|
||||
# - config.LOG_WARN
|
||||
# - config.LOG_INFO
|
||||
# - config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO
|
||||
|
||||
|
||||
# enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: %AUTO_WATCH%
|
||||
|
||||
|
||||
# satart these browsers
|
||||
# available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
|
||||
browsers: [%BROWSERS%]
|
||||
|
||||
|
||||
# Continuous Integration mode
|
||||
# if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: false
|
||||
|
||||
# Concurrency level
|
||||
# how many browser instances should be started simultaneously
|
||||
concurrency: Infinity
|
||||
68
my-app/node_modules/karma/config.tpl.ts
generated
vendored
Executable file
68
my-app/node_modules/karma/config.tpl.ts
generated
vendored
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
// Karma configuration
|
||||
// Generated on %DATE%
|
||||
|
||||
module.exports = (config) => {
|
||||
config.set({
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '%BASE_PATH%',
|
||||
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
|
||||
frameworks: [%FRAMEWORKS%],
|
||||
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [%FILES%
|
||||
],
|
||||
|
||||
|
||||
// list of files / patterns to exclude
|
||||
exclude: [%EXCLUDE%
|
||||
],
|
||||
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
|
||||
preprocessors: {%PREPROCESSORS%
|
||||
},
|
||||
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
|
||||
reporters: ['progress'],
|
||||
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: %AUTO_WATCH%,
|
||||
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
|
||||
browsers: [%BROWSERS%],
|
||||
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: false,
|
||||
|
||||
// Concurrency level
|
||||
// how many browser instances should be started simultaneously
|
||||
concurrency: Infinity
|
||||
})
|
||||
}
|
||||
161
my-app/node_modules/karma/context/karma.js
generated
vendored
Executable file
161
my-app/node_modules/karma/context/karma.js
generated
vendored
Executable file
|
|
@ -0,0 +1,161 @@
|
|||
// Load our dependencies
|
||||
var stringify = require('../common/stringify')
|
||||
|
||||
// Define our context Karma constructor
|
||||
function ContextKarma (callParentKarmaMethod) {
|
||||
// Define local variables
|
||||
var hasError = false
|
||||
var self = this
|
||||
var isLoaded = false
|
||||
|
||||
// Define our loggers
|
||||
// DEV: These are intentionally repeated in client and context
|
||||
this.log = function (type, args) {
|
||||
var values = []
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
values.push(this.stringify(args[i], 3))
|
||||
}
|
||||
|
||||
this.info({ log: values.join(', '), type: type })
|
||||
}
|
||||
|
||||
this.stringify = stringify
|
||||
|
||||
// Define our proxy error handler
|
||||
// DEV: We require one in our context to track `hasError`
|
||||
this.error = function () {
|
||||
hasError = true
|
||||
callParentKarmaMethod('error', [].slice.call(arguments))
|
||||
return false
|
||||
}
|
||||
|
||||
// Define our start handler
|
||||
function UNIMPLEMENTED_START () {
|
||||
this.error('You need to include some adapter that implements __karma__.start method!')
|
||||
}
|
||||
// all files loaded, let's start the execution
|
||||
this.loaded = function () {
|
||||
// has error -> cancel
|
||||
if (!hasError && !isLoaded) {
|
||||
isLoaded = true
|
||||
try {
|
||||
this.start(this.config)
|
||||
} catch (error) {
|
||||
this.error(error.stack || error.toString())
|
||||
}
|
||||
}
|
||||
|
||||
// remove reference to child iframe
|
||||
this.start = UNIMPLEMENTED_START
|
||||
}
|
||||
// supposed to be overridden by the context
|
||||
// TODO(vojta): support multiple callbacks (queue)
|
||||
this.start = UNIMPLEMENTED_START
|
||||
|
||||
// Define proxy methods
|
||||
// DEV: This is a closured `for` loop (same as a `forEach`) for IE support
|
||||
var proxyMethods = ['complete', 'info', 'result']
|
||||
for (var i = 0; i < proxyMethods.length; i++) {
|
||||
(function bindProxyMethod (methodName) {
|
||||
self[methodName] = function boundProxyMethod () {
|
||||
callParentKarmaMethod(methodName, [].slice.call(arguments))
|
||||
}
|
||||
}(proxyMethods[i]))
|
||||
}
|
||||
|
||||
// Define bindings for context window
|
||||
this.setupContext = function (contextWindow) {
|
||||
// If we clear the context after every run and we already had an error
|
||||
// then stop now. Otherwise, carry on.
|
||||
if (self.config.clearContext && hasError) {
|
||||
return
|
||||
}
|
||||
|
||||
// Perform window level bindings
|
||||
// DEV: We return `self.error` since we want to `return false` to ignore errors
|
||||
contextWindow.onerror = function () {
|
||||
return self.error.apply(self, arguments)
|
||||
}
|
||||
|
||||
contextWindow.onbeforeunload = function () {
|
||||
return self.error('Some of your tests did a full page reload!')
|
||||
}
|
||||
|
||||
contextWindow.dump = function () {
|
||||
self.log('dump', arguments)
|
||||
}
|
||||
|
||||
var _confirm = contextWindow.confirm
|
||||
var _prompt = contextWindow.prompt
|
||||
|
||||
contextWindow.alert = function (msg) {
|
||||
self.log('alert', [msg])
|
||||
}
|
||||
|
||||
contextWindow.confirm = function (msg) {
|
||||
self.log('confirm', [msg])
|
||||
return _confirm(msg)
|
||||
}
|
||||
|
||||
contextWindow.prompt = function (msg, defaultVal) {
|
||||
self.log('prompt', [msg, defaultVal])
|
||||
return _prompt(msg, defaultVal)
|
||||
}
|
||||
|
||||
// If we want to overload our console, then do it
|
||||
function getConsole (currentWindow) {
|
||||
return currentWindow.console || {
|
||||
log: function () {},
|
||||
info: function () {},
|
||||
warn: function () {},
|
||||
error: function () {},
|
||||
debug: function () {}
|
||||
}
|
||||
}
|
||||
if (self.config.captureConsole) {
|
||||
// patch the console
|
||||
var localConsole = contextWindow.console = getConsole(contextWindow)
|
||||
var logMethods = ['log', 'info', 'warn', 'error', 'debug']
|
||||
var patchConsoleMethod = function (method) {
|
||||
var orig = localConsole[method]
|
||||
if (!orig) {
|
||||
return
|
||||
}
|
||||
localConsole[method] = function () {
|
||||
self.log(method, arguments)
|
||||
try {
|
||||
return Function.prototype.apply.call(orig, localConsole, arguments)
|
||||
} catch (error) {
|
||||
self.log('warn', ['Console method ' + method + ' threw: ' + error])
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < logMethods.length; i++) {
|
||||
patchConsoleMethod(logMethods[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define call/proxy methods
|
||||
ContextKarma.getDirectCallParentKarmaMethod = function (parentWindow) {
|
||||
return function directCallParentKarmaMethod (method, args) {
|
||||
// If the method doesn't exist, then error out
|
||||
if (!parentWindow.karma[method]) {
|
||||
parentWindow.karma.error('Expected Karma method "' + method + '" to exist but it doesn\'t')
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, run our method
|
||||
parentWindow.karma[method].apply(parentWindow.karma, args)
|
||||
}
|
||||
}
|
||||
ContextKarma.getPostMessageCallParentKarmaMethod = function (parentWindow) {
|
||||
return function postMessageCallParentKarmaMethod (method, args) {
|
||||
parentWindow.postMessage({ __karmaMethod: method, __karmaArguments: args }, window.location.origin)
|
||||
}
|
||||
}
|
||||
|
||||
// Export our module
|
||||
module.exports = ContextKarma
|
||||
21
my-app/node_modules/karma/context/main.js
generated
vendored
Executable file
21
my-app/node_modules/karma/context/main.js
generated
vendored
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
// Load in our dependencies
|
||||
var ContextKarma = require('./karma')
|
||||
|
||||
// Resolve our parent window
|
||||
var parentWindow = window.opener || window.parent
|
||||
|
||||
// Define a remote call method for Karma
|
||||
var callParentKarmaMethod = ContextKarma.getDirectCallParentKarmaMethod(parentWindow)
|
||||
|
||||
// If we don't have access to the window, then use `postMessage`
|
||||
// DEV: In Electron, we don't have access to the parent window due to it being in a separate process
|
||||
// DEV: We avoid using this in Internet Explorer as they only support strings
|
||||
// https://caniuse.com/?search=postmessage
|
||||
var haveParentAccess = false
|
||||
try { haveParentAccess = !!parentWindow.window } catch (err) { /* Ignore errors (likely permission errors) */ }
|
||||
if (!haveParentAccess) {
|
||||
callParentKarmaMethod = ContextKarma.getPostMessageCallParentKarmaMethod(parentWindow)
|
||||
}
|
||||
|
||||
// Define a window-scoped Karma
|
||||
window.__karma__ = new ContextKarma(callParentKarmaMethod)
|
||||
13
my-app/node_modules/karma/cucumber.js
generated
vendored
Executable file
13
my-app/node_modules/karma/cucumber.js
generated
vendored
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
// Shared configuration for Cucumber.js tests.
|
||||
// See https://github.com/cucumber/cucumber-js/blob/master/docs/cli.md#profiles
|
||||
const options = [
|
||||
'--format progress',
|
||||
'--require test/e2e/support/env.js',
|
||||
'--require test/e2e/support/world.js',
|
||||
'--require test/e2e/step_definitions/core_steps.js',
|
||||
'--require test/e2e/step_definitions/hooks.js'
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
default: options.join(' ')
|
||||
}
|
||||
271
my-app/node_modules/karma/lib/browser.js
generated
vendored
Executable file
271
my-app/node_modules/karma/lib/browser.js
generated
vendored
Executable file
|
|
@ -0,0 +1,271 @@
|
|||
'use strict'
|
||||
|
||||
const BrowserResult = require('./browser_result')
|
||||
const helper = require('./helper')
|
||||
const logger = require('./logger')
|
||||
|
||||
const CONNECTED = 'CONNECTED' // The browser is connected but not yet been commanded to execute tests.
|
||||
const CONFIGURING = 'CONFIGURING' // The browser has been told to execute tests; it is configuring before tests execution.
|
||||
const EXECUTING = 'EXECUTING' // The browser is executing the tests.
|
||||
const EXECUTING_DISCONNECTED = 'EXECUTING_DISCONNECTED' // The browser is executing the tests, but temporarily disconnect (waiting for socket reconnecting).
|
||||
const DISCONNECTED = 'DISCONNECTED' // The browser got completely disconnected (e.g. browser crash) and can be only restored with a restart of execution.
|
||||
|
||||
class Browser {
|
||||
constructor (id, fullName, collection, emitter, socket, timer, disconnectDelay,
|
||||
noActivityTimeout, singleRun, clientConfig) {
|
||||
this.id = id
|
||||
this.fullName = fullName
|
||||
this.name = helper.browserFullNameToShort(fullName)
|
||||
this.lastResult = new BrowserResult()
|
||||
this.disconnectsCount = 0
|
||||
this.activeSockets = [socket]
|
||||
this.noActivityTimeout = noActivityTimeout
|
||||
this.singleRun = singleRun
|
||||
this.clientConfig = clientConfig
|
||||
this.collection = collection
|
||||
this.emitter = emitter
|
||||
this.socket = socket
|
||||
this.timer = timer
|
||||
this.disconnectDelay = disconnectDelay
|
||||
|
||||
this.log = logger.create(this.name)
|
||||
|
||||
this.noActivityTimeoutId = null
|
||||
this.pendingDisconnect = null
|
||||
this.setState(CONNECTED)
|
||||
}
|
||||
|
||||
init () {
|
||||
this.log.info(`Connected on socket ${this.socket.id} with id ${this.id}`)
|
||||
|
||||
this.bindSocketEvents(this.socket)
|
||||
this.collection.add(this)
|
||||
this.emitter.emit('browser_register', this)
|
||||
}
|
||||
|
||||
setState (toState) {
|
||||
this.log.debug(`${this.state} -> ${toState}`)
|
||||
this.state = toState
|
||||
}
|
||||
|
||||
onKarmaError (error) {
|
||||
if (this.isNotConnected()) {
|
||||
this.lastResult.error = true
|
||||
}
|
||||
this.emitter.emit('browser_error', this, error)
|
||||
this.refreshNoActivityTimeout()
|
||||
}
|
||||
|
||||
onInfo (info) {
|
||||
if (helper.isDefined(info.dump)) {
|
||||
this.emitter.emit('browser_log', this, info.dump, 'dump')
|
||||
}
|
||||
|
||||
if (helper.isDefined(info.log)) {
|
||||
this.emitter.emit('browser_log', this, info.log, info.type)
|
||||
} else if (helper.isDefined(info.total)) {
|
||||
if (this.state === EXECUTING) {
|
||||
this.lastResult.total = info.total
|
||||
}
|
||||
} else if (!helper.isDefined(info.dump)) {
|
||||
this.emitter.emit('browser_info', this, info)
|
||||
}
|
||||
|
||||
this.refreshNoActivityTimeout()
|
||||
}
|
||||
|
||||
onStart (info) {
|
||||
if (info.total === null) {
|
||||
this.log.warn('Adapter did not report total number of specs.')
|
||||
}
|
||||
|
||||
this.lastResult = new BrowserResult(info.total)
|
||||
this.setState(EXECUTING)
|
||||
this.emitter.emit('browser_start', this, info)
|
||||
this.refreshNoActivityTimeout()
|
||||
}
|
||||
|
||||
onComplete (result) {
|
||||
if (this.isNotConnected()) {
|
||||
this.setState(CONNECTED)
|
||||
this.lastResult.totalTimeEnd()
|
||||
|
||||
this.emitter.emit('browsers_change', this.collection)
|
||||
this.emitter.emit('browser_complete', this, result)
|
||||
|
||||
this.clearNoActivityTimeout()
|
||||
}
|
||||
}
|
||||
|
||||
onSocketDisconnect (reason, disconnectedSocket) {
|
||||
helper.arrayRemove(this.activeSockets, disconnectedSocket)
|
||||
if (this.activeSockets.length) {
|
||||
this.log.debug(`Disconnected ${disconnectedSocket.id}, still have ${this.getActiveSocketsIds()}`)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isConnected()) {
|
||||
this.disconnect(`Client disconnected from CONNECTED state (${reason})`)
|
||||
} else if ([CONFIGURING, EXECUTING].includes(this.state)) {
|
||||
this.log.debug(`Disconnected during run, waiting ${this.disconnectDelay}ms for reconnecting.`)
|
||||
this.setState(EXECUTING_DISCONNECTED)
|
||||
|
||||
this.pendingDisconnect = this.timer.setTimeout(() => {
|
||||
this.lastResult.totalTimeEnd()
|
||||
this.lastResult.disconnected = true
|
||||
this.disconnect(`reconnect failed before timeout of ${this.disconnectDelay}ms (${reason})`)
|
||||
this.emitter.emit('browser_complete', this)
|
||||
}, this.disconnectDelay)
|
||||
|
||||
this.clearNoActivityTimeout()
|
||||
}
|
||||
}
|
||||
|
||||
reconnect (newSocket, clientSaysReconnect) {
|
||||
if (!clientSaysReconnect || this.state === DISCONNECTED) {
|
||||
this.log.info(`Disconnected browser returned on socket ${newSocket.id} with id ${this.id}.`)
|
||||
this.setState(CONNECTED)
|
||||
|
||||
// The disconnected browser is already part of the collection.
|
||||
// Update the collection view in the UI (header on client.html)
|
||||
this.emitter.emit('browsers_change', this.collection)
|
||||
// Notify the launcher
|
||||
this.emitter.emit('browser_register', this)
|
||||
// Execute tests if configured to do so.
|
||||
if (this.singleRun) {
|
||||
this.execute()
|
||||
}
|
||||
} else if (this.state === EXECUTING_DISCONNECTED) {
|
||||
this.log.debug('Lost socket connection, but browser continued to execute. Reconnected ' +
|
||||
`on socket ${newSocket.id}.`)
|
||||
this.setState(EXECUTING)
|
||||
} else if ([CONNECTED, CONFIGURING, EXECUTING].includes(this.state)) {
|
||||
this.log.debug(`Rebinding to new socket ${newSocket.id} (already have ` +
|
||||
`${this.getActiveSocketsIds()})`)
|
||||
}
|
||||
|
||||
if (!this.activeSockets.some((s) => s.id === newSocket.id)) {
|
||||
this.activeSockets.push(newSocket)
|
||||
this.bindSocketEvents(newSocket)
|
||||
}
|
||||
|
||||
if (this.pendingDisconnect) {
|
||||
this.timer.clearTimeout(this.pendingDisconnect)
|
||||
}
|
||||
|
||||
this.refreshNoActivityTimeout()
|
||||
}
|
||||
|
||||
onResult (result) {
|
||||
if (Array.isArray(result)) {
|
||||
result.forEach(this.onResult, this)
|
||||
} else if (this.isNotConnected()) {
|
||||
this.lastResult.add(result)
|
||||
this.emitter.emit('spec_complete', this, result)
|
||||
}
|
||||
this.refreshNoActivityTimeout()
|
||||
}
|
||||
|
||||
execute () {
|
||||
this.activeSockets.forEach((socket) => socket.emit('execute', this.clientConfig))
|
||||
this.setState(CONFIGURING)
|
||||
this.refreshNoActivityTimeout()
|
||||
}
|
||||
|
||||
getActiveSocketsIds () {
|
||||
return this.activeSockets.map((s) => s.id).join(', ')
|
||||
}
|
||||
|
||||
disconnect (reason) {
|
||||
this.log.warn(`Disconnected (${this.disconnectsCount} times) ${reason || ''}`)
|
||||
this.disconnectsCount++
|
||||
this.emitter.emit('browser_error', this, `Disconnected ${reason || ''}`)
|
||||
this.remove()
|
||||
}
|
||||
|
||||
remove () {
|
||||
this.setState(DISCONNECTED)
|
||||
this.collection.remove(this)
|
||||
}
|
||||
|
||||
refreshNoActivityTimeout () {
|
||||
if (this.noActivityTimeout) {
|
||||
this.clearNoActivityTimeout()
|
||||
|
||||
this.noActivityTimeoutId = this.timer.setTimeout(() => {
|
||||
this.lastResult.totalTimeEnd()
|
||||
this.lastResult.disconnected = true
|
||||
this.disconnect(`, because no message in ${this.noActivityTimeout} ms.`)
|
||||
this.emitter.emit('browser_complete', this)
|
||||
}, this.noActivityTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
clearNoActivityTimeout () {
|
||||
if (this.noActivityTimeout && this.noActivityTimeoutId) {
|
||||
this.timer.clearTimeout(this.noActivityTimeoutId)
|
||||
this.noActivityTimeoutId = null
|
||||
}
|
||||
}
|
||||
|
||||
bindSocketEvents (socket) {
|
||||
// TODO: check which of these events are actually emitted by socket
|
||||
socket.on('disconnect', (reason) => this.onSocketDisconnect(reason, socket))
|
||||
socket.on('start', (info) => this.onStart(info))
|
||||
socket.on('karma_error', (error) => this.onKarmaError(error))
|
||||
socket.on('complete', (result) => this.onComplete(result))
|
||||
socket.on('info', (info) => this.onInfo(info))
|
||||
socket.on('result', (result) => this.onResult(result))
|
||||
}
|
||||
|
||||
isConnected () {
|
||||
return this.state === CONNECTED
|
||||
}
|
||||
|
||||
isNotConnected () {
|
||||
return !this.isConnected()
|
||||
}
|
||||
|
||||
serialize () {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
isConnected: this.state === CONNECTED
|
||||
}
|
||||
}
|
||||
|
||||
toString () {
|
||||
return this.name
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
return {
|
||||
id: this.id,
|
||||
fullName: this.fullName,
|
||||
name: this.name,
|
||||
state: this.state,
|
||||
lastResult: this.lastResult,
|
||||
disconnectsCount: this.disconnectsCount,
|
||||
noActivityTimeout: this.noActivityTimeout,
|
||||
disconnectDelay: this.disconnectDelay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Browser.factory = function (
|
||||
id, fullName, /* capturedBrowsers */ collection, emitter, socket, timer,
|
||||
/* config.browserDisconnectTimeout */ disconnectDelay,
|
||||
/* config.browserNoActivityTimeout */ noActivityTimeout,
|
||||
/* config.singleRun */ singleRun,
|
||||
/* config.client */ clientConfig) {
|
||||
return new Browser(id, fullName, collection, emitter, socket, timer,
|
||||
disconnectDelay, noActivityTimeout, singleRun, clientConfig)
|
||||
}
|
||||
|
||||
Browser.STATE_CONNECTED = CONNECTED
|
||||
Browser.STATE_CONFIGURING = CONFIGURING
|
||||
Browser.STATE_EXECUTING = EXECUTING
|
||||
Browser.STATE_EXECUTING_DISCONNECTED = EXECUTING_DISCONNECTED
|
||||
Browser.STATE_DISCONNECTED = DISCONNECTED
|
||||
|
||||
module.exports = Browser
|
||||
103
my-app/node_modules/karma/lib/browser_collection.js
generated
vendored
Executable file
103
my-app/node_modules/karma/lib/browser_collection.js
generated
vendored
Executable file
|
|
@ -0,0 +1,103 @@
|
|||
'use strict'
|
||||
|
||||
const BrowserResult = require('./browser_result')
|
||||
const helper = require('./helper')
|
||||
|
||||
class BrowserCollection {
|
||||
constructor (emitter, browsers = []) {
|
||||
this.browsers = browsers
|
||||
this.emitter = emitter
|
||||
}
|
||||
|
||||
add (browser) {
|
||||
this.browsers.push(browser)
|
||||
this.emitter.emit('browsers_change', this)
|
||||
}
|
||||
|
||||
remove (browser) {
|
||||
if (helper.arrayRemove(this.browsers, browser)) {
|
||||
this.emitter.emit('browsers_change', this)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
getById (browserId) {
|
||||
return this.browsers.find((browser) => browser.id === browserId) || null
|
||||
}
|
||||
|
||||
getNonReady () {
|
||||
return this.browsers.filter((browser) => !browser.isConnected())
|
||||
}
|
||||
|
||||
areAllReady () {
|
||||
return this.browsers.every((browser) => browser.isConnected())
|
||||
}
|
||||
|
||||
serialize () {
|
||||
return this.browsers.map((browser) => browser.serialize())
|
||||
}
|
||||
|
||||
calculateExitCode (results, singleRunBrowserNotCaptured, config) {
|
||||
config = config || {}
|
||||
if (results.disconnected || singleRunBrowserNotCaptured) {
|
||||
return 1
|
||||
}
|
||||
if (results.skipped && config.failOnSkippedTests) {
|
||||
return 1
|
||||
}
|
||||
if (results.success + results.failed === 0 && !!config.failOnEmptyTestSuite) {
|
||||
return 1
|
||||
}
|
||||
if (results.error) {
|
||||
return 1
|
||||
}
|
||||
if (config.failOnFailingTestSuite === false) {
|
||||
return 0 // Tests executed without infrastructure error, exit with 0 independent of test status.
|
||||
}
|
||||
return results.failed ? 1 : 0
|
||||
}
|
||||
|
||||
getResults (singleRunBrowserNotCaptured, config) {
|
||||
const results = { success: 0, failed: 0, skipped: 0, error: false, disconnected: false, exitCode: 0 }
|
||||
this.browsers.forEach((browser) => {
|
||||
results.success += browser.lastResult.success
|
||||
results.failed += browser.lastResult.failed
|
||||
results.skipped += browser.lastResult.skipped
|
||||
results.error = results.error || browser.lastResult.error
|
||||
results.disconnected = results.disconnected || browser.lastResult.disconnected
|
||||
})
|
||||
|
||||
results.exitCode = this.calculateExitCode(results, singleRunBrowserNotCaptured, config)
|
||||
return results
|
||||
}
|
||||
|
||||
clearResults () {
|
||||
this.browsers.forEach((browser) => {
|
||||
browser.lastResult = new BrowserResult()
|
||||
})
|
||||
}
|
||||
|
||||
clone () {
|
||||
return new BrowserCollection(this.emitter, this.browsers.slice())
|
||||
}
|
||||
|
||||
// Array APIs
|
||||
map (callback, context) {
|
||||
return this.browsers.map(callback, context)
|
||||
}
|
||||
|
||||
forEach (callback, context) {
|
||||
return this.browsers.forEach(callback, context)
|
||||
}
|
||||
|
||||
get length () {
|
||||
return this.browsers.length
|
||||
}
|
||||
}
|
||||
|
||||
BrowserCollection.factory = function (emitter) {
|
||||
return new BrowserCollection(emitter)
|
||||
}
|
||||
|
||||
module.exports = BrowserCollection
|
||||
30
my-app/node_modules/karma/lib/browser_result.js
generated
vendored
Executable file
30
my-app/node_modules/karma/lib/browser_result.js
generated
vendored
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
'use strict'
|
||||
|
||||
class BrowserResult {
|
||||
constructor (total = 0) {
|
||||
this.startTime = Date.now()
|
||||
|
||||
this.total = total
|
||||
this.skipped = this.failed = this.success = 0
|
||||
this.netTime = this.totalTime = 0
|
||||
this.disconnected = this.error = false
|
||||
}
|
||||
|
||||
totalTimeEnd () {
|
||||
this.totalTime = Date.now() - this.startTime
|
||||
}
|
||||
|
||||
add (result) {
|
||||
if (result.skipped) {
|
||||
this.skipped++
|
||||
} else if (result.success) {
|
||||
this.success++
|
||||
} else {
|
||||
this.failed++
|
||||
}
|
||||
|
||||
this.netTime += result.time
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BrowserResult
|
||||
331
my-app/node_modules/karma/lib/cli.js
generated
vendored
Executable file
331
my-app/node_modules/karma/lib/cli.js
generated
vendored
Executable file
|
|
@ -0,0 +1,331 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const yargs = require('yargs')
|
||||
const fs = require('graceful-fs')
|
||||
|
||||
const Server = require('./server')
|
||||
const helper = require('./helper')
|
||||
const constant = require('./constants')
|
||||
const cfg = require('./config')
|
||||
|
||||
function processArgs (argv, options, fs, path) {
|
||||
Object.getOwnPropertyNames(argv).forEach(function (name) {
|
||||
let argumentValue = argv[name]
|
||||
if (name !== '_' && name !== '$0') {
|
||||
if (Array.isArray(argumentValue)) {
|
||||
argumentValue = argumentValue.pop() // If the same argument is defined multiple times, override.
|
||||
}
|
||||
options[helper.dashToCamel(name)] = argumentValue
|
||||
}
|
||||
})
|
||||
|
||||
if (helper.isString(options.autoWatch)) {
|
||||
options.autoWatch = options.autoWatch === 'true'
|
||||
}
|
||||
|
||||
if (helper.isString(options.colors)) {
|
||||
options.colors = options.colors === 'true'
|
||||
}
|
||||
|
||||
if (helper.isString(options.failOnEmptyTestSuite)) {
|
||||
options.failOnEmptyTestSuite = options.failOnEmptyTestSuite === 'true'
|
||||
}
|
||||
|
||||
if (helper.isString(options.failOnFailingTestSuite)) {
|
||||
options.failOnFailingTestSuite = options.failOnFailingTestSuite === 'true'
|
||||
}
|
||||
|
||||
if (helper.isString(options.formatError)) {
|
||||
let required
|
||||
try {
|
||||
required = require(options.formatError)
|
||||
} catch (err) {
|
||||
console.error('Could not require formatError: ' + options.formatError, err)
|
||||
}
|
||||
// support exports.formatError and module.exports = function
|
||||
options.formatError = required.formatError || required
|
||||
if (!helper.isFunction(options.formatError)) {
|
||||
console.error(`Format error must be a function, got: ${typeof options.formatError}`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if (helper.isString(options.logLevel)) {
|
||||
const logConstant = constant['LOG_' + options.logLevel.toUpperCase()]
|
||||
if (helper.isDefined(logConstant)) {
|
||||
options.logLevel = logConstant
|
||||
} else {
|
||||
console.error('Log level must be one of disable, error, warn, info, or debug.')
|
||||
process.exit(1)
|
||||
}
|
||||
} else if (helper.isDefined(options.logLevel)) {
|
||||
console.error('Log level must be one of disable, error, warn, info, or debug.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (helper.isString(options.singleRun)) {
|
||||
options.singleRun = options.singleRun === 'true'
|
||||
}
|
||||
|
||||
if (helper.isString(options.browsers)) {
|
||||
options.browsers = options.browsers.split(',')
|
||||
}
|
||||
|
||||
if (options.reportSlowerThan === false) {
|
||||
options.reportSlowerThan = 0
|
||||
}
|
||||
|
||||
if (helper.isString(options.reporters)) {
|
||||
options.reporters = options.reporters.split(',')
|
||||
}
|
||||
|
||||
if (helper.isString(options.removedFiles)) {
|
||||
options.removedFiles = options.removedFiles.split(',')
|
||||
}
|
||||
|
||||
if (helper.isString(options.addedFiles)) {
|
||||
options.addedFiles = options.addedFiles.split(',')
|
||||
}
|
||||
|
||||
if (helper.isString(options.changedFiles)) {
|
||||
options.changedFiles = options.changedFiles.split(',')
|
||||
}
|
||||
|
||||
if (helper.isString(options.refresh)) {
|
||||
options.refresh = options.refresh === 'true'
|
||||
}
|
||||
|
||||
let configFile = argv.configFile
|
||||
|
||||
if (!configFile) {
|
||||
// default config file (if exists)
|
||||
if (fs.existsSync('./karma.conf.js')) {
|
||||
configFile = './karma.conf.js'
|
||||
} else if (fs.existsSync('./karma.conf.coffee')) {
|
||||
configFile = './karma.conf.coffee'
|
||||
} else if (fs.existsSync('./karma.conf.ts')) {
|
||||
configFile = './karma.conf.ts'
|
||||
} else if (fs.existsSync('./.config/karma.conf.js')) {
|
||||
configFile = './.config/karma.conf.js'
|
||||
} else if (fs.existsSync('./.config/karma.conf.coffee')) {
|
||||
configFile = './.config/karma.conf.coffee'
|
||||
} else if (fs.existsSync('./.config/karma.conf.ts')) {
|
||||
configFile = './.config/karma.conf.ts'
|
||||
}
|
||||
}
|
||||
|
||||
options.configFile = configFile ? path.resolve(configFile) : null
|
||||
|
||||
if (options.cmd === 'run') {
|
||||
options.clientArgs = parseClientArgs(process.argv)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
function parseClientArgs (argv) {
|
||||
// extract any args after '--' as clientArgs
|
||||
let clientArgs = []
|
||||
argv = argv.slice(2)
|
||||
const idx = argv.indexOf('--')
|
||||
if (idx !== -1) {
|
||||
clientArgs = argv.slice(idx + 1)
|
||||
}
|
||||
return clientArgs
|
||||
}
|
||||
|
||||
// return only args that occur before `--`
|
||||
function argsBeforeDoubleDash (argv) {
|
||||
const idx = argv.indexOf('--')
|
||||
|
||||
return idx === -1 ? argv : argv.slice(0, idx)
|
||||
}
|
||||
|
||||
function describeRoot () {
|
||||
return yargs
|
||||
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
|
||||
'Run --help with particular command to see its description and available options.\n\n' +
|
||||
'Usage:\n' +
|
||||
' $0 <command>')
|
||||
.command('init [configFile]', 'Initialize a config file.', describeInit)
|
||||
.command('start [configFile]', 'Start the server / do a single run.', describeStart)
|
||||
.command('run [configFile]', 'Trigger a test run.', describeRun)
|
||||
.command('stop [configFile]', 'Stop the server.', describeStop)
|
||||
.command('completion', 'Shell completion for karma.', describeCompletion)
|
||||
.demandCommand(1, 'Command not specified.')
|
||||
.strictCommands()
|
||||
.describe('help', 'Print usage and options.')
|
||||
.describe('version', 'Print current version.')
|
||||
}
|
||||
|
||||
function describeInit (yargs) {
|
||||
yargs
|
||||
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
|
||||
'INIT - Initialize a config file.\n\n' +
|
||||
'Usage:\n' +
|
||||
' $0 init [configFile]')
|
||||
.strictCommands(false)
|
||||
.version(false)
|
||||
.positional('configFile', {
|
||||
describe: 'Name of the generated Karma configuration file',
|
||||
type: 'string'
|
||||
})
|
||||
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
|
||||
.describe('colors', 'Use colors when reporting and printing logs.')
|
||||
.describe('no-colors', 'Do not use colors when reporting or printing logs.')
|
||||
}
|
||||
|
||||
function describeStart (yargs) {
|
||||
yargs
|
||||
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
|
||||
'START - Start the server / do a single run.\n\n' +
|
||||
'Usage:\n' +
|
||||
' $0 start [configFile]')
|
||||
.strictCommands(false)
|
||||
.version(false)
|
||||
.positional('configFile', {
|
||||
describe: 'Path to the Karma configuration file',
|
||||
type: 'string'
|
||||
})
|
||||
.describe('port', '<integer> Port where the server is running.')
|
||||
.describe('auto-watch', 'Auto watch source files and run on change.')
|
||||
.describe('detached', 'Detach the server.')
|
||||
.describe('no-auto-watch', 'Do not watch source files.')
|
||||
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
|
||||
.describe('colors', 'Use colors when reporting and printing logs.')
|
||||
.describe('no-colors', 'Do not use colors when reporting or printing logs.')
|
||||
.describe('reporters', 'List of reporters (available: dots, progress, junit, growl, coverage).')
|
||||
.describe('browsers', 'List of browsers to start (eg. --browsers Chrome,ChromeCanary,Firefox).')
|
||||
.describe('capture-timeout', '<integer> Kill browser if does not capture in given time [ms].')
|
||||
.describe('single-run', 'Run the test when browsers captured and exit.')
|
||||
.describe('no-single-run', 'Disable single-run.')
|
||||
.describe('report-slower-than', '<integer> Report tests that are slower than given time [ms].')
|
||||
.describe('fail-on-empty-test-suite', 'Fail on empty test suite.')
|
||||
.describe('no-fail-on-empty-test-suite', 'Do not fail on empty test suite.')
|
||||
.describe('fail-on-failing-test-suite', 'Fail on failing test suite.')
|
||||
.describe('no-fail-on-failing-test-suite', 'Do not fail on failing test suite.')
|
||||
.option('format-error', {
|
||||
describe: 'A path to a file that exports the format function.',
|
||||
type: 'string'
|
||||
})
|
||||
}
|
||||
|
||||
function describeRun (yargs) {
|
||||
yargs
|
||||
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
|
||||
'RUN - Run the tests (requires running server).\n\n' +
|
||||
'Usage:\n' +
|
||||
' $0 run [configFile] [-- <clientArgs>]')
|
||||
.strictCommands(false)
|
||||
.version(false)
|
||||
.positional('configFile', {
|
||||
describe: 'Path to the Karma configuration file',
|
||||
type: 'string'
|
||||
})
|
||||
.describe('port', '<integer> Port where the server is listening.')
|
||||
.describe('no-refresh', 'Do not re-glob all the patterns.')
|
||||
.describe('fail-on-empty-test-suite', 'Fail on empty test suite.')
|
||||
.describe('no-fail-on-empty-test-suite', 'Do not fail on empty test suite.')
|
||||
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
|
||||
.describe('colors', 'Use colors when reporting and printing logs.')
|
||||
.describe('no-colors', 'Do not use colors when reporting or printing logs.')
|
||||
.option('removed-files', {
|
||||
describe: 'Comma-separated paths to removed files. Useful when automatic file watching is disabled.',
|
||||
type: 'string'
|
||||
})
|
||||
.option('changed-files', {
|
||||
describe: 'Comma-separated paths to changed files. Useful when automatic file watching is disabled.',
|
||||
type: 'string'
|
||||
})
|
||||
.option('added-files', {
|
||||
describe: 'Comma-separated paths to added files. Useful when automatic file watching is disabled.',
|
||||
type: 'string'
|
||||
})
|
||||
}
|
||||
|
||||
function describeStop (yargs) {
|
||||
yargs
|
||||
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
|
||||
'STOP - Stop the server (requires running server).\n\n' +
|
||||
'Usage:\n' +
|
||||
' $0 stop [configFile]')
|
||||
.strictCommands(false)
|
||||
.version(false)
|
||||
.positional('configFile', {
|
||||
describe: 'Path to the Karma configuration file',
|
||||
type: 'string'
|
||||
})
|
||||
.describe('port', '<integer> Port where the server is listening.')
|
||||
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
|
||||
}
|
||||
|
||||
function describeCompletion (yargs) {
|
||||
yargs
|
||||
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
|
||||
'COMPLETION - Bash/ZSH completion for karma.\n\n' +
|
||||
'Installation:\n' +
|
||||
' $0 completion >> ~/.bashrc')
|
||||
.version(false)
|
||||
}
|
||||
|
||||
function printRunnerProgress (data) {
|
||||
process.stdout.write(data)
|
||||
}
|
||||
|
||||
exports.process = () => {
|
||||
const argv = describeRoot().parse(argsBeforeDoubleDash(process.argv.slice(2)))
|
||||
return processArgs(argv, { cmd: argv._.shift() }, fs, path)
|
||||
}
|
||||
|
||||
exports.run = async () => {
|
||||
const cliOptions = exports.process()
|
||||
const cmd = cliOptions.cmd // prevent config from changing the command
|
||||
const cmdNeedsConfig = cmd === 'start' || cmd === 'run' || cmd === 'stop'
|
||||
if (cmdNeedsConfig) {
|
||||
let config
|
||||
try {
|
||||
config = await cfg.parseConfig(
|
||||
cliOptions.configFile,
|
||||
cliOptions,
|
||||
{
|
||||
promiseConfig: true,
|
||||
throwErrors: true
|
||||
}
|
||||
)
|
||||
} catch (karmaConfigException) {
|
||||
// The reject reason/exception isn't used to log a message since
|
||||
// parseConfig already calls a configured logger method with an almost
|
||||
// identical message.
|
||||
|
||||
// The `run` function is a private application, not a public API. We don't
|
||||
// need to worry about process.exit vs throw vs promise rejection here.
|
||||
process.exit(1)
|
||||
}
|
||||
switch (cmd) {
|
||||
case 'start': {
|
||||
const server = new Server(config)
|
||||
await server.start()
|
||||
return server
|
||||
}
|
||||
case 'run':
|
||||
return require('./runner')
|
||||
.run(config)
|
||||
.on('progress', printRunnerProgress)
|
||||
case 'stop':
|
||||
return require('./stopper').stop(config)
|
||||
}
|
||||
} else {
|
||||
switch (cmd) {
|
||||
case 'init':
|
||||
return require('./init').init(cliOptions)
|
||||
case 'completion':
|
||||
return require('./completion').completion(cliOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just for testing
|
||||
exports.processArgs = processArgs
|
||||
exports.parseClientArgs = parseClientArgs
|
||||
exports.argsBeforeDoubleDash = argsBeforeDoubleDash
|
||||
126
my-app/node_modules/karma/lib/completion.js
generated
vendored
Executable file
126
my-app/node_modules/karma/lib/completion.js
generated
vendored
Executable file
|
|
@ -0,0 +1,126 @@
|
|||
'use strict'
|
||||
|
||||
const glob = require('glob')
|
||||
|
||||
const CUSTOM = ['']
|
||||
const BOOLEAN = false
|
||||
|
||||
const options = {
|
||||
start: {
|
||||
'--port': CUSTOM,
|
||||
'--auto-watch': BOOLEAN,
|
||||
'--no-auto-watch': BOOLEAN,
|
||||
'--log-level': ['disable', 'debug', 'info', 'warn', 'error'],
|
||||
'--colors': BOOLEAN,
|
||||
'--no-colors': BOOLEAN,
|
||||
'--reporters': ['dots', 'progress'],
|
||||
'--no-reporters': BOOLEAN,
|
||||
'--browsers': ['Chrome', 'ChromeHeadless', 'ChromeCanary', 'Firefox', 'PhantomJS', 'Safari', 'Opera'],
|
||||
'--no-browsers': BOOLEAN,
|
||||
'--single-run': BOOLEAN,
|
||||
'--no-single-run': BOOLEAN,
|
||||
'--help': BOOLEAN
|
||||
},
|
||||
init: {
|
||||
'--log-level': ['disable', 'debug', 'info', 'warn', 'error'],
|
||||
'--colors': BOOLEAN,
|
||||
'--no-colors': BOOLEAN,
|
||||
'--help': BOOLEAN
|
||||
},
|
||||
run: {
|
||||
'--no-refresh': BOOLEAN,
|
||||
'--port': CUSTOM,
|
||||
'--help': BOOLEAN
|
||||
}
|
||||
}
|
||||
|
||||
function opositeWord (word) {
|
||||
if (word.startsWith('-')) {
|
||||
return word.startsWith('--no-') ? `--${word.slice(5)}` : `--no-${word.slice(2)}`
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function sendCompletion (possibleWords, env) {
|
||||
const regexp = new RegExp('^' + env.last)
|
||||
possibleWords
|
||||
.filter((word) => regexp.test(word) && !env.words.includes(word) && !env.words.includes(opositeWord(word)))
|
||||
.forEach((word) => {
|
||||
console.log(word)
|
||||
})
|
||||
}
|
||||
|
||||
function sendCompletionFiles (env) {
|
||||
glob(env.last + '*', { mark: true, nocase: true }, (err, files) => {
|
||||
if (err) return console.error(err)
|
||||
|
||||
if (files.length === 1 && files[0].endsWith('/')) {
|
||||
sendCompletionFiles({ last: files[0] })
|
||||
} else {
|
||||
console.log(files.join('\n'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function complete (env) {
|
||||
if (env.count === 1) {
|
||||
return sendCompletion(env.words[0].startsWith('-') ? ['--help', '--version'] : Object.keys(options), env)
|
||||
} else if (env.count === 2 && !env.words[1].startsWith('-')) {
|
||||
return sendCompletionFiles(env)
|
||||
}
|
||||
|
||||
const cmdOptions = options[env.words[0]]
|
||||
|
||||
if (cmdOptions) {
|
||||
if (cmdOptions[env.prev] === CUSTOM && env.last) {
|
||||
console.log(env.last)
|
||||
} else {
|
||||
return sendCompletion(cmdOptions[env.prev] || Object.keys(cmdOptions), env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function completion () {
|
||||
if (process.argv[3] === '--') {
|
||||
return complete({
|
||||
words: process.argv.slice(5),
|
||||
count: parseInt(process.env.COMP_CWORD, 10),
|
||||
last: process.argv[process.argv.length - 1],
|
||||
prev: process.argv[process.argv.length - 2]
|
||||
})
|
||||
}
|
||||
|
||||
// just print out the karma-completion.sh
|
||||
const fs = require('graceful-fs')
|
||||
const path = require('path')
|
||||
|
||||
fs.readFile(path.resolve(__dirname, '../scripts/karma-completion.sh'), 'utf8', function (err, data) {
|
||||
if (err) return console.error(err)
|
||||
|
||||
process.stdout.write(data)
|
||||
process.stdout.on('error', function (error) {
|
||||
// Darwin is a real dick sometimes.
|
||||
//
|
||||
// This is necessary because the "source" or "." program in
|
||||
// bash on OS X closes its file argument before reading
|
||||
// from it, meaning that you get exactly 1 write, which will
|
||||
// work most of the time, and will always raise an EPIPE.
|
||||
//
|
||||
// Really, one should not be tossing away EPIPE errors, or any
|
||||
// errors, so casually. But, without this, `. <(karma completion)`
|
||||
// can never ever work on OS X.
|
||||
if (error.errno === 'EPIPE') {
|
||||
error = null
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// PUBLIC API
|
||||
exports.completion = completion
|
||||
|
||||
// for testing
|
||||
exports.opositeWord = opositeWord
|
||||
exports.sendCompletion = sendCompletion
|
||||
exports.complete = complete
|
||||
544
my-app/node_modules/karma/lib/config.js
generated
vendored
Executable file
544
my-app/node_modules/karma/lib/config.js
generated
vendored
Executable file
|
|
@ -0,0 +1,544 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
const logger = require('./logger')
|
||||
const log = logger.create('config')
|
||||
const helper = require('./helper')
|
||||
const constant = require('./constants')
|
||||
|
||||
const _ = require('lodash')
|
||||
|
||||
let COFFEE_SCRIPT_AVAILABLE = false
|
||||
let LIVE_SCRIPT_AVAILABLE = false
|
||||
let TYPE_SCRIPT_AVAILABLE = false
|
||||
|
||||
try {
|
||||
require('coffeescript').register()
|
||||
COFFEE_SCRIPT_AVAILABLE = true
|
||||
} catch {}
|
||||
|
||||
// LiveScript is required here to enable config files written in LiveScript.
|
||||
// It's not directly used in this file.
|
||||
try {
|
||||
require('LiveScript')
|
||||
LIVE_SCRIPT_AVAILABLE = true
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
require('ts-node')
|
||||
TYPE_SCRIPT_AVAILABLE = true
|
||||
} catch {}
|
||||
|
||||
class Pattern {
|
||||
constructor (pattern, served, included, watched, nocache, type, isBinary, integrity) {
|
||||
this.pattern = pattern
|
||||
this.served = helper.isDefined(served) ? served : true
|
||||
this.included = helper.isDefined(included) ? included : true
|
||||
this.watched = helper.isDefined(watched) ? watched : true
|
||||
this.nocache = helper.isDefined(nocache) ? nocache : false
|
||||
this.weight = helper.mmPatternWeight(pattern)
|
||||
this.type = type
|
||||
this.isBinary = isBinary
|
||||
this.integrity = integrity
|
||||
}
|
||||
|
||||
compare (other) {
|
||||
return helper.mmComparePatternWeights(this.weight, other.weight)
|
||||
}
|
||||
}
|
||||
|
||||
class UrlPattern extends Pattern {
|
||||
constructor (url, type, integrity) {
|
||||
super(url, false, true, false, false, type, undefined, integrity)
|
||||
}
|
||||
}
|
||||
|
||||
function createPatternObject (pattern) {
|
||||
if (pattern && helper.isString(pattern)) {
|
||||
return helper.isUrlAbsolute(pattern)
|
||||
? new UrlPattern(pattern)
|
||||
: new Pattern(pattern)
|
||||
} else if (helper.isObject(pattern) && pattern.pattern && helper.isString(pattern.pattern)) {
|
||||
return helper.isUrlAbsolute(pattern.pattern)
|
||||
? new UrlPattern(pattern.pattern, pattern.type, pattern.integrity)
|
||||
: new Pattern(pattern.pattern, pattern.served, pattern.included, pattern.watched, pattern.nocache, pattern.type)
|
||||
} else {
|
||||
log.warn(`Invalid pattern ${pattern}!\n\tExpected string or object with "pattern" property.`)
|
||||
return new Pattern(null, false, false, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeUrl (url) {
|
||||
if (!url.startsWith('/')) {
|
||||
url = `/${url}`
|
||||
}
|
||||
|
||||
if (!url.endsWith('/')) {
|
||||
url = url + '/'
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
function normalizeUrlRoot (urlRoot) {
|
||||
const normalizedUrlRoot = normalizeUrl(urlRoot)
|
||||
|
||||
if (normalizedUrlRoot !== urlRoot) {
|
||||
log.warn(`urlRoot normalized to "${normalizedUrlRoot}"`)
|
||||
}
|
||||
|
||||
return normalizedUrlRoot
|
||||
}
|
||||
|
||||
function normalizeProxyPath (proxyPath) {
|
||||
const normalizedProxyPath = normalizeUrl(proxyPath)
|
||||
|
||||
if (normalizedProxyPath !== proxyPath) {
|
||||
log.warn(`proxyPath normalized to "${normalizedProxyPath}"`)
|
||||
}
|
||||
|
||||
return normalizedProxyPath
|
||||
}
|
||||
|
||||
function normalizeConfig (config, configFilePath) {
|
||||
function basePathResolve (relativePath) {
|
||||
if (helper.isUrlAbsolute(relativePath)) {
|
||||
return relativePath
|
||||
} else if (helper.isDefined(config.basePath) && helper.isDefined(relativePath)) {
|
||||
return path.resolve(config.basePath, relativePath)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function createPatternMapper (resolve) {
|
||||
return (objectPattern) => Object.assign(objectPattern, { pattern: resolve(objectPattern.pattern) })
|
||||
}
|
||||
|
||||
if (helper.isString(configFilePath)) {
|
||||
config.basePath = path.resolve(path.dirname(configFilePath), config.basePath) // resolve basePath
|
||||
config.exclude.push(configFilePath) // always ignore the config file itself
|
||||
} else {
|
||||
config.basePath = path.resolve(config.basePath || '.')
|
||||
}
|
||||
|
||||
config.files = config.files.map(createPatternObject).map(createPatternMapper(basePathResolve))
|
||||
config.exclude = config.exclude.map(basePathResolve)
|
||||
config.customContextFile = config.customContextFile && basePathResolve(config.customContextFile)
|
||||
config.customDebugFile = config.customDebugFile && basePathResolve(config.customDebugFile)
|
||||
config.customClientContextFile = config.customClientContextFile && basePathResolve(config.customClientContextFile)
|
||||
|
||||
// normalize paths on windows
|
||||
config.basePath = helper.normalizeWinPath(config.basePath)
|
||||
config.files = config.files.map(createPatternMapper(helper.normalizeWinPath))
|
||||
config.exclude = config.exclude.map(helper.normalizeWinPath)
|
||||
config.customContextFile = helper.normalizeWinPath(config.customContextFile)
|
||||
config.customDebugFile = helper.normalizeWinPath(config.customDebugFile)
|
||||
config.customClientContextFile = helper.normalizeWinPath(config.customClientContextFile)
|
||||
|
||||
// normalize urlRoot
|
||||
config.urlRoot = normalizeUrlRoot(config.urlRoot)
|
||||
|
||||
// normalize and default upstream proxy settings if given
|
||||
if (config.upstreamProxy) {
|
||||
const proxy = config.upstreamProxy
|
||||
proxy.path = helper.isDefined(proxy.path) ? normalizeProxyPath(proxy.path) : '/'
|
||||
proxy.hostname = helper.isDefined(proxy.hostname) ? proxy.hostname : 'localhost'
|
||||
proxy.port = helper.isDefined(proxy.port) ? proxy.port : 9875
|
||||
|
||||
// force protocol to end with ':'
|
||||
proxy.protocol = (proxy.protocol || 'http').split(':')[0] + ':'
|
||||
if (proxy.protocol.match(/https?:/) === null) {
|
||||
log.warn(`"${proxy.protocol}" is not a supported upstream proxy protocol, defaulting to "http:"`)
|
||||
proxy.protocol = 'http:'
|
||||
}
|
||||
}
|
||||
|
||||
// force protocol to end with ':'
|
||||
config.protocol = (config.protocol || 'http').split(':')[0] + ':'
|
||||
if (config.protocol.match(/https?:/) === null) {
|
||||
log.warn(`"${config.protocol}" is not a supported protocol, defaulting to "http:"`)
|
||||
config.protocol = 'http:'
|
||||
}
|
||||
|
||||
if (config.proxies && Object.prototype.hasOwnProperty.call(config.proxies, config.urlRoot)) {
|
||||
log.warn(`"${config.urlRoot}" is proxied, you should probably change urlRoot to avoid conflicts`)
|
||||
}
|
||||
|
||||
if (config.singleRun && config.autoWatch) {
|
||||
log.debug('autoWatch set to false, because of singleRun')
|
||||
config.autoWatch = false
|
||||
}
|
||||
|
||||
if (config.runInParent) {
|
||||
log.debug('useIframe set to false, because using runInParent')
|
||||
config.useIframe = false
|
||||
}
|
||||
|
||||
if (!config.singleRun && !config.useIframe && config.runInParent) {
|
||||
log.debug('singleRun set to true, because using runInParent')
|
||||
config.singleRun = true
|
||||
}
|
||||
|
||||
if (helper.isString(config.reporters)) {
|
||||
config.reporters = config.reporters.split(',')
|
||||
}
|
||||
|
||||
if (config.client && config.client.args) {
|
||||
assert(Array.isArray(config.client.args), 'Invalid configuration: client.args must be an array of strings')
|
||||
}
|
||||
|
||||
if (config.browsers) {
|
||||
assert(Array.isArray(config.browsers), 'Invalid configuration: browsers option must be an array')
|
||||
}
|
||||
|
||||
if (config.formatError) {
|
||||
assert(helper.isFunction(config.formatError), 'Invalid configuration: formatError option must be a function.')
|
||||
}
|
||||
|
||||
if (config.processKillTimeout) {
|
||||
assert(helper.isNumber(config.processKillTimeout), 'Invalid configuration: processKillTimeout option must be a number.')
|
||||
}
|
||||
|
||||
if (config.browserSocketTimeout) {
|
||||
assert(helper.isNumber(config.browserSocketTimeout), 'Invalid configuration: browserSocketTimeout option must be a number.')
|
||||
}
|
||||
|
||||
if (config.pingTimeout) {
|
||||
assert(helper.isNumber(config.pingTimeout), 'Invalid configuration: pingTimeout option must be a number.')
|
||||
}
|
||||
|
||||
const defaultClient = config.defaultClient || {}
|
||||
Object.keys(defaultClient).forEach(function (key) {
|
||||
const option = config.client[key]
|
||||
config.client[key] = helper.isDefined(option) ? option : defaultClient[key]
|
||||
})
|
||||
|
||||
// normalize preprocessors
|
||||
const preprocessors = config.preprocessors || {}
|
||||
const normalizedPreprocessors = config.preprocessors = Object.create(null)
|
||||
|
||||
Object.keys(preprocessors).forEach(function (pattern) {
|
||||
const normalizedPattern = helper.normalizeWinPath(basePathResolve(pattern))
|
||||
|
||||
normalizedPreprocessors[normalizedPattern] = helper.isString(preprocessors[pattern])
|
||||
? [preprocessors[pattern]] : preprocessors[pattern]
|
||||
})
|
||||
|
||||
// define custom launchers/preprocessors/reporters - create a new plugin
|
||||
const module = Object.create(null)
|
||||
let hasSomeInlinedPlugin = false
|
||||
const types = ['launcher', 'preprocessor', 'reporter']
|
||||
|
||||
types.forEach(function (type) {
|
||||
const definitions = config[`custom${helper.ucFirst(type)}s`] || {}
|
||||
|
||||
Object.keys(definitions).forEach(function (name) {
|
||||
const definition = definitions[name]
|
||||
|
||||
if (!helper.isObject(definition)) {
|
||||
return log.warn(`Can not define ${type} ${name}. Definition has to be an object.`)
|
||||
}
|
||||
|
||||
if (!helper.isString(definition.base)) {
|
||||
return log.warn(`Can not define ${type} ${name}. Missing base ${type}.`)
|
||||
}
|
||||
|
||||
const token = type + ':' + definition.base
|
||||
const locals = {
|
||||
args: ['value', definition]
|
||||
}
|
||||
|
||||
module[type + ':' + name] = ['factory', function (injector) {
|
||||
const plugin = injector.createChild([locals], [token]).get(token)
|
||||
if (type === 'launcher' && helper.isDefined(definition.displayName)) {
|
||||
plugin.displayName = definition.displayName
|
||||
}
|
||||
return plugin
|
||||
}]
|
||||
hasSomeInlinedPlugin = true
|
||||
})
|
||||
})
|
||||
|
||||
if (hasSomeInlinedPlugin) {
|
||||
config.plugins.push(module)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
class Config {
|
||||
constructor () {
|
||||
this.LOG_DISABLE = constant.LOG_DISABLE
|
||||
this.LOG_ERROR = constant.LOG_ERROR
|
||||
this.LOG_WARN = constant.LOG_WARN
|
||||
this.LOG_INFO = constant.LOG_INFO
|
||||
this.LOG_DEBUG = constant.LOG_DEBUG
|
||||
|
||||
// DEFAULT CONFIG
|
||||
this.frameworks = []
|
||||
this.protocol = 'http:'
|
||||
this.port = constant.DEFAULT_PORT
|
||||
this.listenAddress = constant.DEFAULT_LISTEN_ADDR
|
||||
this.hostname = constant.DEFAULT_HOSTNAME
|
||||
this.httpsServerConfig = {}
|
||||
this.basePath = ''
|
||||
this.files = []
|
||||
this.browserConsoleLogOptions = {
|
||||
level: 'debug',
|
||||
format: '%b %T: %m',
|
||||
terminal: true
|
||||
}
|
||||
this.customContextFile = null
|
||||
this.customDebugFile = null
|
||||
this.customClientContextFile = null
|
||||
this.exclude = []
|
||||
this.logLevel = constant.LOG_INFO
|
||||
this.colors = true
|
||||
this.autoWatch = true
|
||||
this.autoWatchBatchDelay = 250
|
||||
this.restartOnFileChange = false
|
||||
this.usePolling = process.platform === 'linux'
|
||||
this.reporters = ['progress']
|
||||
this.singleRun = false
|
||||
this.browsers = []
|
||||
this.captureTimeout = 60000
|
||||
this.pingTimeout = 5000
|
||||
this.proxies = {}
|
||||
this.proxyValidateSSL = true
|
||||
this.preprocessors = {}
|
||||
this.preprocessor_priority = {}
|
||||
this.urlRoot = '/'
|
||||
this.upstreamProxy = undefined
|
||||
this.reportSlowerThan = 0
|
||||
this.loggers = [constant.CONSOLE_APPENDER]
|
||||
this.transports = ['polling', 'websocket']
|
||||
this.forceJSONP = false
|
||||
this.plugins = ['karma-*']
|
||||
this.defaultClient = this.client = {
|
||||
args: [],
|
||||
useIframe: true,
|
||||
runInParent: false,
|
||||
captureConsole: true,
|
||||
clearContext: true,
|
||||
allowedReturnUrlPatterns: ['^https?://']
|
||||
}
|
||||
this.browserDisconnectTimeout = 2000
|
||||
this.browserDisconnectTolerance = 0
|
||||
this.browserNoActivityTimeout = 30000
|
||||
this.processKillTimeout = 2000
|
||||
this.concurrency = Infinity
|
||||
this.failOnEmptyTestSuite = true
|
||||
this.retryLimit = 2
|
||||
this.detached = false
|
||||
this.crossOriginAttribute = true
|
||||
this.browserSocketTimeout = 20000
|
||||
}
|
||||
|
||||
set (newConfig) {
|
||||
_.mergeWith(this, newConfig, (obj, src) => {
|
||||
// Overwrite arrays to keep consistent with #283
|
||||
if (Array.isArray(src)) {
|
||||
return src
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' +
|
||||
' config.set({\n' +
|
||||
' // your config\n' +
|
||||
' });\n' +
|
||||
' };\n'
|
||||
|
||||
/**
|
||||
* Retrieve a parsed and finalized Karma `Config` instance. This `karmaConfig`
|
||||
* object may be used to configure public API methods such a `Server`,
|
||||
* `runner.run`, and `stopper.stop`.
|
||||
*
|
||||
* @param {?string} [configFilePath=null]
|
||||
* A string representing a file system path pointing to the config file
|
||||
* whose default export is a function that will be used to set Karma
|
||||
* configuration options. This function will be passed an instance of the
|
||||
* `Config` class as its first argument. If this option is not provided,
|
||||
* then only the options provided by the `cliOptions` argument will be
|
||||
* set.
|
||||
* @param {Object} cliOptions
|
||||
* An object whose values will take priority over options set in the
|
||||
* config file. The config object passed to function exported by the
|
||||
* config file will already have these options applied. Any changes the
|
||||
* config file makes to these options will effectively be ignored in the
|
||||
* final configuration.
|
||||
*
|
||||
* `cliOptions` all the same options as the config file and is applied
|
||||
* using the same `config.set()` method.
|
||||
* @param {Object} parseOptions
|
||||
* @param {boolean} [parseOptions.promiseConfig=false]
|
||||
* When `true`, a promise that resolves to a `Config` object will be
|
||||
* returned. This also allows the function exported by config files (if
|
||||
* provided) to be asynchronous by returning a promise. Resolving this
|
||||
* promise indicates that all async activity has completed. The resolution
|
||||
* value itself is ignored, all configuration must be done with
|
||||
* `config.set`.
|
||||
* @param {boolean} [parseOptions.throwErrors=false]
|
||||
* When `true`, process exiting on critical failures will be disabled. In
|
||||
* The error will be thrown as an exception. If
|
||||
* `parseOptions.promiseConfig` is also `true`, then the error will
|
||||
* instead be used as the promise's reject reason.
|
||||
* @returns {Config|Promise<Config>}
|
||||
*/
|
||||
function parseConfig (configFilePath, cliOptions, parseOptions) {
|
||||
const promiseConfig = parseOptions && parseOptions.promiseConfig === true
|
||||
const throwErrors = parseOptions && parseOptions.throwErrors === true
|
||||
const shouldSetupLoggerEarly = promiseConfig
|
||||
if (shouldSetupLoggerEarly) {
|
||||
// `setupFromConfig` provides defaults for `colors` and `logLevel`.
|
||||
// `setup` provides defaults for `appenders`
|
||||
// The first argument MUST BE an object
|
||||
logger.setupFromConfig({})
|
||||
}
|
||||
function fail () {
|
||||
log.error(...arguments)
|
||||
if (throwErrors) {
|
||||
const errorMessage = Array.from(arguments).join(' ')
|
||||
const err = new Error(errorMessage)
|
||||
if (promiseConfig) {
|
||||
return Promise.reject(err)
|
||||
}
|
||||
throw err
|
||||
} else {
|
||||
const warningMessage =
|
||||
'The `parseConfig()` function historically called `process.exit(1)`' +
|
||||
' when it failed. This behavior is now deprecated and function will' +
|
||||
' throw an error in the next major release. To suppress this warning' +
|
||||
' pass `throwErrors: true` as a third argument to opt-in into the new' +
|
||||
' behavior and adjust your code to respond to the exception' +
|
||||
' accordingly.' +
|
||||
' Example: `parseConfig(path, cliOptions, { throwErrors: true })`'
|
||||
log.warn(warningMessage)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
let configModule
|
||||
if (configFilePath) {
|
||||
try {
|
||||
if (path.extname(configFilePath) === '.ts' && TYPE_SCRIPT_AVAILABLE) {
|
||||
require('ts-node').register()
|
||||
}
|
||||
configModule = require(configFilePath)
|
||||
if (typeof configModule === 'object' && typeof configModule.default !== 'undefined') {
|
||||
configModule = configModule.default
|
||||
}
|
||||
} catch (e) {
|
||||
const extension = path.extname(configFilePath)
|
||||
if (extension === '.coffee' && !COFFEE_SCRIPT_AVAILABLE) {
|
||||
log.error('You need to install CoffeeScript.\n npm install coffeescript --save-dev')
|
||||
} else if (extension === '.ls' && !LIVE_SCRIPT_AVAILABLE) {
|
||||
log.error('You need to install LiveScript.\n npm install LiveScript --save-dev')
|
||||
} else if (extension === '.ts' && !TYPE_SCRIPT_AVAILABLE) {
|
||||
log.error('You need to install TypeScript.\n npm install typescript ts-node --save-dev')
|
||||
}
|
||||
return fail('Error in config file!\n ' + e.stack || e)
|
||||
}
|
||||
if (!helper.isFunction(configModule)) {
|
||||
return fail('Config file must export a function!\n' + CONFIG_SYNTAX_HELP)
|
||||
}
|
||||
} else {
|
||||
configModule = () => {} // if no config file path is passed, we define a dummy config module.
|
||||
}
|
||||
|
||||
const config = new Config()
|
||||
|
||||
// save and reset hostname and listenAddress so we can detect if the user
|
||||
// changed them
|
||||
const defaultHostname = config.hostname
|
||||
config.hostname = null
|
||||
const defaultListenAddress = config.listenAddress
|
||||
config.listenAddress = null
|
||||
|
||||
// add the user's configuration in
|
||||
config.set(cliOptions)
|
||||
|
||||
let configModuleReturn
|
||||
try {
|
||||
configModuleReturn = configModule(config)
|
||||
} catch (e) {
|
||||
return fail('Error in config file!\n', e)
|
||||
}
|
||||
function finalizeConfig (config) {
|
||||
// merge the config from config file and cliOptions (precedence)
|
||||
config.set(cliOptions)
|
||||
|
||||
// if the user changed listenAddress, but didn't set a hostname, warn them
|
||||
if (config.hostname === null && config.listenAddress !== null) {
|
||||
log.warn(`ListenAddress was set to ${config.listenAddress} but hostname was left as the default: ` +
|
||||
`${defaultHostname}. If your browsers fail to connect, consider changing the hostname option.`)
|
||||
}
|
||||
// restore values that weren't overwritten by the user
|
||||
if (config.hostname === null) {
|
||||
config.hostname = defaultHostname
|
||||
}
|
||||
if (config.listenAddress === null) {
|
||||
config.listenAddress = defaultListenAddress
|
||||
}
|
||||
|
||||
// configure the logger as soon as we can
|
||||
logger.setup(config.logLevel, config.colors, config.loggers)
|
||||
|
||||
log.debug(configFilePath ? `Loading config ${configFilePath}` : 'No config file specified.')
|
||||
|
||||
return normalizeConfig(config, configFilePath)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return value is a function or (non-null) object that has a `then` method.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @see {@link https://promisesaplus.com/}
|
||||
*/
|
||||
const returnIsThenable = (
|
||||
(
|
||||
(configModuleReturn != null && typeof configModuleReturn === 'object') ||
|
||||
typeof configModuleReturn === 'function'
|
||||
) && typeof configModuleReturn.then === 'function'
|
||||
)
|
||||
if (returnIsThenable) {
|
||||
if (promiseConfig !== true) {
|
||||
const errorMessage =
|
||||
'The `parseOptions.promiseConfig` option must be set to `true` to ' +
|
||||
'enable promise return values from configuration files. ' +
|
||||
'Example: `parseConfig(path, cliOptions, { promiseConfig: true })`'
|
||||
return fail(errorMessage)
|
||||
}
|
||||
return configModuleReturn.then(
|
||||
function onKarmaConfigModuleFulfilled (/* ignoredResolutionValue */) {
|
||||
return finalizeConfig(config)
|
||||
},
|
||||
function onKarmaConfigModuleRejected (reason) {
|
||||
return fail('Error in config file!\n', reason)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
if (promiseConfig) {
|
||||
try {
|
||||
return Promise.resolve(finalizeConfig(config))
|
||||
} catch (exception) {
|
||||
return Promise.reject(exception)
|
||||
}
|
||||
} else {
|
||||
return finalizeConfig(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PUBLIC API
|
||||
exports.parseConfig = parseConfig
|
||||
exports.Pattern = Pattern
|
||||
exports.createPatternObject = createPatternObject
|
||||
exports.Config = Config
|
||||
43
my-app/node_modules/karma/lib/constants.js
generated
vendored
Executable file
43
my-app/node_modules/karma/lib/constants.js
generated
vendored
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('graceful-fs')
|
||||
const path = require('path')
|
||||
|
||||
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '/../package.json')).toString())
|
||||
|
||||
exports.VERSION = pkg.version
|
||||
|
||||
exports.DEFAULT_PORT = process.env.PORT || 9876
|
||||
exports.DEFAULT_HOSTNAME = process.env.IP || 'localhost'
|
||||
exports.DEFAULT_LISTEN_ADDR = process.env.LISTEN_ADDR || '0.0.0.0'
|
||||
|
||||
// log levels
|
||||
exports.LOG_DISABLE = 'OFF'
|
||||
exports.LOG_ERROR = 'ERROR'
|
||||
exports.LOG_WARN = 'WARN'
|
||||
exports.LOG_INFO = 'INFO'
|
||||
exports.LOG_DEBUG = 'DEBUG'
|
||||
exports.LOG_LOG = 'LOG'
|
||||
exports.LOG_PRIORITIES = [
|
||||
exports.LOG_DISABLE,
|
||||
exports.LOG_ERROR,
|
||||
exports.LOG_WARN,
|
||||
exports.LOG_LOG,
|
||||
exports.LOG_INFO,
|
||||
exports.LOG_DEBUG
|
||||
]
|
||||
|
||||
// Default patterns for the pattern layout.
|
||||
exports.COLOR_PATTERN = '%[%d{DATETIME}:%p [%c]: %]%m'
|
||||
exports.NO_COLOR_PATTERN = '%d{DATETIME}:%p [%c]: %m'
|
||||
|
||||
// Default console appender
|
||||
exports.CONSOLE_APPENDER = {
|
||||
type: 'console',
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: exports.COLOR_PATTERN
|
||||
}
|
||||
}
|
||||
|
||||
exports.EXIT_CODE = '\x1FEXIT'
|
||||
11
my-app/node_modules/karma/lib/detached.js
generated
vendored
Executable file
11
my-app/node_modules/karma/lib/detached.js
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
|
||||
const Server = require('./server')
|
||||
const configurationFile = process.argv[2]
|
||||
const fileContents = fs.readFileSync(configurationFile, 'utf-8')
|
||||
fs.unlink(configurationFile, function () {})
|
||||
const data = JSON.parse(fileContents)
|
||||
const server = new Server(data)
|
||||
server.start(data)
|
||||
33
my-app/node_modules/karma/lib/emitter_wrapper.js
generated
vendored
Executable file
33
my-app/node_modules/karma/lib/emitter_wrapper.js
generated
vendored
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
'use strict'
|
||||
|
||||
class EmitterWrapper {
|
||||
constructor (emitter) {
|
||||
this.listeners = {}
|
||||
this.emitter = emitter
|
||||
}
|
||||
|
||||
addListener (event, listener) {
|
||||
this.emitter.addListener(event, listener)
|
||||
this.listeners[event] = this.listeners[event] || []
|
||||
this.listeners[event].push(listener)
|
||||
return this
|
||||
}
|
||||
|
||||
on (event, listener) {
|
||||
return this.addListener(event, listener)
|
||||
}
|
||||
|
||||
removeAllListeners (event) {
|
||||
const events = event ? [event] : Object.keys(this.listeners)
|
||||
events.forEach((event) => {
|
||||
this.listeners[event].forEach((listener) => {
|
||||
this.emitter.removeListener(event, listener)
|
||||
})
|
||||
delete this.listeners[event]
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EmitterWrapper
|
||||
67
my-app/node_modules/karma/lib/events.js
generated
vendored
Executable file
67
my-app/node_modules/karma/lib/events.js
generated
vendored
Executable file
|
|
@ -0,0 +1,67 @@
|
|||
'use strict'
|
||||
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const helper = require('./helper')
|
||||
|
||||
function bufferEvents (emitter, eventsToBuffer) {
|
||||
const listeners = []
|
||||
const eventsToReply = []
|
||||
|
||||
function genericListener () {
|
||||
eventsToReply.push(Array.from(arguments))
|
||||
}
|
||||
|
||||
eventsToBuffer.forEach((eventName) => {
|
||||
const listener = genericListener.bind(null, eventName)
|
||||
listeners.push(listener)
|
||||
emitter.on(eventName, listener)
|
||||
})
|
||||
|
||||
return function () {
|
||||
listeners.forEach((listener, i) => {
|
||||
emitter.removeListener(eventsToBuffer[i], listener)
|
||||
})
|
||||
|
||||
eventsToReply.forEach((args) => {
|
||||
EventEmitter.prototype.emit.apply(emitter, args)
|
||||
})
|
||||
|
||||
listeners.length = 0
|
||||
eventsToReply.length = 0
|
||||
}
|
||||
}
|
||||
|
||||
class KarmaEventEmitter extends EventEmitter {
|
||||
bind (object) {
|
||||
for (const method in object) {
|
||||
if (method.startsWith('on') && helper.isFunction(object[method])) {
|
||||
this.on(helper.camelToSnake(method.slice(2)), function () {
|
||||
// We do not use an arrow function here, to supply the caller as this.
|
||||
object[method].apply(object, Array.from(arguments).concat(this))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitAsync (name) {
|
||||
// TODO(vojta): allow passing args
|
||||
// TODO(vojta): ignore/throw if listener call done() multiple times
|
||||
let pending = this.listeners(name).length
|
||||
const deferred = helper.defer()
|
||||
|
||||
this.emit(name, () => {
|
||||
if (!--pending) {
|
||||
deferred.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
if (!pending) {
|
||||
deferred.resolve()
|
||||
}
|
||||
|
||||
return deferred.promise
|
||||
}
|
||||
}
|
||||
|
||||
exports.EventEmitter = KarmaEventEmitter
|
||||
exports.bufferEvents = bufferEvents
|
||||
96
my-app/node_modules/karma/lib/executor.js
generated
vendored
Executable file
96
my-app/node_modules/karma/lib/executor.js
generated
vendored
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
'use strict'
|
||||
|
||||
const log = require('./logger').create()
|
||||
|
||||
class Executor {
|
||||
constructor (capturedBrowsers, config, emitter) {
|
||||
this.capturedBrowsers = capturedBrowsers
|
||||
this.config = config
|
||||
this.emitter = emitter
|
||||
|
||||
this.executionScheduled = false
|
||||
this.errorsScheduled = []
|
||||
this.pendingCount = 0
|
||||
this.runningBrowsers = null
|
||||
|
||||
this.emitter.on('run_complete', () => this.onRunComplete())
|
||||
this.emitter.on('browser_complete', () => this.onBrowserComplete())
|
||||
}
|
||||
|
||||
schedule () {
|
||||
if (this.capturedBrowsers.length === 0) {
|
||||
log.warn(`No captured browser, open ${this.config.protocol}//${this.config.hostname}:${this.config.port}${this.config.urlRoot}`)
|
||||
return false
|
||||
} else if (this.capturedBrowsers.areAllReady()) {
|
||||
log.debug('All browsers are ready, executing')
|
||||
log.debug(`Captured ${this.capturedBrowsers.length} browsers`)
|
||||
this.executionScheduled = false
|
||||
this.capturedBrowsers.clearResults()
|
||||
this.pendingCount = this.capturedBrowsers.length
|
||||
this.runningBrowsers = this.capturedBrowsers.clone()
|
||||
this.emitter.emit('run_start', this.runningBrowsers)
|
||||
this.socketIoSockets.emit('execute', this.config.client)
|
||||
return true
|
||||
} else {
|
||||
log.info('Delaying execution, these browsers are not ready: ' + this.capturedBrowsers.getNonReady().join(', '))
|
||||
this.executionScheduled = true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule an error to be reported
|
||||
* @param {string} errorMessage
|
||||
* @returns {boolean} a boolean indicating whether or not the error was handled synchronously
|
||||
*/
|
||||
scheduleError (errorMessage) {
|
||||
// We don't want to interfere with any running test.
|
||||
// Verify that no test is running before reporting the error.
|
||||
if (this.capturedBrowsers.areAllReady()) {
|
||||
log.warn(errorMessage)
|
||||
const errorResult = {
|
||||
success: 0,
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
error: errorMessage,
|
||||
exitCode: 1
|
||||
}
|
||||
const noBrowsersStartedTests = []
|
||||
this.emitter.emit('run_start', noBrowsersStartedTests) // A run cannot complete without being started
|
||||
this.emitter.emit('run_complete', noBrowsersStartedTests, errorResult)
|
||||
return true
|
||||
} else {
|
||||
this.errorsScheduled.push(errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
onRunComplete () {
|
||||
if (this.executionScheduled) {
|
||||
this.schedule()
|
||||
}
|
||||
if (this.errorsScheduled.length) {
|
||||
const errorsToReport = this.errorsScheduled
|
||||
this.errorsScheduled = []
|
||||
errorsToReport.forEach((error) => this.scheduleError(error))
|
||||
}
|
||||
}
|
||||
|
||||
onBrowserComplete () {
|
||||
this.pendingCount--
|
||||
|
||||
if (!this.pendingCount) {
|
||||
// Ensure run_complete is emitted in the next tick
|
||||
// so it is never emitted before browser_complete
|
||||
setTimeout(() => {
|
||||
this.emitter.emit('run_complete', this.runningBrowsers, this.runningBrowsers.getResults())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executor.factory = function (capturedBrowsers, config, emitter) {
|
||||
return new Executor(capturedBrowsers, config, emitter)
|
||||
}
|
||||
|
||||
module.exports = Executor
|
||||
242
my-app/node_modules/karma/lib/file-list.js
generated
vendored
Executable file
242
my-app/node_modules/karma/lib/file-list.js
generated
vendored
Executable file
|
|
@ -0,0 +1,242 @@
|
|||
'use strict'
|
||||
|
||||
const { promisify } = require('util')
|
||||
const mm = require('minimatch')
|
||||
const Glob = require('glob').Glob
|
||||
const fs = require('graceful-fs')
|
||||
const statAsync = promisify(fs.stat.bind(fs))
|
||||
const pathLib = require('path')
|
||||
const _ = require('lodash')
|
||||
|
||||
const File = require('./file')
|
||||
const Url = require('./url')
|
||||
const helper = require('./helper')
|
||||
const log = require('./logger').create('filelist')
|
||||
const createPatternObject = require('./config').createPatternObject
|
||||
|
||||
class FileList {
|
||||
constructor (patterns, excludes, emitter, preprocess, autoWatchBatchDelay) {
|
||||
this._patterns = patterns || []
|
||||
this._excludes = excludes || []
|
||||
this._emitter = emitter
|
||||
this._preprocess = preprocess
|
||||
|
||||
this.buckets = new Map()
|
||||
|
||||
// A promise that is pending if and only if we are active in this.refresh_()
|
||||
this._refreshing = null
|
||||
|
||||
const emit = () => {
|
||||
this._emitter.emit('file_list_modified', this.files)
|
||||
}
|
||||
|
||||
const debouncedEmit = _.debounce(emit, autoWatchBatchDelay)
|
||||
this._emitModified = (immediate) => {
|
||||
immediate ? emit() : debouncedEmit()
|
||||
}
|
||||
}
|
||||
|
||||
_findExcluded (path) {
|
||||
return this._excludes.find((pattern) => mm(path, pattern))
|
||||
}
|
||||
|
||||
_findIncluded (path) {
|
||||
return this._patterns.find((pattern) => mm(path, pattern.pattern))
|
||||
}
|
||||
|
||||
_findFile (path, pattern) {
|
||||
if (!path || !pattern) return
|
||||
return this._getFilesByPattern(pattern.pattern).find((file) => file.originalPath === path)
|
||||
}
|
||||
|
||||
_exists (path) {
|
||||
return !!this._patterns.find((pattern) => mm(path, pattern.pattern) && this._findFile(path, pattern))
|
||||
}
|
||||
|
||||
_getFilesByPattern (pattern) {
|
||||
return this.buckets.get(pattern) || []
|
||||
}
|
||||
|
||||
_refresh () {
|
||||
const matchedFiles = new Set()
|
||||
|
||||
let lastCompletedRefresh = this._refreshing
|
||||
lastCompletedRefresh = Promise.all(
|
||||
this._patterns.map(async ({ pattern, type, nocache, isBinary, integrity }) => {
|
||||
if (helper.isUrlAbsolute(pattern)) {
|
||||
this.buckets.set(pattern, [new Url(pattern, type, integrity)])
|
||||
return
|
||||
}
|
||||
|
||||
const mg = new Glob(pathLib.normalize(pattern), { cwd: '/', follow: true, nodir: true, sync: true })
|
||||
|
||||
const files = mg.found
|
||||
.filter((path) => {
|
||||
if (this._findExcluded(path)) {
|
||||
log.debug(`Excluded file "${path}"`)
|
||||
return false
|
||||
} else if (matchedFiles.has(path)) {
|
||||
return false
|
||||
} else {
|
||||
matchedFiles.add(path)
|
||||
return true
|
||||
}
|
||||
})
|
||||
.map((path) => new File(path, mg.statCache[path].mtime, nocache, type, isBinary))
|
||||
|
||||
if (nocache) {
|
||||
log.debug(`Not preprocessing "${pattern}" due to nocache`)
|
||||
} else {
|
||||
await Promise.all(files.map((file) => this._preprocess(file)))
|
||||
}
|
||||
|
||||
this.buckets.set(pattern, files)
|
||||
|
||||
if (_.isEmpty(mg.found)) {
|
||||
log.warn(`Pattern "${pattern}" does not match any file.`)
|
||||
} else if (_.isEmpty(files)) {
|
||||
log.warn(`All files matched by "${pattern}" were excluded or matched by prior matchers.`)
|
||||
}
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
// When we return from this function the file processing chain will be
|
||||
// complete. In the case of two fast refresh() calls, the second call
|
||||
// will overwrite this._refreshing, and we want the status to reflect
|
||||
// the second call and skip the modification event from the first call.
|
||||
if (this._refreshing !== lastCompletedRefresh) {
|
||||
return this._refreshing
|
||||
}
|
||||
this._emitModified(true)
|
||||
return this.files
|
||||
})
|
||||
|
||||
return lastCompletedRefresh
|
||||
}
|
||||
|
||||
get files () {
|
||||
const served = []
|
||||
const included = {}
|
||||
const lookup = {}
|
||||
this._patterns.forEach((p) => {
|
||||
// This needs to be here sadly, as plugins are modifiying
|
||||
// the _patterns directly resulting in elements not being
|
||||
// instantiated properly
|
||||
if (p.constructor.name !== 'Pattern') {
|
||||
p = createPatternObject(p)
|
||||
}
|
||||
|
||||
const files = this._getFilesByPattern(p.pattern)
|
||||
files.sort((a, b) => {
|
||||
if (a.path > b.path) return 1
|
||||
if (a.path < b.path) return -1
|
||||
|
||||
return 0
|
||||
})
|
||||
|
||||
if (p.served) {
|
||||
served.push(...files)
|
||||
}
|
||||
|
||||
files.forEach((file) => {
|
||||
if (lookup[file.path] && lookup[file.path].compare(p) < 0) return
|
||||
|
||||
lookup[file.path] = p
|
||||
if (p.included) {
|
||||
included[file.path] = file
|
||||
} else {
|
||||
delete included[file.path]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
served: _.uniq(served, 'path'),
|
||||
included: _.values(included)
|
||||
}
|
||||
}
|
||||
|
||||
refresh () {
|
||||
this._refreshing = this._refresh()
|
||||
return this._refreshing
|
||||
}
|
||||
|
||||
reload (patterns, excludes) {
|
||||
this._patterns = patterns || []
|
||||
this._excludes = excludes || []
|
||||
|
||||
return this.refresh()
|
||||
}
|
||||
|
||||
async addFile (path) {
|
||||
const excluded = this._findExcluded(path)
|
||||
if (excluded) {
|
||||
log.debug(`Add file "${path}" ignored. Excluded by "${excluded}".`)
|
||||
return this.files
|
||||
}
|
||||
|
||||
const pattern = this._findIncluded(path)
|
||||
if (!pattern) {
|
||||
log.debug(`Add file "${path}" ignored. Does not match any pattern.`)
|
||||
return this.files
|
||||
}
|
||||
|
||||
if (this._exists(path)) {
|
||||
log.debug(`Add file "${path}" ignored. Already in the list.`)
|
||||
return this.files
|
||||
}
|
||||
|
||||
const file = new File(path)
|
||||
this._getFilesByPattern(pattern.pattern).push(file)
|
||||
|
||||
const [stat] = await Promise.all([statAsync(path), this._refreshing])
|
||||
file.mtime = stat.mtime
|
||||
await this._preprocess(file)
|
||||
|
||||
log.info(`Added file "${path}".`)
|
||||
this._emitModified()
|
||||
return this.files
|
||||
}
|
||||
|
||||
async changeFile (path, force) {
|
||||
const pattern = this._findIncluded(path)
|
||||
const file = this._findFile(path, pattern)
|
||||
|
||||
if (!file) {
|
||||
log.debug(`Changed file "${path}" ignored. Does not match any file in the list.`)
|
||||
return this.files
|
||||
}
|
||||
|
||||
const [stat] = await Promise.all([statAsync(path), this._refreshing])
|
||||
if (force || stat.mtime > file.mtime) {
|
||||
file.mtime = stat.mtime
|
||||
await this._preprocess(file)
|
||||
log.info(`Changed file "${path}".`)
|
||||
this._emitModified(force)
|
||||
}
|
||||
return this.files
|
||||
}
|
||||
|
||||
async removeFile (path) {
|
||||
const pattern = this._findIncluded(path)
|
||||
const file = this._findFile(path, pattern)
|
||||
|
||||
if (file) {
|
||||
helper.arrayRemove(this._getFilesByPattern(pattern.pattern), file)
|
||||
log.info(`Removed file "${path}".`)
|
||||
|
||||
this._emitModified()
|
||||
} else {
|
||||
log.debug(`Removed file "${path}" ignored. Does not match any file in the list.`)
|
||||
}
|
||||
return this.files
|
||||
}
|
||||
}
|
||||
|
||||
FileList.factory = function (config, emitter, preprocess) {
|
||||
return new FileList(config.files, config.exclude, emitter, preprocess, config.autoWatchBatchDelay)
|
||||
}
|
||||
|
||||
FileList.factory.$inject = ['config', 'emitter', 'preprocess']
|
||||
|
||||
module.exports = FileList
|
||||
49
my-app/node_modules/karma/lib/file.js
generated
vendored
Executable file
49
my-app/node_modules/karma/lib/file.js
generated
vendored
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
/**
|
||||
* File object used for tracking files in `file-list.js`.
|
||||
*/
|
||||
class File {
|
||||
constructor (path, mtime, doNotCache, type, isBinary, integrity) {
|
||||
// used for serving (processed path, eg some/file.coffee -> some/file.coffee.js)
|
||||
this.path = path
|
||||
|
||||
// original absolute path, id of the file
|
||||
this.originalPath = path
|
||||
|
||||
// where the content is stored (processed)
|
||||
this.contentPath = path
|
||||
|
||||
// encodings format {[encodingType]: encodedContent}
|
||||
// example: {gzip: <Buffer 1f 8b 08...>}
|
||||
this.encodings = Object.create(null)
|
||||
|
||||
this.mtime = mtime
|
||||
this.isUrl = false
|
||||
|
||||
this.doNotCache = doNotCache === undefined ? false : doNotCache
|
||||
|
||||
this.type = type
|
||||
|
||||
// Tri state: null means probe file for binary.
|
||||
this.isBinary = isBinary === undefined ? null : isBinary
|
||||
|
||||
this.integrity = integrity
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect type from the file extension.
|
||||
* @returns {string} detected file type or empty string
|
||||
*/
|
||||
detectType () {
|
||||
return path.extname(this.path).slice(1)
|
||||
}
|
||||
|
||||
toString () {
|
||||
return this.path
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = File
|
||||
171
my-app/node_modules/karma/lib/helper.js
generated
vendored
Executable file
171
my-app/node_modules/karma/lib/helper.js
generated
vendored
Executable file
|
|
@ -0,0 +1,171 @@
|
|||
'use strict'
|
||||
|
||||
const _ = require('lodash')
|
||||
const mkdirp = require('mkdirp')
|
||||
const useragent = require('ua-parser-js')
|
||||
const mm = require('minimatch')
|
||||
|
||||
exports.browserFullNameToShort = (fullName) => {
|
||||
const ua = useragent(fullName)
|
||||
if (!ua.browser.name && !ua.browser.version && !ua.os.name && !ua.os.version) {
|
||||
return fullName
|
||||
}
|
||||
return `${ua.browser.name} ${ua.browser.version || '0.0.0'} (${ua.os.name} ${ua.os.version || '0.0.0'})`
|
||||
}
|
||||
|
||||
exports.isDefined = (value) => {
|
||||
return !_.isUndefined(value)
|
||||
}
|
||||
|
||||
const parser = (pattern, out) => {
|
||||
if (pattern.length === 0) return out
|
||||
const p = /^(\[[^\]]*\]|[*+@?]\((.+?)\))/g
|
||||
const matches = p.exec(pattern)
|
||||
if (!matches) {
|
||||
const c = pattern[0]
|
||||
let t = 'word'
|
||||
if (c === '*') {
|
||||
t = 'star'
|
||||
} else if (c === '?') {
|
||||
t = 'optional'
|
||||
}
|
||||
out[t]++
|
||||
return parser(pattern.slice(1), out)
|
||||
}
|
||||
if (matches[2] !== undefined) {
|
||||
out.ext_glob++
|
||||
parser(matches[2], out)
|
||||
return parser(pattern.slice(matches[0].length), out)
|
||||
}
|
||||
out.range++
|
||||
return parser(pattern.slice(matches[0].length), out)
|
||||
}
|
||||
|
||||
const gsParser = (pattern, out) => {
|
||||
if (pattern === '**') {
|
||||
out.glob_star++
|
||||
return out
|
||||
}
|
||||
return parser(pattern, out)
|
||||
}
|
||||
|
||||
const compareWeightObject = (w1, w2) => {
|
||||
return exports.mmComparePatternWeights(
|
||||
[w1.glob_star, w1.star, w1.ext_glob, w1.range, w1.optional],
|
||||
[w2.glob_star, w2.star, w2.ext_glob, w2.range, w2.optional]
|
||||
)
|
||||
}
|
||||
|
||||
exports.mmPatternWeight = (pattern) => {
|
||||
const m = new mm.Minimatch(pattern)
|
||||
if (!m.globParts) return [0, 0, 0, 0, 0, 0]
|
||||
const result = m.globParts.reduce((prev, p) => {
|
||||
const r = p.reduce((prev, p) => {
|
||||
return gsParser(p, prev)
|
||||
}, { glob_star: 0, ext_glob: 0, word: 0, star: 0, optional: 0, range: 0 })
|
||||
if (prev === undefined) return r
|
||||
return compareWeightObject(r, prev) > 0 ? r : prev
|
||||
}, undefined)
|
||||
result.glob_sets = m.set.length
|
||||
return [result.glob_sets, result.glob_star, result.star, result.ext_glob, result.range, result.optional]
|
||||
}
|
||||
|
||||
exports.mmComparePatternWeights = (weight1, weight2) => {
|
||||
const n1 = weight1[0]
|
||||
const n2 = weight2[0]
|
||||
const diff = n1 - n2
|
||||
if (diff !== 0) return diff / Math.abs(diff)
|
||||
return weight1.length > 1 ? exports.mmComparePatternWeights(weight1.slice(1), weight2.slice(1)) : 0
|
||||
}
|
||||
|
||||
exports.isFunction = _.isFunction
|
||||
exports.isString = _.isString
|
||||
exports.isObject = _.isObject
|
||||
exports.isArray = _.isArray
|
||||
exports.isNumber = _.isNumber
|
||||
|
||||
const ABS_URL = /^https?:\/\//
|
||||
exports.isUrlAbsolute = (url) => {
|
||||
return ABS_URL.test(url)
|
||||
}
|
||||
|
||||
exports.camelToSnake = (camelCase) => {
|
||||
return camelCase.replace(/[A-Z]/g, (match, pos) => {
|
||||
return (pos > 0 ? '_' : '') + match.toLowerCase()
|
||||
})
|
||||
}
|
||||
|
||||
exports.ucFirst = (word) => {
|
||||
return word.charAt(0).toUpperCase() + word.slice(1)
|
||||
}
|
||||
|
||||
exports.dashToCamel = (dash) => {
|
||||
const words = dash.split('-')
|
||||
return words.shift() + words.map(exports.ucFirst).join('')
|
||||
}
|
||||
|
||||
exports.arrayRemove = (collection, item) => {
|
||||
const idx = collection.indexOf(item)
|
||||
|
||||
if (idx !== -1) {
|
||||
collection.splice(idx, 1)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
exports.merge = function () {
|
||||
const args = Array.prototype.slice.call(arguments, 0)
|
||||
args.unshift({})
|
||||
return _.merge.apply({}, args)
|
||||
}
|
||||
|
||||
exports.formatTimeInterval = (time) => {
|
||||
const mins = Math.floor(time / 60000)
|
||||
const secs = (time - mins * 60000) / 1000
|
||||
let str = secs + (secs === 1 ? ' sec' : ' secs')
|
||||
|
||||
if (mins) {
|
||||
str = mins + (mins === 1 ? ' min ' : ' mins ') + str
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
const replaceWinPath = (path) => {
|
||||
return _.isString(path) ? path.replace(/\\/g, '/') : path
|
||||
}
|
||||
|
||||
exports.normalizeWinPath = process.platform === 'win32' ? replaceWinPath : _.identity
|
||||
|
||||
exports.mkdirIfNotExists = (directory, done) => {
|
||||
mkdirp(directory, done)
|
||||
}
|
||||
|
||||
exports.defer = () => {
|
||||
let res
|
||||
let rej
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
res = resolve
|
||||
rej = reject
|
||||
})
|
||||
|
||||
return {
|
||||
resolve: res,
|
||||
reject: rej,
|
||||
promise: promise
|
||||
}
|
||||
}
|
||||
|
||||
exports.saveOriginalArgs = (config) => {
|
||||
if (config && config.client && config.client.args) {
|
||||
config.client.originalArgs = _.cloneDeep(config.client.args)
|
||||
}
|
||||
}
|
||||
|
||||
exports.restoreOriginalArgs = (config) => {
|
||||
if (config && config.client && config.client.originalArgs) {
|
||||
config.client.args = _.cloneDeep(config.client.originalArgs)
|
||||
}
|
||||
}
|
||||
18
my-app/node_modules/karma/lib/index.js
generated
vendored
Executable file
18
my-app/node_modules/karma/lib/index.js
generated
vendored
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
'use strict'
|
||||
|
||||
const constants = require('./constants')
|
||||
const Server = require('./server')
|
||||
const runner = require('./runner')
|
||||
const stopper = require('./stopper')
|
||||
const launcher = require('./launcher')
|
||||
const cfg = require('./config')
|
||||
|
||||
module.exports = {
|
||||
constants: constants,
|
||||
VERSION: constants.VERSION,
|
||||
Server: Server,
|
||||
runner: runner,
|
||||
stopper: stopper,
|
||||
launcher: launcher,
|
||||
config: { parseConfig: cfg.parseConfig } // lets start with only opening up the `parseConfig` api
|
||||
}
|
||||
239
my-app/node_modules/karma/lib/init.js
generated
vendored
Executable file
239
my-app/node_modules/karma/lib/init.js
generated
vendored
Executable file
|
|
@ -0,0 +1,239 @@
|
|||
'use strict'
|
||||
|
||||
const readline = require('readline')
|
||||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
const mm = require('minimatch')
|
||||
const exec = require('child_process').exec
|
||||
|
||||
const helper = require('./helper')
|
||||
const logger = require('./logger')
|
||||
|
||||
const log = logger.create('init')
|
||||
const logQueue = require('./init/log-queue')
|
||||
|
||||
const StateMachine = require('./init/state_machine')
|
||||
const COLOR_SCHEME = require('./init/color_schemes')
|
||||
const formatters = require('./init/formatters')
|
||||
|
||||
// TODO(vojta): coverage
|
||||
// TODO(vojta): html preprocessors
|
||||
// TODO(vojta): SauceLabs
|
||||
// TODO(vojta): BrowserStack
|
||||
|
||||
let NODE_MODULES_DIR = path.resolve(__dirname, '../..')
|
||||
|
||||
// Karma is not in node_modules, probably a symlink,
|
||||
// use current working dir.
|
||||
if (!/node_modules$/.test(NODE_MODULES_DIR)) {
|
||||
NODE_MODULES_DIR = path.resolve('node_modules')
|
||||
}
|
||||
|
||||
function installPackage (pkgName) {
|
||||
// Do not install if already installed.
|
||||
try {
|
||||
require(NODE_MODULES_DIR + '/' + pkgName)
|
||||
return
|
||||
} catch (e) {}
|
||||
|
||||
log.debug(`Missing plugin "${pkgName}". Installing...`)
|
||||
|
||||
const options = {
|
||||
cwd: path.resolve(NODE_MODULES_DIR, '..')
|
||||
}
|
||||
|
||||
exec(`npm install ${pkgName} --save-dev`, options, function (err, stdout, stderr) {
|
||||
// Put the logs into the queue and print them after answering current question.
|
||||
// Otherwise the log would clobber the interactive terminal.
|
||||
logQueue.push(function () {
|
||||
if (!err) {
|
||||
log.debug(`${pkgName} successfully installed.`)
|
||||
} else if (/is not in the npm registry/.test(stderr)) {
|
||||
log.warn(`Failed to install "${pkgName}". It is not in the npm registry!\n Please install it manually.`)
|
||||
} else if (/Error: EACCES/.test(stderr)) {
|
||||
log.warn(`Failed to install "${pkgName}". No permissions to write in ${options.cwd}!\n Please install it manually.`)
|
||||
} else {
|
||||
log.warn(`Failed to install "${pkgName}"\n Please install it manually.`)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function validatePattern (pattern) {
|
||||
if (!glob.sync(pattern).length) {
|
||||
log.warn('There is no file matching this pattern.\n')
|
||||
}
|
||||
}
|
||||
|
||||
function validateBrowser (name) {
|
||||
// TODO(vojta): check if the path resolves to a binary
|
||||
installPackage('karma-' + name.toLowerCase().replace('headless', '').replace('canary', '') + '-launcher')
|
||||
}
|
||||
|
||||
function validateFramework (name) {
|
||||
installPackage('karma-' + name)
|
||||
}
|
||||
|
||||
function validateRequireJs (useRequire) {
|
||||
if (useRequire) {
|
||||
validateFramework('requirejs')
|
||||
}
|
||||
}
|
||||
|
||||
var questions = [{
|
||||
id: 'framework',
|
||||
question: 'Which testing framework do you want to use ?',
|
||||
hint: 'Press tab to list possible options. Enter to move to the next question.',
|
||||
options: ['jasmine', 'mocha', 'qunit', 'nodeunit', 'nunit', ''],
|
||||
validate: validateFramework
|
||||
}, {
|
||||
id: 'requirejs',
|
||||
question: 'Do you want to use Require.js ?',
|
||||
hint: 'This will add Require.js plugin.\nPress tab to list possible options. Enter to move to the next question.',
|
||||
options: ['no', 'yes'],
|
||||
validate: validateRequireJs,
|
||||
boolean: true
|
||||
}, {
|
||||
id: 'browsers',
|
||||
question: 'Do you want to capture any browsers automatically ?',
|
||||
hint: 'Press tab to list possible options. Enter empty string to move to the next question.',
|
||||
options: ['Chrome', 'ChromeHeadless', 'ChromeCanary', 'Firefox', 'Safari', 'PhantomJS', 'Opera', 'IE', ''],
|
||||
validate: validateBrowser,
|
||||
multiple: true
|
||||
}, {
|
||||
id: 'files',
|
||||
question: 'What is the location of your source and test files ?',
|
||||
hint: 'You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".\nEnter empty string to move to the next question.',
|
||||
multiple: true,
|
||||
validate: validatePattern
|
||||
}, {
|
||||
id: 'exclude',
|
||||
question: 'Should any of the files included by the previous patterns be excluded ?',
|
||||
hint: 'You can use glob patterns, eg. "**/*.swp".\nEnter empty string to move to the next question.',
|
||||
multiple: true,
|
||||
validate: validatePattern
|
||||
}, {
|
||||
id: 'generateTestMain',
|
||||
question: 'Do you wanna generate a bootstrap file for RequireJS?',
|
||||
hint: 'This will generate test-main.js/coffee that configures RequireJS and starts the tests.',
|
||||
options: ['no', 'yes'],
|
||||
boolean: true,
|
||||
condition: (answers) => answers.requirejs
|
||||
}, {
|
||||
id: 'includedFiles',
|
||||
question: 'Which files do you want to include with <script> tag ?',
|
||||
hint: 'This should be a script that bootstraps your test by configuring Require.js and ' +
|
||||
'kicking __karma__.start(), probably your test-main.js file.\n' +
|
||||
'Enter empty string to move to the next question.',
|
||||
multiple: true,
|
||||
validate: validatePattern,
|
||||
condition: (answers) => answers.requirejs && !answers.generateTestMain
|
||||
}, {
|
||||
id: 'autoWatch',
|
||||
question: 'Do you want Karma to watch all the files and run the tests on change ?',
|
||||
hint: 'Press tab to list possible options.',
|
||||
options: ['yes', 'no'],
|
||||
boolean: true
|
||||
}]
|
||||
|
||||
function getBasePath (configFilePath, cwd) {
|
||||
const configParts = path.dirname(configFilePath).split(path.sep)
|
||||
const cwdParts = cwd.split(path.sep)
|
||||
const base = []
|
||||
|
||||
while (configParts.length && configParts[0] === cwdParts[0]) {
|
||||
configParts.shift()
|
||||
cwdParts.shift()
|
||||
}
|
||||
|
||||
while (configParts.length) {
|
||||
const part = configParts.shift()
|
||||
if (part === '..') {
|
||||
base.unshift(cwdParts.pop())
|
||||
} else if (part !== '.') {
|
||||
base.unshift('..')
|
||||
}
|
||||
}
|
||||
|
||||
return base.join(path.sep)
|
||||
}
|
||||
|
||||
function processAnswers (answers, basePath, testMainFile) {
|
||||
const processedAnswers = {
|
||||
basePath: basePath,
|
||||
files: answers.files,
|
||||
onlyServedFiles: [],
|
||||
exclude: answers.exclude,
|
||||
autoWatch: answers.autoWatch,
|
||||
generateTestMain: answers.generateTestMain,
|
||||
browsers: answers.browsers,
|
||||
frameworks: [],
|
||||
preprocessors: {}
|
||||
}
|
||||
|
||||
if (answers.framework) {
|
||||
processedAnswers.frameworks.push(answers.framework)
|
||||
}
|
||||
|
||||
if (answers.requirejs) {
|
||||
processedAnswers.frameworks.push('requirejs')
|
||||
processedAnswers.files = answers.includedFiles || []
|
||||
processedAnswers.onlyServedFiles = answers.files
|
||||
|
||||
if (answers.generateTestMain) {
|
||||
processedAnswers.files.push(testMainFile)
|
||||
}
|
||||
}
|
||||
|
||||
const allPatterns = answers.files.concat(answers.includedFiles || [])
|
||||
if (allPatterns.some((pattern) => mm(pattern, '**/*.coffee'))) {
|
||||
installPackage('karma-coffee-preprocessor')
|
||||
processedAnswers.preprocessors['**/*.coffee'] = ['coffee']
|
||||
}
|
||||
|
||||
return processedAnswers
|
||||
}
|
||||
|
||||
exports.init = function (config) {
|
||||
logger.setupFromConfig(config)
|
||||
|
||||
const colorScheme = !helper.isDefined(config.colors) || config.colors ? COLOR_SCHEME.ON : COLOR_SCHEME.OFF
|
||||
// need to be registered before creating readlineInterface
|
||||
process.stdin.on('keypress', function (s, key) {
|
||||
sm.onKeypress(key)
|
||||
})
|
||||
|
||||
const rli = readline.createInterface(process.stdin, process.stdout)
|
||||
const sm = new StateMachine(rli, colorScheme)
|
||||
|
||||
rli.on('line', sm.onLine.bind(sm))
|
||||
|
||||
// clean colors
|
||||
rli.on('SIGINT', function () {
|
||||
sm.kill()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
sm.process(questions, function (answers) {
|
||||
const cwd = process.cwd()
|
||||
const configFile = config.configFile || 'karma.conf.js'
|
||||
const isCoffee = path.extname(configFile) === '.coffee'
|
||||
const testMainFile = isCoffee ? 'test-main.coffee' : 'test-main.js'
|
||||
const formatter = formatters.createForPath(configFile)
|
||||
const processedAnswers = processAnswers(answers, getBasePath(configFile, cwd), testMainFile)
|
||||
const configFilePath = path.resolve(cwd, configFile)
|
||||
const testMainFilePath = path.resolve(cwd, testMainFile)
|
||||
|
||||
if (isCoffee) {
|
||||
installPackage('coffeescript')
|
||||
}
|
||||
|
||||
if (processedAnswers.generateTestMain) {
|
||||
formatter.writeRequirejsConfigFile(testMainFilePath)
|
||||
console.log(colorScheme.success(`RequireJS bootstrap file generated at "${testMainFilePath}".`))
|
||||
}
|
||||
|
||||
formatter.writeConfigFile(configFilePath, processedAnswers)
|
||||
console.log(colorScheme.success(`Config file generated at "${configFilePath}".`))
|
||||
})
|
||||
}
|
||||
28
my-app/node_modules/karma/lib/init/color_schemes.js
generated
vendored
Executable file
28
my-app/node_modules/karma/lib/init/color_schemes.js
generated
vendored
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
const COLORS_ON = {
|
||||
RESET: '\x1B[39m',
|
||||
ANSWER: '\x1B[36m', // NYAN
|
||||
SUCCESS: '\x1B[32m', // GREEN
|
||||
QUESTION: '\x1B[1m', // BOLD
|
||||
question: function (str) {
|
||||
return this.QUESTION + str + '\x1B[22m'
|
||||
},
|
||||
success: function (str) {
|
||||
return this.SUCCESS + str + this.RESET
|
||||
}
|
||||
}
|
||||
|
||||
const COLORS_OFF = {
|
||||
RESET: '',
|
||||
ANSWER: '',
|
||||
SUCCESS: '',
|
||||
QUESTION: '',
|
||||
question: function (str) {
|
||||
return str
|
||||
},
|
||||
success: function (str) {
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
exports.ON = COLORS_ON
|
||||
exports.OFF = COLORS_OFF
|
||||
116
my-app/node_modules/karma/lib/init/formatters.js
generated
vendored
Executable file
116
my-app/node_modules/karma/lib/init/formatters.js
generated
vendored
Executable file
|
|
@ -0,0 +1,116 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const FileUtils = require('../utils/file-utils')
|
||||
|
||||
function quote (value) {
|
||||
return `'${value}'`
|
||||
}
|
||||
|
||||
function formatLine (items) {
|
||||
return items.map(quote).join(', ')
|
||||
}
|
||||
|
||||
function formatMultiLines (items) {
|
||||
return items
|
||||
.map((file) => '\n ' + file)
|
||||
.join(',')
|
||||
}
|
||||
|
||||
function formatFiles (includedFiles, onlyServedFiles) {
|
||||
const lines = []
|
||||
.concat(includedFiles.map(quote))
|
||||
.concat(onlyServedFiles.map((file) => `{ pattern: ${quote(file)}, included: false }`))
|
||||
|
||||
return formatMultiLines(lines)
|
||||
}
|
||||
|
||||
function formatPreprocessors (preprocessors) {
|
||||
const lines = Object.keys(preprocessors)
|
||||
.map((pattern) => `${quote(pattern)}: [${formatLine(preprocessors[pattern])}]`)
|
||||
|
||||
return formatMultiLines(lines)
|
||||
}
|
||||
|
||||
function getConfigPath (file) {
|
||||
return path.join(__dirname, `/../../${file}`)
|
||||
}
|
||||
|
||||
class JavaScriptFormatter {
|
||||
constructor () {
|
||||
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.js')
|
||||
this.REQUIREJS_TEMPLATE_FILE = getConfigPath('requirejs.config.tpl.js')
|
||||
}
|
||||
|
||||
generateConfigFile (answers) {
|
||||
const replacements = this.formatAnswers(answers)
|
||||
|
||||
return FileUtils
|
||||
.readFile(this.TEMPLATE_FILE_PATH)
|
||||
.replace(/%(.*)%/g, (a, key) => replacements[key])
|
||||
}
|
||||
|
||||
writeConfigFile (path, answers) {
|
||||
FileUtils.saveFile(path, this.generateConfigFile(answers))
|
||||
}
|
||||
|
||||
writeRequirejsConfigFile (path) {
|
||||
FileUtils.copyFile(this.REQUIREJS_TEMPLATE_FILE, path)
|
||||
}
|
||||
|
||||
formatAnswers (answers) {
|
||||
return {
|
||||
DATE: new Date(),
|
||||
BASE_PATH: answers.basePath,
|
||||
FRAMEWORKS: formatLine(answers.frameworks),
|
||||
FILES: formatFiles(answers.files, answers.onlyServedFiles),
|
||||
EXCLUDE: formatFiles(answers.exclude, []),
|
||||
AUTO_WATCH: answers.autoWatch ? 'true' : 'false',
|
||||
BROWSERS: formatLine(answers.browsers),
|
||||
PREPROCESSORS: formatPreprocessors(answers.preprocessors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CoffeeFormatter extends JavaScriptFormatter {
|
||||
constructor () {
|
||||
super()
|
||||
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.coffee')
|
||||
this.REQUIREJS_TEMPLATE_FILE = getConfigPath('requirejs.config.tpl.coffee')
|
||||
}
|
||||
}
|
||||
|
||||
class LiveFormatter extends JavaScriptFormatter {
|
||||
constructor () {
|
||||
super()
|
||||
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.ls')
|
||||
}
|
||||
}
|
||||
|
||||
class TypeFormatter extends JavaScriptFormatter {
|
||||
constructor () {
|
||||
super()
|
||||
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.ts')
|
||||
}
|
||||
}
|
||||
|
||||
exports.JavaScript = JavaScriptFormatter
|
||||
exports.Coffee = CoffeeFormatter
|
||||
exports.Live = LiveFormatter
|
||||
exports.Type = TypeFormatter
|
||||
|
||||
exports.createForPath = function (path) {
|
||||
if (/\.coffee$/.test(path)) {
|
||||
return new CoffeeFormatter()
|
||||
}
|
||||
|
||||
if (/\.ls$/.test(path)) {
|
||||
return new LiveFormatter()
|
||||
}
|
||||
|
||||
if (/\.ts$/.test(path)) {
|
||||
return new TypeFormatter()
|
||||
}
|
||||
|
||||
return new JavaScriptFormatter()
|
||||
}
|
||||
15
my-app/node_modules/karma/lib/init/log-queue.js
generated
vendored
Executable file
15
my-app/node_modules/karma/lib/init/log-queue.js
generated
vendored
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
'use strict'
|
||||
|
||||
const logQueue = []
|
||||
function printLogQueue () {
|
||||
logQueue.forEach((log) => log())
|
||||
logQueue.length = 0
|
||||
}
|
||||
|
||||
function push (log) {
|
||||
logQueue.push(log)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
printLogQueue, push
|
||||
}
|
||||
143
my-app/node_modules/karma/lib/init/state_machine.js
generated
vendored
Executable file
143
my-app/node_modules/karma/lib/init/state_machine.js
generated
vendored
Executable file
|
|
@ -0,0 +1,143 @@
|
|||
'use strict'
|
||||
|
||||
const logQueue = require('./log-queue')
|
||||
|
||||
let questions
|
||||
let currentQuestion
|
||||
let answers
|
||||
let currentOptions
|
||||
let currentOptionsPointer
|
||||
let currentQuestionId
|
||||
let done
|
||||
|
||||
class StateMachine {
|
||||
constructor (rli, colors) {
|
||||
this.rli = rli
|
||||
this.colors = colors
|
||||
}
|
||||
|
||||
showPrompt () {
|
||||
this.rli.write(this.colors.ANSWER)
|
||||
this.rli.prompt()
|
||||
}
|
||||
|
||||
onKeypress (key) {
|
||||
if (!currentOptions || !key) {
|
||||
return
|
||||
}
|
||||
|
||||
if (key.name === 'tab' || key.name === 'right' || key.name === 'down') {
|
||||
this.suggestOption(currentOptionsPointer + 1)
|
||||
} else if (key.name === 'left' || key.name === 'up') {
|
||||
this.suggestOption(currentOptionsPointer - 1)
|
||||
}
|
||||
|
||||
if (!key.ctrl && !key.meta && key.name !== 'enter' && key.name !== 'return') {
|
||||
key.name = 'escape'
|
||||
}
|
||||
}
|
||||
|
||||
suggestOption (index) {
|
||||
if (!currentOptions) {
|
||||
return
|
||||
}
|
||||
|
||||
if (index === -1) {
|
||||
currentOptionsPointer = currentOptions.length - 1
|
||||
} else if (index === currentOptions.length) {
|
||||
currentOptionsPointer = 0
|
||||
} else {
|
||||
currentOptionsPointer = index
|
||||
}
|
||||
|
||||
this.rli._deleteLineLeft()
|
||||
this.rli._deleteLineRight()
|
||||
this.rli.write(currentOptions[currentOptionsPointer])
|
||||
}
|
||||
|
||||
kill () {
|
||||
currentOptions = null
|
||||
currentQuestionId = null
|
||||
this.rli.write('\n' + this.colors.RESET + '\n')
|
||||
this.rli.close()
|
||||
}
|
||||
|
||||
onLine (line) {
|
||||
if (currentQuestionId) {
|
||||
this.rli.write(this.colors.RESET)
|
||||
line = line.trim().replace(this.colors.ANSWER, '').replace(this.colors.RESET, '')
|
||||
|
||||
if (currentOptions) {
|
||||
currentOptionsPointer = currentOptions.indexOf(line)
|
||||
if (currentOptionsPointer === -1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (line === '') {
|
||||
line = null
|
||||
}
|
||||
|
||||
if (currentQuestion.boolean) {
|
||||
line = (line === 'yes' || line === 'true' || line === 'on')
|
||||
}
|
||||
|
||||
if (line !== null && currentQuestion.validate) {
|
||||
currentQuestion.validate(line)
|
||||
}
|
||||
|
||||
if (currentQuestion.multiple) {
|
||||
answers[currentQuestionId] = answers[currentQuestionId] || []
|
||||
if (line !== null) {
|
||||
answers[currentQuestionId].push(line)
|
||||
this.showPrompt()
|
||||
|
||||
if (currentOptions) {
|
||||
currentOptions.splice(currentOptionsPointer, 1)
|
||||
currentOptionsPointer = -1
|
||||
}
|
||||
} else {
|
||||
this.nextQuestion()
|
||||
}
|
||||
} else {
|
||||
answers[currentQuestionId] = line
|
||||
this.nextQuestion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextQuestion () {
|
||||
currentQuestion = questions.shift()
|
||||
|
||||
while (currentQuestion && currentQuestion.condition && !currentQuestion.condition(answers)) {
|
||||
currentQuestion = questions.shift()
|
||||
}
|
||||
|
||||
logQueue.printLogQueue()
|
||||
|
||||
if (currentQuestion) {
|
||||
currentQuestionId = null
|
||||
|
||||
this.rli.write('\n' + this.colors.question(currentQuestion.question) + '\n')
|
||||
this.rli.write(currentQuestion.hint + '\n')
|
||||
this.showPrompt()
|
||||
|
||||
currentOptions = currentQuestion.options || null
|
||||
currentQuestionId = currentQuestion.id
|
||||
this.suggestOption(0)
|
||||
} else {
|
||||
this.kill()
|
||||
done(answers)
|
||||
}
|
||||
}
|
||||
|
||||
process (_questions, _done) {
|
||||
questions = _questions
|
||||
answers = {}
|
||||
done = _done
|
||||
|
||||
this.nextQuestion()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StateMachine
|
||||
199
my-app/node_modules/karma/lib/launcher.js
generated
vendored
Executable file
199
my-app/node_modules/karma/lib/launcher.js
generated
vendored
Executable file
|
|
@ -0,0 +1,199 @@
|
|||
'use strict'
|
||||
|
||||
const Jobs = require('qjobs')
|
||||
|
||||
const log = require('./logger').create('launcher')
|
||||
|
||||
const baseDecorator = require('./launchers/base').decoratorFactory
|
||||
const captureTimeoutDecorator = require('./launchers/capture_timeout').decoratorFactory
|
||||
const retryDecorator = require('./launchers/retry').decoratorFactory
|
||||
const processDecorator = require('./launchers/process').decoratorFactory
|
||||
|
||||
// TODO(vojta): remove once nobody uses it
|
||||
const baseBrowserDecoratorFactory = function (
|
||||
baseLauncherDecorator,
|
||||
captureTimeoutLauncherDecorator,
|
||||
retryLauncherDecorator,
|
||||
processLauncherDecorator,
|
||||
processKillTimeout
|
||||
) {
|
||||
return function (launcher) {
|
||||
baseLauncherDecorator(launcher)
|
||||
captureTimeoutLauncherDecorator(launcher)
|
||||
retryLauncherDecorator(launcher)
|
||||
processLauncherDecorator(launcher, processKillTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
class Launcher {
|
||||
constructor (server, emitter, injector) {
|
||||
this._server = server
|
||||
this._emitter = emitter
|
||||
this._injector = injector
|
||||
this._browsers = []
|
||||
this._lastStartTime = null
|
||||
|
||||
// Attach list of dependency injection parameters to methods.
|
||||
this.launch.$inject = [
|
||||
'config.browsers',
|
||||
'config.concurrency'
|
||||
]
|
||||
|
||||
this.launchSingle.$inject = [
|
||||
'config.protocol',
|
||||
'config.hostname',
|
||||
'config.port',
|
||||
'config.urlRoot',
|
||||
'config.upstreamProxy',
|
||||
'config.processKillTimeout'
|
||||
]
|
||||
|
||||
this._emitter.on('exit', (callback) => this.killAll(callback))
|
||||
}
|
||||
|
||||
getBrowserById (id) {
|
||||
return this._browsers.find((browser) => browser.id === id)
|
||||
}
|
||||
|
||||
launchSingle (protocol, hostname, port, urlRoot, upstreamProxy, processKillTimeout) {
|
||||
if (upstreamProxy) {
|
||||
protocol = upstreamProxy.protocol
|
||||
hostname = upstreamProxy.hostname
|
||||
port = upstreamProxy.port
|
||||
urlRoot = upstreamProxy.path + urlRoot.slice(1)
|
||||
}
|
||||
|
||||
return (name) => {
|
||||
let browser
|
||||
const locals = {
|
||||
id: ['value', Launcher.generateId()],
|
||||
name: ['value', name],
|
||||
processKillTimeout: ['value', processKillTimeout],
|
||||
baseLauncherDecorator: ['factory', baseDecorator],
|
||||
captureTimeoutLauncherDecorator: ['factory', captureTimeoutDecorator],
|
||||
retryLauncherDecorator: ['factory', retryDecorator],
|
||||
processLauncherDecorator: ['factory', processDecorator],
|
||||
baseBrowserDecorator: ['factory', baseBrowserDecoratorFactory]
|
||||
}
|
||||
|
||||
// TODO(vojta): determine script from name
|
||||
if (name.includes('/')) {
|
||||
name = 'Script'
|
||||
}
|
||||
|
||||
try {
|
||||
browser = this._injector.createChild([locals], ['launcher:' + name]).get('launcher:' + name)
|
||||
} catch (e) {
|
||||
if (e.message.includes(`No provider for "launcher:${name}"`)) {
|
||||
log.error(`Cannot load browser "${name}": it is not registered! Perhaps you are missing some plugin?`)
|
||||
} else {
|
||||
log.error(`Cannot load browser "${name}"!\n ` + e.stack)
|
||||
}
|
||||
|
||||
this._emitter.emit('load_error', 'launcher', name)
|
||||
return
|
||||
}
|
||||
|
||||
this.jobs.add((args, done) => {
|
||||
log.info(`Starting browser ${browser.displayName || browser.name}`)
|
||||
|
||||
browser.on('browser_process_failure', () => done(browser.error))
|
||||
|
||||
browser.on('done', () => {
|
||||
if (!browser.error && browser.state !== browser.STATE_RESTARTING) {
|
||||
done(null, browser)
|
||||
}
|
||||
})
|
||||
|
||||
browser.start(`${protocol}//${hostname}:${port}${urlRoot}`)
|
||||
}, [])
|
||||
|
||||
this.jobs.run()
|
||||
this._browsers.push(browser)
|
||||
}
|
||||
}
|
||||
|
||||
launch (names, concurrency) {
|
||||
log.info(`Launching browsers ${names.join(', ')} with concurrency ${concurrency === Infinity ? 'unlimited' : concurrency}`)
|
||||
this.jobs = new Jobs({ maxConcurrency: concurrency })
|
||||
|
||||
this._lastStartTime = Date.now()
|
||||
|
||||
if (this._server.loadErrors.length) {
|
||||
this.jobs.add((args, done) => done(), [])
|
||||
} else {
|
||||
names.forEach((name) => this._injector.invoke(this.launchSingle, this)(name))
|
||||
}
|
||||
|
||||
this.jobs.on('end', (err) => {
|
||||
log.debug('Finished all browsers')
|
||||
|
||||
if (err) {
|
||||
log.error(err)
|
||||
}
|
||||
})
|
||||
|
||||
this.jobs.run()
|
||||
|
||||
return this._browsers
|
||||
}
|
||||
|
||||
kill (id, callback) {
|
||||
callback = callback || function () {}
|
||||
const browser = this.getBrowserById(id)
|
||||
|
||||
if (browser) {
|
||||
browser.forceKill().then(callback)
|
||||
return true
|
||||
}
|
||||
process.nextTick(callback)
|
||||
return false
|
||||
}
|
||||
|
||||
restart (id) {
|
||||
const browser = this.getBrowserById(id)
|
||||
if (browser) {
|
||||
browser.restart()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
killAll (callback) {
|
||||
callback = callback || function () {}
|
||||
log.debug('Disconnecting all browsers')
|
||||
|
||||
if (!this._browsers.length) {
|
||||
return process.nextTick(callback)
|
||||
}
|
||||
|
||||
Promise.all(
|
||||
this._browsers
|
||||
.map((browser) => browser.forceKill())
|
||||
).then(callback)
|
||||
}
|
||||
|
||||
areAllCaptured () {
|
||||
return this._browsers.every((browser) => browser.isCaptured())
|
||||
}
|
||||
|
||||
markCaptured (id) {
|
||||
const browser = this.getBrowserById(id)
|
||||
if (browser) {
|
||||
browser.markCaptured()
|
||||
log.debug(`${browser.name} (id ${browser.id}) captured in ${(Date.now() - this._lastStartTime) / 1000} secs`)
|
||||
}
|
||||
}
|
||||
|
||||
static generateId () {
|
||||
return Math.floor(Math.random() * 100000000).toString()
|
||||
}
|
||||
}
|
||||
|
||||
Launcher.factory = function (server, emitter, injector) {
|
||||
return new Launcher(server, emitter, injector)
|
||||
}
|
||||
|
||||
Launcher.factory.$inject = ['server', 'emitter', 'injector']
|
||||
|
||||
exports.Launcher = Launcher
|
||||
140
my-app/node_modules/karma/lib/launchers/base.js
generated
vendored
Executable file
140
my-app/node_modules/karma/lib/launchers/base.js
generated
vendored
Executable file
|
|
@ -0,0 +1,140 @@
|
|||
const KarmaEventEmitter = require('../events').EventEmitter
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
|
||||
const log = require('../logger').create('launcher')
|
||||
const helper = require('../helper')
|
||||
|
||||
const BEING_CAPTURED = 'BEING_CAPTURED'
|
||||
const CAPTURED = 'CAPTURED'
|
||||
const BEING_KILLED = 'BEING_KILLED'
|
||||
const FINISHED = 'FINISHED'
|
||||
const RESTARTING = 'RESTARTING'
|
||||
const BEING_FORCE_KILLED = 'BEING_FORCE_KILLED'
|
||||
|
||||
/**
|
||||
* Base launcher that any custom launcher extends.
|
||||
*/
|
||||
function BaseLauncher (id, emitter) {
|
||||
if (this.start) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(vojta): figure out how to do inheritance with DI
|
||||
Object.keys(EventEmitter.prototype).forEach(function (method) {
|
||||
this[method] = EventEmitter.prototype[method]
|
||||
}, this)
|
||||
|
||||
this.bind = KarmaEventEmitter.prototype.bind.bind(this)
|
||||
this.emitAsync = KarmaEventEmitter.prototype.emitAsync.bind(this)
|
||||
|
||||
this.id = id
|
||||
this._state = null
|
||||
Object.defineProperty(this, 'state', {
|
||||
get: () => {
|
||||
return this._state
|
||||
},
|
||||
set: (toState) => {
|
||||
log.debug(`${this._state} -> ${toState}`)
|
||||
this._state = toState
|
||||
}
|
||||
})
|
||||
|
||||
this.error = null
|
||||
|
||||
let killingPromise
|
||||
let previousUrl
|
||||
|
||||
this.start = function (url) {
|
||||
previousUrl = url
|
||||
|
||||
this.error = null
|
||||
this.state = BEING_CAPTURED
|
||||
this.emit('start', url + '?id=' + this.id + (helper.isDefined(this.displayName) ? '&displayName=' + encodeURIComponent(this.displayName) : ''))
|
||||
}
|
||||
|
||||
this.kill = function () {
|
||||
// Already killed, or being killed.
|
||||
if (killingPromise) {
|
||||
return killingPromise
|
||||
}
|
||||
|
||||
killingPromise = this.emitAsync('kill').then(() => {
|
||||
this.state = FINISHED
|
||||
})
|
||||
|
||||
this.state = BEING_KILLED
|
||||
|
||||
return killingPromise
|
||||
}
|
||||
|
||||
this.forceKill = function () {
|
||||
this.kill()
|
||||
this.state = BEING_FORCE_KILLED
|
||||
|
||||
return killingPromise
|
||||
}
|
||||
|
||||
this.restart = function () {
|
||||
if (this.state === BEING_FORCE_KILLED) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!killingPromise) {
|
||||
killingPromise = this.emitAsync('kill')
|
||||
}
|
||||
|
||||
killingPromise.then(() => {
|
||||
if (this.state === BEING_FORCE_KILLED) {
|
||||
this.state = FINISHED
|
||||
} else {
|
||||
killingPromise = null
|
||||
log.debug(`Restarting ${this.name}`)
|
||||
this.start(previousUrl)
|
||||
}
|
||||
})
|
||||
|
||||
this.state = RESTARTING
|
||||
}
|
||||
|
||||
this.markCaptured = function () {
|
||||
if (this.state === BEING_CAPTURED) {
|
||||
this.state = CAPTURED
|
||||
}
|
||||
}
|
||||
|
||||
this.isCaptured = function () {
|
||||
return this.state === CAPTURED
|
||||
}
|
||||
|
||||
this.toString = function () {
|
||||
return this.name
|
||||
}
|
||||
|
||||
this._done = function (error) {
|
||||
killingPromise = killingPromise || Promise.resolve()
|
||||
|
||||
this.error = this.error || error
|
||||
this.emit('done')
|
||||
|
||||
if (this.error && this.state !== BEING_FORCE_KILLED && this.state !== RESTARTING) {
|
||||
emitter.emit('browser_process_failure', this)
|
||||
}
|
||||
|
||||
this.state = FINISHED
|
||||
}
|
||||
|
||||
this.STATE_BEING_CAPTURED = BEING_CAPTURED
|
||||
this.STATE_CAPTURED = CAPTURED
|
||||
this.STATE_BEING_KILLED = BEING_KILLED
|
||||
this.STATE_FINISHED = FINISHED
|
||||
this.STATE_RESTARTING = RESTARTING
|
||||
this.STATE_BEING_FORCE_KILLED = BEING_FORCE_KILLED
|
||||
}
|
||||
|
||||
BaseLauncher.decoratorFactory = function (id, emitter) {
|
||||
return function (launcher) {
|
||||
BaseLauncher.call(launcher, id, emitter)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseLauncher
|
||||
43
my-app/node_modules/karma/lib/launchers/capture_timeout.js
generated
vendored
Executable file
43
my-app/node_modules/karma/lib/launchers/capture_timeout.js
generated
vendored
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
const log = require('../logger').create('launcher')
|
||||
|
||||
/**
|
||||
* Kill browser if it does not capture in given `captureTimeout`.
|
||||
*/
|
||||
function CaptureTimeoutLauncher (timer, captureTimeout) {
|
||||
if (!captureTimeout) {
|
||||
return
|
||||
}
|
||||
|
||||
let pendingTimeoutId = null
|
||||
|
||||
this.on('start', () => {
|
||||
pendingTimeoutId = timer.setTimeout(() => {
|
||||
pendingTimeoutId = null
|
||||
if (this.state !== this.STATE_BEING_CAPTURED) {
|
||||
return
|
||||
}
|
||||
|
||||
log.warn(`${this.name} has not captured in ${captureTimeout} ms, killing.`)
|
||||
this.error = 'timeout'
|
||||
this.kill()
|
||||
}, captureTimeout)
|
||||
})
|
||||
|
||||
this.on('done', () => {
|
||||
if (pendingTimeoutId) {
|
||||
timer.clearTimeout(pendingTimeoutId)
|
||||
pendingTimeoutId = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
CaptureTimeoutLauncher.decoratorFactory = function (timer,
|
||||
/* config.captureTimeout */ captureTimeout) {
|
||||
return function (launcher) {
|
||||
CaptureTimeoutLauncher.call(launcher, timer, captureTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
CaptureTimeoutLauncher.decoratorFactory.$inject = ['timer', 'config.captureTimeout']
|
||||
|
||||
module.exports = CaptureTimeoutLauncher
|
||||
185
my-app/node_modules/karma/lib/launchers/process.js
generated
vendored
Executable file
185
my-app/node_modules/karma/lib/launchers/process.js
generated
vendored
Executable file
|
|
@ -0,0 +1,185 @@
|
|||
const path = require('path')
|
||||
const log = require('../logger').create('launcher')
|
||||
const env = process.env
|
||||
|
||||
function ProcessLauncher (spawn, tempDir, timer, processKillTimeout) {
|
||||
const self = this
|
||||
let onExitCallback
|
||||
const killTimeout = processKillTimeout || 2000
|
||||
// Will hold output from the spawned child process
|
||||
const streamedOutputs = {
|
||||
stdout: '',
|
||||
stderr: ''
|
||||
}
|
||||
|
||||
this._tempDir = tempDir.getPath(`/karma-${this.id.toString()}`)
|
||||
|
||||
this.on('start', function (url) {
|
||||
tempDir.create(self._tempDir)
|
||||
self._start(url)
|
||||
})
|
||||
|
||||
this.on('kill', function (done) {
|
||||
if (!self._process) {
|
||||
return process.nextTick(done)
|
||||
}
|
||||
|
||||
onExitCallback = done
|
||||
self._process.kill()
|
||||
self._killTimer = timer.setTimeout(self._onKillTimeout, killTimeout)
|
||||
})
|
||||
|
||||
this._start = function (url) {
|
||||
self._execCommand(self._getCommand(), self._getOptions(url))
|
||||
}
|
||||
|
||||
this._getCommand = function () {
|
||||
return env[self.ENV_CMD] || self.DEFAULT_CMD[process.platform]
|
||||
}
|
||||
|
||||
this._getOptions = function (url) {
|
||||
return [url]
|
||||
}
|
||||
|
||||
// Normalize the command, remove quotes (spawn does not like them).
|
||||
this._normalizeCommand = function (cmd) {
|
||||
if (cmd.charAt(0) === cmd.charAt(cmd.length - 1) && '\'`"'.includes(cmd.charAt(0))) {
|
||||
cmd = cmd.slice(1, -1)
|
||||
log.warn(`The path should not be quoted.\n Normalized the path to ${cmd}`)
|
||||
}
|
||||
|
||||
return path.normalize(cmd)
|
||||
}
|
||||
|
||||
this._onStdout = function (data) {
|
||||
streamedOutputs.stdout += data
|
||||
}
|
||||
|
||||
this._onStderr = function (data) {
|
||||
streamedOutputs.stderr += data
|
||||
}
|
||||
|
||||
this._execCommand = function (cmd, args) {
|
||||
if (!cmd) {
|
||||
log.error(`No binary for ${self.name} browser on your platform.\n Please, set "${self.ENV_CMD}" env variable.`)
|
||||
|
||||
// disable restarting
|
||||
self._retryLimit = -1
|
||||
|
||||
return self._clearTempDirAndReportDone('no binary')
|
||||
}
|
||||
|
||||
cmd = this._normalizeCommand(cmd)
|
||||
|
||||
log.debug(cmd + ' ' + args.join(' '))
|
||||
self._process = spawn(cmd, args)
|
||||
let errorOutput = ''
|
||||
|
||||
self._process.stdout.on('data', self._onStdout)
|
||||
|
||||
self._process.stderr.on('data', self._onStderr)
|
||||
|
||||
self._process.on('exit', function (code, signal) {
|
||||
self._onProcessExit(code, signal, errorOutput)
|
||||
})
|
||||
|
||||
self._process.on('error', function (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
self._retryLimit = -1
|
||||
errorOutput = `Can not find the binary ${cmd}\n\tPlease set env variable ${self.ENV_CMD}`
|
||||
} else if (err.code === 'EACCES') {
|
||||
self._retryLimit = -1
|
||||
errorOutput = `Permission denied accessing the binary ${cmd}\n\tMaybe it's a directory?`
|
||||
} else {
|
||||
errorOutput += err.toString()
|
||||
}
|
||||
self._onProcessExit(-1, null, errorOutput)
|
||||
})
|
||||
|
||||
self._process.stderr.on('data', function (errBuff) {
|
||||
errorOutput += errBuff.toString()
|
||||
})
|
||||
}
|
||||
|
||||
this._onProcessExit = function (code, signal, errorOutput) {
|
||||
if (!self._process) {
|
||||
// Both exit and error events trigger _onProcessExit(), but we only need one cleanup.
|
||||
return
|
||||
}
|
||||
log.debug(`Process ${self.name} exited with code ${code} and signal ${signal}`)
|
||||
|
||||
let error = null
|
||||
|
||||
if (self.state === self.STATE_BEING_CAPTURED) {
|
||||
log.error(`Cannot start ${self.name}\n\t${errorOutput}`)
|
||||
error = 'cannot start'
|
||||
}
|
||||
|
||||
if (self.state === self.STATE_CAPTURED) {
|
||||
log.error(`${self.name} crashed.\n\t${errorOutput}`)
|
||||
error = 'crashed'
|
||||
}
|
||||
|
||||
if (error) {
|
||||
log.error(`${self.name} stdout: ${streamedOutputs.stdout}`)
|
||||
log.error(`${self.name} stderr: ${streamedOutputs.stderr}`)
|
||||
}
|
||||
|
||||
self._process = null
|
||||
streamedOutputs.stdout = ''
|
||||
streamedOutputs.stderr = ''
|
||||
if (self._killTimer) {
|
||||
timer.clearTimeout(self._killTimer)
|
||||
self._killTimer = null
|
||||
}
|
||||
self._clearTempDirAndReportDone(error)
|
||||
}
|
||||
|
||||
this._clearTempDirAndReportDone = function (error) {
|
||||
tempDir.remove(self._tempDir, function () {
|
||||
self._done(error)
|
||||
if (onExitCallback) {
|
||||
onExitCallback()
|
||||
onExitCallback = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this._onKillTimeout = function () {
|
||||
if (self.state !== self.STATE_BEING_KILLED && self.state !== self.STATE_BEING_FORCE_KILLED) {
|
||||
return
|
||||
}
|
||||
|
||||
log.warn(`${self.name} was not killed in ${killTimeout} ms, sending SIGKILL.`)
|
||||
self._process.kill('SIGKILL')
|
||||
|
||||
// NOTE: https://github.com/karma-runner/karma/pull/1184
|
||||
// NOTE: SIGKILL is just a signal. Processes should never ignore it, but they can.
|
||||
// If a process gets into a state where it doesn't respond in a reasonable amount of time
|
||||
// Karma should warn, and continue as though the kill succeeded.
|
||||
// This a certainly suboptimal, but it is better than having the test harness hang waiting
|
||||
// for a zombie child process to exit.
|
||||
self._killTimer = timer.setTimeout(function () {
|
||||
log.warn(`${self.name} was not killed by SIGKILL in ${killTimeout} ms, continuing.`)
|
||||
self._onProcessExit(-1, null, '')
|
||||
}, killTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
ProcessLauncher.decoratorFactory = function (timer) {
|
||||
return function (launcher, processKillTimeout) {
|
||||
const spawn = require('child_process').spawn
|
||||
|
||||
function spawnWithoutOutput () {
|
||||
const proc = spawn.apply(null, arguments)
|
||||
proc.stdout.resume()
|
||||
proc.stderr.resume()
|
||||
|
||||
return proc
|
||||
}
|
||||
|
||||
ProcessLauncher.call(launcher, spawnWithoutOutput, require('../temp_dir'), timer, processKillTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ProcessLauncher
|
||||
31
my-app/node_modules/karma/lib/launchers/retry.js
generated
vendored
Executable file
31
my-app/node_modules/karma/lib/launchers/retry.js
generated
vendored
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
const log = require('../logger').create('launcher')
|
||||
|
||||
function RetryLauncher (retryLimit) {
|
||||
this._retryLimit = retryLimit
|
||||
|
||||
this.on('done', () => {
|
||||
if (!this.error) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this._retryLimit > 0) {
|
||||
log.info(`Trying to start ${this.name} again (${retryLimit - this._retryLimit + 1}/${retryLimit}).`)
|
||||
this.restart()
|
||||
this._retryLimit--
|
||||
} else if (this._retryLimit === 0) {
|
||||
log.error(`${this.name} failed ${retryLimit} times (${this.error}). Giving up.`)
|
||||
} else {
|
||||
log.debug(`${this.name} failed (${this.error}). Not restarting.`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
RetryLauncher.decoratorFactory = function (retryLimit) {
|
||||
return function (launcher) {
|
||||
RetryLauncher.call(launcher, retryLimit)
|
||||
}
|
||||
}
|
||||
|
||||
RetryLauncher.decoratorFactory.$inject = ['config.retryLimit']
|
||||
|
||||
module.exports = RetryLauncher
|
||||
115
my-app/node_modules/karma/lib/logger.js
generated
vendored
Executable file
115
my-app/node_modules/karma/lib/logger.js
generated
vendored
Executable file
|
|
@ -0,0 +1,115 @@
|
|||
// This is the **logger** module for *Karma*. It uses
|
||||
// [log4js](https://github.com/nomiddlename/log4js-node) to handle and
|
||||
// configure all logging that happens inside of *Karma*.
|
||||
|
||||
// ### Helpers and Setup
|
||||
|
||||
let log4js = require('log4js')
|
||||
const helper = require('./helper')
|
||||
const constant = require('./constants')
|
||||
|
||||
// #### Public Functions
|
||||
|
||||
// Setup the logger by passing in the configuration options. It needs
|
||||
// three arguments:
|
||||
//
|
||||
// setup(logLevel, colors, appenders)
|
||||
//
|
||||
// * `logLevel`: *String* Defines the global log level.
|
||||
// * `colors`: *Boolean* Use colors in the stdout or not.
|
||||
// * `appenders`: *Object* This will be passed as appenders to log4js
|
||||
// to allow for fine grained configuration of log4js. For more information
|
||||
// see https://github.com/nomiddlename/log4js-node.
|
||||
// *Array* is also accepted for backwards compatibility.
|
||||
function setup (level, colors, appenders) {
|
||||
// Turn color on/off on the console appenders with pattern layout
|
||||
const pattern = colors ? constant.COLOR_PATTERN : constant.NO_COLOR_PATTERN
|
||||
if (appenders) {
|
||||
// Convert Array to Object for backwards compatibility.
|
||||
if (appenders.map) {
|
||||
if (appenders.length === 0) {
|
||||
appenders = [constant.CONSOLE_APPENDER]
|
||||
}
|
||||
const v1Appenders = appenders
|
||||
appenders = {}
|
||||
v1Appenders.forEach(function (appender, index) {
|
||||
if (appender.type === 'console') {
|
||||
appenders.console = appender
|
||||
if (helper.isDefined(appender.layout) && appender.layout.type === 'pattern') {
|
||||
appender.layout.pattern = pattern
|
||||
}
|
||||
} else {
|
||||
appenders[index + ''] = appender
|
||||
}
|
||||
return appender
|
||||
})
|
||||
}
|
||||
} else {
|
||||
appenders = { console: constant.CONSOLE_APPENDER }
|
||||
}
|
||||
|
||||
log4js.configure({
|
||||
appenders: appenders,
|
||||
categories: {
|
||||
default: {
|
||||
appenders: Object.keys(appenders),
|
||||
level: level
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Setup the logger by passing in the config object. The function sets the
|
||||
// `colors` and `logLevel` if they are defined. It takes two arguments:
|
||||
//
|
||||
// setupFromConfig(config, appenders)
|
||||
//
|
||||
// * `config`: *Object* The configuration object.
|
||||
// * `appenders`: *Object* This will be passed as appenders to log4js
|
||||
// to allow for fine grained configuration of log4js. For more information
|
||||
// see https://github.com/nomiddlename/log4js-node.
|
||||
// *Array* is also accepted for backwards compatibility.
|
||||
function setupFromConfig (config, appenders) {
|
||||
let useColors = true
|
||||
let logLevel = constant.LOG_INFO
|
||||
|
||||
if (helper.isDefined(config.colors)) {
|
||||
useColors = config.colors
|
||||
}
|
||||
|
||||
if (helper.isDefined(config.logLevel)) {
|
||||
logLevel = config.logLevel
|
||||
}
|
||||
setup(logLevel, useColors, appenders)
|
||||
}
|
||||
|
||||
const loggerCache = {}
|
||||
|
||||
// Create a new logger. There are two optional arguments
|
||||
// * `name`, which defaults to `karma` and
|
||||
// If the `name = 'socket.io'` this will create a special wrapper
|
||||
// to be used as a logger for socket.io.
|
||||
// * `level`, which defaults to the global level.
|
||||
function create (name, level) {
|
||||
name = name || 'karma'
|
||||
let logger
|
||||
if (Object.prototype.hasOwnProperty.call(loggerCache, name)) {
|
||||
logger = loggerCache[name]
|
||||
} else {
|
||||
logger = log4js.getLogger(name)
|
||||
loggerCache[name] = logger
|
||||
}
|
||||
if (helper.isDefined(level)) {
|
||||
logger.setLevel(level)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// #### Publish
|
||||
|
||||
exports.create = create
|
||||
exports.setup = setup
|
||||
exports.setupFromConfig = setupFromConfig
|
||||
exports._rebindLog4js4testing = function (mockLog4js) {
|
||||
log4js = mockLog4js
|
||||
}
|
||||
105
my-app/node_modules/karma/lib/middleware/common.js
generated
vendored
Executable file
105
my-app/node_modules/karma/lib/middleware/common.js
generated
vendored
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* This module contains some common helpers shared between middlewares
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const mime = require('mime')
|
||||
const parseRange = require('range-parser')
|
||||
const log = require('../logger').create('web-server')
|
||||
|
||||
function createServeFile (fs, directory, config) {
|
||||
const cache = Object.create(null)
|
||||
|
||||
return function (filepath, rangeHeader, response, transform, content, doNotCache) {
|
||||
let responseData
|
||||
|
||||
function convertForRangeRequest () {
|
||||
const range = parseRange(responseData.length, rangeHeader)
|
||||
if (range === -2) {
|
||||
return 200 // malformed header string
|
||||
} else if (range === -1) {
|
||||
responseData = Buffer.alloc(0) // unsatisfiable range
|
||||
return 416
|
||||
} else if (range.type === 'bytes') {
|
||||
responseData = Buffer.from(responseData)
|
||||
if (range.length === 1) {
|
||||
const { start, end } = range[0]
|
||||
response.setHeader('Content-Range', `bytes ${start}-${end}/${responseData.length}`)
|
||||
response.setHeader('Accept-Ranges', 'bytes')
|
||||
response.setHeader('Content-Length', end - start + 1)
|
||||
responseData = responseData.slice(start, end + 1)
|
||||
return 206
|
||||
} else {
|
||||
responseData = Buffer.alloc(0) // Multiple ranges are not supported. Maybe future?
|
||||
return 416
|
||||
}
|
||||
}
|
||||
return 200 // All other states, ignore
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
filepath = directory + filepath
|
||||
}
|
||||
|
||||
if (!content && cache[filepath]) {
|
||||
content = cache[filepath]
|
||||
}
|
||||
|
||||
if (config && config.customHeaders && config.customHeaders.length > 0) {
|
||||
config.customHeaders.forEach((header) => {
|
||||
const regex = new RegExp(header.match)
|
||||
if (regex.test(filepath)) {
|
||||
log.debug(`setting header: ${header.name} for: ${filepath}`)
|
||||
response.setHeader(header.name, header.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (content && !doNotCache) {
|
||||
log.debug(`serving (cached): ${filepath}`)
|
||||
response.setHeader('Content-Type', mime.getType(filepath, 'text/plain'))
|
||||
responseData = (transform && transform(content)) || content
|
||||
response.writeHead(rangeHeader ? convertForRangeRequest() : 200)
|
||||
return response.end(responseData)
|
||||
}
|
||||
|
||||
return fs.readFile(filepath, function (error, data) {
|
||||
if (error) {
|
||||
return serve404(response, filepath)
|
||||
}
|
||||
|
||||
if (!doNotCache) {
|
||||
cache[filepath] = data.toString()
|
||||
}
|
||||
|
||||
log.debug('serving: ' + filepath)
|
||||
response.setHeader('Content-Type', mime.getType(filepath, 'text/plain'))
|
||||
responseData = (transform && transform(data.toString())) || data
|
||||
response.writeHead(rangeHeader ? convertForRangeRequest() : 200)
|
||||
|
||||
return response.end(responseData)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function serve404 (response, path) {
|
||||
log.warn(`404: ${path}`)
|
||||
response.writeHead(404)
|
||||
return response.end('NOT FOUND')
|
||||
}
|
||||
|
||||
function setNoCacheHeaders (response) {
|
||||
response.setHeader('Cache-Control', 'no-cache')
|
||||
response.setHeader('Pragma', 'no-cache')
|
||||
response.setHeader('Expires', (new Date(0)).toUTCString())
|
||||
}
|
||||
|
||||
function setHeavyCacheHeaders (response) {
|
||||
response.setHeader('Cache-Control', 'public, max-age=31536000')
|
||||
}
|
||||
|
||||
// PUBLIC API
|
||||
exports.createServeFile = createServeFile
|
||||
exports.setNoCacheHeaders = setNoCacheHeaders
|
||||
exports.setHeavyCacheHeaders = setHeavyCacheHeaders
|
||||
exports.serve404 = serve404
|
||||
259
my-app/node_modules/karma/lib/middleware/karma.js
generated
vendored
Executable file
259
my-app/node_modules/karma/lib/middleware/karma.js
generated
vendored
Executable file
|
|
@ -0,0 +1,259 @@
|
|||
/**
|
||||
* Karma middleware is responsible for serving:
|
||||
* - client.html (the entrypoint for capturing a browser)
|
||||
* - debug.html
|
||||
* - context.html (the execution context, loaded within an iframe)
|
||||
* - karma.js
|
||||
*
|
||||
* The main part is generating context.html, as it contains:
|
||||
* - generating mappings
|
||||
* - including <script> and <link> tags
|
||||
* - setting propert caching headers
|
||||
*/
|
||||
|
||||
const url = require('url')
|
||||
|
||||
const log = require('../logger').create('middleware:karma')
|
||||
const stripHost = require('./strip_host').stripHost
|
||||
const common = require('./common')
|
||||
|
||||
const VERSION = require('../constants').VERSION
|
||||
const SCRIPT_TYPE = {
|
||||
js: 'text/javascript',
|
||||
module: 'module'
|
||||
}
|
||||
const FILE_TYPES = [
|
||||
'css',
|
||||
'html',
|
||||
'js',
|
||||
'module',
|
||||
'dom'
|
||||
]
|
||||
|
||||
function filePathToUrlPath (filePath, basePath, urlRoot, proxyPath) {
|
||||
if (filePath.startsWith(basePath)) {
|
||||
return proxyPath + urlRoot.slice(1) + 'base' + filePath.slice(basePath.length)
|
||||
}
|
||||
return proxyPath + urlRoot.slice(1) + 'absolute' + filePath
|
||||
}
|
||||
|
||||
function getQuery (urlStr) {
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
return url.parse(urlStr, true).query || {}
|
||||
}
|
||||
|
||||
function getXUACompatibleMetaElement (url) {
|
||||
const query = getQuery(url)
|
||||
if (query['x-ua-compatible']) {
|
||||
return `<meta http-equiv="X-UA-Compatible" content="${query['x-ua-compatible']}"/>`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function getXUACompatibleUrl (url) {
|
||||
const query = getQuery(url)
|
||||
if (query['x-ua-compatible']) {
|
||||
return '?x-ua-compatible=' + encodeURIComponent(query['x-ua-compatible'])
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function createKarmaMiddleware (
|
||||
filesPromise,
|
||||
serveStaticFile,
|
||||
serveFile,
|
||||
injector,
|
||||
basePath,
|
||||
urlRoot,
|
||||
upstreamProxy,
|
||||
browserSocketTimeout
|
||||
) {
|
||||
const proxyPath = upstreamProxy ? upstreamProxy.path : '/'
|
||||
return function (request, response, next) {
|
||||
// These config values should be up to date on every request
|
||||
const client = injector.get('config.client')
|
||||
const customContextFile = injector.get('config.customContextFile')
|
||||
const customDebugFile = injector.get('config.customDebugFile')
|
||||
const customClientContextFile = injector.get('config.customClientContextFile')
|
||||
const includeCrossOriginAttribute = injector.get('config.crossOriginAttribute')
|
||||
|
||||
const normalizedUrl = stripHost(request.url) || request.url
|
||||
// For backwards compatibility in middleware plugins, remove in v4.
|
||||
request.normalizedUrl = normalizedUrl
|
||||
|
||||
let requestUrl = normalizedUrl.replace(/\?.*/, '')
|
||||
const requestedRangeHeader = request.headers.range
|
||||
|
||||
// redirect /__karma__ to /__karma__ (trailing slash)
|
||||
if (requestUrl === urlRoot.slice(0, -1)) {
|
||||
response.setHeader('Location', proxyPath + urlRoot.slice(1))
|
||||
response.writeHead(301)
|
||||
return response.end('MOVED PERMANENTLY')
|
||||
}
|
||||
|
||||
// ignore urls outside urlRoot
|
||||
if (!requestUrl.startsWith(urlRoot)) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// remove urlRoot prefix
|
||||
requestUrl = requestUrl.slice(urlRoot.length - 1)
|
||||
|
||||
// serve client.html
|
||||
if (requestUrl === '/') {
|
||||
// redirect client_with_context.html
|
||||
if (!client.useIframe && client.runInParent) {
|
||||
requestUrl = '/client_with_context.html'
|
||||
} else { // serve client.html
|
||||
return serveStaticFile('/client.html', requestedRangeHeader, response, (data) =>
|
||||
data
|
||||
.replace('%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url))
|
||||
.replace('%X_UA_COMPATIBLE_URL%', getXUACompatibleUrl(request.url)))
|
||||
}
|
||||
}
|
||||
|
||||
if (['/karma.js', '/context.js', '/debug.js'].includes(requestUrl)) {
|
||||
return serveStaticFile(requestUrl, requestedRangeHeader, response, (data) =>
|
||||
data
|
||||
.replace('%KARMA_URL_ROOT%', urlRoot)
|
||||
.replace('%KARMA_VERSION%', VERSION)
|
||||
.replace('%KARMA_PROXY_PATH%', proxyPath)
|
||||
.replace('%BROWSER_SOCKET_TIMEOUT%', browserSocketTimeout))
|
||||
}
|
||||
|
||||
// serve the favicon
|
||||
if (requestUrl === '/favicon.ico') {
|
||||
return serveStaticFile(requestUrl, requestedRangeHeader, response)
|
||||
}
|
||||
|
||||
// serve context.html - execution context within the iframe
|
||||
// or debug.html - execution context without channel to the server
|
||||
const isRequestingContextFile = requestUrl === '/context.html'
|
||||
const isRequestingDebugFile = requestUrl === '/debug.html'
|
||||
const isRequestingClientContextFile = requestUrl === '/client_with_context.html'
|
||||
if (isRequestingContextFile || isRequestingDebugFile || isRequestingClientContextFile) {
|
||||
return filesPromise.then((files) => {
|
||||
let fileServer
|
||||
let requestedFileUrl
|
||||
log.debug('custom files', customContextFile, customDebugFile, customClientContextFile)
|
||||
if (isRequestingContextFile && customContextFile) {
|
||||
log.debug(`Serving customContextFile ${customContextFile}`)
|
||||
fileServer = serveFile
|
||||
requestedFileUrl = customContextFile
|
||||
} else if (isRequestingDebugFile && customDebugFile) {
|
||||
log.debug(`Serving customDebugFile ${customDebugFile}`)
|
||||
fileServer = serveFile
|
||||
requestedFileUrl = customDebugFile
|
||||
} else if (isRequestingClientContextFile && customClientContextFile) {
|
||||
log.debug(`Serving customClientContextFile ${customClientContextFile}`)
|
||||
fileServer = serveFile
|
||||
requestedFileUrl = customClientContextFile
|
||||
} else {
|
||||
log.debug(`Serving static request ${requestUrl}`)
|
||||
fileServer = serveStaticFile
|
||||
requestedFileUrl = requestUrl
|
||||
}
|
||||
|
||||
fileServer(requestedFileUrl, requestedRangeHeader, response, function (data) {
|
||||
common.setNoCacheHeaders(response)
|
||||
|
||||
const scriptTags = []
|
||||
for (const file of files.included) {
|
||||
let filePath = file.path
|
||||
const fileType = file.type || file.detectType()
|
||||
|
||||
if (!FILE_TYPES.includes(fileType)) {
|
||||
if (file.type == null) {
|
||||
log.warn(
|
||||
'Unable to determine file type from the file extension, defaulting to js.\n' +
|
||||
` To silence the warning specify a valid type for ${file.originalPath} in the configuration file.\n` +
|
||||
' See https://karma-runner.github.io/latest/config/files.html'
|
||||
)
|
||||
} else {
|
||||
log.warn(`Invalid file type (${file.type || 'empty string'}), defaulting to js.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (!file.isUrl) {
|
||||
filePath = filePathToUrlPath(filePath, basePath, urlRoot, proxyPath)
|
||||
|
||||
if (requestUrl === '/context.html') {
|
||||
filePath += '?' + file.sha
|
||||
}
|
||||
}
|
||||
|
||||
const integrityAttribute = file.integrity ? ` integrity="${file.integrity}"` : ''
|
||||
const crossOriginAttribute = includeCrossOriginAttribute ? ' crossorigin="anonymous"' : ''
|
||||
if (fileType === 'css') {
|
||||
scriptTags.push(`<link type="text/css" href="${filePath}" rel="stylesheet"${integrityAttribute}${crossOriginAttribute}>`)
|
||||
} else if (fileType === 'dom') {
|
||||
scriptTags.push(file.content)
|
||||
} else if (fileType === 'html') {
|
||||
scriptTags.push(`<link href="${filePath}" rel="import"${integrityAttribute}${crossOriginAttribute}>`)
|
||||
} else {
|
||||
const scriptType = (SCRIPT_TYPE[fileType] || 'text/javascript')
|
||||
if (fileType === 'module') {
|
||||
scriptTags.push(`<script onerror="throw 'Error loading ${filePath}'" type="${scriptType}" src="${filePath}"${integrityAttribute}${crossOriginAttribute}></script>`)
|
||||
} else {
|
||||
scriptTags.push(`<script type="${scriptType}" src="${filePath}"${integrityAttribute}${crossOriginAttribute}></script>`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const scriptUrls = []
|
||||
// For client_with_context, html elements are not added directly through an iframe.
|
||||
// Instead, scriptTags is stored to window.__karma__.scriptUrls first. Later, the
|
||||
// client will read window.__karma__.scriptUrls and dynamically add them to the DOM
|
||||
// using DOMParser.
|
||||
if (requestUrl === '/client_with_context.html') {
|
||||
for (const script of scriptTags) {
|
||||
scriptUrls.push(
|
||||
// Escape characters with special roles (tags) in HTML. Open angle brackets are parsed as tags
|
||||
// immediately, even if it is within double quotations in browsers
|
||||
script.replace(/</g, '\\x3C').replace(/>/g, '\\x3E'))
|
||||
}
|
||||
}
|
||||
|
||||
const mappings = data.includes('%MAPPINGS%') ? files.served.map((file) => {
|
||||
const filePath = filePathToUrlPath(file.path, basePath, urlRoot, proxyPath)
|
||||
.replace(/\\/g, '\\\\') // Windows paths contain backslashes and generate bad IDs if not escaped
|
||||
.replace(/'/g, '\\\'') // Escape single quotes - double quotes should not be allowed!
|
||||
|
||||
return ` '${filePath}': '${file.sha}'`
|
||||
}) : []
|
||||
|
||||
return data
|
||||
.replace('%SCRIPTS%', () => scriptTags.join('\n'))
|
||||
.replace('%CLIENT_CONFIG%', 'window.__karma__.config = ' + JSON.stringify(client) + ';\n')
|
||||
.replace('%SCRIPT_URL_ARRAY%', () => 'window.__karma__.scriptUrls = ' + JSON.stringify(scriptUrls) + ';\n')
|
||||
.replace('%MAPPINGS%', () => 'window.__karma__.files = {\n' + mappings.join(',\n') + '\n};\n')
|
||||
.replace('%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url))
|
||||
})
|
||||
})
|
||||
} else if (requestUrl === '/context.json') {
|
||||
return filesPromise.then((files) => {
|
||||
common.setNoCacheHeaders(response)
|
||||
response.writeHead(200)
|
||||
response.end(JSON.stringify({
|
||||
files: files.included.map((file) => filePathToUrlPath(file.path + '?' + file.sha, basePath, urlRoot, proxyPath))
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
createKarmaMiddleware.$inject = [
|
||||
'filesPromise',
|
||||
'serveStaticFile',
|
||||
'serveFile',
|
||||
'injector',
|
||||
'config.basePath',
|
||||
'config.urlRoot',
|
||||
'config.upstreamProxy',
|
||||
'config.browserSocketTimeout'
|
||||
]
|
||||
|
||||
// PUBLIC API
|
||||
exports.create = createKarmaMiddleware
|
||||
130
my-app/node_modules/karma/lib/middleware/proxy.js
generated
vendored
Executable file
130
my-app/node_modules/karma/lib/middleware/proxy.js
generated
vendored
Executable file
|
|
@ -0,0 +1,130 @@
|
|||
const url = require('url')
|
||||
const { Agent: httpAgent } = require('http')
|
||||
const { Agent: httpsAgent } = require('https')
|
||||
const httpProxy = require('http-proxy')
|
||||
const _ = require('lodash')
|
||||
const { lookup } = require('../utils/dns-utils')
|
||||
|
||||
const log = require('../logger').create('proxy')
|
||||
|
||||
function parseProxyConfig (proxies, config) {
|
||||
proxies = proxies || []
|
||||
return _.sortBy(_.map(proxies, function (proxyConfiguration, proxyPath) {
|
||||
if (typeof proxyConfiguration === 'string') {
|
||||
proxyConfiguration = { target: proxyConfiguration }
|
||||
}
|
||||
let proxyUrl = proxyConfiguration.target
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
const proxyDetails = url.parse(proxyUrl)
|
||||
let pathname = proxyDetails.pathname
|
||||
|
||||
if (proxyPath.endsWith('/') && !proxyUrl.endsWith('/')) {
|
||||
log.warn(`proxy "${proxyUrl}" normalized to "${proxyUrl}/"`)
|
||||
proxyUrl += '/'
|
||||
pathname += '/'
|
||||
}
|
||||
|
||||
if (!proxyPath.endsWith('/') && proxyUrl.endsWith('/')) {
|
||||
log.warn(`proxy "${proxyPath}" normalized to "${proxyPath}/"`)
|
||||
proxyPath += '/'
|
||||
}
|
||||
|
||||
if (pathname === '/' && !proxyUrl.endsWith('/')) {
|
||||
pathname = ''
|
||||
}
|
||||
|
||||
const hostname = proxyDetails.hostname || config.hostname
|
||||
const protocol = proxyDetails.protocol || config.protocol
|
||||
const defaultPorts = {
|
||||
'http:': '80',
|
||||
'https:': '443'
|
||||
}
|
||||
const port = proxyDetails.port || defaultPorts[proxyDetails.protocol] || config.port
|
||||
const changeOrigin = proxyConfiguration.changeOrigin || false
|
||||
const Agent = protocol === 'https:' ? httpsAgent : httpAgent
|
||||
const agent = new Agent({
|
||||
keepAlive: true,
|
||||
lookup
|
||||
})
|
||||
const proxy = httpProxy.createProxyServer({
|
||||
target: { host: hostname, port, protocol },
|
||||
xfwd: true,
|
||||
changeOrigin: changeOrigin,
|
||||
secure: config.proxyValidateSSL,
|
||||
agent
|
||||
})
|
||||
|
||||
;['proxyReq', 'proxyRes'].forEach(function (name) {
|
||||
const callback = proxyDetails[name] || config[name]
|
||||
if (callback) {
|
||||
proxy.on(name, callback)
|
||||
}
|
||||
})
|
||||
|
||||
proxy.on('error', function proxyError (err, req, res) {
|
||||
if (err.code === 'ECONNRESET' && req.socket.destroyed) {
|
||||
log.debug(`failed to proxy ${req.url} (browser hung up the socket)`)
|
||||
} else {
|
||||
log.warn(`failed to proxy ${req.url} (${err.message})`)
|
||||
}
|
||||
|
||||
res.destroy()
|
||||
})
|
||||
|
||||
return { path: proxyPath, baseUrl: pathname, host: hostname, port, proxy, agent }
|
||||
}), 'path').reverse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handler which understands the proxies and its redirects, along with the proxy to use
|
||||
* @param proxies An array of proxy record objects
|
||||
* @param urlRoot The URL root that karma is mounted on
|
||||
* @return {Function} handler function
|
||||
*/
|
||||
function createProxyHandler (proxies, urlRoot) {
|
||||
if (!proxies.length) {
|
||||
const nullProxy = (request, response, next) => next()
|
||||
nullProxy.upgrade = () => {}
|
||||
return nullProxy
|
||||
}
|
||||
|
||||
function createProxy (request, response, next) {
|
||||
const proxyRecord = proxies.find((p) => request.url.startsWith(p.path))
|
||||
if (proxyRecord) {
|
||||
log.debug(`proxying request - ${request.url} to ${proxyRecord.host}:${proxyRecord.port}`)
|
||||
request.url = request.url.replace(proxyRecord.path, proxyRecord.baseUrl)
|
||||
proxyRecord.proxy.web(request, response)
|
||||
} else {
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
createProxy.upgrade = function (request, socket, head) {
|
||||
// special-case karma's route to avoid upgrading it
|
||||
if (request.url.startsWith(urlRoot)) {
|
||||
log.debug(`NOT upgrading proxyWebSocketRequest ${request.url}`)
|
||||
return
|
||||
}
|
||||
|
||||
const proxyRecord = proxies.find((p) => request.url.startsWith(p.path))
|
||||
if (proxyRecord) {
|
||||
log.debug(`upgrade proxyWebSocketRequest ${request.url} to ${proxyRecord.host}:${proxyRecord.port}`)
|
||||
request.url = request.url.replace(proxyRecord.path, proxyRecord.baseUrl)
|
||||
proxyRecord.proxy.ws(request, socket, head)
|
||||
}
|
||||
}
|
||||
|
||||
return createProxy
|
||||
}
|
||||
|
||||
exports.create = function (/* config */config, /* config.proxies */proxies, /* emitter */emitter) {
|
||||
const proxyRecords = parseProxyConfig(proxies, config)
|
||||
emitter.on('exit', (done) => {
|
||||
log.debug('Destroying proxy agents')
|
||||
proxyRecords.forEach((proxyRecord) => {
|
||||
proxyRecord.agent.destroy()
|
||||
})
|
||||
done()
|
||||
})
|
||||
return createProxyHandler(proxyRecords, config.urlRoot)
|
||||
}
|
||||
114
my-app/node_modules/karma/lib/middleware/runner.js
generated
vendored
Executable file
114
my-app/node_modules/karma/lib/middleware/runner.js
generated
vendored
Executable file
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
* Runner middleware is responsible for communication with `karma run`.
|
||||
*
|
||||
* It basically triggers a test run and streams stdout back.
|
||||
*/
|
||||
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const helper = require('../helper')
|
||||
const log = require('../logger').create()
|
||||
const constant = require('../constants')
|
||||
const json = require('body-parser').json()
|
||||
|
||||
// TODO(vojta): disable when single-run mode
|
||||
function createRunnerMiddleware (emitter, fileList, capturedBrowsers, reporter, executor,
|
||||
/* config.protocol */ protocol, /* config.hostname */ hostname, /* config.port */
|
||||
port, /* config.urlRoot */ urlRoot, config) {
|
||||
helper.saveOriginalArgs(config)
|
||||
return function (request, response, next) {
|
||||
if (request.url !== '/__run__' && request.url !== urlRoot + 'run') {
|
||||
return next()
|
||||
}
|
||||
|
||||
log.debug('Execution (fired by runner)')
|
||||
response.writeHead(200)
|
||||
|
||||
if (!capturedBrowsers.length) {
|
||||
const url = `${protocol}//${hostname}:${port}${urlRoot}`
|
||||
return response.end(`No captured browser, open ${url}\n`)
|
||||
}
|
||||
|
||||
json(request, response, function () {
|
||||
if (!capturedBrowsers.areAllReady([])) {
|
||||
response.write('Waiting for previous execution...\n')
|
||||
}
|
||||
|
||||
const data = request.body
|
||||
|
||||
updateClientArgs(data)
|
||||
handleRun(data)
|
||||
refreshFileList(data).then(() => {
|
||||
executor.schedule()
|
||||
}).catch((error) => {
|
||||
const errorMessage = `Error during refresh file list. ${error.stack || error}`
|
||||
executor.scheduleError(errorMessage)
|
||||
})
|
||||
})
|
||||
|
||||
function updateClientArgs (data) {
|
||||
helper.restoreOriginalArgs(config)
|
||||
if (_.isEmpty(data.args)) {
|
||||
log.debug('Ignoring empty client.args from run command')
|
||||
} else if ((_.isArray(data.args) && _.isArray(config.client.args)) ||
|
||||
(_.isPlainObject(data.args) && _.isPlainObject(config.client.args))) {
|
||||
log.debug('Merging client.args with ', data.args)
|
||||
config.client.args = _.merge(config.client.args, data.args)
|
||||
} else {
|
||||
log.warn('Replacing client.args with ', data.args, ' as their types do not match.')
|
||||
config.client.args = data.args
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshFileList (data) {
|
||||
let fullRefresh = true
|
||||
|
||||
if (helper.isArray(data.changedFiles)) {
|
||||
await Promise.all(data.changedFiles.map(async function (filepath) {
|
||||
await fileList.changeFile(path.resolve(config.basePath, filepath))
|
||||
fullRefresh = false
|
||||
}))
|
||||
}
|
||||
|
||||
if (helper.isArray(data.addedFiles)) {
|
||||
await Promise.all(data.addedFiles.map(async function (filepath) {
|
||||
await fileList.addFile(path.resolve(config.basePath, filepath))
|
||||
fullRefresh = false
|
||||
}))
|
||||
}
|
||||
|
||||
if (helper.isArray(data.removedFiles)) {
|
||||
await Promise.all(data.removedFiles.map(async function (filepath) {
|
||||
await fileList.removeFile(path.resolve(config.basePath, filepath))
|
||||
fullRefresh = false
|
||||
}))
|
||||
}
|
||||
|
||||
if (fullRefresh && data.refresh !== false) {
|
||||
log.debug('Refreshing all the files / patterns')
|
||||
await fileList.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
function handleRun (data) {
|
||||
emitter.once('run_start', function () {
|
||||
const responseWrite = response.write.bind(response)
|
||||
responseWrite.colors = data.colors
|
||||
reporter.addAdapter(responseWrite)
|
||||
|
||||
// clean up, close runner response
|
||||
emitter.once('run_complete', function (_browsers, results) {
|
||||
reporter.removeAdapter(responseWrite)
|
||||
const emptyTestSuite = (results.failed + results.success) === 0 ? 0 : 1
|
||||
response.end(constant.EXIT_CODE + emptyTestSuite + results.exitCode)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createRunnerMiddleware.$inject = ['emitter', 'fileList', 'capturedBrowsers', 'reporter', 'executor',
|
||||
'config.protocol', 'config.hostname', 'config.port', 'config.urlRoot', 'config']
|
||||
|
||||
// PUBLIC API
|
||||
exports.create = createRunnerMiddleware
|
||||
67
my-app/node_modules/karma/lib/middleware/source_files.js
generated
vendored
Executable file
67
my-app/node_modules/karma/lib/middleware/source_files.js
generated
vendored
Executable file
|
|
@ -0,0 +1,67 @@
|
|||
'use strict'
|
||||
|
||||
const querystring = require('querystring')
|
||||
const common = require('./common')
|
||||
|
||||
const log = require('../logger').create('middleware:source-files')
|
||||
|
||||
function findByPath (files, path) {
|
||||
return Array.from(files).find((file) => file.path === path)
|
||||
}
|
||||
|
||||
function composeUrl (url, basePath, urlRoot) {
|
||||
return url
|
||||
.replace(urlRoot, '/')
|
||||
.replace(/\?.*$/, '')
|
||||
.replace(/^\/absolute/, '')
|
||||
.replace(/^\/base/, basePath)
|
||||
}
|
||||
|
||||
// Source Files middleware is responsible for serving all the source files under the test.
|
||||
function createSourceFilesMiddleware (filesPromise, serveFile, basePath, urlRoot) {
|
||||
return function (request, response, next) {
|
||||
const requestedFilePath = composeUrl(request.url, basePath, urlRoot)
|
||||
// When a path contains HTML-encoded characters (e.g %2F used by Jenkins for branches with /)
|
||||
const requestedFilePathUnescaped = composeUrl(querystring.unescape(request.url), basePath, urlRoot)
|
||||
|
||||
request.pause()
|
||||
|
||||
log.debug(`Requesting ${request.url}`)
|
||||
log.debug(`Fetching ${requestedFilePath}`)
|
||||
|
||||
return filesPromise.then(function (files) {
|
||||
// TODO(vojta): change served to be a map rather then an array
|
||||
const file = findByPath(files.served, requestedFilePath) || findByPath(files.served, requestedFilePathUnescaped)
|
||||
const rangeHeader = request.headers.range
|
||||
|
||||
if (file) {
|
||||
const acceptEncodingHeader = request.headers['accept-encoding']
|
||||
const matchedEncoding = Object.keys(file.encodings).find(
|
||||
(encoding) => new RegExp(`(^|.*, ?)${encoding}(,|$)`).test(acceptEncodingHeader)
|
||||
)
|
||||
const content = file.encodings[matchedEncoding] || file.content
|
||||
|
||||
serveFile(file.contentPath || file.path, rangeHeader, response, function () {
|
||||
if (/\?\w+/.test(request.url)) {
|
||||
common.setHeavyCacheHeaders(response) // files with timestamps - cache one year, rely on timestamps
|
||||
} else {
|
||||
common.setNoCacheHeaders(response) // without timestamps - no cache (debug)
|
||||
}
|
||||
if (matchedEncoding) {
|
||||
response.setHeader('Content-Encoding', matchedEncoding)
|
||||
}
|
||||
}, content, file.doNotCache)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
|
||||
request.resume()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
createSourceFilesMiddleware.$inject = [
|
||||
'filesPromise', 'serveFile', 'config.basePath', 'config.urlRoot'
|
||||
]
|
||||
|
||||
exports.create = createSourceFilesMiddleware
|
||||
18
my-app/node_modules/karma/lib/middleware/stopper.js
generated
vendored
Executable file
18
my-app/node_modules/karma/lib/middleware/stopper.js
generated
vendored
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Stopper middleware is responsible for communicating with `karma stop`.
|
||||
*/
|
||||
|
||||
const log = require('../logger').create('middleware:stopper')
|
||||
|
||||
function createStopperMiddleware (urlRoot) {
|
||||
return function (request, response, next) {
|
||||
if (request.url !== urlRoot + 'stop') return next()
|
||||
response.writeHead(200)
|
||||
log.info('Stopping server')
|
||||
response.end('OK')
|
||||
process.kill(process.pid, 'SIGINT')
|
||||
}
|
||||
}
|
||||
|
||||
createStopperMiddleware.$inject = ['config.urlRoot']
|
||||
exports.create = createStopperMiddleware
|
||||
11
my-app/node_modules/karma/lib/middleware/strip_host.js
generated
vendored
Executable file
11
my-app/node_modules/karma/lib/middleware/strip_host.js
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Strip hostname from request path
|
||||
* This to handle requests that uses (normally over proxies) an absoluteURI as request path
|
||||
*/
|
||||
|
||||
function stripHostFromUrl (url) {
|
||||
return url.replace(/^https?:\/\/[a-z.:\d-]+\//, '/')
|
||||
}
|
||||
|
||||
// PUBLIC API
|
||||
exports.stripHost = stripHostFromUrl
|
||||
98
my-app/node_modules/karma/lib/plugin.js
generated
vendored
Executable file
98
my-app/node_modules/karma/lib/plugin.js
generated
vendored
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('graceful-fs')
|
||||
const path = require('path')
|
||||
const helper = require('./helper')
|
||||
|
||||
const log = require('./logger').create('plugin')
|
||||
|
||||
const IGNORED_PACKAGES = ['karma-cli', 'karma-runner.github.com']
|
||||
|
||||
function resolve (plugins, emitter) {
|
||||
const modules = []
|
||||
|
||||
function requirePlugin (name) {
|
||||
log.debug(`Loading plugin ${name}.`)
|
||||
try {
|
||||
modules.push(require(name))
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND' && e.message.includes(name)) {
|
||||
log.error(`Cannot find plugin "${name}".\n Did you forget to install it?\n npm install ${name} --save-dev`)
|
||||
} else {
|
||||
log.error(`Error during loading "${name}" plugin:\n ${e.message}`)
|
||||
}
|
||||
emitter.emit('load_error', 'plug_in', name)
|
||||
}
|
||||
}
|
||||
|
||||
plugins.forEach(function (plugin) {
|
||||
if (helper.isString(plugin)) {
|
||||
if (!plugin.includes('*')) {
|
||||
requirePlugin(plugin)
|
||||
return
|
||||
}
|
||||
const pluginDirectory = path.normalize(path.join(__dirname, '/../..'))
|
||||
const regexp = new RegExp(`^${plugin.replace(/\*/g, '.*').replace(/\//g, '[/\\\\]')}`)
|
||||
|
||||
log.debug(`Loading ${plugin} from ${pluginDirectory}`)
|
||||
fs.readdirSync(pluginDirectory)
|
||||
.map((e) => {
|
||||
const modulePath = path.join(pluginDirectory, e)
|
||||
if (e[0] === '@') {
|
||||
return fs.readdirSync(modulePath).map((e) => path.join(modulePath, e))
|
||||
}
|
||||
return modulePath
|
||||
})
|
||||
.reduce((a, x) => a.concat(x), [])
|
||||
.map((modulePath) => path.relative(pluginDirectory, modulePath))
|
||||
.filter((moduleName) => !IGNORED_PACKAGES.includes(moduleName) && regexp.test(moduleName))
|
||||
.forEach((pluginName) => requirePlugin(path.join(pluginDirectory, pluginName)))
|
||||
} else if (helper.isObject(plugin)) {
|
||||
log.debug(`Loading inline plugin defining ${Object.keys(plugin).join(', ')}.`)
|
||||
modules.push(plugin)
|
||||
} else {
|
||||
log.error(`Invalid plugin ${plugin}`)
|
||||
emitter.emit('load_error', 'plug_in', plugin)
|
||||
}
|
||||
})
|
||||
|
||||
return modules
|
||||
}
|
||||
|
||||
/**
|
||||
Create a function to handle errors in plugin loading.
|
||||
@param {Object} injector, the dict of dependency injection objects.
|
||||
@return function closed over injector, which reports errors.
|
||||
*/
|
||||
function createInstantiatePlugin (injector) {
|
||||
const emitter = injector.get('emitter')
|
||||
// Cache to avoid report errors multiple times per plugin.
|
||||
const pluginInstances = new Map()
|
||||
return function instantiatePlugin (kind, name) {
|
||||
if (pluginInstances.has(name)) {
|
||||
return pluginInstances.get(name)
|
||||
}
|
||||
|
||||
let p
|
||||
try {
|
||||
p = injector.get(`${kind}:${name}`)
|
||||
if (!p) {
|
||||
log.error(`Failed to instantiate ${kind} ${name}`)
|
||||
emitter.emit('load_error', kind, name)
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.message.includes(`No provider for "${kind}:${name}"`)) {
|
||||
log.error(`Cannot load "${name}", it is not registered!\n Perhaps you are missing some plugin?`)
|
||||
} else {
|
||||
log.error(`Cannot load "${name}"!\n ` + e.stack)
|
||||
}
|
||||
emitter.emit('load_error', kind, name)
|
||||
}
|
||||
pluginInstances.set(name, p, `${kind}:${name}`)
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
createInstantiatePlugin.$inject = ['injector']
|
||||
|
||||
module.exports = { resolve, createInstantiatePlugin }
|
||||
111
my-app/node_modules/karma/lib/preprocessor.js
generated
vendored
Executable file
111
my-app/node_modules/karma/lib/preprocessor.js
generated
vendored
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
'use strict'
|
||||
|
||||
const util = require('util')
|
||||
const fs = require('graceful-fs')
|
||||
// bind need only for mock unit tests
|
||||
const readFile = util.promisify(fs.readFile.bind(fs))
|
||||
const tryToRead = function (path, log) {
|
||||
const maxRetries = 3
|
||||
let promise = readFile(path)
|
||||
for (let retryCount = 1; retryCount <= maxRetries; retryCount++) {
|
||||
promise = promise.catch((err) => {
|
||||
log.warn(err)
|
||||
log.warn('retrying ' + retryCount)
|
||||
return readFile(path)
|
||||
})
|
||||
}
|
||||
return promise.catch((err) => {
|
||||
log.warn(err)
|
||||
return Promise.reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
const mm = require('minimatch')
|
||||
const { isBinaryFile } = require('isbinaryfile')
|
||||
const _ = require('lodash')
|
||||
const CryptoUtils = require('./utils/crypto-utils')
|
||||
|
||||
const log = require('./logger').create('preprocess')
|
||||
|
||||
function executeProcessor (process, file, content) {
|
||||
let done = null
|
||||
const donePromise = new Promise((resolve, reject) => {
|
||||
done = function (error, content) {
|
||||
// normalize B-C
|
||||
if (arguments.length === 1 && typeof error === 'string') {
|
||||
content = error
|
||||
error = null
|
||||
}
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(content)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (process(content, file, done) || Promise.resolve()).then((content) => {
|
||||
if (content) {
|
||||
// async process correctly returned content
|
||||
return content
|
||||
}
|
||||
// process called done() (Either old sync api or an async function that did not return content)
|
||||
return donePromise
|
||||
})
|
||||
}
|
||||
|
||||
async function runProcessors (preprocessors, file, content) {
|
||||
try {
|
||||
for (const process of preprocessors) {
|
||||
content = await executeProcessor(process, file, content)
|
||||
}
|
||||
} catch (error) {
|
||||
file.contentPath = null
|
||||
file.content = null
|
||||
throw error
|
||||
}
|
||||
|
||||
file.contentPath = null
|
||||
file.content = content
|
||||
file.sha = CryptoUtils.sha1(content)
|
||||
}
|
||||
|
||||
function createPriorityPreprocessor (config = {}, preprocessorPriority, basePath, instantiatePlugin) {
|
||||
_.union.apply(_, Object.values(config)).forEach((name) => instantiatePlugin('preprocessor', name))
|
||||
return async function preprocess (file) {
|
||||
const buffer = await tryToRead(file.originalPath, log)
|
||||
let isBinary = file.isBinary
|
||||
if (isBinary == null) {
|
||||
// Pattern did not specify, probe for it.
|
||||
isBinary = await isBinaryFile(buffer, buffer.length)
|
||||
}
|
||||
|
||||
const preprocessorNames = Object.keys(config).reduce((ppNames, pattern) => {
|
||||
if (mm(file.originalPath, pattern, { dot: true })) {
|
||||
ppNames = _.union(ppNames, config[pattern])
|
||||
}
|
||||
return ppNames
|
||||
}, [])
|
||||
|
||||
// Apply preprocessor priority.
|
||||
const preprocessors = preprocessorNames
|
||||
.map((name) => [name, preprocessorPriority[name] || 0])
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map((duo) => duo[0])
|
||||
.reduce((preProcs, name) => {
|
||||
const p = instantiatePlugin('preprocessor', name)
|
||||
|
||||
if (!isBinary || (p && p.handleBinaryFiles)) {
|
||||
preProcs.push(p)
|
||||
} else {
|
||||
log.warn(`Ignored preprocessing ${file.originalPath} because ${name} has handleBinaryFiles=false.`)
|
||||
}
|
||||
return preProcs
|
||||
}, [])
|
||||
|
||||
await runProcessors(preprocessors, file, isBinary ? buffer : buffer.toString())
|
||||
}
|
||||
}
|
||||
|
||||
createPriorityPreprocessor.$inject = ['config.preprocessors', 'config.preprocessor_priority', 'config.basePath', 'instantiatePlugin']
|
||||
exports.createPriorityPreprocessor = createPriorityPreprocessor
|
||||
152
my-app/node_modules/karma/lib/reporter.js
generated
vendored
Executable file
152
my-app/node_modules/karma/lib/reporter.js
generated
vendored
Executable file
|
|
@ -0,0 +1,152 @@
|
|||
'use strict'
|
||||
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
const resolve = require('url').resolve
|
||||
const SourceMapConsumer = require('source-map').SourceMapConsumer
|
||||
const _ = require('lodash')
|
||||
|
||||
const PathUtils = require('./utils/path-utils')
|
||||
const log = require('./logger').create('reporter')
|
||||
const MultiReporter = require('./reporters/multi')
|
||||
const baseReporterDecoratorFactory = require('./reporters/base').decoratorFactory
|
||||
|
||||
function createErrorFormatter (config, emitter, SourceMapConsumer) {
|
||||
const basePath = config.basePath
|
||||
const urlRoot = config.urlRoot === '/' ? '' : (config.urlRoot || '')
|
||||
let lastServedFiles = []
|
||||
|
||||
emitter.on('file_list_modified', (files) => {
|
||||
lastServedFiles = files.served
|
||||
})
|
||||
|
||||
const URL_REGEXP = new RegExp('(?:https?:\\/\\/' +
|
||||
config.hostname + '(?:\\:' + config.port + ')?' + ')?\\/?' +
|
||||
urlRoot + '\\/?' +
|
||||
'(base/|absolute)' + // prefix, including slash for base/ to create relative paths.
|
||||
'((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
|
||||
'(\\?\\w*)?' + // sha
|
||||
'(\\:(\\d+))?' + // line
|
||||
'(\\:(\\d+))?' + // column
|
||||
'', 'g')
|
||||
|
||||
const cache = new WeakMap()
|
||||
|
||||
function getSourceMapConsumer (sourceMap) {
|
||||
if (!cache.has(sourceMap)) {
|
||||
cache.set(sourceMap, new SourceMapConsumer(sourceMap))
|
||||
}
|
||||
return cache.get(sourceMap)
|
||||
}
|
||||
|
||||
return function (input, indentation) {
|
||||
indentation = _.isString(indentation) ? indentation : ''
|
||||
if (_.isError(input)) {
|
||||
input = input.message
|
||||
} else if (_.isEmpty(input)) {
|
||||
input = ''
|
||||
} else if (!_.isString(input)) {
|
||||
input = JSON.stringify(input, null, indentation)
|
||||
}
|
||||
|
||||
let msg = input.replace(URL_REGEXP, function (stackTracePath, prefix, path, __, ___, line, ____, column) {
|
||||
const normalizedPath = prefix === 'base/' ? `${basePath}/${path}` : path
|
||||
const file = lastServedFiles.find((file) => file.path === normalizedPath)
|
||||
|
||||
if (file && file.sourceMap && line) {
|
||||
line = +line
|
||||
column = +column
|
||||
|
||||
// When no column is given and we default to 0, it doesn't make sense to only search for smaller
|
||||
// or equal columns in the sourcemap, let's search for equal or greater columns.
|
||||
const bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND
|
||||
|
||||
try {
|
||||
const zeroBasedColumn = Math.max(0, (column || 1) - 1)
|
||||
const original = getSourceMapConsumer(file.sourceMap).originalPositionFor({ line, column: zeroBasedColumn, bias })
|
||||
|
||||
// If there is no original position/source for the current stack trace path, then
|
||||
// we return early with the formatted generated position. This handles the case of
|
||||
// generated code which does not map to anything, see Case 1 of the source-map spec.
|
||||
// https://sourcemaps.info/spec.html.
|
||||
if (original.source === null) {
|
||||
return PathUtils.formatPathMapping(path, line, column)
|
||||
}
|
||||
|
||||
// Source maps often only have a local file name, resolve to turn into a full path if
|
||||
// the path is not absolute yet.
|
||||
const oneBasedOriginalColumn = original.column == null ? original.column : original.column + 1
|
||||
return `${PathUtils.formatPathMapping(resolve(path, original.source), original.line, oneBasedOriginalColumn)} <- ${PathUtils.formatPathMapping(path, line, column)}`
|
||||
} catch (e) {
|
||||
log.warn(`An unexpected error occurred while resolving the original position for: ${stackTracePath}`)
|
||||
log.warn(e)
|
||||
}
|
||||
}
|
||||
|
||||
return PathUtils.formatPathMapping(path, line, column) || prefix
|
||||
})
|
||||
|
||||
if (indentation) {
|
||||
msg = indentation + msg.replace(/\n/g, '\n' + indentation)
|
||||
}
|
||||
|
||||
return config.formatError ? config.formatError(msg) : msg + '\n'
|
||||
}
|
||||
}
|
||||
|
||||
function createReporters (names, config, emitter, injector) {
|
||||
const errorFormatter = createErrorFormatter(config, emitter, SourceMapConsumer)
|
||||
const reporters = []
|
||||
|
||||
names.forEach((name) => {
|
||||
if (['dots', 'progress'].includes(name)) {
|
||||
[
|
||||
require(`./reporters/${name}`),
|
||||
require(`./reporters/${name}_color`)
|
||||
].forEach((Reporter) => {
|
||||
reporters.push(new Reporter(errorFormatter, config.reportSlowerThan, config.colors, config.browserConsoleLogOptions))
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const locals = {
|
||||
baseReporterDecorator: ['factory', baseReporterDecoratorFactory],
|
||||
formatError: ['value', errorFormatter]
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug(`Trying to load reporter: ${name}`)
|
||||
reporters.push(injector.createChild([locals], ['reporter:' + name]).get('reporter:' + name))
|
||||
} catch (e) {
|
||||
if (e.message.includes(`No provider for "reporter:${name}"`)) {
|
||||
log.error(`Can not load reporter "${name}", it is not registered!\n Perhaps you are missing some plugin?`)
|
||||
} else {
|
||||
log.error(`Can not load "${name}"!\n ${e.stack}`)
|
||||
}
|
||||
emitter.emit('load_error', 'reporter', name)
|
||||
return
|
||||
}
|
||||
|
||||
const colorName = name + '_color'
|
||||
if (!names.includes(colorName)) {
|
||||
try {
|
||||
log.debug(`Trying to load color-version of reporter: ${name} (${colorName})`)
|
||||
reporters.push(injector.createChild([locals], ['reporter:' + colorName]).get('reporter:' + name))
|
||||
} catch (e) {
|
||||
log.debug('Couldn\'t load color-version.')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
reporters.forEach((reporter) => emitter.bind(reporter))
|
||||
|
||||
return new MultiReporter(reporters)
|
||||
}
|
||||
|
||||
createReporters.$inject = [
|
||||
'config.reporters',
|
||||
'config',
|
||||
'emitter',
|
||||
'injector'
|
||||
]
|
||||
|
||||
exports.createReporters = createReporters
|
||||
162
my-app/node_modules/karma/lib/reporters/base.js
generated
vendored
Executable file
162
my-app/node_modules/karma/lib/reporters/base.js
generated
vendored
Executable file
|
|
@ -0,0 +1,162 @@
|
|||
'use strict'
|
||||
|
||||
const util = require('util')
|
||||
|
||||
const constants = require('../constants')
|
||||
const helper = require('../helper')
|
||||
|
||||
const BaseReporter = function (formatError, reportSlow, useColors, browserConsoleLogOptions, adapter) {
|
||||
this.adapters = [adapter || process.stdout.write.bind(process.stdout)]
|
||||
|
||||
this.USE_COLORS = false
|
||||
this.EXCLUSIVELY_USE_COLORS = undefined
|
||||
this.LOG_SINGLE_BROWSER = '%s: %s\n'
|
||||
this.LOG_MULTI_BROWSER = '%s %s: %s\n'
|
||||
|
||||
this.SPEC_FAILURE = '%s %s FAILED' + '\n'
|
||||
this.SPEC_SLOW = '%s SLOW %s: %s\n'
|
||||
this.ERROR = '%s ERROR\n'
|
||||
|
||||
this.FINISHED_ERROR = ' ERROR'
|
||||
this.FINISHED_SUCCESS = ' SUCCESS'
|
||||
this.FINISHED_DISCONNECTED = ' DISCONNECTED'
|
||||
|
||||
this.X_FAILED = ' (%d FAILED)'
|
||||
|
||||
this.TOTAL_SUCCESS = 'TOTAL: %d SUCCESS\n'
|
||||
this.TOTAL_FAILED = 'TOTAL: %d FAILED, %d SUCCESS\n'
|
||||
|
||||
this.onRunStart = () => {
|
||||
this._browsers = []
|
||||
}
|
||||
|
||||
this.onBrowserStart = (browser) => {
|
||||
this._browsers.push(browser)
|
||||
}
|
||||
|
||||
this.renderBrowser = (browser) => {
|
||||
const results = browser.lastResult
|
||||
const totalExecuted = results.success + results.failed
|
||||
let msg = `${browser}: Executed ${totalExecuted} of ${results.total}`
|
||||
|
||||
if (results.failed) {
|
||||
msg += util.format(this.X_FAILED, results.failed)
|
||||
}
|
||||
|
||||
if (results.skipped) {
|
||||
msg += ` (skipped ${results.skipped})`
|
||||
}
|
||||
|
||||
if (browser.isConnected) {
|
||||
if (results.disconnected) {
|
||||
msg += this.FINISHED_DISCONNECTED
|
||||
} else if (results.error) {
|
||||
msg += this.FINISHED_ERROR
|
||||
} else if (!results.failed) {
|
||||
msg += this.FINISHED_SUCCESS
|
||||
}
|
||||
|
||||
msg += ` (${helper.formatTimeInterval(results.totalTime)} / ${helper.formatTimeInterval(results.netTime)})`
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
this.write = function () {
|
||||
const msg = util.format.apply(null, Array.prototype.slice.call(arguments))
|
||||
this.adapters.forEach((adapter) => {
|
||||
if (!helper.isDefined(adapter.colors)) {
|
||||
adapter.colors = useColors
|
||||
}
|
||||
if (!helper.isDefined(this.EXCLUSIVELY_USE_COLORS) || adapter.colors === this.EXCLUSIVELY_USE_COLORS) {
|
||||
return adapter(msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.writeCommonMsg = function () {
|
||||
this.write.apply(this, arguments)
|
||||
}
|
||||
|
||||
this.onBrowserError = (browser, error) => {
|
||||
this.writeCommonMsg(util.format(this.ERROR, browser) + formatError(error, ' '))
|
||||
}
|
||||
|
||||
this.onBrowserLog = (browser, log, type) => {
|
||||
if (!browserConsoleLogOptions || !browserConsoleLogOptions.terminal) return
|
||||
type = type.toUpperCase()
|
||||
if (browserConsoleLogOptions.level) {
|
||||
const logPriority = constants.LOG_PRIORITIES.indexOf(browserConsoleLogOptions.level.toUpperCase())
|
||||
if (constants.LOG_PRIORITIES.indexOf(type) > logPriority) return
|
||||
}
|
||||
if (!helper.isString(log)) {
|
||||
// TODO(vojta): change util to new syntax (config object)
|
||||
log = util.inspect(log, false, undefined, this.USE_COLORS)
|
||||
}
|
||||
if (this._browsers && this._browsers.length === 1) {
|
||||
this.writeCommonMsg(util.format(this.LOG_SINGLE_BROWSER, type, log))
|
||||
} else {
|
||||
this.writeCommonMsg(util.format(this.LOG_MULTI_BROWSER, browser, type, log))
|
||||
}
|
||||
}
|
||||
|
||||
this.onSpecComplete = (browser, result) => {
|
||||
if (result.skipped) {
|
||||
this.specSkipped(browser, result)
|
||||
} else if (result.success) {
|
||||
this.specSuccess(browser, result)
|
||||
} else {
|
||||
this.specFailure(browser, result)
|
||||
}
|
||||
|
||||
if (reportSlow && result.time > reportSlow) {
|
||||
const specName = result.suite.join(' ') + ' ' + result.description
|
||||
const time = helper.formatTimeInterval(result.time)
|
||||
|
||||
this.writeCommonMsg(util.format(this.SPEC_SLOW, browser, time, specName))
|
||||
}
|
||||
}
|
||||
|
||||
this.specSuccess = () => {
|
||||
}
|
||||
|
||||
this.specSkipped = () => {
|
||||
}
|
||||
|
||||
this.specFailure = (browser, result) => {
|
||||
const specName = result.suite.join(' ') + ' ' + result.description
|
||||
let msg = util.format(this.SPEC_FAILURE, browser, specName)
|
||||
|
||||
result.log.forEach((log) => {
|
||||
msg += formatError(log, '\t')
|
||||
})
|
||||
|
||||
this.writeCommonMsg(msg)
|
||||
}
|
||||
|
||||
this.onRunComplete = (browsers, results) => {
|
||||
if (browsers.length >= 1 && !results.error && !results.disconnected) {
|
||||
if (!results.failed) {
|
||||
this.write(this.TOTAL_SUCCESS, results.success)
|
||||
} else {
|
||||
this.write(this.TOTAL_FAILED, results.failed, results.success)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseReporter.decoratorFactory = function (formatError, reportSlow, useColors, browserConsoleLogOptions) {
|
||||
return function (self) {
|
||||
BaseReporter.call(self, formatError, reportSlow, useColors, browserConsoleLogOptions)
|
||||
}
|
||||
}
|
||||
|
||||
BaseReporter.decoratorFactory.$inject = [
|
||||
'formatError',
|
||||
'config.reportSlowerThan',
|
||||
'config.colors',
|
||||
'config.browserConsoleLogOptions'
|
||||
]
|
||||
|
||||
// PUBLISH
|
||||
module.exports = BaseReporter
|
||||
24
my-app/node_modules/karma/lib/reporters/base_color.js
generated
vendored
Executable file
24
my-app/node_modules/karma/lib/reporters/base_color.js
generated
vendored
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
const { red, yellow, green, cyan } = require('@colors/colors/safe')
|
||||
|
||||
function BaseColorReporter () {
|
||||
this.USE_COLORS = true
|
||||
|
||||
this.LOG_SINGLE_BROWSER = '%s: ' + cyan('%s') + '\n'
|
||||
this.LOG_MULTI_BROWSER = '%s %s: ' + cyan('%s') + '\n'
|
||||
|
||||
this.SPEC_FAILURE = red('%s %s FAILED') + '\n'
|
||||
this.SPEC_SLOW = yellow('%s SLOW %s: %s') + '\n'
|
||||
this.ERROR = red('%s ERROR') + '\n'
|
||||
|
||||
this.FINISHED_ERROR = red(' ERROR')
|
||||
this.FINISHED_SUCCESS = green(' SUCCESS')
|
||||
this.FINISHED_DISCONNECTED = red(' DISCONNECTED')
|
||||
|
||||
this.X_FAILED = red(' (%d FAILED)')
|
||||
|
||||
this.TOTAL_SUCCESS = green('TOTAL: %d SUCCESS') + '\n'
|
||||
this.TOTAL_FAILED = red('TOTAL: %d FAILED, %d SUCCESS') + '\n'
|
||||
}
|
||||
|
||||
// PUBLISH
|
||||
module.exports = BaseColorReporter
|
||||
47
my-app/node_modules/karma/lib/reporters/dots.js
generated
vendored
Executable file
47
my-app/node_modules/karma/lib/reporters/dots.js
generated
vendored
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
const BaseReporter = require('./base')
|
||||
|
||||
function DotsReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
|
||||
BaseReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
|
||||
|
||||
const DOTS_WRAP = 80
|
||||
this.EXCLUSIVELY_USE_COLORS = false
|
||||
this.onRunStart = function () {
|
||||
this._browsers = []
|
||||
this._dotsCount = 0
|
||||
}
|
||||
|
||||
this.onBrowserStart = function (browser) {
|
||||
this._browsers.push(browser)
|
||||
}
|
||||
|
||||
this.writeCommonMsg = function (msg) {
|
||||
if (this._dotsCount) {
|
||||
this._dotsCount = 0
|
||||
msg = '\n' + msg
|
||||
}
|
||||
|
||||
this.write(msg)
|
||||
}
|
||||
|
||||
this.specSuccess = function () {
|
||||
this._dotsCount = (this._dotsCount + 1) % DOTS_WRAP
|
||||
this.write(this._dotsCount ? '.' : '.\n')
|
||||
}
|
||||
|
||||
this.onBrowserComplete = function (browser) {
|
||||
this.writeCommonMsg(this.renderBrowser(browser) + '\n')
|
||||
}
|
||||
|
||||
this.onRunComplete = function (browsers, results) {
|
||||
if (browsers.length > 1 && !results.disconnected && !results.error) {
|
||||
if (!results.failed) {
|
||||
this.write(this.TOTAL_SUCCESS, results.success)
|
||||
} else {
|
||||
this.write(this.TOTAL_FAILED, results.failed, results.success)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PUBLISH
|
||||
module.exports = DotsReporter
|
||||
11
my-app/node_modules/karma/lib/reporters/dots_color.js
generated
vendored
Executable file
11
my-app/node_modules/karma/lib/reporters/dots_color.js
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
const DotsReporter = require('./dots')
|
||||
const BaseColorReporter = require('./base_color')
|
||||
|
||||
function DotsColorReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
|
||||
DotsReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
|
||||
BaseColorReporter.call(this)
|
||||
this.EXCLUSIVELY_USE_COLORS = true
|
||||
}
|
||||
|
||||
// PUBLISH
|
||||
module.exports = DotsColorReporter
|
||||
19
my-app/node_modules/karma/lib/reporters/multi.js
generated
vendored
Executable file
19
my-app/node_modules/karma/lib/reporters/multi.js
generated
vendored
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
'use strict'
|
||||
|
||||
const helper = require('../helper')
|
||||
|
||||
class MultiReporter {
|
||||
constructor (reporters) {
|
||||
this._reporters = reporters
|
||||
}
|
||||
|
||||
addAdapter (adapter) {
|
||||
this._reporters.forEach((reporter) => reporter.adapters.push(adapter))
|
||||
}
|
||||
|
||||
removeAdapter (adapter) {
|
||||
this._reporters.forEach((reporter) => helper.arrayRemove(reporter.adapters, adapter))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MultiReporter
|
||||
63
my-app/node_modules/karma/lib/reporters/progress.js
generated
vendored
Executable file
63
my-app/node_modules/karma/lib/reporters/progress.js
generated
vendored
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
const BaseReporter = require('./base')
|
||||
|
||||
function ProgressReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
|
||||
BaseReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
|
||||
|
||||
this.EXCLUSIVELY_USE_COLORS = false
|
||||
this._browsers = []
|
||||
|
||||
this.writeCommonMsg = function (msg) {
|
||||
this.write(this._remove() + msg + this._render())
|
||||
}
|
||||
|
||||
this.specSuccess = function () {
|
||||
this.write(this._refresh())
|
||||
}
|
||||
|
||||
this.onBrowserComplete = function () {
|
||||
this.write(this._refresh())
|
||||
}
|
||||
|
||||
this.onRunStart = function () {
|
||||
this._browsers = []
|
||||
this._isRendered = false
|
||||
}
|
||||
|
||||
this.onBrowserStart = function (browser) {
|
||||
this._browsers.push(browser)
|
||||
|
||||
if (this._isRendered) {
|
||||
this.write('\n')
|
||||
}
|
||||
|
||||
this.write(this._refresh())
|
||||
}
|
||||
|
||||
this._remove = function () {
|
||||
if (!this._isRendered) {
|
||||
return ''
|
||||
}
|
||||
|
||||
let cmd = ''
|
||||
this._browsers.forEach(function () {
|
||||
cmd += '\x1B[1A' + '\x1B[2K'
|
||||
})
|
||||
|
||||
this._isRendered = false
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
this._render = function () {
|
||||
this._isRendered = true
|
||||
|
||||
return this._browsers.map(this.renderBrowser).join('\n') + '\n'
|
||||
}
|
||||
|
||||
this._refresh = function () {
|
||||
return this._remove() + this._render()
|
||||
}
|
||||
}
|
||||
|
||||
// PUBLISH
|
||||
module.exports = ProgressReporter
|
||||
11
my-app/node_modules/karma/lib/reporters/progress_color.js
generated
vendored
Executable file
11
my-app/node_modules/karma/lib/reporters/progress_color.js
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
const ProgressReporter = require('./progress')
|
||||
const BaseColorReporter = require('./base_color')
|
||||
|
||||
function ProgressColorReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
|
||||
ProgressReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
|
||||
BaseColorReporter.call(this)
|
||||
this.EXCLUSIVELY_USE_COLORS = true
|
||||
}
|
||||
|
||||
// PUBLISH
|
||||
module.exports = ProgressColorReporter
|
||||
113
my-app/node_modules/karma/lib/runner.js
generated
vendored
Executable file
113
my-app/node_modules/karma/lib/runner.js
generated
vendored
Executable file
|
|
@ -0,0 +1,113 @@
|
|||
'use strict'
|
||||
|
||||
const http = require('http')
|
||||
|
||||
const constant = require('./constants')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const helper = require('./helper')
|
||||
const cfg = require('./config')
|
||||
const logger = require('./logger')
|
||||
const { lookup } = require('./utils/dns-utils')
|
||||
const log = logger.create('runner')
|
||||
|
||||
function parseExitCode (buffer, defaultExitCode, failOnEmptyTestSuite) {
|
||||
const tailPos = buffer.length - Buffer.byteLength(constant.EXIT_CODE) - 2
|
||||
|
||||
if (tailPos < 0) {
|
||||
return { exitCode: defaultExitCode, buffer }
|
||||
}
|
||||
|
||||
const tail = buffer.slice(tailPos)
|
||||
const tailStr = tail.toString()
|
||||
if (tailStr.slice(0, -2) === constant.EXIT_CODE) {
|
||||
const emptyInt = parseInt(tailStr.slice(-2, -1), 10)
|
||||
let exitCode = parseInt(tailStr.slice(-1), 10)
|
||||
if (failOnEmptyTestSuite === false && emptyInt === 0) {
|
||||
log.warn('Test suite was empty.')
|
||||
exitCode = 0
|
||||
}
|
||||
return { exitCode, buffer: buffer.slice(0, tailPos) }
|
||||
}
|
||||
|
||||
return { exitCode: defaultExitCode, buffer }
|
||||
}
|
||||
|
||||
// TODO(vojta): read config file (port, host, urlRoot)
|
||||
function run (cliOptionsOrConfig, done) {
|
||||
cliOptionsOrConfig = cliOptionsOrConfig || {}
|
||||
done = helper.isFunction(done) ? done : process.exit
|
||||
|
||||
let config
|
||||
if (cliOptionsOrConfig instanceof cfg.Config) {
|
||||
config = cliOptionsOrConfig
|
||||
} else {
|
||||
logger.setupFromConfig({
|
||||
colors: cliOptionsOrConfig.colors,
|
||||
logLevel: cliOptionsOrConfig.logLevel
|
||||
})
|
||||
const deprecatedCliOptionsMessage =
|
||||
'Passing raw CLI options to `runner(config, done)` is deprecated. Use ' +
|
||||
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
|
||||
'to prepare a processed `Config` instance and pass that as the ' +
|
||||
'`config` argument instead.'
|
||||
log.warn(deprecatedCliOptionsMessage)
|
||||
try {
|
||||
config = cfg.parseConfig(
|
||||
cliOptionsOrConfig.configFile,
|
||||
cliOptionsOrConfig,
|
||||
{
|
||||
promiseConfig: false,
|
||||
throwErrors: true
|
||||
}
|
||||
)
|
||||
} catch (parseConfigError) {
|
||||
// TODO: change how `done` falls back to exit in next major version
|
||||
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
|
||||
done(1)
|
||||
}
|
||||
}
|
||||
let exitCode = 1
|
||||
const emitter = new EventEmitter()
|
||||
const options = {
|
||||
hostname: config.hostname,
|
||||
path: config.urlRoot + 'run',
|
||||
port: config.port,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
lookup
|
||||
}
|
||||
|
||||
const request = http.request(options, function (response) {
|
||||
response.on('data', function (buffer) {
|
||||
const parsedResult = parseExitCode(buffer, exitCode, config.failOnEmptyTestSuite)
|
||||
exitCode = parsedResult.exitCode
|
||||
emitter.emit('progress', parsedResult.buffer)
|
||||
})
|
||||
|
||||
response.on('end', () => done(exitCode))
|
||||
})
|
||||
|
||||
request.on('error', function (e) {
|
||||
if (e.code === 'ECONNREFUSED') {
|
||||
log.error('There is no server listening on port %d', options.port)
|
||||
done(1, e.code)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
})
|
||||
|
||||
request.end(JSON.stringify({
|
||||
args: config.clientArgs,
|
||||
removedFiles: config.removedFiles,
|
||||
changedFiles: config.changedFiles,
|
||||
addedFiles: config.addedFiles,
|
||||
refresh: config.refresh,
|
||||
colors: config.colors
|
||||
}))
|
||||
|
||||
return emitter
|
||||
}
|
||||
|
||||
exports.run = run
|
||||
487
my-app/node_modules/karma/lib/server.js
generated
vendored
Executable file
487
my-app/node_modules/karma/lib/server.js
generated
vendored
Executable file
|
|
@ -0,0 +1,487 @@
|
|||
'use strict'
|
||||
|
||||
const SocketIO = require('socket.io')
|
||||
const di = require('di')
|
||||
const util = require('util')
|
||||
const spawn = require('child_process').spawn
|
||||
const tmp = require('tmp')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const NetUtils = require('./utils/net-utils')
|
||||
const root = global || window || this
|
||||
|
||||
const cfg = require('./config')
|
||||
const logger = require('./logger')
|
||||
const constant = require('./constants')
|
||||
const watcher = require('./watcher')
|
||||
const plugin = require('./plugin')
|
||||
|
||||
const createServeFile = require('./web-server').createServeFile
|
||||
const createServeStaticFile = require('./web-server').createServeStaticFile
|
||||
const createFilesPromise = require('./web-server').createFilesPromise
|
||||
const createWebServer = require('./web-server').createWebServer
|
||||
const preprocessor = require('./preprocessor')
|
||||
const Launcher = require('./launcher').Launcher
|
||||
const FileList = require('./file-list')
|
||||
const reporter = require('./reporter')
|
||||
const helper = require('./helper')
|
||||
const events = require('./events')
|
||||
const KarmaEventEmitter = events.EventEmitter
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const Executor = require('./executor')
|
||||
const Browser = require('./browser')
|
||||
const BrowserCollection = require('./browser_collection')
|
||||
const EmitterWrapper = require('./emitter_wrapper')
|
||||
const processWrapper = new EmitterWrapper(process)
|
||||
|
||||
function createSocketIoServer (webServer, executor, config) {
|
||||
const server = new SocketIO.Server(webServer, {
|
||||
// avoid destroying http upgrades from socket.io to get proxied websockets working
|
||||
destroyUpgrade: false,
|
||||
path: config.urlRoot + 'socket.io/',
|
||||
transports: config.transports,
|
||||
forceJSONP: config.forceJSONP,
|
||||
// Default is 5000 in socket.io v2.x and v3.x.
|
||||
pingTimeout: config.pingTimeout || 5000,
|
||||
// Default in v2 is 1e8 and coverage results can fail at 1e6
|
||||
maxHttpBufferSize: 1e8
|
||||
})
|
||||
|
||||
// hack to overcome circular dependency
|
||||
executor.socketIoSockets = server.sockets
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
class Server extends KarmaEventEmitter {
|
||||
constructor (cliOptionsOrConfig, done) {
|
||||
super()
|
||||
cliOptionsOrConfig = cliOptionsOrConfig || {}
|
||||
this.log = logger.create('karma-server')
|
||||
done = helper.isFunction(done) ? done : process.exit
|
||||
this.loadErrors = []
|
||||
|
||||
let config
|
||||
if (cliOptionsOrConfig instanceof cfg.Config) {
|
||||
config = cliOptionsOrConfig
|
||||
} else {
|
||||
logger.setupFromConfig({
|
||||
colors: cliOptionsOrConfig.colors,
|
||||
logLevel: cliOptionsOrConfig.logLevel
|
||||
})
|
||||
const deprecatedCliOptionsMessage =
|
||||
'Passing raw CLI options to `new Server(config, done)` is ' +
|
||||
'deprecated. Use ' +
|
||||
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
|
||||
'to prepare a processed `Config` instance and pass that as the ' +
|
||||
'`config` argument instead.'
|
||||
this.log.warn(deprecatedCliOptionsMessage)
|
||||
try {
|
||||
config = cfg.parseConfig(
|
||||
cliOptionsOrConfig.configFile,
|
||||
cliOptionsOrConfig,
|
||||
{
|
||||
promiseConfig: false,
|
||||
throwErrors: true
|
||||
}
|
||||
)
|
||||
} catch (parseConfigError) {
|
||||
// TODO: change how `done` falls back to exit in next major version
|
||||
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
|
||||
done(1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.log.debug('Final config', util.inspect(config, false, /** depth **/ null))
|
||||
|
||||
if (!config.autoWatch && !config.singleRun) {
|
||||
this.log.warn('`autowatch` and `singleRun` are both `false`. In order to execute tests use `karma run`.')
|
||||
}
|
||||
|
||||
let modules = [{
|
||||
helper: ['value', helper],
|
||||
logger: ['value', logger],
|
||||
done: ['value', done || process.exit],
|
||||
emitter: ['value', this],
|
||||
server: ['value', this],
|
||||
watcher: ['value', watcher],
|
||||
launcher: ['factory', Launcher.factory],
|
||||
config: ['value', config],
|
||||
instantiatePlugin: ['factory', plugin.createInstantiatePlugin],
|
||||
preprocess: ['factory', preprocessor.createPriorityPreprocessor],
|
||||
fileList: ['factory', FileList.factory],
|
||||
webServer: ['factory', createWebServer],
|
||||
serveFile: ['factory', createServeFile],
|
||||
serveStaticFile: ['factory', createServeStaticFile],
|
||||
filesPromise: ['factory', createFilesPromise],
|
||||
socketServer: ['factory', createSocketIoServer],
|
||||
executor: ['factory', Executor.factory],
|
||||
// TODO: Deprecated. Remove in the next major
|
||||
customFileHandlers: ['value', []],
|
||||
reporter: ['factory', reporter.createReporters],
|
||||
capturedBrowsers: ['factory', BrowserCollection.factory],
|
||||
args: ['value', {}],
|
||||
timer: ['value', {
|
||||
setTimeout () {
|
||||
return setTimeout.apply(root, arguments)
|
||||
},
|
||||
clearTimeout
|
||||
}]
|
||||
}]
|
||||
|
||||
this.on('load_error', (type, name) => {
|
||||
this.log.debug(`Registered a load error of type ${type} with name ${name}`)
|
||||
this.loadErrors.push([type, name])
|
||||
})
|
||||
|
||||
modules = modules.concat(plugin.resolve(config.plugins, this))
|
||||
this._injector = new di.Injector(modules)
|
||||
}
|
||||
|
||||
async start () {
|
||||
const config = this.get('config')
|
||||
try {
|
||||
this._boundServer = await NetUtils.bindAvailablePort(config.port, config.listenAddress)
|
||||
this._boundServer.on('connection', (socket) => {
|
||||
// Attach an error handler to avoid UncaughtException errors.
|
||||
socket.on('error', (err) => {
|
||||
// Errors on this socket are retried, ignore them
|
||||
this.log.debug('Ignoring error on webserver connection: ' + err)
|
||||
})
|
||||
})
|
||||
config.port = this._boundServer.address().port
|
||||
await this._injector.invoke(this._start, this)
|
||||
} catch (err) {
|
||||
this.log.error(`Server start failed on port ${config.port}: ${err}`)
|
||||
this._close(1)
|
||||
}
|
||||
}
|
||||
|
||||
get (token) {
|
||||
return this._injector.get(token)
|
||||
}
|
||||
|
||||
refreshFiles () {
|
||||
return this._fileList ? this._fileList.refresh() : Promise.resolve()
|
||||
}
|
||||
|
||||
refreshFile (path) {
|
||||
return this._fileList ? this._fileList.changeFile(path) : Promise.resolve()
|
||||
}
|
||||
|
||||
emitExitAsync (code) {
|
||||
const name = 'exit'
|
||||
let pending = this.listeners(name).length
|
||||
const deferred = helper.defer()
|
||||
|
||||
function resolve () {
|
||||
deferred.resolve(code)
|
||||
}
|
||||
|
||||
try {
|
||||
this.emit(name, (newCode) => {
|
||||
if (newCode && typeof newCode === 'number') {
|
||||
// Only update code if it is given and not zero
|
||||
code = newCode
|
||||
}
|
||||
if (!--pending) {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
|
||||
if (!pending) {
|
||||
resolve()
|
||||
}
|
||||
} catch (err) {
|
||||
deferred.reject(err)
|
||||
}
|
||||
return deferred.promise
|
||||
}
|
||||
|
||||
async _start (config, launcher, preprocess, fileList, capturedBrowsers, executor, done) {
|
||||
if (config.detached) {
|
||||
this._detach(config, done)
|
||||
return
|
||||
}
|
||||
|
||||
this._fileList = fileList
|
||||
|
||||
await Promise.all(
|
||||
config.frameworks.map((framework) => this._injector.get('framework:' + framework))
|
||||
)
|
||||
|
||||
const webServer = this._injector.get('webServer')
|
||||
const socketServer = this._injector.get('socketServer')
|
||||
|
||||
const singleRunDoneBrowsers = Object.create(null)
|
||||
const singleRunBrowsers = new BrowserCollection(new EventEmitter())
|
||||
let singleRunBrowserNotCaptured = false
|
||||
|
||||
webServer.on('error', (err) => {
|
||||
this.log.error(`Webserver fail ${err}`)
|
||||
this._close(1)
|
||||
})
|
||||
|
||||
const afterPreprocess = () => {
|
||||
if (config.autoWatch) {
|
||||
const watcher = this.get('watcher')
|
||||
this._injector.invoke(watcher)
|
||||
}
|
||||
|
||||
webServer.listen(this._boundServer, () => {
|
||||
this.log.info(`Karma v${constant.VERSION} server started at ${config.protocol}//${config.hostname}:${config.port}${config.urlRoot}`)
|
||||
|
||||
this.emit('listening', config.port)
|
||||
if (config.browsers && config.browsers.length) {
|
||||
this._injector.invoke(launcher.launch, launcher).forEach((browserLauncher) => {
|
||||
singleRunDoneBrowsers[browserLauncher.id] = false
|
||||
})
|
||||
}
|
||||
if (this.loadErrors.length > 0) {
|
||||
this.log.error(new Error(`Found ${this.loadErrors.length} load error${this.loadErrors.length === 1 ? '' : 's'}`))
|
||||
this._close(1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fileList.refresh().then(afterPreprocess, (err) => {
|
||||
this.log.error('Error during file loading or preprocessing\n' + err.stack || err)
|
||||
afterPreprocess()
|
||||
})
|
||||
|
||||
this.on('browsers_change', () => socketServer.sockets.emit('info', capturedBrowsers.serialize()))
|
||||
|
||||
this.on('browser_register', (browser) => {
|
||||
launcher.markCaptured(browser.id)
|
||||
|
||||
if (launcher.areAllCaptured()) {
|
||||
this.emit('browsers_ready')
|
||||
|
||||
if (config.autoWatch) {
|
||||
executor.schedule()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (config.browserConsoleLogOptions && config.browserConsoleLogOptions.path) {
|
||||
const configLevel = config.browserConsoleLogOptions.level || 'debug'
|
||||
const configFormat = config.browserConsoleLogOptions.format || '%b %T: %m'
|
||||
const configPath = config.browserConsoleLogOptions.path
|
||||
const configPathDir = path.dirname(configPath)
|
||||
if (!fs.existsSync(configPathDir)) fs.mkdirSync(configPathDir, { recursive: true })
|
||||
this.log.info(`Writing browser console to file: ${configPath}`)
|
||||
const browserLogFile = fs.openSync(configPath, 'w+')
|
||||
const levels = ['log', 'error', 'warn', 'info', 'debug']
|
||||
this.on('browser_log', function (browser, message, level) {
|
||||
if (levels.indexOf(level.toLowerCase()) > levels.indexOf(configLevel)) {
|
||||
return
|
||||
}
|
||||
if (!helper.isString(message)) {
|
||||
message = util.inspect(message, { showHidden: false, colors: false })
|
||||
}
|
||||
const logMap = { '%m': message, '%t': level.toLowerCase(), '%T': level.toUpperCase(), '%b': browser }
|
||||
const logString = configFormat.replace(/%[mtTb]/g, (m) => logMap[m])
|
||||
this.log.debug(`Writing browser console line: ${logString}`)
|
||||
fs.writeSync(browserLogFile, logString + '\n')
|
||||
})
|
||||
}
|
||||
|
||||
socketServer.sockets.on('connection', (socket) => {
|
||||
this.log.debug(`A browser has connected on socket ${socket.id}`)
|
||||
|
||||
const replySocketEvents = events.bufferEvents(socket, ['start', 'info', 'karma_error', 'result', 'complete'])
|
||||
|
||||
socket.on('error', (err) => {
|
||||
this.log.debug('karma server socket error: ' + err)
|
||||
})
|
||||
|
||||
socket.on('register', (info) => {
|
||||
const knownBrowser = info.id ? (capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)) : null
|
||||
|
||||
if (knownBrowser) {
|
||||
knownBrowser.reconnect(socket, info.isSocketReconnect)
|
||||
} else {
|
||||
const newBrowser = this._injector.createChild([{
|
||||
id: ['value', info.id || null],
|
||||
fullName: ['value', (helper.isDefined(info.displayName) ? info.displayName : info.name)],
|
||||
socket: ['value', socket]
|
||||
}]).invoke(Browser.factory)
|
||||
|
||||
newBrowser.init()
|
||||
|
||||
if (config.singleRun) {
|
||||
newBrowser.execute()
|
||||
singleRunBrowsers.add(newBrowser)
|
||||
}
|
||||
}
|
||||
|
||||
replySocketEvents()
|
||||
})
|
||||
})
|
||||
|
||||
const emitRunCompleteIfAllBrowsersDone = () => {
|
||||
if (Object.keys(singleRunDoneBrowsers).every((key) => singleRunDoneBrowsers[key])) {
|
||||
this.emit('run_complete', singleRunBrowsers, singleRunBrowsers.getResults(singleRunBrowserNotCaptured, config))
|
||||
}
|
||||
}
|
||||
|
||||
this.on('browser_complete', (completedBrowser) => {
|
||||
if (completedBrowser.lastResult.disconnected && completedBrowser.disconnectsCount <= config.browserDisconnectTolerance) {
|
||||
this.log.info(`Restarting ${completedBrowser.name} (${completedBrowser.disconnectsCount} of ${config.browserDisconnectTolerance} attempts)`)
|
||||
|
||||
if (!launcher.restart(completedBrowser.id)) {
|
||||
this.emit('browser_restart_failure', completedBrowser)
|
||||
}
|
||||
} else {
|
||||
this.emit('browser_complete_with_no_more_retries', completedBrowser)
|
||||
}
|
||||
})
|
||||
|
||||
this.on('stop', (done) => {
|
||||
this.log.debug('Received stop event, exiting.')
|
||||
this._close()
|
||||
done()
|
||||
})
|
||||
|
||||
if (config.singleRun) {
|
||||
this.on('browser_restart_failure', (completedBrowser) => {
|
||||
singleRunDoneBrowsers[completedBrowser.id] = true
|
||||
emitRunCompleteIfAllBrowsersDone()
|
||||
})
|
||||
|
||||
// This is the normal exit trigger.
|
||||
this.on('browser_complete_with_no_more_retries', function (completedBrowser) {
|
||||
singleRunDoneBrowsers[completedBrowser.id] = true
|
||||
|
||||
if (launcher.kill(completedBrowser.id)) {
|
||||
completedBrowser.remove()
|
||||
}
|
||||
|
||||
emitRunCompleteIfAllBrowsersDone()
|
||||
})
|
||||
|
||||
this.on('browser_process_failure', (browserLauncher) => {
|
||||
singleRunDoneBrowsers[browserLauncher.id] = true
|
||||
singleRunBrowserNotCaptured = true
|
||||
|
||||
emitRunCompleteIfAllBrowsersDone()
|
||||
})
|
||||
|
||||
this.on('run_complete', (browsers, results) => {
|
||||
this.log.debug('Run complete, exiting.')
|
||||
this._close(results.exitCode)
|
||||
})
|
||||
|
||||
this.emit('run_start', singleRunBrowsers)
|
||||
}
|
||||
|
||||
if (config.autoWatch) {
|
||||
this.on('file_list_modified', () => {
|
||||
this.log.debug('List of files has changed, trying to execute')
|
||||
if (config.restartOnFileChange) {
|
||||
socketServer.sockets.emit('stop')
|
||||
}
|
||||
executor.schedule()
|
||||
})
|
||||
}
|
||||
|
||||
processWrapper.on('SIGINT', () => this._close())
|
||||
processWrapper.on('SIGTERM', () => this._close())
|
||||
|
||||
const reportError = (error) => {
|
||||
this.log.error(error)
|
||||
process.emit('infrastructure_error', error)
|
||||
this._close(1)
|
||||
}
|
||||
|
||||
processWrapper.on('unhandledRejection', (error) => {
|
||||
this.log.error(`UnhandledRejection: ${error.stack || error.message || String(error)}`)
|
||||
reportError(error)
|
||||
})
|
||||
|
||||
processWrapper.on('uncaughtException', (error) => {
|
||||
this.log.error(`UncaughtException: ${error.stack || error.message || String(error)}`)
|
||||
reportError(error)
|
||||
})
|
||||
}
|
||||
|
||||
_detach (config, done) {
|
||||
const tmpFile = tmp.fileSync({ keep: true })
|
||||
this.log.info('Starting karma detached')
|
||||
this.log.info('Run "karma stop" to stop the server.')
|
||||
this.log.debug(`Writing config to tmp-file ${tmpFile.name}`)
|
||||
config.detached = false
|
||||
try {
|
||||
fs.writeFileSync(tmpFile.name, JSON.stringify(config), 'utf8')
|
||||
} catch (e) {
|
||||
this.log.error("Couldn't write temporary configuration file")
|
||||
done(1)
|
||||
return
|
||||
}
|
||||
const child = spawn(process.argv[0], [path.resolve(__dirname, '../lib/detached.js'), tmpFile.name], {
|
||||
detached: true,
|
||||
stdio: 'ignore'
|
||||
})
|
||||
child.unref()
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup all resources allocated by Karma and call the `done` callback
|
||||
* with the result of the tests execution.
|
||||
*
|
||||
* @param [exitCode] - Optional exit code. If omitted will be computed by
|
||||
* 'exit' event listeners.
|
||||
*/
|
||||
_close (exitCode) {
|
||||
const webServer = this._injector.get('webServer')
|
||||
const socketServer = this._injector.get('socketServer')
|
||||
const done = this._injector.get('done')
|
||||
|
||||
const webServerCloseTimeout = 3000
|
||||
const sockets = socketServer.sockets.sockets
|
||||
|
||||
Object.keys(sockets).forEach((id) => {
|
||||
const socket = sockets[id]
|
||||
socket.removeAllListeners('disconnect')
|
||||
if (!socket.disconnected) {
|
||||
process.nextTick(socket.disconnect.bind(socket))
|
||||
}
|
||||
})
|
||||
|
||||
this.emitExitAsync(exitCode).catch((err) => {
|
||||
this.log.error('Error while calling exit event listeners\n' + err.stack || err)
|
||||
return 1
|
||||
}).then((code) => {
|
||||
socketServer.sockets.removeAllListeners()
|
||||
socketServer.close()
|
||||
|
||||
let removeAllListenersDone = false
|
||||
const removeAllListeners = () => {
|
||||
if (removeAllListenersDone) {
|
||||
return
|
||||
}
|
||||
removeAllListenersDone = true
|
||||
webServer.removeAllListeners()
|
||||
processWrapper.removeAllListeners()
|
||||
done(code || 0)
|
||||
}
|
||||
|
||||
const closeTimeout = setTimeout(removeAllListeners, webServerCloseTimeout)
|
||||
|
||||
webServer.close(() => {
|
||||
clearTimeout(closeTimeout)
|
||||
removeAllListeners()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
stop () {
|
||||
return this.emitAsync('stop')
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype._start.$inject = ['config', 'launcher', 'preprocess', 'fileList', 'capturedBrowsers', 'executor', 'done']
|
||||
|
||||
module.exports = Server
|
||||
69
my-app/node_modules/karma/lib/stopper.js
generated
vendored
Executable file
69
my-app/node_modules/karma/lib/stopper.js
generated
vendored
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
const http = require('http')
|
||||
const cfg = require('./config')
|
||||
const logger = require('./logger')
|
||||
const helper = require('./helper')
|
||||
const { lookup } = require('./utils/dns-utils')
|
||||
|
||||
exports.stop = function (cliOptionsOrConfig, done) {
|
||||
cliOptionsOrConfig = cliOptionsOrConfig || {}
|
||||
const log = logger.create('stopper')
|
||||
done = helper.isFunction(done) ? done : process.exit
|
||||
|
||||
let config
|
||||
if (cliOptionsOrConfig instanceof cfg.Config) {
|
||||
config = cliOptionsOrConfig
|
||||
} else {
|
||||
logger.setupFromConfig({
|
||||
colors: cliOptionsOrConfig.colors,
|
||||
logLevel: cliOptionsOrConfig.logLevel
|
||||
})
|
||||
const deprecatedCliOptionsMessage =
|
||||
'Passing raw CLI options to `stopper(config, done)` is deprecated. Use ' +
|
||||
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
|
||||
'to prepare a processed `Config` instance and pass that as the ' +
|
||||
'`config` argument instead.'
|
||||
log.warn(deprecatedCliOptionsMessage)
|
||||
try {
|
||||
config = cfg.parseConfig(
|
||||
cliOptionsOrConfig.configFile,
|
||||
cliOptionsOrConfig,
|
||||
{
|
||||
promiseConfig: false,
|
||||
throwErrors: true
|
||||
}
|
||||
)
|
||||
} catch (parseConfigError) {
|
||||
// TODO: change how `done` falls back to exit in next major version
|
||||
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
|
||||
done(1)
|
||||
}
|
||||
}
|
||||
|
||||
const request = http.request({
|
||||
hostname: config.hostname,
|
||||
path: config.urlRoot + 'stop',
|
||||
port: config.port,
|
||||
method: 'GET',
|
||||
lookup
|
||||
})
|
||||
|
||||
request.on('response', function (response) {
|
||||
if (response.statusCode === 200) {
|
||||
log.info('Server stopped.')
|
||||
done(0)
|
||||
} else {
|
||||
log.error(`Server returned status code: ${response.statusCode}`)
|
||||
done(1)
|
||||
}
|
||||
})
|
||||
|
||||
request.on('error', function (e) {
|
||||
if (e.code === 'ECONNREFUSED') {
|
||||
log.error(`There is no server listening on port ${config.port}`)
|
||||
done(1, e.code)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
})
|
||||
request.end()
|
||||
}
|
||||
31
my-app/node_modules/karma/lib/temp_dir.js
generated
vendored
Executable file
31
my-app/node_modules/karma/lib/temp_dir.js
generated
vendored
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const fs = require('graceful-fs')
|
||||
const rimraf = require('rimraf')
|
||||
const log = require('./logger').create('temp-dir')
|
||||
|
||||
const TEMP_DIR = require('os').tmpdir()
|
||||
|
||||
module.exports = {
|
||||
getPath (suffix) {
|
||||
return path.normalize(TEMP_DIR + suffix)
|
||||
},
|
||||
|
||||
create (path) {
|
||||
log.debug(`Creating temp dir at ${path}`)
|
||||
|
||||
try {
|
||||
fs.mkdirSync(path)
|
||||
} catch (e) {
|
||||
log.warn(`Failed to create a temp dir at ${path}`)
|
||||
}
|
||||
|
||||
return path
|
||||
},
|
||||
|
||||
remove (path, done) {
|
||||
log.debug(`Cleaning temp dir ${path}`)
|
||||
rimraf(path, done)
|
||||
}
|
||||
}
|
||||
31
my-app/node_modules/karma/lib/url.js
generated
vendored
Executable file
31
my-app/node_modules/karma/lib/url.js
generated
vendored
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const { URL } = require('url')
|
||||
|
||||
/**
|
||||
* Url object used for tracking files in `file-list.js`.
|
||||
*/
|
||||
class Url {
|
||||
constructor (path, type, integrity) {
|
||||
this.path = path
|
||||
this.originalPath = path
|
||||
this.type = type
|
||||
this.integrity = integrity
|
||||
this.isUrl = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect type from the file extension in the path part of the URL.
|
||||
* @returns {string} detected file type or empty string
|
||||
*/
|
||||
detectType () {
|
||||
return path.extname(new URL(this.path).pathname).slice(1)
|
||||
}
|
||||
|
||||
toString () {
|
||||
return this.path
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Url
|
||||
14
my-app/node_modules/karma/lib/utils/crypto-utils.js
generated
vendored
Executable file
14
my-app/node_modules/karma/lib/utils/crypto-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
'use strict'
|
||||
|
||||
const crypto = require('crypto')
|
||||
|
||||
const CryptoUtils = {
|
||||
sha1 (data) {
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update(data)
|
||||
.digest('hex')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CryptoUtils
|
||||
11
my-app/node_modules/karma/lib/utils/dns-utils.js
generated
vendored
Executable file
11
my-app/node_modules/karma/lib/utils/dns-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
const dns = require('dns')
|
||||
|
||||
// Node >=17 has different DNS resolution (see
|
||||
// https://github.com/nodejs/node/issues/40702), it resolves domains
|
||||
// according to the OS settings instead of IPv4-address first. The Karma server
|
||||
// only listens on IPv4 address (127.0.0.1) by default, but the requests are
|
||||
// sent to `localhost` in several places and `localhost` is resolved into IPv6
|
||||
// address (`::`). So the run/stop/proxy request is unable to reach the Karma
|
||||
// server and produces an error. To mitigate this issue karma force the
|
||||
// IPv4-address first approach in Node >=17 as well.
|
||||
module.exports.lookup = (hostname, options, callback) => dns.lookup(hostname, { ...options, verbatim: false }, callback)
|
||||
25
my-app/node_modules/karma/lib/utils/file-utils.js
generated
vendored
Executable file
25
my-app/node_modules/karma/lib/utils/file-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('graceful-fs')
|
||||
|
||||
const FileUtils = {
|
||||
readFile (path) {
|
||||
return fs.readFileSync(path).toString()
|
||||
},
|
||||
|
||||
saveFile (path, content) {
|
||||
fs.writeFileSync(path, content)
|
||||
},
|
||||
|
||||
copyFile (src, dest) {
|
||||
FileUtils.saveFile(dest, FileUtils.readFile(src))
|
||||
},
|
||||
|
||||
removeFileIfExists (src) {
|
||||
if (fs.existsSync(src)) {
|
||||
fs.unlinkSync(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileUtils
|
||||
27
my-app/node_modules/karma/lib/utils/net-utils.js
generated
vendored
Executable file
27
my-app/node_modules/karma/lib/utils/net-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
'use strict'
|
||||
|
||||
const net = require('net')
|
||||
|
||||
const NetUtils = {
|
||||
bindAvailablePort (port, listenAddress) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer()
|
||||
|
||||
server
|
||||
.on('error', (err) => {
|
||||
server.close()
|
||||
if (err.code === 'EADDRINUSE' || err.code === 'EACCES') {
|
||||
server.listen(++port, listenAddress)
|
||||
} else {
|
||||
reject(new Error(`Failed to bind ${port}: ` + (err.stack || err)))
|
||||
}
|
||||
})
|
||||
.on('listening', () => {
|
||||
resolve(server)
|
||||
})
|
||||
.listen(port, listenAddress)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NetUtils
|
||||
16
my-app/node_modules/karma/lib/utils/path-utils.js
generated
vendored
Executable file
16
my-app/node_modules/karma/lib/utils/path-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const PathUtils = {
|
||||
formatPathMapping (path, line, column) {
|
||||
return path + (line ? `:${line}` : '') + (column ? `:${column}` : '')
|
||||
},
|
||||
|
||||
calculateAbsolutePath (karmaRelativePath) {
|
||||
return path.join(__dirname, '..', '..', karmaRelativePath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = PathUtils
|
||||
14
my-app/node_modules/karma/lib/utils/pattern-utils.js
generated
vendored
Executable file
14
my-app/node_modules/karma/lib/utils/pattern-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const PatternUtils = {
|
||||
getBaseDir (pattern) {
|
||||
return pattern
|
||||
.replace(/[/\\][^/\\]*\*.*$/, '') // remove parts with *
|
||||
.replace(/[/\\][^/\\]*[!+]\(.*$/, '') // remove parts with !(...) and +(...)
|
||||
.replace(/[/\\][^/\\]*\)\?.*$/, '') || path.sep // remove parts with (...)?
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PatternUtils
|
||||
85
my-app/node_modules/karma/lib/watcher.js
generated
vendored
Executable file
85
my-app/node_modules/karma/lib/watcher.js
generated
vendored
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
'use strict'
|
||||
|
||||
const mm = require('minimatch')
|
||||
const braces = require('braces')
|
||||
const PatternUtils = require('./utils/pattern-utils')
|
||||
|
||||
const helper = require('./helper')
|
||||
const log = require('./logger').create('watcher')
|
||||
|
||||
const DIR_SEP = require('path').sep
|
||||
|
||||
function watchPatterns (patterns, watcher) {
|
||||
let expandedPatterns = []
|
||||
patterns.map((pattern) => {
|
||||
// expand ['a/{b,c}'] to ['a/b', 'a/c']
|
||||
expandedPatterns = expandedPatterns.concat(braces.expand(pattern, { keepEscaping: true }))
|
||||
})
|
||||
expandedPatterns
|
||||
.map(PatternUtils.getBaseDir)
|
||||
.filter((path, index, paths) => paths.indexOf(path) === index) // filter unique values
|
||||
.forEach((path, index, paths) => {
|
||||
if (!paths.some((p) => path.startsWith(p + DIR_SEP))) {
|
||||
watcher.add(path)
|
||||
log.debug(`Watching "${path}"`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function checkAnyPathMatch (patterns, path) {
|
||||
return patterns.some((pattern) => mm(path, pattern, { dot: true }))
|
||||
}
|
||||
|
||||
function createIgnore (patterns, excludes) {
|
||||
return function (path, stat) {
|
||||
if (stat && !stat.isDirectory()) {
|
||||
return !checkAnyPathMatch(patterns, path) || checkAnyPathMatch(excludes, path)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getWatchedPatterns (patterns) {
|
||||
return patterns
|
||||
.filter((pattern) => pattern.watched)
|
||||
.map((pattern) => pattern.pattern)
|
||||
}
|
||||
|
||||
function watch (patterns, excludes, fileList, usePolling, emitter) {
|
||||
const watchedPatterns = getWatchedPatterns(patterns)
|
||||
// Lazy-load 'chokidar' to make the dependency optional. This is desired when
|
||||
// third-party watchers are in use.
|
||||
const chokidar = require('chokidar')
|
||||
const watcher = new chokidar.FSWatcher({
|
||||
usePolling: usePolling,
|
||||
ignorePermissionErrors: true,
|
||||
ignoreInitial: true,
|
||||
ignored: createIgnore(watchedPatterns, excludes)
|
||||
})
|
||||
|
||||
watchPatterns(watchedPatterns, watcher)
|
||||
|
||||
watcher
|
||||
.on('add', (path) => fileList.addFile(helper.normalizeWinPath(path)))
|
||||
.on('change', (path) => fileList.changeFile(helper.normalizeWinPath(path)))
|
||||
.on('unlink', (path) => fileList.removeFile(helper.normalizeWinPath(path)))
|
||||
.on('error', log.debug.bind(log))
|
||||
|
||||
emitter.on('exit', (done) => {
|
||||
watcher.close()
|
||||
done()
|
||||
})
|
||||
|
||||
return watcher
|
||||
}
|
||||
|
||||
watch.$inject = [
|
||||
'config.files',
|
||||
'config.exclude',
|
||||
'fileList',
|
||||
'config.usePolling',
|
||||
'emitter'
|
||||
]
|
||||
|
||||
module.exports = watch
|
||||
118
my-app/node_modules/karma/lib/web-server.js
generated
vendored
Executable file
118
my-app/node_modules/karma/lib/web-server.js
generated
vendored
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('graceful-fs')
|
||||
const http = require('http')
|
||||
const https = require('https')
|
||||
const path = require('path')
|
||||
const connect = require('connect')
|
||||
const mimeType = require('mime')
|
||||
|
||||
const common = require('./middleware/common')
|
||||
const runnerMiddleware = require('./middleware/runner')
|
||||
const stopperMiddleware = require('./middleware/stopper')
|
||||
const karmaMiddleware = require('./middleware/karma')
|
||||
const sourceFilesMiddleware = require('./middleware/source_files')
|
||||
const proxyMiddleware = require('./middleware/proxy')
|
||||
|
||||
const log = require('./logger').create('web-server')
|
||||
|
||||
function createCustomHandler (customFileHandlers, config) {
|
||||
let warningDone = false
|
||||
|
||||
return function (request, response, next) {
|
||||
const handler = customFileHandlers.find((handler) => handler.urlRegex.test(request.url))
|
||||
|
||||
if (customFileHandlers.length > 0 && !warningDone) {
|
||||
warningDone = true
|
||||
log.warn('The `customFileHandlers` is deprecated and will be removed in Karma 7. Please upgrade plugins relying on this provider.')
|
||||
}
|
||||
|
||||
return handler
|
||||
? handler.handler(request, response, 'fake/static', 'fake/adapter', config.basePath, 'fake/root')
|
||||
: next()
|
||||
}
|
||||
}
|
||||
|
||||
createCustomHandler.$inject = ['customFileHandlers', 'config']
|
||||
|
||||
function createFilesPromise (emitter, fileList) {
|
||||
// Set an empty list of files to avoid race issues with
|
||||
// file_list_modified not having been emitted yet
|
||||
let files = fileList.files
|
||||
emitter.on('file_list_modified', (filesParam) => { files = filesParam })
|
||||
|
||||
return {
|
||||
then (...args) {
|
||||
return Promise.resolve(files).then(...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createServeStaticFile (config) {
|
||||
return common.createServeFile(fs, path.normalize(path.join(__dirname, '/../static')), config)
|
||||
}
|
||||
createServeStaticFile.$inject = ['config']
|
||||
|
||||
function createServeFile (config) {
|
||||
return common.createServeFile(fs, null, config)
|
||||
}
|
||||
createServeFile.$inject = ['config']
|
||||
|
||||
function createWebServer (injector, config) {
|
||||
const { mime = {} } = config
|
||||
mimeType.define({ ...mime }, true)
|
||||
|
||||
const proxyMiddlewareInstance = injector.invoke(proxyMiddleware.create)
|
||||
|
||||
log.debug('Instantiating middleware')
|
||||
const handler = connect()
|
||||
|
||||
if (config.beforeMiddleware) {
|
||||
config.beforeMiddleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware)))
|
||||
}
|
||||
|
||||
handler.use(injector.invoke(runnerMiddleware.create))
|
||||
handler.use(injector.invoke(stopperMiddleware.create))
|
||||
handler.use(injector.invoke(karmaMiddleware.create))
|
||||
handler.use(injector.invoke(sourceFilesMiddleware.create))
|
||||
// TODO(vojta): extract the proxy into a plugin
|
||||
handler.use(proxyMiddlewareInstance)
|
||||
// TODO: Deprecated. Remove in the next major
|
||||
handler.use(injector.invoke(createCustomHandler))
|
||||
|
||||
if (config.middleware) {
|
||||
config.middleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware)))
|
||||
}
|
||||
|
||||
handler.use((request, response) => common.serve404(response, request.url))
|
||||
|
||||
let serverClass = http
|
||||
const serverArguments = [handler]
|
||||
|
||||
if (config.protocol === 'https:') {
|
||||
serverClass = https
|
||||
serverArguments.unshift(config.httpsServerOptions || {})
|
||||
}
|
||||
|
||||
if (config.httpModule) {
|
||||
serverClass = config.httpModule
|
||||
}
|
||||
|
||||
const server = serverClass.createServer.apply(null, serverArguments)
|
||||
|
||||
server.on('upgrade', function (req, socket, head) {
|
||||
log.debug(`upgrade ${req.url}`)
|
||||
proxyMiddlewareInstance.upgrade(req, socket, head)
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
createWebServer.$inject = ['injector', 'config']
|
||||
|
||||
module.exports = {
|
||||
createWebServer,
|
||||
createServeFile,
|
||||
createServeStaticFile,
|
||||
createFilesPromise
|
||||
}
|
||||
13
my-app/node_modules/karma/local.log
generated
vendored
Executable file
13
my-app/node_modules/karma/local.log
generated
vendored
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
(Not all processes could be identified, non-owned process info
|
||||
will not be shown, you would have to be root to see it all.)
|
||||
(Not all processes could be identified, non-owned process info
|
||||
will not be shown, you would have to be root to see it all.)
|
||||
Fri Apr 21 2023 23:39:54:641 GMT+0000 (UTC) -- Starting configuration console on http://localhost:45454
|
||||
Fri Apr 21 2023 23:39:55:274 GMT+0000 (UTC) -- [INFO] Started the BrowserStack Binary server on 45691, PID: 5418
|
||||
Fri Apr 21 2023 23:39:55:473 GMT+0000 (UTC) -- [SUCCESS] You can now access your local server(s) in our remote browser
|
||||
|
||||
Fri Apr 21 2023 23:39:56:230 GMT+0000 (UTC) -- Press Ctrl-C to exit
|
||||
|
||||
|
||||
345
my-app/node_modules/karma/node_modules/ansi-styles/index.d.ts
generated
vendored
Executable file
345
my-app/node_modules/karma/node_modules/ansi-styles/index.d.ts
generated
vendored
Executable file
|
|
@ -0,0 +1,345 @@
|
|||
declare type CSSColor =
|
||||
| 'aliceblue'
|
||||
| 'antiquewhite'
|
||||
| 'aqua'
|
||||
| 'aquamarine'
|
||||
| 'azure'
|
||||
| 'beige'
|
||||
| 'bisque'
|
||||
| 'black'
|
||||
| 'blanchedalmond'
|
||||
| 'blue'
|
||||
| 'blueviolet'
|
||||
| 'brown'
|
||||
| 'burlywood'
|
||||
| 'cadetblue'
|
||||
| 'chartreuse'
|
||||
| 'chocolate'
|
||||
| 'coral'
|
||||
| 'cornflowerblue'
|
||||
| 'cornsilk'
|
||||
| 'crimson'
|
||||
| 'cyan'
|
||||
| 'darkblue'
|
||||
| 'darkcyan'
|
||||
| 'darkgoldenrod'
|
||||
| 'darkgray'
|
||||
| 'darkgreen'
|
||||
| 'darkgrey'
|
||||
| 'darkkhaki'
|
||||
| 'darkmagenta'
|
||||
| 'darkolivegreen'
|
||||
| 'darkorange'
|
||||
| 'darkorchid'
|
||||
| 'darkred'
|
||||
| 'darksalmon'
|
||||
| 'darkseagreen'
|
||||
| 'darkslateblue'
|
||||
| 'darkslategray'
|
||||
| 'darkslategrey'
|
||||
| 'darkturquoise'
|
||||
| 'darkviolet'
|
||||
| 'deeppink'
|
||||
| 'deepskyblue'
|
||||
| 'dimgray'
|
||||
| 'dimgrey'
|
||||
| 'dodgerblue'
|
||||
| 'firebrick'
|
||||
| 'floralwhite'
|
||||
| 'forestgreen'
|
||||
| 'fuchsia'
|
||||
| 'gainsboro'
|
||||
| 'ghostwhite'
|
||||
| 'gold'
|
||||
| 'goldenrod'
|
||||
| 'gray'
|
||||
| 'green'
|
||||
| 'greenyellow'
|
||||
| 'grey'
|
||||
| 'honeydew'
|
||||
| 'hotpink'
|
||||
| 'indianred'
|
||||
| 'indigo'
|
||||
| 'ivory'
|
||||
| 'khaki'
|
||||
| 'lavender'
|
||||
| 'lavenderblush'
|
||||
| 'lawngreen'
|
||||
| 'lemonchiffon'
|
||||
| 'lightblue'
|
||||
| 'lightcoral'
|
||||
| 'lightcyan'
|
||||
| 'lightgoldenrodyellow'
|
||||
| 'lightgray'
|
||||
| 'lightgreen'
|
||||
| 'lightgrey'
|
||||
| 'lightpink'
|
||||
| 'lightsalmon'
|
||||
| 'lightseagreen'
|
||||
| 'lightskyblue'
|
||||
| 'lightslategray'
|
||||
| 'lightslategrey'
|
||||
| 'lightsteelblue'
|
||||
| 'lightyellow'
|
||||
| 'lime'
|
||||
| 'limegreen'
|
||||
| 'linen'
|
||||
| 'magenta'
|
||||
| 'maroon'
|
||||
| 'mediumaquamarine'
|
||||
| 'mediumblue'
|
||||
| 'mediumorchid'
|
||||
| 'mediumpurple'
|
||||
| 'mediumseagreen'
|
||||
| 'mediumslateblue'
|
||||
| 'mediumspringgreen'
|
||||
| 'mediumturquoise'
|
||||
| 'mediumvioletred'
|
||||
| 'midnightblue'
|
||||
| 'mintcream'
|
||||
| 'mistyrose'
|
||||
| 'moccasin'
|
||||
| 'navajowhite'
|
||||
| 'navy'
|
||||
| 'oldlace'
|
||||
| 'olive'
|
||||
| 'olivedrab'
|
||||
| 'orange'
|
||||
| 'orangered'
|
||||
| 'orchid'
|
||||
| 'palegoldenrod'
|
||||
| 'palegreen'
|
||||
| 'paleturquoise'
|
||||
| 'palevioletred'
|
||||
| 'papayawhip'
|
||||
| 'peachpuff'
|
||||
| 'peru'
|
||||
| 'pink'
|
||||
| 'plum'
|
||||
| 'powderblue'
|
||||
| 'purple'
|
||||
| 'rebeccapurple'
|
||||
| 'red'
|
||||
| 'rosybrown'
|
||||
| 'royalblue'
|
||||
| 'saddlebrown'
|
||||
| 'salmon'
|
||||
| 'sandybrown'
|
||||
| 'seagreen'
|
||||
| 'seashell'
|
||||
| 'sienna'
|
||||
| 'silver'
|
||||
| 'skyblue'
|
||||
| 'slateblue'
|
||||
| 'slategray'
|
||||
| 'slategrey'
|
||||
| 'snow'
|
||||
| 'springgreen'
|
||||
| 'steelblue'
|
||||
| 'tan'
|
||||
| 'teal'
|
||||
| 'thistle'
|
||||
| 'tomato'
|
||||
| 'turquoise'
|
||||
| 'violet'
|
||||
| 'wheat'
|
||||
| 'white'
|
||||
| 'whitesmoke'
|
||||
| 'yellow'
|
||||
| 'yellowgreen';
|
||||
|
||||
declare namespace ansiStyles {
|
||||
interface ColorConvert {
|
||||
/**
|
||||
The RGB color space.
|
||||
|
||||
@param red - (`0`-`255`)
|
||||
@param green - (`0`-`255`)
|
||||
@param blue - (`0`-`255`)
|
||||
*/
|
||||
rgb(red: number, green: number, blue: number): string;
|
||||
|
||||
/**
|
||||
The RGB HEX color space.
|
||||
|
||||
@param hex - A hexadecimal string containing RGB data.
|
||||
*/
|
||||
hex(hex: string): string;
|
||||
|
||||
/**
|
||||
@param keyword - A CSS color name.
|
||||
*/
|
||||
keyword(keyword: CSSColor): string;
|
||||
|
||||
/**
|
||||
The HSL color space.
|
||||
|
||||
@param hue - (`0`-`360`)
|
||||
@param saturation - (`0`-`100`)
|
||||
@param lightness - (`0`-`100`)
|
||||
*/
|
||||
hsl(hue: number, saturation: number, lightness: number): string;
|
||||
|
||||
/**
|
||||
The HSV color space.
|
||||
|
||||
@param hue - (`0`-`360`)
|
||||
@param saturation - (`0`-`100`)
|
||||
@param value - (`0`-`100`)
|
||||
*/
|
||||
hsv(hue: number, saturation: number, value: number): string;
|
||||
|
||||
/**
|
||||
The HSV color space.
|
||||
|
||||
@param hue - (`0`-`360`)
|
||||
@param whiteness - (`0`-`100`)
|
||||
@param blackness - (`0`-`100`)
|
||||
*/
|
||||
hwb(hue: number, whiteness: number, blackness: number): string;
|
||||
|
||||
/**
|
||||
Use a [4-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4-bit) to set text color.
|
||||
*/
|
||||
ansi(ansi: number): string;
|
||||
|
||||
/**
|
||||
Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color.
|
||||
*/
|
||||
ansi256(ansi: number): string;
|
||||
}
|
||||
|
||||
interface CSPair {
|
||||
/**
|
||||
The ANSI terminal control sequence for starting this style.
|
||||
*/
|
||||
readonly open: string;
|
||||
|
||||
/**
|
||||
The ANSI terminal control sequence for ending this style.
|
||||
*/
|
||||
readonly close: string;
|
||||
}
|
||||
|
||||
interface ColorBase {
|
||||
readonly ansi: ColorConvert;
|
||||
readonly ansi256: ColorConvert;
|
||||
readonly ansi16m: ColorConvert;
|
||||
|
||||
/**
|
||||
The ANSI terminal control sequence for ending this color.
|
||||
*/
|
||||
readonly close: string;
|
||||
}
|
||||
|
||||
interface Modifier {
|
||||
/**
|
||||
Resets the current color chain.
|
||||
*/
|
||||
readonly reset: CSPair;
|
||||
|
||||
/**
|
||||
Make text bold.
|
||||
*/
|
||||
readonly bold: CSPair;
|
||||
|
||||
/**
|
||||
Emitting only a small amount of light.
|
||||
*/
|
||||
readonly dim: CSPair;
|
||||
|
||||
/**
|
||||
Make text italic. (Not widely supported)
|
||||
*/
|
||||
readonly italic: CSPair;
|
||||
|
||||
/**
|
||||
Make text underline. (Not widely supported)
|
||||
*/
|
||||
readonly underline: CSPair;
|
||||
|
||||
/**
|
||||
Inverse background and foreground colors.
|
||||
*/
|
||||
readonly inverse: CSPair;
|
||||
|
||||
/**
|
||||
Prints the text, but makes it invisible.
|
||||
*/
|
||||
readonly hidden: CSPair;
|
||||
|
||||
/**
|
||||
Puts a horizontal line through the center of the text. (Not widely supported)
|
||||
*/
|
||||
readonly strikethrough: CSPair;
|
||||
}
|
||||
|
||||
interface ForegroundColor {
|
||||
readonly black: CSPair;
|
||||
readonly red: CSPair;
|
||||
readonly green: CSPair;
|
||||
readonly yellow: CSPair;
|
||||
readonly blue: CSPair;
|
||||
readonly cyan: CSPair;
|
||||
readonly magenta: CSPair;
|
||||
readonly white: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `blackBright`.
|
||||
*/
|
||||
readonly gray: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `blackBright`.
|
||||
*/
|
||||
readonly grey: CSPair;
|
||||
|
||||
readonly blackBright: CSPair;
|
||||
readonly redBright: CSPair;
|
||||
readonly greenBright: CSPair;
|
||||
readonly yellowBright: CSPair;
|
||||
readonly blueBright: CSPair;
|
||||
readonly cyanBright: CSPair;
|
||||
readonly magentaBright: CSPair;
|
||||
readonly whiteBright: CSPair;
|
||||
}
|
||||
|
||||
interface BackgroundColor {
|
||||
readonly bgBlack: CSPair;
|
||||
readonly bgRed: CSPair;
|
||||
readonly bgGreen: CSPair;
|
||||
readonly bgYellow: CSPair;
|
||||
readonly bgBlue: CSPair;
|
||||
readonly bgCyan: CSPair;
|
||||
readonly bgMagenta: CSPair;
|
||||
readonly bgWhite: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `bgBlackBright`.
|
||||
*/
|
||||
readonly bgGray: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `bgBlackBright`.
|
||||
*/
|
||||
readonly bgGrey: CSPair;
|
||||
|
||||
readonly bgBlackBright: CSPair;
|
||||
readonly bgRedBright: CSPair;
|
||||
readonly bgGreenBright: CSPair;
|
||||
readonly bgYellowBright: CSPair;
|
||||
readonly bgBlueBright: CSPair;
|
||||
readonly bgCyanBright: CSPair;
|
||||
readonly bgMagentaBright: CSPair;
|
||||
readonly bgWhiteBright: CSPair;
|
||||
}
|
||||
}
|
||||
|
||||
declare const ansiStyles: {
|
||||
readonly modifier: ansiStyles.Modifier;
|
||||
readonly color: ansiStyles.ForegroundColor & ansiStyles.ColorBase;
|
||||
readonly bgColor: ansiStyles.BackgroundColor & ansiStyles.ColorBase;
|
||||
readonly codes: ReadonlyMap<number, number>;
|
||||
} & ansiStyles.BackgroundColor & ansiStyles.ForegroundColor & ansiStyles.Modifier;
|
||||
|
||||
export = ansiStyles;
|
||||
163
my-app/node_modules/karma/node_modules/ansi-styles/index.js
generated
vendored
Executable file
163
my-app/node_modules/karma/node_modules/ansi-styles/index.js
generated
vendored
Executable file
|
|
@ -0,0 +1,163 @@
|
|||
'use strict';
|
||||
|
||||
const wrapAnsi16 = (fn, offset) => (...args) => {
|
||||
const code = fn(...args);
|
||||
return `\u001B[${code + offset}m`;
|
||||
};
|
||||
|
||||
const wrapAnsi256 = (fn, offset) => (...args) => {
|
||||
const code = fn(...args);
|
||||
return `\u001B[${38 + offset};5;${code}m`;
|
||||
};
|
||||
|
||||
const wrapAnsi16m = (fn, offset) => (...args) => {
|
||||
const rgb = fn(...args);
|
||||
return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
|
||||
};
|
||||
|
||||
const ansi2ansi = n => n;
|
||||
const rgb2rgb = (r, g, b) => [r, g, b];
|
||||
|
||||
const setLazyProperty = (object, property, get) => {
|
||||
Object.defineProperty(object, property, {
|
||||
get: () => {
|
||||
const value = get();
|
||||
|
||||
Object.defineProperty(object, property, {
|
||||
value,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
return value;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
};
|
||||
|
||||
/** @type {typeof import('color-convert')} */
|
||||
let colorConvert;
|
||||
const makeDynamicStyles = (wrap, targetSpace, identity, isBackground) => {
|
||||
if (colorConvert === undefined) {
|
||||
colorConvert = require('color-convert');
|
||||
}
|
||||
|
||||
const offset = isBackground ? 10 : 0;
|
||||
const styles = {};
|
||||
|
||||
for (const [sourceSpace, suite] of Object.entries(colorConvert)) {
|
||||
const name = sourceSpace === 'ansi16' ? 'ansi' : sourceSpace;
|
||||
if (sourceSpace === targetSpace) {
|
||||
styles[name] = wrap(identity, offset);
|
||||
} else if (typeof suite === 'object') {
|
||||
styles[name] = wrap(suite[targetSpace], offset);
|
||||
}
|
||||
}
|
||||
|
||||
return styles;
|
||||
};
|
||||
|
||||
function assembleStyles() {
|
||||
const codes = new Map();
|
||||
const styles = {
|
||||
modifier: {
|
||||
reset: [0, 0],
|
||||
// 21 isn't widely supported and 22 does the same thing
|
||||
bold: [1, 22],
|
||||
dim: [2, 22],
|
||||
italic: [3, 23],
|
||||
underline: [4, 24],
|
||||
inverse: [7, 27],
|
||||
hidden: [8, 28],
|
||||
strikethrough: [9, 29]
|
||||
},
|
||||
color: {
|
||||
black: [30, 39],
|
||||
red: [31, 39],
|
||||
green: [32, 39],
|
||||
yellow: [33, 39],
|
||||
blue: [34, 39],
|
||||
magenta: [35, 39],
|
||||
cyan: [36, 39],
|
||||
white: [37, 39],
|
||||
|
||||
// Bright color
|
||||
blackBright: [90, 39],
|
||||
redBright: [91, 39],
|
||||
greenBright: [92, 39],
|
||||
yellowBright: [93, 39],
|
||||
blueBright: [94, 39],
|
||||
magentaBright: [95, 39],
|
||||
cyanBright: [96, 39],
|
||||
whiteBright: [97, 39]
|
||||
},
|
||||
bgColor: {
|
||||
bgBlack: [40, 49],
|
||||
bgRed: [41, 49],
|
||||
bgGreen: [42, 49],
|
||||
bgYellow: [43, 49],
|
||||
bgBlue: [44, 49],
|
||||
bgMagenta: [45, 49],
|
||||
bgCyan: [46, 49],
|
||||
bgWhite: [47, 49],
|
||||
|
||||
// Bright color
|
||||
bgBlackBright: [100, 49],
|
||||
bgRedBright: [101, 49],
|
||||
bgGreenBright: [102, 49],
|
||||
bgYellowBright: [103, 49],
|
||||
bgBlueBright: [104, 49],
|
||||
bgMagentaBright: [105, 49],
|
||||
bgCyanBright: [106, 49],
|
||||
bgWhiteBright: [107, 49]
|
||||
}
|
||||
};
|
||||
|
||||
// Alias bright black as gray (and grey)
|
||||
styles.color.gray = styles.color.blackBright;
|
||||
styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
|
||||
styles.color.grey = styles.color.blackBright;
|
||||
styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
|
||||
|
||||
for (const [groupName, group] of Object.entries(styles)) {
|
||||
for (const [styleName, style] of Object.entries(group)) {
|
||||
styles[styleName] = {
|
||||
open: `\u001B[${style[0]}m`,
|
||||
close: `\u001B[${style[1]}m`
|
||||
};
|
||||
|
||||
group[styleName] = styles[styleName];
|
||||
|
||||
codes.set(style[0], style[1]);
|
||||
}
|
||||
|
||||
Object.defineProperty(styles, groupName, {
|
||||
value: group,
|
||||
enumerable: false
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(styles, 'codes', {
|
||||
value: codes,
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
styles.color.close = '\u001B[39m';
|
||||
styles.bgColor.close = '\u001B[49m';
|
||||
|
||||
setLazyProperty(styles.color, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, false));
|
||||
setLazyProperty(styles.color, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, false));
|
||||
setLazyProperty(styles.color, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, false));
|
||||
setLazyProperty(styles.bgColor, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, true));
|
||||
setLazyProperty(styles.bgColor, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, true));
|
||||
setLazyProperty(styles.bgColor, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, true));
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
// Make the export immutable
|
||||
Object.defineProperty(module, 'exports', {
|
||||
enumerable: true,
|
||||
get: assembleStyles
|
||||
});
|
||||
9
my-app/node_modules/karma/node_modules/ansi-styles/license
generated
vendored
Executable file
9
my-app/node_modules/karma/node_modules/ansi-styles/license
generated
vendored
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
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.
|
||||
56
my-app/node_modules/karma/node_modules/ansi-styles/package.json
generated
vendored
Executable file
56
my-app/node_modules/karma/node_modules/ansi-styles/package.json
generated
vendored
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"name": "ansi-styles",
|
||||
"version": "4.3.0",
|
||||
"description": "ANSI escape codes for styling strings in the terminal",
|
||||
"license": "MIT",
|
||||
"repository": "chalk/ansi-styles",
|
||||
"funding": "https://github.com/chalk/ansi-styles?sponsor=1",
|
||||
"author": {
|
||||
"name": "Sindre Sorhus",
|
||||
"email": "sindresorhus@gmail.com",
|
||||
"url": "sindresorhus.com"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "xo && ava && tsd",
|
||||
"screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"keywords": [
|
||||
"ansi",
|
||||
"styles",
|
||||
"color",
|
||||
"colour",
|
||||
"colors",
|
||||
"terminal",
|
||||
"console",
|
||||
"cli",
|
||||
"string",
|
||||
"tty",
|
||||
"escape",
|
||||
"formatting",
|
||||
"rgb",
|
||||
"256",
|
||||
"shell",
|
||||
"xterm",
|
||||
"log",
|
||||
"logging",
|
||||
"command-line",
|
||||
"text"
|
||||
],
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/color-convert": "^1.9.0",
|
||||
"ava": "^2.3.0",
|
||||
"svg-term-cli": "^2.1.1",
|
||||
"tsd": "^0.11.0",
|
||||
"xo": "^0.25.3"
|
||||
}
|
||||
}
|
||||
152
my-app/node_modules/karma/node_modules/ansi-styles/readme.md
generated
vendored
Executable file
152
my-app/node_modules/karma/node_modules/ansi-styles/readme.md
generated
vendored
Executable file
|
|
@ -0,0 +1,152 @@
|
|||
# ansi-styles [](https://travis-ci.org/chalk/ansi-styles)
|
||||
|
||||
> [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal
|
||||
|
||||
You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.
|
||||
|
||||
<img src="screenshot.svg" width="900">
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install ansi-styles
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const style = require('ansi-styles');
|
||||
|
||||
console.log(`${style.green.open}Hello world!${style.green.close}`);
|
||||
|
||||
|
||||
// Color conversion between 16/256/truecolor
|
||||
// NOTE: If conversion goes to 16 colors or 256 colors, the original color
|
||||
// may be degraded to fit that color palette. This means terminals
|
||||
// that do not support 16 million colors will best-match the
|
||||
// original color.
|
||||
console.log(style.bgColor.ansi.hsl(120, 80, 72) + 'Hello world!' + style.bgColor.close);
|
||||
console.log(style.color.ansi256.rgb(199, 20, 250) + 'Hello world!' + style.color.close);
|
||||
console.log(style.color.ansi16m.hex('#abcdef') + 'Hello world!' + style.color.close);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
Each style has an `open` and `close` property.
|
||||
|
||||
## Styles
|
||||
|
||||
### Modifiers
|
||||
|
||||
- `reset`
|
||||
- `bold`
|
||||
- `dim`
|
||||
- `italic` *(Not widely supported)*
|
||||
- `underline`
|
||||
- `inverse`
|
||||
- `hidden`
|
||||
- `strikethrough` *(Not widely supported)*
|
||||
|
||||
### Colors
|
||||
|
||||
- `black`
|
||||
- `red`
|
||||
- `green`
|
||||
- `yellow`
|
||||
- `blue`
|
||||
- `magenta`
|
||||
- `cyan`
|
||||
- `white`
|
||||
- `blackBright` (alias: `gray`, `grey`)
|
||||
- `redBright`
|
||||
- `greenBright`
|
||||
- `yellowBright`
|
||||
- `blueBright`
|
||||
- `magentaBright`
|
||||
- `cyanBright`
|
||||
- `whiteBright`
|
||||
|
||||
### Background colors
|
||||
|
||||
- `bgBlack`
|
||||
- `bgRed`
|
||||
- `bgGreen`
|
||||
- `bgYellow`
|
||||
- `bgBlue`
|
||||
- `bgMagenta`
|
||||
- `bgCyan`
|
||||
- `bgWhite`
|
||||
- `bgBlackBright` (alias: `bgGray`, `bgGrey`)
|
||||
- `bgRedBright`
|
||||
- `bgGreenBright`
|
||||
- `bgYellowBright`
|
||||
- `bgBlueBright`
|
||||
- `bgMagentaBright`
|
||||
- `bgCyanBright`
|
||||
- `bgWhiteBright`
|
||||
|
||||
## Advanced usage
|
||||
|
||||
By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.
|
||||
|
||||
- `style.modifier`
|
||||
- `style.color`
|
||||
- `style.bgColor`
|
||||
|
||||
###### Example
|
||||
|
||||
```js
|
||||
console.log(style.color.green.open);
|
||||
```
|
||||
|
||||
Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values.
|
||||
|
||||
###### Example
|
||||
|
||||
```js
|
||||
console.log(style.codes.get(36));
|
||||
//=> 39
|
||||
```
|
||||
|
||||
## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
|
||||
|
||||
`ansi-styles` uses the [`color-convert`](https://github.com/Qix-/color-convert) package to allow for converting between various colors and ANSI escapes, with support for 256 and 16 million colors.
|
||||
|
||||
The following color spaces from `color-convert` are supported:
|
||||
|
||||
- `rgb`
|
||||
- `hex`
|
||||
- `keyword`
|
||||
- `hsl`
|
||||
- `hsv`
|
||||
- `hwb`
|
||||
- `ansi`
|
||||
- `ansi256`
|
||||
|
||||
To use these, call the associated conversion function with the intended output, for example:
|
||||
|
||||
```js
|
||||
style.color.ansi.rgb(100, 200, 15); // RGB to 16 color ansi foreground code
|
||||
style.bgColor.ansi.rgb(100, 200, 15); // RGB to 16 color ansi background code
|
||||
|
||||
style.color.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
|
||||
style.bgColor.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
|
||||
|
||||
style.color.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color foreground code
|
||||
style.bgColor.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color background code
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal
|
||||
|
||||
## Maintainers
|
||||
|
||||
- [Sindre Sorhus](https://github.com/sindresorhus)
|
||||
- [Josh Junon](https://github.com/qix-)
|
||||
|
||||
## For enterprise
|
||||
|
||||
Available as part of the Tidelift Subscription.
|
||||
|
||||
The maintainers of `ansi-styles` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-ansi-styles?utm_source=npm-ansi-styles&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
|
||||
121
my-app/node_modules/karma/node_modules/cliui/CHANGELOG.md
generated
vendored
Executable file
121
my-app/node_modules/karma/node_modules/cliui/CHANGELOG.md
generated
vendored
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [7.0.4](https://www.github.com/yargs/cliui/compare/v7.0.3...v7.0.4) (2020-11-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deno:** import UIOptions from definitions ([#97](https://www.github.com/yargs/cliui/issues/97)) ([f04f343](https://www.github.com/yargs/cliui/commit/f04f3439bc78114c7e90f82ff56f5acf16268ea8))
|
||||
|
||||
### [7.0.3](https://www.github.com/yargs/cliui/compare/v7.0.2...v7.0.3) (2020-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **exports:** node 13.0 and 13.1 require the dotted object form _with_ a string fallback ([#93](https://www.github.com/yargs/cliui/issues/93)) ([eca16fc](https://www.github.com/yargs/cliui/commit/eca16fc05d26255df3280906c36d7f0e5b05c6e9))
|
||||
|
||||
### [7.0.2](https://www.github.com/yargs/cliui/compare/v7.0.1...v7.0.2) (2020-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **exports:** node 13.0-13.6 require a string fallback ([#91](https://www.github.com/yargs/cliui/issues/91)) ([b529d7e](https://www.github.com/yargs/cliui/commit/b529d7e432901af1af7848b23ed6cf634497d961))
|
||||
|
||||
### [7.0.1](https://www.github.com/yargs/cliui/compare/v7.0.0...v7.0.1) (2020-08-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** main should be build/index.cjs ([dc29a3c](https://www.github.com/yargs/cliui/commit/dc29a3cc617a410aa850e06337b5954b04f2cb4d))
|
||||
|
||||
## [7.0.0](https://www.github.com/yargs/cliui/compare/v6.0.0...v7.0.0) (2020-08-16)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* tsc/ESM/Deno support (#82)
|
||||
* modernize deps and build (#80)
|
||||
|
||||
### Build System
|
||||
|
||||
* modernize deps and build ([#80](https://www.github.com/yargs/cliui/issues/80)) ([339d08d](https://www.github.com/yargs/cliui/commit/339d08dc71b15a3928aeab09042af94db2f43743))
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* tsc/ESM/Deno support ([#82](https://www.github.com/yargs/cliui/issues/82)) ([4b777a5](https://www.github.com/yargs/cliui/commit/4b777a5fe01c5d8958c6708695d6aab7dbe5706c))
|
||||
|
||||
## [6.0.0](https://www.github.com/yargs/cliui/compare/v5.0.0...v6.0.0) (2019-11-10)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* update deps, drop Node 6
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* update deps, drop Node 6 ([62056df](https://www.github.com/yargs/cliui/commit/62056df))
|
||||
|
||||
## [5.0.0](https://github.com/yargs/cliui/compare/v4.1.0...v5.0.0) (2019-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update wrap-ansi to fix compatibility with latest versions of chalk. ([#60](https://github.com/yargs/cliui/issues/60)) ([7bf79ae](https://github.com/yargs/cliui/commit/7bf79ae))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Drop support for node < 6.
|
||||
|
||||
|
||||
|
||||
<a name="4.1.0"></a>
|
||||
## [4.1.0](https://github.com/yargs/cliui/compare/v4.0.0...v4.1.0) (2018-04-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add resetOutput method ([#57](https://github.com/yargs/cliui/issues/57)) ([7246902](https://github.com/yargs/cliui/commit/7246902))
|
||||
|
||||
|
||||
|
||||
<a name="4.0.0"></a>
|
||||
## [4.0.0](https://github.com/yargs/cliui/compare/v3.2.0...v4.0.0) (2017-12-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* downgrades strip-ansi to version 3.0.1 ([#54](https://github.com/yargs/cliui/issues/54)) ([5764c46](https://github.com/yargs/cliui/commit/5764c46))
|
||||
* set env variable FORCE_COLOR. ([#56](https://github.com/yargs/cliui/issues/56)) ([7350e36](https://github.com/yargs/cliui/commit/7350e36))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* drop support for node < 4 ([#53](https://github.com/yargs/cliui/issues/53)) ([b105376](https://github.com/yargs/cliui/commit/b105376))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add fallback for window width ([#45](https://github.com/yargs/cliui/issues/45)) ([d064922](https://github.com/yargs/cliui/commit/d064922))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* officially drop support for Node < 4
|
||||
|
||||
|
||||
|
||||
<a name="3.2.0"></a>
|
||||
## [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* reduces tarball size ([acc6c33](https://github.com/yargs/cliui/commit/acc6c33))
|
||||
|
||||
### Features
|
||||
|
||||
* adds standard-version for release management ([ff84e32](https://github.com/yargs/cliui/commit/ff84e32))
|
||||
14
my-app/node_modules/karma/node_modules/cliui/LICENSE.txt
generated
vendored
Executable file
14
my-app/node_modules/karma/node_modules/cliui/LICENSE.txt
generated
vendored
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
Copyright (c) 2015, 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.
|
||||
141
my-app/node_modules/karma/node_modules/cliui/README.md
generated
vendored
Executable file
141
my-app/node_modules/karma/node_modules/cliui/README.md
generated
vendored
Executable file
|
|
@ -0,0 +1,141 @@
|
|||
# cliui
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/cliui)
|
||||
[](https://conventionalcommits.org)
|
||||

|
||||
|
||||
easily create complex multi-column command-line-interfaces.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const ui = require('cliui')()
|
||||
|
||||
ui.div('Usage: $0 [command] [options]')
|
||||
|
||||
ui.div({
|
||||
text: 'Options:',
|
||||
padding: [2, 0, 1, 0]
|
||||
})
|
||||
|
||||
ui.div(
|
||||
{
|
||||
text: "-f, --file",
|
||||
width: 20,
|
||||
padding: [0, 4, 0, 4]
|
||||
},
|
||||
{
|
||||
text: "the file to load." +
|
||||
chalk.green("(if this description is long it wraps).")
|
||||
,
|
||||
width: 20
|
||||
},
|
||||
{
|
||||
text: chalk.red("[required]"),
|
||||
align: 'right'
|
||||
}
|
||||
)
|
||||
|
||||
console.log(ui.toString())
|
||||
```
|
||||
|
||||
## Deno/ESM Support
|
||||
|
||||
As of `v7` `cliui` supports [Deno](https://github.com/denoland/deno) and
|
||||
[ESM](https://nodejs.org/api/esm.html#esm_ecmascript_modules):
|
||||
|
||||
```typescript
|
||||
import cliui from "https://deno.land/x/cliui/deno.ts";
|
||||
|
||||
const ui = cliui({})
|
||||
|
||||
ui.div('Usage: $0 [command] [options]')
|
||||
|
||||
ui.div({
|
||||
text: 'Options:',
|
||||
padding: [2, 0, 1, 0]
|
||||
})
|
||||
|
||||
ui.div({
|
||||
text: "-f, --file",
|
||||
width: 20,
|
||||
padding: [0, 4, 0, 4]
|
||||
})
|
||||
|
||||
console.log(ui.toString())
|
||||
```
|
||||
|
||||
<img width="500" src="screenshot.png">
|
||||
|
||||
## Layout DSL
|
||||
|
||||
cliui exposes a simple layout DSL:
|
||||
|
||||
If you create a single `ui.div`, passing a string rather than an
|
||||
object:
|
||||
|
||||
* `\n`: characters will be interpreted as new rows.
|
||||
* `\t`: characters will be interpreted as new columns.
|
||||
* `\s`: characters will be interpreted as padding.
|
||||
|
||||
**as an example...**
|
||||
|
||||
```js
|
||||
var ui = require('./')({
|
||||
width: 60
|
||||
})
|
||||
|
||||
ui.div(
|
||||
'Usage: node ./bin/foo.js\n' +
|
||||
' <regex>\t provide a regex\n' +
|
||||
' <glob>\t provide a glob\t [required]'
|
||||
)
|
||||
|
||||
console.log(ui.toString())
|
||||
```
|
||||
|
||||
**will output:**
|
||||
|
||||
```shell
|
||||
Usage: node ./bin/foo.js
|
||||
<regex> provide a regex
|
||||
<glob> provide a glob [required]
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
```js
|
||||
cliui = require('cliui')
|
||||
```
|
||||
|
||||
### cliui({width: integer})
|
||||
|
||||
Specify the maximum width of the UI being generated.
|
||||
If no width is provided, cliui will try to get the current window's width and use it, and if that doesn't work, width will be set to `80`.
|
||||
|
||||
### cliui({wrap: boolean})
|
||||
|
||||
Enable or disable the wrapping of text in a column.
|
||||
|
||||
### cliui.div(column, column, column)
|
||||
|
||||
Create a row with any number of columns, a column
|
||||
can either be a string, or an object with the following
|
||||
options:
|
||||
|
||||
* **text:** some text to place in the column.
|
||||
* **width:** the width of a column.
|
||||
* **align:** alignment, `right` or `center`.
|
||||
* **padding:** `[top, right, bottom, left]`.
|
||||
* **border:** should a border be placed around the div?
|
||||
|
||||
### cliui.span(column, column, column)
|
||||
|
||||
Similar to `div`, except the next row will be appended without
|
||||
a new line being created.
|
||||
|
||||
### cliui.resetOutput()
|
||||
|
||||
Resets the UI elements of the current cliui instance, maintaining the values
|
||||
set for `width` and `wrap`.
|
||||
302
my-app/node_modules/karma/node_modules/cliui/build/index.cjs
generated
vendored
Executable file
302
my-app/node_modules/karma/node_modules/cliui/build/index.cjs
generated
vendored
Executable file
|
|
@ -0,0 +1,302 @@
|
|||
'use strict';
|
||||
|
||||
const align = {
|
||||
right: alignRight,
|
||||
center: alignCenter
|
||||
};
|
||||
const top = 0;
|
||||
const right = 1;
|
||||
const bottom = 2;
|
||||
const left = 3;
|
||||
class UI {
|
||||
constructor(opts) {
|
||||
var _a;
|
||||
this.width = opts.width;
|
||||
this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true;
|
||||
this.rows = [];
|
||||
}
|
||||
span(...args) {
|
||||
const cols = this.div(...args);
|
||||
cols.span = true;
|
||||
}
|
||||
resetOutput() {
|
||||
this.rows = [];
|
||||
}
|
||||
div(...args) {
|
||||
if (args.length === 0) {
|
||||
this.div('');
|
||||
}
|
||||
if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') {
|
||||
return this.applyLayoutDSL(args[0]);
|
||||
}
|
||||
const cols = args.map(arg => {
|
||||
if (typeof arg === 'string') {
|
||||
return this.colFromString(arg);
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
this.rows.push(cols);
|
||||
return cols;
|
||||
}
|
||||
shouldApplyLayoutDSL(...args) {
|
||||
return args.length === 1 && typeof args[0] === 'string' &&
|
||||
/[\t\n]/.test(args[0]);
|
||||
}
|
||||
applyLayoutDSL(str) {
|
||||
const rows = str.split('\n').map(row => row.split('\t'));
|
||||
let leftColumnWidth = 0;
|
||||
// simple heuristic for layout, make sure the
|
||||
// second column lines up along the left-hand.
|
||||
// don't allow the first column to take up more
|
||||
// than 50% of the screen.
|
||||
rows.forEach(columns => {
|
||||
if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) {
|
||||
leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0]));
|
||||
}
|
||||
});
|
||||
// generate a table:
|
||||
// replacing ' ' with padding calculations.
|
||||
// using the algorithmically generated width.
|
||||
rows.forEach(columns => {
|
||||
this.div(...columns.map((r, i) => {
|
||||
return {
|
||||
text: r.trim(),
|
||||
padding: this.measurePadding(r),
|
||||
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
|
||||
};
|
||||
}));
|
||||
});
|
||||
return this.rows[this.rows.length - 1];
|
||||
}
|
||||
colFromString(text) {
|
||||
return {
|
||||
text,
|
||||
padding: this.measurePadding(text)
|
||||
};
|
||||
}
|
||||
measurePadding(str) {
|
||||
// measure padding without ansi escape codes
|
||||
const noAnsi = mixin.stripAnsi(str);
|
||||
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length];
|
||||
}
|
||||
toString() {
|
||||
const lines = [];
|
||||
this.rows.forEach(row => {
|
||||
this.rowToString(row, lines);
|
||||
});
|
||||
// don't display any lines with the
|
||||
// hidden flag set.
|
||||
return lines
|
||||
.filter(line => !line.hidden)
|
||||
.map(line => line.text)
|
||||
.join('\n');
|
||||
}
|
||||
rowToString(row, lines) {
|
||||
this.rasterize(row).forEach((rrow, r) => {
|
||||
let str = '';
|
||||
rrow.forEach((col, c) => {
|
||||
const { width } = row[c]; // the width with padding.
|
||||
const wrapWidth = this.negatePadding(row[c]); // the width without padding.
|
||||
let ts = col; // temporary string used during alignment/padding.
|
||||
if (wrapWidth > mixin.stringWidth(col)) {
|
||||
ts += ' '.repeat(wrapWidth - mixin.stringWidth(col));
|
||||
}
|
||||
// align the string within its column.
|
||||
if (row[c].align && row[c].align !== 'left' && this.wrap) {
|
||||
const fn = align[row[c].align];
|
||||
ts = fn(ts, wrapWidth);
|
||||
if (mixin.stringWidth(ts) < wrapWidth) {
|
||||
ts += ' '.repeat((width || 0) - mixin.stringWidth(ts) - 1);
|
||||
}
|
||||
}
|
||||
// apply border and padding to string.
|
||||
const padding = row[c].padding || [0, 0, 0, 0];
|
||||
if (padding[left]) {
|
||||
str += ' '.repeat(padding[left]);
|
||||
}
|
||||
str += addBorder(row[c], ts, '| ');
|
||||
str += ts;
|
||||
str += addBorder(row[c], ts, ' |');
|
||||
if (padding[right]) {
|
||||
str += ' '.repeat(padding[right]);
|
||||
}
|
||||
// if prior row is span, try to render the
|
||||
// current row on the prior line.
|
||||
if (r === 0 && lines.length > 0) {
|
||||
str = this.renderInline(str, lines[lines.length - 1]);
|
||||
}
|
||||
});
|
||||
// remove trailing whitespace.
|
||||
lines.push({
|
||||
text: str.replace(/ +$/, ''),
|
||||
span: row.span
|
||||
});
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
// if the full 'source' can render in
|
||||
// the target line, do so.
|
||||
renderInline(source, previousLine) {
|
||||
const match = source.match(/^ */);
|
||||
const leadingWhitespace = match ? match[0].length : 0;
|
||||
const target = previousLine.text;
|
||||
const targetTextWidth = mixin.stringWidth(target.trimRight());
|
||||
if (!previousLine.span) {
|
||||
return source;
|
||||
}
|
||||
// if we're not applying wrapping logic,
|
||||
// just always append to the span.
|
||||
if (!this.wrap) {
|
||||
previousLine.hidden = true;
|
||||
return target + source;
|
||||
}
|
||||
if (leadingWhitespace < targetTextWidth) {
|
||||
return source;
|
||||
}
|
||||
previousLine.hidden = true;
|
||||
return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft();
|
||||
}
|
||||
rasterize(row) {
|
||||
const rrows = [];
|
||||
const widths = this.columnWidths(row);
|
||||
let wrapped;
|
||||
// word wrap all columns, and create
|
||||
// a data-structure that is easy to rasterize.
|
||||
row.forEach((col, c) => {
|
||||
// leave room for left and right padding.
|
||||
col.width = widths[c];
|
||||
if (this.wrap) {
|
||||
wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n');
|
||||
}
|
||||
else {
|
||||
wrapped = col.text.split('\n');
|
||||
}
|
||||
if (col.border) {
|
||||
wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.');
|
||||
wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'");
|
||||
}
|
||||
// add top and bottom padding.
|
||||
if (col.padding) {
|
||||
wrapped.unshift(...new Array(col.padding[top] || 0).fill(''));
|
||||
wrapped.push(...new Array(col.padding[bottom] || 0).fill(''));
|
||||
}
|
||||
wrapped.forEach((str, r) => {
|
||||
if (!rrows[r]) {
|
||||
rrows.push([]);
|
||||
}
|
||||
const rrow = rrows[r];
|
||||
for (let i = 0; i < c; i++) {
|
||||
if (rrow[i] === undefined) {
|
||||
rrow.push('');
|
||||
}
|
||||
}
|
||||
rrow.push(str);
|
||||
});
|
||||
});
|
||||
return rrows;
|
||||
}
|
||||
negatePadding(col) {
|
||||
let wrapWidth = col.width || 0;
|
||||
if (col.padding) {
|
||||
wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0);
|
||||
}
|
||||
if (col.border) {
|
||||
wrapWidth -= 4;
|
||||
}
|
||||
return wrapWidth;
|
||||
}
|
||||
columnWidths(row) {
|
||||
if (!this.wrap) {
|
||||
return row.map(col => {
|
||||
return col.width || mixin.stringWidth(col.text);
|
||||
});
|
||||
}
|
||||
let unset = row.length;
|
||||
let remainingWidth = this.width;
|
||||
// column widths can be set in config.
|
||||
const widths = row.map(col => {
|
||||
if (col.width) {
|
||||
unset--;
|
||||
remainingWidth -= col.width;
|
||||
return col.width;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
// any unset widths should be calculated.
|
||||
const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0;
|
||||
return widths.map((w, i) => {
|
||||
if (w === undefined) {
|
||||
return Math.max(unsetWidth, _minWidth(row[i]));
|
||||
}
|
||||
return w;
|
||||
});
|
||||
}
|
||||
}
|
||||
function addBorder(col, ts, style) {
|
||||
if (col.border) {
|
||||
if (/[.']-+[.']/.test(ts)) {
|
||||
return '';
|
||||
}
|
||||
if (ts.trim().length !== 0) {
|
||||
return style;
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// calculates the minimum width of
|
||||
// a column, based on padding preferences.
|
||||
function _minWidth(col) {
|
||||
const padding = col.padding || [];
|
||||
const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0);
|
||||
if (col.border) {
|
||||
return minWidth + 4;
|
||||
}
|
||||
return minWidth;
|
||||
}
|
||||
function getWindowWidth() {
|
||||
/* istanbul ignore next: depends on terminal */
|
||||
if (typeof process === 'object' && process.stdout && process.stdout.columns) {
|
||||
return process.stdout.columns;
|
||||
}
|
||||
return 80;
|
||||
}
|
||||
function alignRight(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
if (strWidth < width) {
|
||||
return ' '.repeat(width - strWidth) + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function alignCenter(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
/* istanbul ignore next */
|
||||
if (strWidth >= width) {
|
||||
return str;
|
||||
}
|
||||
return ' '.repeat((width - strWidth) >> 1) + str;
|
||||
}
|
||||
let mixin;
|
||||
function cliui(opts, _mixin) {
|
||||
mixin = _mixin;
|
||||
return new UI({
|
||||
width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(),
|
||||
wrap: opts === null || opts === void 0 ? void 0 : opts.wrap
|
||||
});
|
||||
}
|
||||
|
||||
// Bootstrap cliui with CommonJS dependencies:
|
||||
const stringWidth = require('string-width');
|
||||
const stripAnsi = require('strip-ansi');
|
||||
const wrap = require('wrap-ansi');
|
||||
function ui(opts) {
|
||||
return cliui(opts, {
|
||||
stringWidth,
|
||||
stripAnsi,
|
||||
wrap
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = ui;
|
||||
287
my-app/node_modules/karma/node_modules/cliui/build/lib/index.js
generated
vendored
Executable file
287
my-app/node_modules/karma/node_modules/cliui/build/lib/index.js
generated
vendored
Executable file
|
|
@ -0,0 +1,287 @@
|
|||
'use strict';
|
||||
const align = {
|
||||
right: alignRight,
|
||||
center: alignCenter
|
||||
};
|
||||
const top = 0;
|
||||
const right = 1;
|
||||
const bottom = 2;
|
||||
const left = 3;
|
||||
export class UI {
|
||||
constructor(opts) {
|
||||
var _a;
|
||||
this.width = opts.width;
|
||||
this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true;
|
||||
this.rows = [];
|
||||
}
|
||||
span(...args) {
|
||||
const cols = this.div(...args);
|
||||
cols.span = true;
|
||||
}
|
||||
resetOutput() {
|
||||
this.rows = [];
|
||||
}
|
||||
div(...args) {
|
||||
if (args.length === 0) {
|
||||
this.div('');
|
||||
}
|
||||
if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') {
|
||||
return this.applyLayoutDSL(args[0]);
|
||||
}
|
||||
const cols = args.map(arg => {
|
||||
if (typeof arg === 'string') {
|
||||
return this.colFromString(arg);
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
this.rows.push(cols);
|
||||
return cols;
|
||||
}
|
||||
shouldApplyLayoutDSL(...args) {
|
||||
return args.length === 1 && typeof args[0] === 'string' &&
|
||||
/[\t\n]/.test(args[0]);
|
||||
}
|
||||
applyLayoutDSL(str) {
|
||||
const rows = str.split('\n').map(row => row.split('\t'));
|
||||
let leftColumnWidth = 0;
|
||||
// simple heuristic for layout, make sure the
|
||||
// second column lines up along the left-hand.
|
||||
// don't allow the first column to take up more
|
||||
// than 50% of the screen.
|
||||
rows.forEach(columns => {
|
||||
if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) {
|
||||
leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0]));
|
||||
}
|
||||
});
|
||||
// generate a table:
|
||||
// replacing ' ' with padding calculations.
|
||||
// using the algorithmically generated width.
|
||||
rows.forEach(columns => {
|
||||
this.div(...columns.map((r, i) => {
|
||||
return {
|
||||
text: r.trim(),
|
||||
padding: this.measurePadding(r),
|
||||
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
|
||||
};
|
||||
}));
|
||||
});
|
||||
return this.rows[this.rows.length - 1];
|
||||
}
|
||||
colFromString(text) {
|
||||
return {
|
||||
text,
|
||||
padding: this.measurePadding(text)
|
||||
};
|
||||
}
|
||||
measurePadding(str) {
|
||||
// measure padding without ansi escape codes
|
||||
const noAnsi = mixin.stripAnsi(str);
|
||||
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length];
|
||||
}
|
||||
toString() {
|
||||
const lines = [];
|
||||
this.rows.forEach(row => {
|
||||
this.rowToString(row, lines);
|
||||
});
|
||||
// don't display any lines with the
|
||||
// hidden flag set.
|
||||
return lines
|
||||
.filter(line => !line.hidden)
|
||||
.map(line => line.text)
|
||||
.join('\n');
|
||||
}
|
||||
rowToString(row, lines) {
|
||||
this.rasterize(row).forEach((rrow, r) => {
|
||||
let str = '';
|
||||
rrow.forEach((col, c) => {
|
||||
const { width } = row[c]; // the width with padding.
|
||||
const wrapWidth = this.negatePadding(row[c]); // the width without padding.
|
||||
let ts = col; // temporary string used during alignment/padding.
|
||||
if (wrapWidth > mixin.stringWidth(col)) {
|
||||
ts += ' '.repeat(wrapWidth - mixin.stringWidth(col));
|
||||
}
|
||||
// align the string within its column.
|
||||
if (row[c].align && row[c].align !== 'left' && this.wrap) {
|
||||
const fn = align[row[c].align];
|
||||
ts = fn(ts, wrapWidth);
|
||||
if (mixin.stringWidth(ts) < wrapWidth) {
|
||||
ts += ' '.repeat((width || 0) - mixin.stringWidth(ts) - 1);
|
||||
}
|
||||
}
|
||||
// apply border and padding to string.
|
||||
const padding = row[c].padding || [0, 0, 0, 0];
|
||||
if (padding[left]) {
|
||||
str += ' '.repeat(padding[left]);
|
||||
}
|
||||
str += addBorder(row[c], ts, '| ');
|
||||
str += ts;
|
||||
str += addBorder(row[c], ts, ' |');
|
||||
if (padding[right]) {
|
||||
str += ' '.repeat(padding[right]);
|
||||
}
|
||||
// if prior row is span, try to render the
|
||||
// current row on the prior line.
|
||||
if (r === 0 && lines.length > 0) {
|
||||
str = this.renderInline(str, lines[lines.length - 1]);
|
||||
}
|
||||
});
|
||||
// remove trailing whitespace.
|
||||
lines.push({
|
||||
text: str.replace(/ +$/, ''),
|
||||
span: row.span
|
||||
});
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
// if the full 'source' can render in
|
||||
// the target line, do so.
|
||||
renderInline(source, previousLine) {
|
||||
const match = source.match(/^ */);
|
||||
const leadingWhitespace = match ? match[0].length : 0;
|
||||
const target = previousLine.text;
|
||||
const targetTextWidth = mixin.stringWidth(target.trimRight());
|
||||
if (!previousLine.span) {
|
||||
return source;
|
||||
}
|
||||
// if we're not applying wrapping logic,
|
||||
// just always append to the span.
|
||||
if (!this.wrap) {
|
||||
previousLine.hidden = true;
|
||||
return target + source;
|
||||
}
|
||||
if (leadingWhitespace < targetTextWidth) {
|
||||
return source;
|
||||
}
|
||||
previousLine.hidden = true;
|
||||
return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft();
|
||||
}
|
||||
rasterize(row) {
|
||||
const rrows = [];
|
||||
const widths = this.columnWidths(row);
|
||||
let wrapped;
|
||||
// word wrap all columns, and create
|
||||
// a data-structure that is easy to rasterize.
|
||||
row.forEach((col, c) => {
|
||||
// leave room for left and right padding.
|
||||
col.width = widths[c];
|
||||
if (this.wrap) {
|
||||
wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n');
|
||||
}
|
||||
else {
|
||||
wrapped = col.text.split('\n');
|
||||
}
|
||||
if (col.border) {
|
||||
wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.');
|
||||
wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'");
|
||||
}
|
||||
// add top and bottom padding.
|
||||
if (col.padding) {
|
||||
wrapped.unshift(...new Array(col.padding[top] || 0).fill(''));
|
||||
wrapped.push(...new Array(col.padding[bottom] || 0).fill(''));
|
||||
}
|
||||
wrapped.forEach((str, r) => {
|
||||
if (!rrows[r]) {
|
||||
rrows.push([]);
|
||||
}
|
||||
const rrow = rrows[r];
|
||||
for (let i = 0; i < c; i++) {
|
||||
if (rrow[i] === undefined) {
|
||||
rrow.push('');
|
||||
}
|
||||
}
|
||||
rrow.push(str);
|
||||
});
|
||||
});
|
||||
return rrows;
|
||||
}
|
||||
negatePadding(col) {
|
||||
let wrapWidth = col.width || 0;
|
||||
if (col.padding) {
|
||||
wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0);
|
||||
}
|
||||
if (col.border) {
|
||||
wrapWidth -= 4;
|
||||
}
|
||||
return wrapWidth;
|
||||
}
|
||||
columnWidths(row) {
|
||||
if (!this.wrap) {
|
||||
return row.map(col => {
|
||||
return col.width || mixin.stringWidth(col.text);
|
||||
});
|
||||
}
|
||||
let unset = row.length;
|
||||
let remainingWidth = this.width;
|
||||
// column widths can be set in config.
|
||||
const widths = row.map(col => {
|
||||
if (col.width) {
|
||||
unset--;
|
||||
remainingWidth -= col.width;
|
||||
return col.width;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
// any unset widths should be calculated.
|
||||
const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0;
|
||||
return widths.map((w, i) => {
|
||||
if (w === undefined) {
|
||||
return Math.max(unsetWidth, _minWidth(row[i]));
|
||||
}
|
||||
return w;
|
||||
});
|
||||
}
|
||||
}
|
||||
function addBorder(col, ts, style) {
|
||||
if (col.border) {
|
||||
if (/[.']-+[.']/.test(ts)) {
|
||||
return '';
|
||||
}
|
||||
if (ts.trim().length !== 0) {
|
||||
return style;
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// calculates the minimum width of
|
||||
// a column, based on padding preferences.
|
||||
function _minWidth(col) {
|
||||
const padding = col.padding || [];
|
||||
const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0);
|
||||
if (col.border) {
|
||||
return minWidth + 4;
|
||||
}
|
||||
return minWidth;
|
||||
}
|
||||
function getWindowWidth() {
|
||||
/* istanbul ignore next: depends on terminal */
|
||||
if (typeof process === 'object' && process.stdout && process.stdout.columns) {
|
||||
return process.stdout.columns;
|
||||
}
|
||||
return 80;
|
||||
}
|
||||
function alignRight(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
if (strWidth < width) {
|
||||
return ' '.repeat(width - strWidth) + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function alignCenter(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
/* istanbul ignore next */
|
||||
if (strWidth >= width) {
|
||||
return str;
|
||||
}
|
||||
return ' '.repeat((width - strWidth) >> 1) + str;
|
||||
}
|
||||
let mixin;
|
||||
export function cliui(opts, _mixin) {
|
||||
mixin = _mixin;
|
||||
return new UI({
|
||||
width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(),
|
||||
wrap: opts === null || opts === void 0 ? void 0 : opts.wrap
|
||||
});
|
||||
}
|
||||
27
my-app/node_modules/karma/node_modules/cliui/build/lib/string-utils.js
generated
vendored
Executable file
27
my-app/node_modules/karma/node_modules/cliui/build/lib/string-utils.js
generated
vendored
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
// Minimal replacement for ansi string helpers "wrap-ansi" and "strip-ansi".
|
||||
// to facilitate ESM and Deno modules.
|
||||
// TODO: look at porting https://www.npmjs.com/package/wrap-ansi to ESM.
|
||||
// The npm application
|
||||
// Copyright (c) npm, Inc. and Contributors
|
||||
// Licensed on the terms of The Artistic License 2.0
|
||||
// See: https://github.com/npm/cli/blob/4c65cd952bc8627811735bea76b9b110cc4fc80e/lib/utils/ansi-trim.js
|
||||
const ansi = new RegExp('\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|' +
|
||||
'\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)', 'g');
|
||||
export function stripAnsi(str) {
|
||||
return str.replace(ansi, '');
|
||||
}
|
||||
export function wrap(str, width) {
|
||||
const [start, end] = str.match(ansi) || ['', ''];
|
||||
str = stripAnsi(str);
|
||||
let wrapped = '';
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (i !== 0 && (i % width) === 0) {
|
||||
wrapped += '\n';
|
||||
}
|
||||
wrapped += str.charAt(i);
|
||||
}
|
||||
if (start && end) {
|
||||
wrapped = `${start}${wrapped}${end}`;
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
13
my-app/node_modules/karma/node_modules/cliui/index.mjs
generated
vendored
Executable file
13
my-app/node_modules/karma/node_modules/cliui/index.mjs
generated
vendored
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
// Bootstrap cliui with CommonJS dependencies:
|
||||
import { cliui } from './build/lib/index.js'
|
||||
import { wrap, stripAnsi } from './build/lib/string-utils.js'
|
||||
|
||||
export default function ui (opts) {
|
||||
return cliui(opts, {
|
||||
stringWidth: (str) => {
|
||||
return [...str].length
|
||||
},
|
||||
stripAnsi,
|
||||
wrap
|
||||
})
|
||||
}
|
||||
83
my-app/node_modules/karma/node_modules/cliui/package.json
generated
vendored
Executable file
83
my-app/node_modules/karma/node_modules/cliui/package.json
generated
vendored
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"name": "cliui",
|
||||
"version": "7.0.4",
|
||||
"description": "easily create complex multi-column command-line-interfaces",
|
||||
"main": "build/index.cjs",
|
||||
"exports": {
|
||||
".": [
|
||||
{
|
||||
"import": "./index.mjs",
|
||||
"require": "./build/index.cjs"
|
||||
},
|
||||
"./build/index.cjs"
|
||||
]
|
||||
},
|
||||
"type": "module",
|
||||
"module": "./index.mjs",
|
||||
"scripts": {
|
||||
"check": "standardx '**/*.ts' && standardx '**/*.js' && standardx '**/*.cjs'",
|
||||
"fix": "standardx --fix '**/*.ts' && standardx --fix '**/*.js' && standardx --fix '**/*.cjs'",
|
||||
"pretest": "rimraf build && tsc -p tsconfig.test.json && cross-env NODE_ENV=test npm run build:cjs",
|
||||
"test": "c8 mocha ./test/*.cjs",
|
||||
"test:esm": "c8 mocha ./test/esm/cliui-test.mjs",
|
||||
"postest": "check",
|
||||
"coverage": "c8 report --check-coverage",
|
||||
"precompile": "rimraf build",
|
||||
"compile": "tsc",
|
||||
"postcompile": "npm run build:cjs",
|
||||
"build:cjs": "rollup -c",
|
||||
"prepare": "npm run compile"
|
||||
},
|
||||
"repository": "yargs/cliui",
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"**/example/**"
|
||||
],
|
||||
"globals": [
|
||||
"it"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"command-line",
|
||||
"layout",
|
||||
"design",
|
||||
"console",
|
||||
"wrap",
|
||||
"table"
|
||||
],
|
||||
"author": "Ben Coe <ben@npmjs.com>",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.27",
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.0",
|
||||
"@typescript-eslint/parser": "^4.0.0",
|
||||
"@wessberg/rollup-plugin-ts": "^1.3.2",
|
||||
"c8": "^7.3.0",
|
||||
"chai": "^4.2.0",
|
||||
"chalk": "^4.1.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^7.6.0",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"gts": "^3.0.0",
|
||||
"mocha": "^8.1.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.23.1",
|
||||
"standardx": "^7.0.0",
|
||||
"typescript": "^4.0.0"
|
||||
},
|
||||
"files": [
|
||||
"build",
|
||||
"index.mjs",
|
||||
"!*.d.ts"
|
||||
],
|
||||
"engine": {
|
||||
"node": ">=10"
|
||||
}
|
||||
}
|
||||
54
my-app/node_modules/karma/node_modules/color-convert/CHANGELOG.md
generated
vendored
Executable file
54
my-app/node_modules/karma/node_modules/color-convert/CHANGELOG.md
generated
vendored
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
# 1.0.0 - 2016-01-07
|
||||
|
||||
- Removed: unused speed test
|
||||
- Added: Automatic routing between previously unsupported conversions
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Removed: `xxx2xxx()` and `xxx2xxxRaw()` functions
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Removed: `convert()` class
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Changed: all functions to lookup dictionary
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Changed: `ansi` to `ansi256`
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Fixed: argument grouping for functions requiring only one argument
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
|
||||
# 0.6.0 - 2015-07-23
|
||||
|
||||
- Added: methods to handle
|
||||
[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 16/256 colors:
|
||||
- rgb2ansi16
|
||||
- rgb2ansi
|
||||
- hsl2ansi16
|
||||
- hsl2ansi
|
||||
- hsv2ansi16
|
||||
- hsv2ansi
|
||||
- hwb2ansi16
|
||||
- hwb2ansi
|
||||
- cmyk2ansi16
|
||||
- cmyk2ansi
|
||||
- keyword2ansi16
|
||||
- keyword2ansi
|
||||
- ansi162rgb
|
||||
- ansi162hsl
|
||||
- ansi162hsv
|
||||
- ansi162hwb
|
||||
- ansi162cmyk
|
||||
- ansi162keyword
|
||||
- ansi2rgb
|
||||
- ansi2hsl
|
||||
- ansi2hsv
|
||||
- ansi2hwb
|
||||
- ansi2cmyk
|
||||
- ansi2keyword
|
||||
([#18](https://github.com/harthur/color-convert/pull/18))
|
||||
|
||||
# 0.5.3 - 2015-06-02
|
||||
|
||||
- Fixed: hsl2hsv does not return `NaN` anymore when using `[0,0,0]`
|
||||
([#15](https://github.com/harthur/color-convert/issues/15))
|
||||
|
||||
---
|
||||
|
||||
Check out commit logs for older releases
|
||||
21
my-app/node_modules/karma/node_modules/color-convert/LICENSE
generated
vendored
Executable file
21
my-app/node_modules/karma/node_modules/color-convert/LICENSE
generated
vendored
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
Copyright (c) 2011-2016 Heather Arthur <fayearthur@gmail.com>
|
||||
|
||||
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.
|
||||
|
||||
68
my-app/node_modules/karma/node_modules/color-convert/README.md
generated
vendored
Executable file
68
my-app/node_modules/karma/node_modules/color-convert/README.md
generated
vendored
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
# color-convert
|
||||
|
||||
[](https://travis-ci.org/Qix-/color-convert)
|
||||
|
||||
Color-convert is a color conversion library for JavaScript and node.
|
||||
It converts all ways between `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `ansi`, `ansi16`, `hex` strings, and CSS `keyword`s (will round to closest):
|
||||
|
||||
```js
|
||||
var convert = require('color-convert');
|
||||
|
||||
convert.rgb.hsl(140, 200, 100); // [96, 48, 59]
|
||||
convert.keyword.rgb('blue'); // [0, 0, 255]
|
||||
|
||||
var rgbChannels = convert.rgb.channels; // 3
|
||||
var cmykChannels = convert.cmyk.channels; // 4
|
||||
var ansiChannels = convert.ansi16.channels; // 1
|
||||
```
|
||||
|
||||
# Install
|
||||
|
||||
```console
|
||||
$ npm install color-convert
|
||||
```
|
||||
|
||||
# API
|
||||
|
||||
Simply get the property of the _from_ and _to_ conversion that you're looking for.
|
||||
|
||||
All functions have a rounded and unrounded variant. By default, return values are rounded. To get the unrounded (raw) results, simply tack on `.raw` to the function.
|
||||
|
||||
All 'from' functions have a hidden property called `.channels` that indicates the number of channels the function expects (not including alpha).
|
||||
|
||||
```js
|
||||
var convert = require('color-convert');
|
||||
|
||||
// Hex to LAB
|
||||
convert.hex.lab('DEADBF'); // [ 76, 21, -2 ]
|
||||
convert.hex.lab.raw('DEADBF'); // [ 75.56213190997677, 20.653827952644754, -2.290532499330533 ]
|
||||
|
||||
// RGB to CMYK
|
||||
convert.rgb.cmyk(167, 255, 4); // [ 35, 0, 98, 0 ]
|
||||
convert.rgb.cmyk.raw(167, 255, 4); // [ 34.509803921568626, 0, 98.43137254901961, 0 ]
|
||||
```
|
||||
|
||||
### Arrays
|
||||
All functions that accept multiple arguments also support passing an array.
|
||||
|
||||
Note that this does **not** apply to functions that convert from a color that only requires one value (e.g. `keyword`, `ansi256`, `hex`, etc.)
|
||||
|
||||
```js
|
||||
var convert = require('color-convert');
|
||||
|
||||
convert.rgb.hex(123, 45, 67); // '7B2D43'
|
||||
convert.rgb.hex([123, 45, 67]); // '7B2D43'
|
||||
```
|
||||
|
||||
## Routing
|
||||
|
||||
Conversions that don't have an _explicitly_ defined conversion (in [conversions.js](conversions.js)), but can be converted by means of sub-conversions (e.g. XYZ -> **RGB** -> CMYK), are automatically routed together. This allows just about any color model supported by `color-convert` to be converted to any other model, so long as a sub-conversion path exists. This is also true for conversions requiring more than one step in between (e.g. LCH -> **LAB** -> **XYZ** -> **RGB** -> Hex).
|
||||
|
||||
Keep in mind that extensive conversions _may_ result in a loss of precision, and exist only to be complete. For a list of "direct" (single-step) conversions, see [conversions.js](conversions.js).
|
||||
|
||||
# Contribute
|
||||
|
||||
If there is a new model you would like to support, or want to add a direct conversion between two existing models, please send us a pull request.
|
||||
|
||||
# License
|
||||
Copyright © 2011-2016, Heather Arthur and Josh Junon. Licensed under the [MIT License](LICENSE).
|
||||
839
my-app/node_modules/karma/node_modules/color-convert/conversions.js
generated
vendored
Executable file
839
my-app/node_modules/karma/node_modules/color-convert/conversions.js
generated
vendored
Executable file
|
|
@ -0,0 +1,839 @@
|
|||
/* MIT license */
|
||||
/* eslint-disable no-mixed-operators */
|
||||
const cssKeywords = require('color-name');
|
||||
|
||||
// NOTE: conversions should only return primitive values (i.e. arrays, or
|
||||
// values that give correct `typeof` results).
|
||||
// do not use box values types (i.e. Number(), String(), etc.)
|
||||
|
||||
const reverseKeywords = {};
|
||||
for (const key of Object.keys(cssKeywords)) {
|
||||
reverseKeywords[cssKeywords[key]] = key;
|
||||
}
|
||||
|
||||
const convert = {
|
||||
rgb: {channels: 3, labels: 'rgb'},
|
||||
hsl: {channels: 3, labels: 'hsl'},
|
||||
hsv: {channels: 3, labels: 'hsv'},
|
||||
hwb: {channels: 3, labels: 'hwb'},
|
||||
cmyk: {channels: 4, labels: 'cmyk'},
|
||||
xyz: {channels: 3, labels: 'xyz'},
|
||||
lab: {channels: 3, labels: 'lab'},
|
||||
lch: {channels: 3, labels: 'lch'},
|
||||
hex: {channels: 1, labels: ['hex']},
|
||||
keyword: {channels: 1, labels: ['keyword']},
|
||||
ansi16: {channels: 1, labels: ['ansi16']},
|
||||
ansi256: {channels: 1, labels: ['ansi256']},
|
||||
hcg: {channels: 3, labels: ['h', 'c', 'g']},
|
||||
apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
|
||||
gray: {channels: 1, labels: ['gray']}
|
||||
};
|
||||
|
||||
module.exports = convert;
|
||||
|
||||
// Hide .channels and .labels properties
|
||||
for (const model of Object.keys(convert)) {
|
||||
if (!('channels' in convert[model])) {
|
||||
throw new Error('missing channels property: ' + model);
|
||||
}
|
||||
|
||||
if (!('labels' in convert[model])) {
|
||||
throw new Error('missing channel labels property: ' + model);
|
||||
}
|
||||
|
||||
if (convert[model].labels.length !== convert[model].channels) {
|
||||
throw new Error('channel and label counts mismatch: ' + model);
|
||||
}
|
||||
|
||||
const {channels, labels} = convert[model];
|
||||
delete convert[model].channels;
|
||||
delete convert[model].labels;
|
||||
Object.defineProperty(convert[model], 'channels', {value: channels});
|
||||
Object.defineProperty(convert[model], 'labels', {value: labels});
|
||||
}
|
||||
|
||||
convert.rgb.hsl = function (rgb) {
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
const min = Math.min(r, g, b);
|
||||
const max = Math.max(r, g, b);
|
||||
const delta = max - min;
|
||||
let h;
|
||||
let s;
|
||||
|
||||
if (max === min) {
|
||||
h = 0;
|
||||
} else if (r === max) {
|
||||
h = (g - b) / delta;
|
||||
} else if (g === max) {
|
||||
h = 2 + (b - r) / delta;
|
||||
} else if (b === max) {
|
||||
h = 4 + (r - g) / delta;
|
||||
}
|
||||
|
||||
h = Math.min(h * 60, 360);
|
||||
|
||||
if (h < 0) {
|
||||
h += 360;
|
||||
}
|
||||
|
||||
const l = (min + max) / 2;
|
||||
|
||||
if (max === min) {
|
||||
s = 0;
|
||||
} else if (l <= 0.5) {
|
||||
s = delta / (max + min);
|
||||
} else {
|
||||
s = delta / (2 - max - min);
|
||||
}
|
||||
|
||||
return [h, s * 100, l * 100];
|
||||
};
|
||||
|
||||
convert.rgb.hsv = function (rgb) {
|
||||
let rdif;
|
||||
let gdif;
|
||||
let bdif;
|
||||
let h;
|
||||
let s;
|
||||
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
const v = Math.max(r, g, b);
|
||||
const diff = v - Math.min(r, g, b);
|
||||
const diffc = function (c) {
|
||||
return (v - c) / 6 / diff + 1 / 2;
|
||||
};
|
||||
|
||||
if (diff === 0) {
|
||||
h = 0;
|
||||
s = 0;
|
||||
} else {
|
||||
s = diff / v;
|
||||
rdif = diffc(r);
|
||||
gdif = diffc(g);
|
||||
bdif = diffc(b);
|
||||
|
||||
if (r === v) {
|
||||
h = bdif - gdif;
|
||||
} else if (g === v) {
|
||||
h = (1 / 3) + rdif - bdif;
|
||||
} else if (b === v) {
|
||||
h = (2 / 3) + gdif - rdif;
|
||||
}
|
||||
|
||||
if (h < 0) {
|
||||
h += 1;
|
||||
} else if (h > 1) {
|
||||
h -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
h * 360,
|
||||
s * 100,
|
||||
v * 100
|
||||
];
|
||||
};
|
||||
|
||||
convert.rgb.hwb = function (rgb) {
|
||||
const r = rgb[0];
|
||||
const g = rgb[1];
|
||||
let b = rgb[2];
|
||||
const h = convert.rgb.hsl(rgb)[0];
|
||||
const w = 1 / 255 * Math.min(r, Math.min(g, b));
|
||||
|
||||
b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
|
||||
|
||||
return [h, w * 100, b * 100];
|
||||
};
|
||||
|
||||
convert.rgb.cmyk = function (rgb) {
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
|
||||
const k = Math.min(1 - r, 1 - g, 1 - b);
|
||||
const c = (1 - r - k) / (1 - k) || 0;
|
||||
const m = (1 - g - k) / (1 - k) || 0;
|
||||
const y = (1 - b - k) / (1 - k) || 0;
|
||||
|
||||
return [c * 100, m * 100, y * 100, k * 100];
|
||||
};
|
||||
|
||||
function comparativeDistance(x, y) {
|
||||
/*
|
||||
See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
|
||||
*/
|
||||
return (
|
||||
((x[0] - y[0]) ** 2) +
|
||||
((x[1] - y[1]) ** 2) +
|
||||
((x[2] - y[2]) ** 2)
|
||||
);
|
||||
}
|
||||
|
||||
convert.rgb.keyword = function (rgb) {
|
||||
const reversed = reverseKeywords[rgb];
|
||||
if (reversed) {
|
||||
return reversed;
|
||||
}
|
||||
|
||||
let currentClosestDistance = Infinity;
|
||||
let currentClosestKeyword;
|
||||
|
||||
for (const keyword of Object.keys(cssKeywords)) {
|
||||
const value = cssKeywords[keyword];
|
||||
|
||||
// Compute comparative distance
|
||||
const distance = comparativeDistance(rgb, value);
|
||||
|
||||
// Check if its less, if so set as closest
|
||||
if (distance < currentClosestDistance) {
|
||||
currentClosestDistance = distance;
|
||||
currentClosestKeyword = keyword;
|
||||
}
|
||||
}
|
||||
|
||||
return currentClosestKeyword;
|
||||
};
|
||||
|
||||
convert.keyword.rgb = function (keyword) {
|
||||
return cssKeywords[keyword];
|
||||
};
|
||||
|
||||
convert.rgb.xyz = function (rgb) {
|
||||
let r = rgb[0] / 255;
|
||||
let g = rgb[1] / 255;
|
||||
let b = rgb[2] / 255;
|
||||
|
||||
// Assume sRGB
|
||||
r = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92);
|
||||
g = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92);
|
||||
b = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92);
|
||||
|
||||
const x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
|
||||
const y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
|
||||
const z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
|
||||
|
||||
return [x * 100, y * 100, z * 100];
|
||||
};
|
||||
|
||||
convert.rgb.lab = function (rgb) {
|
||||
const xyz = convert.rgb.xyz(rgb);
|
||||
let x = xyz[0];
|
||||
let y = xyz[1];
|
||||
let z = xyz[2];
|
||||
|
||||
x /= 95.047;
|
||||
y /= 100;
|
||||
z /= 108.883;
|
||||
|
||||
x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);
|
||||
y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);
|
||||
z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);
|
||||
|
||||
const l = (116 * y) - 16;
|
||||
const a = 500 * (x - y);
|
||||
const b = 200 * (y - z);
|
||||
|
||||
return [l, a, b];
|
||||
};
|
||||
|
||||
convert.hsl.rgb = function (hsl) {
|
||||
const h = hsl[0] / 360;
|
||||
const s = hsl[1] / 100;
|
||||
const l = hsl[2] / 100;
|
||||
let t2;
|
||||
let t3;
|
||||
let val;
|
||||
|
||||
if (s === 0) {
|
||||
val = l * 255;
|
||||
return [val, val, val];
|
||||
}
|
||||
|
||||
if (l < 0.5) {
|
||||
t2 = l * (1 + s);
|
||||
} else {
|
||||
t2 = l + s - l * s;
|
||||
}
|
||||
|
||||
const t1 = 2 * l - t2;
|
||||
|
||||
const rgb = [0, 0, 0];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
t3 = h + 1 / 3 * -(i - 1);
|
||||
if (t3 < 0) {
|
||||
t3++;
|
||||
}
|
||||
|
||||
if (t3 > 1) {
|
||||
t3--;
|
||||
}
|
||||
|
||||
if (6 * t3 < 1) {
|
||||
val = t1 + (t2 - t1) * 6 * t3;
|
||||
} else if (2 * t3 < 1) {
|
||||
val = t2;
|
||||
} else if (3 * t3 < 2) {
|
||||
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
|
||||
} else {
|
||||
val = t1;
|
||||
}
|
||||
|
||||
rgb[i] = val * 255;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
};
|
||||
|
||||
convert.hsl.hsv = function (hsl) {
|
||||
const h = hsl[0];
|
||||
let s = hsl[1] / 100;
|
||||
let l = hsl[2] / 100;
|
||||
let smin = s;
|
||||
const lmin = Math.max(l, 0.01);
|
||||
|
||||
l *= 2;
|
||||
s *= (l <= 1) ? l : 2 - l;
|
||||
smin *= lmin <= 1 ? lmin : 2 - lmin;
|
||||
const v = (l + s) / 2;
|
||||
const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
|
||||
|
||||
return [h, sv * 100, v * 100];
|
||||
};
|
||||
|
||||
convert.hsv.rgb = function (hsv) {
|
||||
const h = hsv[0] / 60;
|
||||
const s = hsv[1] / 100;
|
||||
let v = hsv[2] / 100;
|
||||
const hi = Math.floor(h) % 6;
|
||||
|
||||
const f = h - Math.floor(h);
|
||||
const p = 255 * v * (1 - s);
|
||||
const q = 255 * v * (1 - (s * f));
|
||||
const t = 255 * v * (1 - (s * (1 - f)));
|
||||
v *= 255;
|
||||
|
||||
switch (hi) {
|
||||
case 0:
|
||||
return [v, t, p];
|
||||
case 1:
|
||||
return [q, v, p];
|
||||
case 2:
|
||||
return [p, v, t];
|
||||
case 3:
|
||||
return [p, q, v];
|
||||
case 4:
|
||||
return [t, p, v];
|
||||
case 5:
|
||||
return [v, p, q];
|
||||
}
|
||||
};
|
||||
|
||||
convert.hsv.hsl = function (hsv) {
|
||||
const h = hsv[0];
|
||||
const s = hsv[1] / 100;
|
||||
const v = hsv[2] / 100;
|
||||
const vmin = Math.max(v, 0.01);
|
||||
let sl;
|
||||
let l;
|
||||
|
||||
l = (2 - s) * v;
|
||||
const lmin = (2 - s) * vmin;
|
||||
sl = s * vmin;
|
||||
sl /= (lmin <= 1) ? lmin : 2 - lmin;
|
||||
sl = sl || 0;
|
||||
l /= 2;
|
||||
|
||||
return [h, sl * 100, l * 100];
|
||||
};
|
||||
|
||||
// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
|
||||
convert.hwb.rgb = function (hwb) {
|
||||
const h = hwb[0] / 360;
|
||||
let wh = hwb[1] / 100;
|
||||
let bl = hwb[2] / 100;
|
||||
const ratio = wh + bl;
|
||||
let f;
|
||||
|
||||
// Wh + bl cant be > 1
|
||||
if (ratio > 1) {
|
||||
wh /= ratio;
|
||||
bl /= ratio;
|
||||
}
|
||||
|
||||
const i = Math.floor(6 * h);
|
||||
const v = 1 - bl;
|
||||
f = 6 * h - i;
|
||||
|
||||
if ((i & 0x01) !== 0) {
|
||||
f = 1 - f;
|
||||
}
|
||||
|
||||
const n = wh + f * (v - wh); // Linear interpolation
|
||||
|
||||
let r;
|
||||
let g;
|
||||
let b;
|
||||
/* eslint-disable max-statements-per-line,no-multi-spaces */
|
||||
switch (i) {
|
||||
default:
|
||||
case 6:
|
||||
case 0: r = v; g = n; b = wh; break;
|
||||
case 1: r = n; g = v; b = wh; break;
|
||||
case 2: r = wh; g = v; b = n; break;
|
||||
case 3: r = wh; g = n; b = v; break;
|
||||
case 4: r = n; g = wh; b = v; break;
|
||||
case 5: r = v; g = wh; b = n; break;
|
||||
}
|
||||
/* eslint-enable max-statements-per-line,no-multi-spaces */
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
};
|
||||
|
||||
convert.cmyk.rgb = function (cmyk) {
|
||||
const c = cmyk[0] / 100;
|
||||
const m = cmyk[1] / 100;
|
||||
const y = cmyk[2] / 100;
|
||||
const k = cmyk[3] / 100;
|
||||
|
||||
const r = 1 - Math.min(1, c * (1 - k) + k);
|
||||
const g = 1 - Math.min(1, m * (1 - k) + k);
|
||||
const b = 1 - Math.min(1, y * (1 - k) + k);
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
};
|
||||
|
||||
convert.xyz.rgb = function (xyz) {
|
||||
const x = xyz[0] / 100;
|
||||
const y = xyz[1] / 100;
|
||||
const z = xyz[2] / 100;
|
||||
let r;
|
||||
let g;
|
||||
let b;
|
||||
|
||||
r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
|
||||
g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
|
||||
b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
|
||||
|
||||
// Assume sRGB
|
||||
r = r > 0.0031308
|
||||
? ((1.055 * (r ** (1.0 / 2.4))) - 0.055)
|
||||
: r * 12.92;
|
||||
|
||||
g = g > 0.0031308
|
||||
? ((1.055 * (g ** (1.0 / 2.4))) - 0.055)
|
||||
: g * 12.92;
|
||||
|
||||
b = b > 0.0031308
|
||||
? ((1.055 * (b ** (1.0 / 2.4))) - 0.055)
|
||||
: b * 12.92;
|
||||
|
||||
r = Math.min(Math.max(0, r), 1);
|
||||
g = Math.min(Math.max(0, g), 1);
|
||||
b = Math.min(Math.max(0, b), 1);
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
};
|
||||
|
||||
convert.xyz.lab = function (xyz) {
|
||||
let x = xyz[0];
|
||||
let y = xyz[1];
|
||||
let z = xyz[2];
|
||||
|
||||
x /= 95.047;
|
||||
y /= 100;
|
||||
z /= 108.883;
|
||||
|
||||
x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);
|
||||
y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);
|
||||
z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);
|
||||
|
||||
const l = (116 * y) - 16;
|
||||
const a = 500 * (x - y);
|
||||
const b = 200 * (y - z);
|
||||
|
||||
return [l, a, b];
|
||||
};
|
||||
|
||||
convert.lab.xyz = function (lab) {
|
||||
const l = lab[0];
|
||||
const a = lab[1];
|
||||
const b = lab[2];
|
||||
let x;
|
||||
let y;
|
||||
let z;
|
||||
|
||||
y = (l + 16) / 116;
|
||||
x = a / 500 + y;
|
||||
z = y - b / 200;
|
||||
|
||||
const y2 = y ** 3;
|
||||
const x2 = x ** 3;
|
||||
const z2 = z ** 3;
|
||||
y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
|
||||
x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
|
||||
z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
|
||||
|
||||
x *= 95.047;
|
||||
y *= 100;
|
||||
z *= 108.883;
|
||||
|
||||
return [x, y, z];
|
||||
};
|
||||
|
||||
convert.lab.lch = function (lab) {
|
||||
const l = lab[0];
|
||||
const a = lab[1];
|
||||
const b = lab[2];
|
||||
let h;
|
||||
|
||||
const hr = Math.atan2(b, a);
|
||||
h = hr * 360 / 2 / Math.PI;
|
||||
|
||||
if (h < 0) {
|
||||
h += 360;
|
||||
}
|
||||
|
||||
const c = Math.sqrt(a * a + b * b);
|
||||
|
||||
return [l, c, h];
|
||||
};
|
||||
|
||||
convert.lch.lab = function (lch) {
|
||||
const l = lch[0];
|
||||
const c = lch[1];
|
||||
const h = lch[2];
|
||||
|
||||
const hr = h / 360 * 2 * Math.PI;
|
||||
const a = c * Math.cos(hr);
|
||||
const b = c * Math.sin(hr);
|
||||
|
||||
return [l, a, b];
|
||||
};
|
||||
|
||||
convert.rgb.ansi16 = function (args, saturation = null) {
|
||||
const [r, g, b] = args;
|
||||
let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; // Hsv -> ansi16 optimization
|
||||
|
||||
value = Math.round(value / 50);
|
||||
|
||||
if (value === 0) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
let ansi = 30
|
||||
+ ((Math.round(b / 255) << 2)
|
||||
| (Math.round(g / 255) << 1)
|
||||
| Math.round(r / 255));
|
||||
|
||||
if (value === 2) {
|
||||
ansi += 60;
|
||||
}
|
||||
|
||||
return ansi;
|
||||
};
|
||||
|
||||
convert.hsv.ansi16 = function (args) {
|
||||
// Optimization here; we already know the value and don't need to get
|
||||
// it converted for us.
|
||||
return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
|
||||
};
|
||||
|
||||
convert.rgb.ansi256 = function (args) {
|
||||
const r = args[0];
|
||||
const g = args[1];
|
||||
const b = args[2];
|
||||
|
||||
// We use the extended greyscale palette here, with the exception of
|
||||
// black and white. normal palette only has 4 greyscale shades.
|
||||
if (r === g && g === b) {
|
||||
if (r < 8) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (r > 248) {
|
||||
return 231;
|
||||
}
|
||||
|
||||
return Math.round(((r - 8) / 247) * 24) + 232;
|
||||
}
|
||||
|
||||
const ansi = 16
|
||||
+ (36 * Math.round(r / 255 * 5))
|
||||
+ (6 * Math.round(g / 255 * 5))
|
||||
+ Math.round(b / 255 * 5);
|
||||
|
||||
return ansi;
|
||||
};
|
||||
|
||||
convert.ansi16.rgb = function (args) {
|
||||
let color = args % 10;
|
||||
|
||||
// Handle greyscale
|
||||
if (color === 0 || color === 7) {
|
||||
if (args > 50) {
|
||||
color += 3.5;
|
||||
}
|
||||
|
||||
color = color / 10.5 * 255;
|
||||
|
||||
return [color, color, color];
|
||||
}
|
||||
|
||||
const mult = (~~(args > 50) + 1) * 0.5;
|
||||
const r = ((color & 1) * mult) * 255;
|
||||
const g = (((color >> 1) & 1) * mult) * 255;
|
||||
const b = (((color >> 2) & 1) * mult) * 255;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
convert.ansi256.rgb = function (args) {
|
||||
// Handle greyscale
|
||||
if (args >= 232) {
|
||||
const c = (args - 232) * 10 + 8;
|
||||
return [c, c, c];
|
||||
}
|
||||
|
||||
args -= 16;
|
||||
|
||||
let rem;
|
||||
const r = Math.floor(args / 36) / 5 * 255;
|
||||
const g = Math.floor((rem = args % 36) / 6) / 5 * 255;
|
||||
const b = (rem % 6) / 5 * 255;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
convert.rgb.hex = function (args) {
|
||||
const integer = ((Math.round(args[0]) & 0xFF) << 16)
|
||||
+ ((Math.round(args[1]) & 0xFF) << 8)
|
||||
+ (Math.round(args[2]) & 0xFF);
|
||||
|
||||
const string = integer.toString(16).toUpperCase();
|
||||
return '000000'.substring(string.length) + string;
|
||||
};
|
||||
|
||||
convert.hex.rgb = function (args) {
|
||||
const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
|
||||
if (!match) {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
|
||||
let colorString = match[0];
|
||||
|
||||
if (match[0].length === 3) {
|
||||
colorString = colorString.split('').map(char => {
|
||||
return char + char;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
const integer = parseInt(colorString, 16);
|
||||
const r = (integer >> 16) & 0xFF;
|
||||
const g = (integer >> 8) & 0xFF;
|
||||
const b = integer & 0xFF;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
convert.rgb.hcg = function (rgb) {
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
const max = Math.max(Math.max(r, g), b);
|
||||
const min = Math.min(Math.min(r, g), b);
|
||||
const chroma = (max - min);
|
||||
let grayscale;
|
||||
let hue;
|
||||
|
||||
if (chroma < 1) {
|
||||
grayscale = min / (1 - chroma);
|
||||
} else {
|
||||
grayscale = 0;
|
||||
}
|
||||
|
||||
if (chroma <= 0) {
|
||||
hue = 0;
|
||||
} else
|
||||
if (max === r) {
|
||||
hue = ((g - b) / chroma) % 6;
|
||||
} else
|
||||
if (max === g) {
|
||||
hue = 2 + (b - r) / chroma;
|
||||
} else {
|
||||
hue = 4 + (r - g) / chroma;
|
||||
}
|
||||
|
||||
hue /= 6;
|
||||
hue %= 1;
|
||||
|
||||
return [hue * 360, chroma * 100, grayscale * 100];
|
||||
};
|
||||
|
||||
convert.hsl.hcg = function (hsl) {
|
||||
const s = hsl[1] / 100;
|
||||
const l = hsl[2] / 100;
|
||||
|
||||
const c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l));
|
||||
|
||||
let f = 0;
|
||||
if (c < 1.0) {
|
||||
f = (l - 0.5 * c) / (1.0 - c);
|
||||
}
|
||||
|
||||
return [hsl[0], c * 100, f * 100];
|
||||
};
|
||||
|
||||
convert.hsv.hcg = function (hsv) {
|
||||
const s = hsv[1] / 100;
|
||||
const v = hsv[2] / 100;
|
||||
|
||||
const c = s * v;
|
||||
let f = 0;
|
||||
|
||||
if (c < 1.0) {
|
||||
f = (v - c) / (1 - c);
|
||||
}
|
||||
|
||||
return [hsv[0], c * 100, f * 100];
|
||||
};
|
||||
|
||||
convert.hcg.rgb = function (hcg) {
|
||||
const h = hcg[0] / 360;
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
|
||||
if (c === 0.0) {
|
||||
return [g * 255, g * 255, g * 255];
|
||||
}
|
||||
|
||||
const pure = [0, 0, 0];
|
||||
const hi = (h % 1) * 6;
|
||||
const v = hi % 1;
|
||||
const w = 1 - v;
|
||||
let mg = 0;
|
||||
|
||||
/* eslint-disable max-statements-per-line */
|
||||
switch (Math.floor(hi)) {
|
||||
case 0:
|
||||
pure[0] = 1; pure[1] = v; pure[2] = 0; break;
|
||||
case 1:
|
||||
pure[0] = w; pure[1] = 1; pure[2] = 0; break;
|
||||
case 2:
|
||||
pure[0] = 0; pure[1] = 1; pure[2] = v; break;
|
||||
case 3:
|
||||
pure[0] = 0; pure[1] = w; pure[2] = 1; break;
|
||||
case 4:
|
||||
pure[0] = v; pure[1] = 0; pure[2] = 1; break;
|
||||
default:
|
||||
pure[0] = 1; pure[1] = 0; pure[2] = w;
|
||||
}
|
||||
/* eslint-enable max-statements-per-line */
|
||||
|
||||
mg = (1.0 - c) * g;
|
||||
|
||||
return [
|
||||
(c * pure[0] + mg) * 255,
|
||||
(c * pure[1] + mg) * 255,
|
||||
(c * pure[2] + mg) * 255
|
||||
];
|
||||
};
|
||||
|
||||
convert.hcg.hsv = function (hcg) {
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
|
||||
const v = c + g * (1.0 - c);
|
||||
let f = 0;
|
||||
|
||||
if (v > 0.0) {
|
||||
f = c / v;
|
||||
}
|
||||
|
||||
return [hcg[0], f * 100, v * 100];
|
||||
};
|
||||
|
||||
convert.hcg.hsl = function (hcg) {
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
|
||||
const l = g * (1.0 - c) + 0.5 * c;
|
||||
let s = 0;
|
||||
|
||||
if (l > 0.0 && l < 0.5) {
|
||||
s = c / (2 * l);
|
||||
} else
|
||||
if (l >= 0.5 && l < 1.0) {
|
||||
s = c / (2 * (1 - l));
|
||||
}
|
||||
|
||||
return [hcg[0], s * 100, l * 100];
|
||||
};
|
||||
|
||||
convert.hcg.hwb = function (hcg) {
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
const v = c + g * (1.0 - c);
|
||||
return [hcg[0], (v - c) * 100, (1 - v) * 100];
|
||||
};
|
||||
|
||||
convert.hwb.hcg = function (hwb) {
|
||||
const w = hwb[1] / 100;
|
||||
const b = hwb[2] / 100;
|
||||
const v = 1 - b;
|
||||
const c = v - w;
|
||||
let g = 0;
|
||||
|
||||
if (c < 1) {
|
||||
g = (v - c) / (1 - c);
|
||||
}
|
||||
|
||||
return [hwb[0], c * 100, g * 100];
|
||||
};
|
||||
|
||||
convert.apple.rgb = function (apple) {
|
||||
return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
|
||||
};
|
||||
|
||||
convert.rgb.apple = function (rgb) {
|
||||
return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
|
||||
};
|
||||
|
||||
convert.gray.rgb = function (args) {
|
||||
return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
|
||||
};
|
||||
|
||||
convert.gray.hsl = function (args) {
|
||||
return [0, 0, args[0]];
|
||||
};
|
||||
|
||||
convert.gray.hsv = convert.gray.hsl;
|
||||
|
||||
convert.gray.hwb = function (gray) {
|
||||
return [0, 100, gray[0]];
|
||||
};
|
||||
|
||||
convert.gray.cmyk = function (gray) {
|
||||
return [0, 0, 0, gray[0]];
|
||||
};
|
||||
|
||||
convert.gray.lab = function (gray) {
|
||||
return [gray[0], 0, 0];
|
||||
};
|
||||
|
||||
convert.gray.hex = function (gray) {
|
||||
const val = Math.round(gray[0] / 100 * 255) & 0xFF;
|
||||
const integer = (val << 16) + (val << 8) + val;
|
||||
|
||||
const string = integer.toString(16).toUpperCase();
|
||||
return '000000'.substring(string.length) + string;
|
||||
};
|
||||
|
||||
convert.rgb.gray = function (rgb) {
|
||||
const val = (rgb[0] + rgb[1] + rgb[2]) / 3;
|
||||
return [val / 255 * 100];
|
||||
};
|
||||
81
my-app/node_modules/karma/node_modules/color-convert/index.js
generated
vendored
Executable file
81
my-app/node_modules/karma/node_modules/color-convert/index.js
generated
vendored
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
const conversions = require('./conversions');
|
||||
const route = require('./route');
|
||||
|
||||
const convert = {};
|
||||
|
||||
const models = Object.keys(conversions);
|
||||
|
||||
function wrapRaw(fn) {
|
||||
const wrappedFn = function (...args) {
|
||||
const arg0 = args[0];
|
||||
if (arg0 === undefined || arg0 === null) {
|
||||
return arg0;
|
||||
}
|
||||
|
||||
if (arg0.length > 1) {
|
||||
args = arg0;
|
||||
}
|
||||
|
||||
return fn(args);
|
||||
};
|
||||
|
||||
// Preserve .conversion property if there is one
|
||||
if ('conversion' in fn) {
|
||||
wrappedFn.conversion = fn.conversion;
|
||||
}
|
||||
|
||||
return wrappedFn;
|
||||
}
|
||||
|
||||
function wrapRounded(fn) {
|
||||
const wrappedFn = function (...args) {
|
||||
const arg0 = args[0];
|
||||
|
||||
if (arg0 === undefined || arg0 === null) {
|
||||
return arg0;
|
||||
}
|
||||
|
||||
if (arg0.length > 1) {
|
||||
args = arg0;
|
||||
}
|
||||
|
||||
const result = fn(args);
|
||||
|
||||
// We're assuming the result is an array here.
|
||||
// see notice in conversions.js; don't use box types
|
||||
// in conversion functions.
|
||||
if (typeof result === 'object') {
|
||||
for (let len = result.length, i = 0; i < len; i++) {
|
||||
result[i] = Math.round(result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Preserve .conversion property if there is one
|
||||
if ('conversion' in fn) {
|
||||
wrappedFn.conversion = fn.conversion;
|
||||
}
|
||||
|
||||
return wrappedFn;
|
||||
}
|
||||
|
||||
models.forEach(fromModel => {
|
||||
convert[fromModel] = {};
|
||||
|
||||
Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
|
||||
Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
|
||||
|
||||
const routes = route(fromModel);
|
||||
const routeModels = Object.keys(routes);
|
||||
|
||||
routeModels.forEach(toModel => {
|
||||
const fn = routes[toModel];
|
||||
|
||||
convert[fromModel][toModel] = wrapRounded(fn);
|
||||
convert[fromModel][toModel].raw = wrapRaw(fn);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = convert;
|
||||
48
my-app/node_modules/karma/node_modules/color-convert/package.json
generated
vendored
Executable file
48
my-app/node_modules/karma/node_modules/color-convert/package.json
generated
vendored
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "color-convert",
|
||||
"description": "Plain color conversion functions",
|
||||
"version": "2.0.1",
|
||||
"author": "Heather Arthur <fayearthur@gmail.com>",
|
||||
"license": "MIT",
|
||||
"repository": "Qix-/color-convert",
|
||||
"scripts": {
|
||||
"pretest": "xo",
|
||||
"test": "node test/basic.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"color",
|
||||
"colour",
|
||||
"convert",
|
||||
"converter",
|
||||
"conversion",
|
||||
"rgb",
|
||||
"hsl",
|
||||
"hsv",
|
||||
"hwb",
|
||||
"cmyk",
|
||||
"ansi",
|
||||
"ansi16"
|
||||
],
|
||||
"files": [
|
||||
"index.js",
|
||||
"conversions.js",
|
||||
"route.js"
|
||||
],
|
||||
"xo": {
|
||||
"rules": {
|
||||
"default-case": 0,
|
||||
"no-inline-comments": 0,
|
||||
"operator-linebreak": 0
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"xo": "^0.24.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
}
|
||||
97
my-app/node_modules/karma/node_modules/color-convert/route.js
generated
vendored
Executable file
97
my-app/node_modules/karma/node_modules/color-convert/route.js
generated
vendored
Executable file
|
|
@ -0,0 +1,97 @@
|
|||
const conversions = require('./conversions');
|
||||
|
||||
/*
|
||||
This function routes a model to all other models.
|
||||
|
||||
all functions that are routed have a property `.conversion` attached
|
||||
to the returned synthetic function. This property is an array
|
||||
of strings, each with the steps in between the 'from' and 'to'
|
||||
color models (inclusive).
|
||||
|
||||
conversions that are not possible simply are not included.
|
||||
*/
|
||||
|
||||
function buildGraph() {
|
||||
const graph = {};
|
||||
// https://jsperf.com/object-keys-vs-for-in-with-closure/3
|
||||
const models = Object.keys(conversions);
|
||||
|
||||
for (let len = models.length, i = 0; i < len; i++) {
|
||||
graph[models[i]] = {
|
||||
// http://jsperf.com/1-vs-infinity
|
||||
// micro-opt, but this is simple.
|
||||
distance: -1,
|
||||
parent: null
|
||||
};
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Breadth-first_search
|
||||
function deriveBFS(fromModel) {
|
||||
const graph = buildGraph();
|
||||
const queue = [fromModel]; // Unshift -> queue -> pop
|
||||
|
||||
graph[fromModel].distance = 0;
|
||||
|
||||
while (queue.length) {
|
||||
const current = queue.pop();
|
||||
const adjacents = Object.keys(conversions[current]);
|
||||
|
||||
for (let len = adjacents.length, i = 0; i < len; i++) {
|
||||
const adjacent = adjacents[i];
|
||||
const node = graph[adjacent];
|
||||
|
||||
if (node.distance === -1) {
|
||||
node.distance = graph[current].distance + 1;
|
||||
node.parent = current;
|
||||
queue.unshift(adjacent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
function link(from, to) {
|
||||
return function (args) {
|
||||
return to(from(args));
|
||||
};
|
||||
}
|
||||
|
||||
function wrapConversion(toModel, graph) {
|
||||
const path = [graph[toModel].parent, toModel];
|
||||
let fn = conversions[graph[toModel].parent][toModel];
|
||||
|
||||
let cur = graph[toModel].parent;
|
||||
while (graph[cur].parent) {
|
||||
path.unshift(graph[cur].parent);
|
||||
fn = link(conversions[graph[cur].parent][cur], fn);
|
||||
cur = graph[cur].parent;
|
||||
}
|
||||
|
||||
fn.conversion = path;
|
||||
return fn;
|
||||
}
|
||||
|
||||
module.exports = function (fromModel) {
|
||||
const graph = deriveBFS(fromModel);
|
||||
const conversion = {};
|
||||
|
||||
const models = Object.keys(graph);
|
||||
for (let len = models.length, i = 0; i < len; i++) {
|
||||
const toModel = models[i];
|
||||
const node = graph[toModel];
|
||||
|
||||
if (node.parent === null) {
|
||||
// No possible conversion, or this node is the source model.
|
||||
continue;
|
||||
}
|
||||
|
||||
conversion[toModel] = wrapConversion(toModel, graph);
|
||||
}
|
||||
|
||||
return conversion;
|
||||
};
|
||||
|
||||
8
my-app/node_modules/karma/node_modules/color-name/LICENSE
generated
vendored
Executable file
8
my-app/node_modules/karma/node_modules/color-name/LICENSE
generated
vendored
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) 2015 Dmitry Ivanov
|
||||
|
||||
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.
|
||||
11
my-app/node_modules/karma/node_modules/color-name/README.md
generated
vendored
Executable file
11
my-app/node_modules/karma/node_modules/color-name/README.md
generated
vendored
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
|
||||
|
||||
[](https://nodei.co/npm/color-name/)
|
||||
|
||||
|
||||
```js
|
||||
var colors = require('color-name');
|
||||
colors.red //[255,0,0]
|
||||
```
|
||||
|
||||
<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
|
||||
152
my-app/node_modules/karma/node_modules/color-name/index.js
generated
vendored
Executable file
152
my-app/node_modules/karma/node_modules/color-name/index.js
generated
vendored
Executable file
|
|
@ -0,0 +1,152 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
"aliceblue": [240, 248, 255],
|
||||
"antiquewhite": [250, 235, 215],
|
||||
"aqua": [0, 255, 255],
|
||||
"aquamarine": [127, 255, 212],
|
||||
"azure": [240, 255, 255],
|
||||
"beige": [245, 245, 220],
|
||||
"bisque": [255, 228, 196],
|
||||
"black": [0, 0, 0],
|
||||
"blanchedalmond": [255, 235, 205],
|
||||
"blue": [0, 0, 255],
|
||||
"blueviolet": [138, 43, 226],
|
||||
"brown": [165, 42, 42],
|
||||
"burlywood": [222, 184, 135],
|
||||
"cadetblue": [95, 158, 160],
|
||||
"chartreuse": [127, 255, 0],
|
||||
"chocolate": [210, 105, 30],
|
||||
"coral": [255, 127, 80],
|
||||
"cornflowerblue": [100, 149, 237],
|
||||
"cornsilk": [255, 248, 220],
|
||||
"crimson": [220, 20, 60],
|
||||
"cyan": [0, 255, 255],
|
||||
"darkblue": [0, 0, 139],
|
||||
"darkcyan": [0, 139, 139],
|
||||
"darkgoldenrod": [184, 134, 11],
|
||||
"darkgray": [169, 169, 169],
|
||||
"darkgreen": [0, 100, 0],
|
||||
"darkgrey": [169, 169, 169],
|
||||
"darkkhaki": [189, 183, 107],
|
||||
"darkmagenta": [139, 0, 139],
|
||||
"darkolivegreen": [85, 107, 47],
|
||||
"darkorange": [255, 140, 0],
|
||||
"darkorchid": [153, 50, 204],
|
||||
"darkred": [139, 0, 0],
|
||||
"darksalmon": [233, 150, 122],
|
||||
"darkseagreen": [143, 188, 143],
|
||||
"darkslateblue": [72, 61, 139],
|
||||
"darkslategray": [47, 79, 79],
|
||||
"darkslategrey": [47, 79, 79],
|
||||
"darkturquoise": [0, 206, 209],
|
||||
"darkviolet": [148, 0, 211],
|
||||
"deeppink": [255, 20, 147],
|
||||
"deepskyblue": [0, 191, 255],
|
||||
"dimgray": [105, 105, 105],
|
||||
"dimgrey": [105, 105, 105],
|
||||
"dodgerblue": [30, 144, 255],
|
||||
"firebrick": [178, 34, 34],
|
||||
"floralwhite": [255, 250, 240],
|
||||
"forestgreen": [34, 139, 34],
|
||||
"fuchsia": [255, 0, 255],
|
||||
"gainsboro": [220, 220, 220],
|
||||
"ghostwhite": [248, 248, 255],
|
||||
"gold": [255, 215, 0],
|
||||
"goldenrod": [218, 165, 32],
|
||||
"gray": [128, 128, 128],
|
||||
"green": [0, 128, 0],
|
||||
"greenyellow": [173, 255, 47],
|
||||
"grey": [128, 128, 128],
|
||||
"honeydew": [240, 255, 240],
|
||||
"hotpink": [255, 105, 180],
|
||||
"indianred": [205, 92, 92],
|
||||
"indigo": [75, 0, 130],
|
||||
"ivory": [255, 255, 240],
|
||||
"khaki": [240, 230, 140],
|
||||
"lavender": [230, 230, 250],
|
||||
"lavenderblush": [255, 240, 245],
|
||||
"lawngreen": [124, 252, 0],
|
||||
"lemonchiffon": [255, 250, 205],
|
||||
"lightblue": [173, 216, 230],
|
||||
"lightcoral": [240, 128, 128],
|
||||
"lightcyan": [224, 255, 255],
|
||||
"lightgoldenrodyellow": [250, 250, 210],
|
||||
"lightgray": [211, 211, 211],
|
||||
"lightgreen": [144, 238, 144],
|
||||
"lightgrey": [211, 211, 211],
|
||||
"lightpink": [255, 182, 193],
|
||||
"lightsalmon": [255, 160, 122],
|
||||
"lightseagreen": [32, 178, 170],
|
||||
"lightskyblue": [135, 206, 250],
|
||||
"lightslategray": [119, 136, 153],
|
||||
"lightslategrey": [119, 136, 153],
|
||||
"lightsteelblue": [176, 196, 222],
|
||||
"lightyellow": [255, 255, 224],
|
||||
"lime": [0, 255, 0],
|
||||
"limegreen": [50, 205, 50],
|
||||
"linen": [250, 240, 230],
|
||||
"magenta": [255, 0, 255],
|
||||
"maroon": [128, 0, 0],
|
||||
"mediumaquamarine": [102, 205, 170],
|
||||
"mediumblue": [0, 0, 205],
|
||||
"mediumorchid": [186, 85, 211],
|
||||
"mediumpurple": [147, 112, 219],
|
||||
"mediumseagreen": [60, 179, 113],
|
||||
"mediumslateblue": [123, 104, 238],
|
||||
"mediumspringgreen": [0, 250, 154],
|
||||
"mediumturquoise": [72, 209, 204],
|
||||
"mediumvioletred": [199, 21, 133],
|
||||
"midnightblue": [25, 25, 112],
|
||||
"mintcream": [245, 255, 250],
|
||||
"mistyrose": [255, 228, 225],
|
||||
"moccasin": [255, 228, 181],
|
||||
"navajowhite": [255, 222, 173],
|
||||
"navy": [0, 0, 128],
|
||||
"oldlace": [253, 245, 230],
|
||||
"olive": [128, 128, 0],
|
||||
"olivedrab": [107, 142, 35],
|
||||
"orange": [255, 165, 0],
|
||||
"orangered": [255, 69, 0],
|
||||
"orchid": [218, 112, 214],
|
||||
"palegoldenrod": [238, 232, 170],
|
||||
"palegreen": [152, 251, 152],
|
||||
"paleturquoise": [175, 238, 238],
|
||||
"palevioletred": [219, 112, 147],
|
||||
"papayawhip": [255, 239, 213],
|
||||
"peachpuff": [255, 218, 185],
|
||||
"peru": [205, 133, 63],
|
||||
"pink": [255, 192, 203],
|
||||
"plum": [221, 160, 221],
|
||||
"powderblue": [176, 224, 230],
|
||||
"purple": [128, 0, 128],
|
||||
"rebeccapurple": [102, 51, 153],
|
||||
"red": [255, 0, 0],
|
||||
"rosybrown": [188, 143, 143],
|
||||
"royalblue": [65, 105, 225],
|
||||
"saddlebrown": [139, 69, 19],
|
||||
"salmon": [250, 128, 114],
|
||||
"sandybrown": [244, 164, 96],
|
||||
"seagreen": [46, 139, 87],
|
||||
"seashell": [255, 245, 238],
|
||||
"sienna": [160, 82, 45],
|
||||
"silver": [192, 192, 192],
|
||||
"skyblue": [135, 206, 235],
|
||||
"slateblue": [106, 90, 205],
|
||||
"slategray": [112, 128, 144],
|
||||
"slategrey": [112, 128, 144],
|
||||
"snow": [255, 250, 250],
|
||||
"springgreen": [0, 255, 127],
|
||||
"steelblue": [70, 130, 180],
|
||||
"tan": [210, 180, 140],
|
||||
"teal": [0, 128, 128],
|
||||
"thistle": [216, 191, 216],
|
||||
"tomato": [255, 99, 71],
|
||||
"turquoise": [64, 224, 208],
|
||||
"violet": [238, 130, 238],
|
||||
"wheat": [245, 222, 179],
|
||||
"white": [255, 255, 255],
|
||||
"whitesmoke": [245, 245, 245],
|
||||
"yellow": [255, 255, 0],
|
||||
"yellowgreen": [154, 205, 50]
|
||||
};
|
||||
28
my-app/node_modules/karma/node_modules/color-name/package.json
generated
vendored
Executable file
28
my-app/node_modules/karma/node_modules/color-name/package.json
generated
vendored
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "color-name",
|
||||
"version": "1.1.4",
|
||||
"description": "A list of color names and its values",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "node test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:colorjs/color-name.git"
|
||||
},
|
||||
"keywords": [
|
||||
"color-name",
|
||||
"color",
|
||||
"color-keyword",
|
||||
"keyword"
|
||||
],
|
||||
"author": "DY <dfcreative@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/colorjs/color-name/issues"
|
||||
},
|
||||
"homepage": "https://github.com/colorjs/color-name"
|
||||
}
|
||||
301
my-app/node_modules/karma/node_modules/source-map/CHANGELOG.md
generated
vendored
Executable file
301
my-app/node_modules/karma/node_modules/source-map/CHANGELOG.md
generated
vendored
Executable file
|
|
@ -0,0 +1,301 @@
|
|||
# Change Log
|
||||
|
||||
## 0.5.6
|
||||
|
||||
* Fix for regression when people were using numbers as names in source maps. See
|
||||
#236.
|
||||
|
||||
## 0.5.5
|
||||
|
||||
* Fix "regression" of unsupported, implementation behavior that half the world
|
||||
happens to have come to depend on. See #235.
|
||||
|
||||
* Fix regression involving function hoisting in SpiderMonkey. See #233.
|
||||
|
||||
## 0.5.4
|
||||
|
||||
* Large performance improvements to source-map serialization. See #228 and #229.
|
||||
|
||||
## 0.5.3
|
||||
|
||||
* Do not include unnecessary distribution files. See
|
||||
commit ef7006f8d1647e0a83fdc60f04f5a7ca54886f86.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
* Include browser distributions of the library in package.json's `files`. See
|
||||
issue #212.
|
||||
|
||||
## 0.5.1
|
||||
|
||||
* Fix latent bugs in IndexedSourceMapConsumer.prototype._parseMappings. See
|
||||
ff05274becc9e6e1295ed60f3ea090d31d843379.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
* Node 0.8 is no longer supported.
|
||||
|
||||
* Use webpack instead of dryice for bundling.
|
||||
|
||||
* Big speedups serializing source maps. See pull request #203.
|
||||
|
||||
* Fix a bug with `SourceMapConsumer.prototype.sourceContentFor` and sources that
|
||||
explicitly start with the source root. See issue #199.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
* Fix an issue where using a `SourceMapGenerator` after having created a
|
||||
`SourceMapConsumer` from it via `SourceMapConsumer.fromSourceMap` failed. See
|
||||
issue #191.
|
||||
|
||||
* Fix an issue with where `SourceMapGenerator` would mistakenly consider
|
||||
different mappings as duplicates of each other and avoid generating them. See
|
||||
issue #192.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
* A very large number of performance improvements, particularly when parsing
|
||||
source maps. Collectively about 75% of time shaved off of the source map
|
||||
parsing benchmark!
|
||||
|
||||
* Fix a bug in `SourceMapConsumer.prototype.allGeneratedPositionsFor` and fuzzy
|
||||
searching in the presence of a column option. See issue #177.
|
||||
|
||||
* Fix a bug with joining a source and its source root when the source is above
|
||||
the root. See issue #182.
|
||||
|
||||
* Add the `SourceMapConsumer.prototype.hasContentsOfAllSources` method to
|
||||
determine when all sources' contents are inlined into the source map. See
|
||||
issue #190.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
* Add an `.npmignore` file so that the benchmarks aren't pulled down by
|
||||
dependent projects. Issue #169.
|
||||
|
||||
* Add an optional `column` argument to
|
||||
`SourceMapConsumer.prototype.allGeneratedPositionsFor` and better handle lines
|
||||
with no mappings. Issues #172 and #173.
|
||||
|
||||
## 0.4.1
|
||||
|
||||
* Fix accidentally defining a global variable. #170.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
* The default direction for fuzzy searching was changed back to its original
|
||||
direction. See #164.
|
||||
|
||||
* There is now a `bias` option you can supply to `SourceMapConsumer` to control
|
||||
the fuzzy searching direction. See #167.
|
||||
|
||||
* About an 8% speed up in parsing source maps. See #159.
|
||||
|
||||
* Added a benchmark for parsing and generating source maps.
|
||||
|
||||
## 0.3.0
|
||||
|
||||
* Change the default direction that searching for positions fuzzes when there is
|
||||
not an exact match. See #154.
|
||||
|
||||
* Support for environments using json2.js for JSON serialization. See #156.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
* Support for consuming "indexed" source maps which do not have any remote
|
||||
sections. See pull request #127. This introduces a minor backwards
|
||||
incompatibility if you are monkey patching `SourceMapConsumer.prototype`
|
||||
methods.
|
||||
|
||||
## 0.1.43
|
||||
|
||||
* Performance improvements for `SourceMapGenerator` and `SourceNode`. See issue
|
||||
#148 for some discussion and issues #150, #151, and #152 for implementations.
|
||||
|
||||
## 0.1.42
|
||||
|
||||
* Fix an issue where `SourceNode`s from different versions of the source-map
|
||||
library couldn't be used in conjunction with each other. See issue #142.
|
||||
|
||||
## 0.1.41
|
||||
|
||||
* Fix a bug with getting the source content of relative sources with a "./"
|
||||
prefix. See issue #145 and [Bug 1090768](bugzil.la/1090768).
|
||||
|
||||
* Add the `SourceMapConsumer.prototype.computeColumnSpans` method to compute the
|
||||
column span of each mapping.
|
||||
|
||||
* Add the `SourceMapConsumer.prototype.allGeneratedPositionsFor` method to find
|
||||
all generated positions associated with a given original source and line.
|
||||
|
||||
## 0.1.40
|
||||
|
||||
* Performance improvements for parsing source maps in SourceMapConsumer.
|
||||
|
||||
## 0.1.39
|
||||
|
||||
* Fix a bug where setting a source's contents to null before any source content
|
||||
had been set before threw a TypeError. See issue #131.
|
||||
|
||||
## 0.1.38
|
||||
|
||||
* Fix a bug where finding relative paths from an empty path were creating
|
||||
absolute paths. See issue #129.
|
||||
|
||||
## 0.1.37
|
||||
|
||||
* Fix a bug where if the source root was an empty string, relative source paths
|
||||
would turn into absolute source paths. Issue #124.
|
||||
|
||||
## 0.1.36
|
||||
|
||||
* Allow the `names` mapping property to be an empty string. Issue #121.
|
||||
|
||||
## 0.1.35
|
||||
|
||||
* A third optional parameter was added to `SourceNode.fromStringWithSourceMap`
|
||||
to specify a path that relative sources in the second parameter should be
|
||||
relative to. Issue #105.
|
||||
|
||||
* If no file property is given to a `SourceMapGenerator`, then the resulting
|
||||
source map will no longer have a `null` file property. The property will
|
||||
simply not exist. Issue #104.
|
||||
|
||||
* Fixed a bug where consecutive newlines were ignored in `SourceNode`s.
|
||||
Issue #116.
|
||||
|
||||
## 0.1.34
|
||||
|
||||
* Make `SourceNode` work with windows style ("\r\n") newlines. Issue #103.
|
||||
|
||||
* Fix bug involving source contents and the
|
||||
`SourceMapGenerator.prototype.applySourceMap`. Issue #100.
|
||||
|
||||
## 0.1.33
|
||||
|
||||
* Fix some edge cases surrounding path joining and URL resolution.
|
||||
|
||||
* Add a third parameter for relative path to
|
||||
`SourceMapGenerator.prototype.applySourceMap`.
|
||||
|
||||
* Fix issues with mappings and EOLs.
|
||||
|
||||
## 0.1.32
|
||||
|
||||
* Fixed a bug where SourceMapConsumer couldn't handle negative relative columns
|
||||
(issue 92).
|
||||
|
||||
* Fixed test runner to actually report number of failed tests as its process
|
||||
exit code.
|
||||
|
||||
* Fixed a typo when reporting bad mappings (issue 87).
|
||||
|
||||
## 0.1.31
|
||||
|
||||
* Delay parsing the mappings in SourceMapConsumer until queried for a source
|
||||
location.
|
||||
|
||||
* Support Sass source maps (which at the time of writing deviate from the spec
|
||||
in small ways) in SourceMapConsumer.
|
||||
|
||||
## 0.1.30
|
||||
|
||||
* Do not join source root with a source, when the source is a data URI.
|
||||
|
||||
* Extend the test runner to allow running single specific test files at a time.
|
||||
|
||||
* Performance improvements in `SourceNode.prototype.walk` and
|
||||
`SourceMapConsumer.prototype.eachMapping`.
|
||||
|
||||
* Source map browser builds will now work inside Workers.
|
||||
|
||||
* Better error messages when attempting to add an invalid mapping to a
|
||||
`SourceMapGenerator`.
|
||||
|
||||
## 0.1.29
|
||||
|
||||
* Allow duplicate entries in the `names` and `sources` arrays of source maps
|
||||
(usually from TypeScript) we are parsing. Fixes github issue 72.
|
||||
|
||||
## 0.1.28
|
||||
|
||||
* Skip duplicate mappings when creating source maps from SourceNode; github
|
||||
issue 75.
|
||||
|
||||
## 0.1.27
|
||||
|
||||
* Don't throw an error when the `file` property is missing in SourceMapConsumer,
|
||||
we don't use it anyway.
|
||||
|
||||
## 0.1.26
|
||||
|
||||
* Fix SourceNode.fromStringWithSourceMap for empty maps. Fixes github issue 70.
|
||||
|
||||
## 0.1.25
|
||||
|
||||
* Make compatible with browserify
|
||||
|
||||
## 0.1.24
|
||||
|
||||
* Fix issue with absolute paths and `file://` URIs. See
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=885597
|
||||
|
||||
## 0.1.23
|
||||
|
||||
* Fix issue with absolute paths and sourcesContent, github issue 64.
|
||||
|
||||
## 0.1.22
|
||||
|
||||
* Ignore duplicate mappings in SourceMapGenerator. Fixes github issue 21.
|
||||
|
||||
## 0.1.21
|
||||
|
||||
* Fixed handling of sources that start with a slash so that they are relative to
|
||||
the source root's host.
|
||||
|
||||
## 0.1.20
|
||||
|
||||
* Fixed github issue #43: absolute URLs aren't joined with the source root
|
||||
anymore.
|
||||
|
||||
## 0.1.19
|
||||
|
||||
* Using Travis CI to run tests.
|
||||
|
||||
## 0.1.18
|
||||
|
||||
* Fixed a bug in the handling of sourceRoot.
|
||||
|
||||
## 0.1.17
|
||||
|
||||
* Added SourceNode.fromStringWithSourceMap.
|
||||
|
||||
## 0.1.16
|
||||
|
||||
* Added missing documentation.
|
||||
|
||||
* Fixed the generating of empty mappings in SourceNode.
|
||||
|
||||
## 0.1.15
|
||||
|
||||
* Added SourceMapGenerator.applySourceMap.
|
||||
|
||||
## 0.1.14
|
||||
|
||||
* The sourceRoot is now handled consistently.
|
||||
|
||||
## 0.1.13
|
||||
|
||||
* Added SourceMapGenerator.fromSourceMap.
|
||||
|
||||
## 0.1.12
|
||||
|
||||
* SourceNode now generates empty mappings too.
|
||||
|
||||
## 0.1.11
|
||||
|
||||
* Added name support to SourceNode.
|
||||
|
||||
## 0.1.10
|
||||
|
||||
* Added sourcesContent support to the customer and generator.
|
||||
28
my-app/node_modules/karma/node_modules/source-map/LICENSE
generated
vendored
Executable file
28
my-app/node_modules/karma/node_modules/source-map/LICENSE
generated
vendored
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
Copyright (c) 2009-2011, Mozilla Foundation and contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the Mozilla Foundation nor the names of project
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue