diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/webgpu-cts | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/webgpu-cts')
144 files changed, 14753 insertions, 8005 deletions
diff --git a/chromium/third_party/webgpu-cts/src/.eslint-resolver.js b/chromium/third_party/webgpu-cts/src/.eslint-resolver.js new file mode 100644 index 00000000000..e2b0f32d354 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/.eslint-resolver.js @@ -0,0 +1,23 @@ +const path = require('path'); +const resolve = require('resolve') + +// Implements the following resolver spec: +// https://github.com/benmosher/eslint-plugin-import/blob/master/resolvers/README.md +exports.interfaceVersion = 2 + +exports.resolve = function (source, file, config) { + if (resolve.isCore(source)) return { found: true, path: null } + + source = source.replace(/\.js$/, '.ts'); + try { + return { + found: true, path: resolve.sync(source, { + extensions: [], + basedir: path.dirname(path.resolve(file)), + ...config, + }) + } + } catch (err) { + return { found: false } + } +} diff --git a/chromium/third_party/webgpu-cts/src/.eslintrc.json b/chromium/third_party/webgpu-cts/src/.eslintrc.json new file mode 100644 index 00000000000..f4f1d2c1f52 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/.eslintrc.json @@ -0,0 +1,73 @@ +{ + "extends": [ + "./node_modules/gts", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript" + ], + "env": { + "browser": true, + "node": true + }, + "plugins": ["node", "ban", "import"], + "rules": { + "ban/ban": [ + "warn", + { + "name": "setTimeout", + "message": "WPT disallows setTimeout; use `framework/util/timeout.js`." + } + ], + "linebreak-style": ["warn", "unix"], + "object-shorthand": "warn", + "no-console": "warn", + "no-undef": "off", + "no-useless-rename": "warn", + "@typescript-eslint/no-inferrable-types": "off", + "import/order": [ + "warn", + { + "groups": ["builtin", "external", "internal", "parent", "sibling", "index"], + "newlines-between": "always", + "alphabetize": { "order": "asc", "caseInsensitive": false } + } + ], + "import/newline-after-import": ["warn", { "count": 1 }], + "import/no-duplicates": "warn", + "import/no-restricted-paths": [ + "error", + { + "zones": [ + { + "target": "./src/webgpu", + "from": "./src/common", + "except": ["./framework", "./tools/crawl.ts", "./constants.ts"], + "message": "Non-framework common/ code imported from webgpu/ suite" + }, + { + "target": "./src/unittests", + "from": "./src/common", + "except": ["./framework", "./tools/crawl.ts", "./constants.ts"], + "message": "Non-framework common/ code imported from unittests/ suite" + }, + { + "target": "./src/webgpu", + "from": "./src/unittests", + "message": "unittests/ suite imported from webgpu/ suite" + }, + { + "target": "./src/common", + "from": "./src", + "except": ["./common"], + "message": "Non common/ code imported from common/" + } + ] + } + ] + }, + "settings": { + "import/resolver": { + "./.eslint-resolver": {} + } + } +} diff --git a/chromium/third_party/webgpu-cts/src/.travis.yml b/chromium/third_party/webgpu-cts/src/.travis.yml index 7bd2152fa45..86f8bd32494 100644 --- a/chromium/third_party/webgpu-cts/src/.travis.yml +++ b/chromium/third_party/webgpu-cts/src/.travis.yml @@ -2,8 +2,6 @@ language: node_js node_js: - 'node' -before_install: yarn global add grunt-cli - deploy: provider: pages skip_cleanup: true diff --git a/chromium/third_party/webgpu-cts/src/.vscode/tasks.json b/chromium/third_party/webgpu-cts/src/.vscode/tasks.json index 8b8758ae40c..85d45561f8b 100644 --- a/chromium/third_party/webgpu-cts/src/.vscode/tasks.json +++ b/chromium/third_party/webgpu-cts/src/.vscode/tasks.json @@ -14,6 +14,13 @@ "type": "grunt", "task": "pre", "problemMatcher": [] + }, + { + "type": "grunt", + "task": "check", + "problemMatcher": [ + "$tsc" + ] } ] } diff --git a/chromium/third_party/webgpu-cts/src/CONTRIBUTING.md b/chromium/third_party/webgpu-cts/src/CONTRIBUTING.md index faf7df58b06..ce0ea903ad6 100644 --- a/chromium/third_party/webgpu-cts/src/CONTRIBUTING.md +++ b/chromium/third_party/webgpu-cts/src/CONTRIBUTING.md @@ -6,7 +6,7 @@ License Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions, you must join the CG. Contributions to the source code repository are subject to the terms of the -[3-Clause BSD License](https://github.com/gpuweb/admin/blob/SourceCodeLicense/LICENSE.txt). +[3-Clause BSD License](./LICENSE.txt). If you are not the sole contributor to a contribution (pull request), please identify all contributors in the pull request comment. diff --git a/chromium/third_party/webgpu-cts/src/Gruntfile.js b/chromium/third_party/webgpu-cts/src/Gruntfile.js index b0515d09c7a..4cf5c1b86c9 100644 --- a/chromium/third_party/webgpu-cts/src/Gruntfile.js +++ b/chromium/third_party/webgpu-cts/src/Gruntfile.js @@ -8,14 +8,6 @@ module.exports = function (grunt) { out: ['out/', 'out-wpt'], }, - mkdir: { - out: { - options: { - create: ['out'], - }, - }, - }, - run: { 'generate-version': { cmd: 'node', @@ -23,7 +15,7 @@ module.exports = function (grunt) { }, 'generate-listings': { cmd: 'node', - args: ['tools/gen_listings', 'webgpu', 'unittests'], + args: ['tools/gen_listings', 'webgpu', 'unittests', 'demo'], }, 'generate-wpt-cts-html': { cmd: 'node', @@ -31,7 +23,7 @@ module.exports = function (grunt) { }, test: { cmd: 'node', - args: ['tools/run', 'unittests:'], + args: ['tools/run', 'unittests:*'], }, 'build-out': { cmd: 'node', @@ -43,16 +35,26 @@ module.exports = function (grunt) { 'src/', ], }, - 'gts-check': { + lint: { cmd: 'node', - args: ['node_modules/gts/build/src/cli', 'check'], + args: ['node_modules/eslint/bin/eslint', 'src/**/*.ts', '--max-warnings=0'], }, - 'gts-fix': { + fix: { cmd: 'node', - args: ['node_modules/gts/build/src/cli', 'fix'], + args: ['node_modules/eslint/bin/eslint', 'src/**/*.ts', '--fix'], }, }, + watch: { + src: { + files: ['src/**/*'], + tasks: ['run:build-out', 'run:lint'], + options: { + spawn: false, + } + } + }, + copy: { 'webgpu-constants': { files: [ @@ -79,9 +81,10 @@ module.exports = function (grunt) { { expand: true, cwd: '.', src: 'LICENSE.txt', dest: 'out-wpt/' }, { expand: true, cwd: 'out', src: 'common/constants.js', dest: 'out-wpt/' }, { expand: true, cwd: 'out', src: 'common/framework/**/*.js', dest: 'out-wpt/' }, - { expand: true, cwd: 'out', src: 'webgpu/**/*.js', dest: 'out-wpt/' }, { expand: true, cwd: 'out', src: 'common/runtime/wpt.js', dest: 'out-wpt/' }, { expand: true, cwd: 'out', src: 'common/runtime/helper/**/*.js', dest: 'out-wpt/' }, + { expand: true, cwd: 'out', src: 'webgpu/**/*.js', dest: 'out-wpt/' }, + { expand: true, cwd: 'src', src: 'webgpu/**/*.html', dest: 'out-wpt/' }, ], }, }, @@ -93,6 +96,19 @@ module.exports = function (grunt) { host: '127.0.0.1', cache: -1, }, + 'background': { + root: '.', + port: 8080, + host: '127.0.0.1', + cache: -1, + runInBackground: true, + logFn: function (req, res, error) { + // Only log errors to not spam the console. + if (error) { + console.error(error); + } + }, + }, }, ts: { @@ -108,9 +124,19 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-http-server'); - grunt.loadNpmTasks('grunt-mkdir'); grunt.loadNpmTasks('grunt-run'); grunt.loadNpmTasks('grunt-ts'); + grunt.loadNpmTasks('grunt-contrib-watch'); + + grunt.event.on('watch', function (action, filepath) { + const buildArgs = grunt.config(['run', 'build-out', 'args']); + buildArgs[buildArgs.length - 1] = filepath; + grunt.config(['run', 'build-out', 'args'], buildArgs); + + const lintArgs = grunt.config(['run', 'lint', 'args']); + lintArgs[lintArgs.length - 1] = filepath; + grunt.config(['run', 'lint', 'args'], lintArgs); + }); const helpMessageTasks = []; function registerTaskAndAddToHelp(name, desc, deps) { @@ -128,7 +154,6 @@ module.exports = function (grunt) { grunt.registerTask('prebuild', 'Pre-build tasks (clean and re-copy)', [ 'clean', - 'mkdir:out', 'copy:webgpu-constants', 'copy:glslang', ]); @@ -148,7 +173,7 @@ module.exports = function (grunt) { registerTaskAndAddToHelp('pre', 'Run all presubmit checks: build+typecheck+test+lint', [ 'set-quiet-mode', 'wpt', - 'run:gts-check', + 'run:lint', ]); registerTaskAndAddToHelp('test', 'Quick development build: build+typecheck+test', [ 'set-quiet-mode', @@ -171,11 +196,15 @@ module.exports = function (grunt) { 'set-quiet-mode', 'copy:webgpu-constants', 'ts:check', - 'run:gts-check', + 'run:lint', + ]); + registerTaskAndAddToHelp('dev', 'Start the dev server, and watch for changes', [ + 'http-server:background', + 'watch', ]); registerTaskAndAddToHelp('serve', 'Serve out/ on 127.0.0.1:8080', ['http-server:.']); - registerTaskAndAddToHelp('fix', 'Fix lint and formatting', ['run:gts-fix']); + registerTaskAndAddToHelp('fix', 'Fix lint and formatting', ['run:fix']); grunt.registerTask('default', '', () => { console.error('\nAvailable tasks (see grunt --help for info):'); diff --git a/chromium/third_party/webgpu-cts/src/README.md b/chromium/third_party/webgpu-cts/src/README.md index e242cbc8e00..75394d297ed 100644 --- a/chromium/third_party/webgpu-cts/src/README.md +++ b/chromium/third_party/webgpu-cts/src/README.md @@ -19,12 +19,11 @@ The WebGPU CTS is written in TypeScript, and builds into two directories: ### Setup -After checking out the repository and installing Yarn, run these commands to -set up dependencies: +After checking out the repository and installing node/npm, run these commands +in the checkout: ```sh -cd webgpu/ -yarn install +npm install npx grunt # show available grunt commands ``` diff --git a/chromium/third_party/webgpu-cts/src/babel.config.js b/chromium/third_party/webgpu-cts/src/babel.config.js index 947be09cd4a..0ba071db6da 100644 --- a/chromium/third_party/webgpu-cts/src/babel.config.js +++ b/chromium/third_party/webgpu-cts/src/babel.config.js @@ -15,6 +15,6 @@ module.exports = function (api) { ], ], compact: false, - shouldPrintComment: val => !/tslint:/.test(val), + shouldPrintComment: val => !/eslint/.test(val), }; }; diff --git a/chromium/third_party/webgpu-cts/src/docs/terms.md b/chromium/third_party/webgpu-cts/src/docs/terms.md index d718c648fba..be9d83a15ee 100644 --- a/chromium/third_party/webgpu-cts/src/docs/terms.md +++ b/chromium/third_party/webgpu-cts/src/docs/terms.md @@ -1,11 +1,36 @@ # Writing Tests -- _Suites_ contain multiple: - - _READMEs_ - - _Test Spec Files_. Contains one: - - _Test Group_. Defines a _test fixture_ and contains multiple: - - _Tests_. Defines a _test function_ and contains multiple: - - _Test Cases_, each with the same test function but different _parameters_. +Each test suite is organized as a tree, both in the filesystem and further within each file. + +- _Suites_, e.g. `src/webgpu/`. + - _READMEs_, e.g. `src/webgpu/README.txt`. + - _Test Spec Files_, e.g. `src/webgpu/examples.spec.ts`. + Identified by their file path. + Each test spec file provides a description and a _Test Group_. + A _Test Group_ defines a test fixture, and contains multiple: + - _Tests_. + Identified by a comma-separated list of parts (e.g. `basic,async`) + which define a path through a filesystem-like tree (analogy: `basic/async.txt`). + Defines a _test function_ and contains multiple: + - _Test Cases_. + Identified by a list of _Public Parameters_ (e.g. `x` = `1`, `y` = `2`). + Each Test Case has the same test function but different Public Parameters. + +## Test Tree + +A _Test Tree_ is a tree whose leaves are individual Test Cases. + +A Test Tree can be thought of as follows: + +- Suite, which is the root of a tree with "leaves" which are: + - Test Spec Files, each of which is a tree with "leaves" which are: + - Tests, each of which is a tree with leaves which are: + - Test Cases. + +(In the implementation, this conceptual tree of trees is decomposed into one big tree +whose leaves are Test Cases.) + +**Type:** `TestTree` ## Suite @@ -22,30 +47,53 @@ Each member of a suite is identified by its path within the suite. Describes (in prose) the contents of a subdirectory in a suite. -**Type:** After a README is loaded, it is stored as a `ReadmeFile`. +READMEs are only processed at build time, when generating the _Listing_ for a suite. -## IDs +**Type:** `TestSuiteListingEntryReadme` -### Test Spec ID +## Queries -Uniquely identifies a single test spec file. -Comprised of suite name (`suite`) and test spec file path relative to the suite root (`path`). +A _Query_ is a structured object which specifies a subset of cases in exactly one Suite. +A Query can be represented uniquely as a string. +Queries are used to: -**Type:** `TestSpecID` +- Identify a subtree of a suite (by identifying the root node of that subtree). +- Identify individual cases. +- Represent the list of tests that a test runner (standalone, wpt, or cmdline) should run. +- Identify subtrees which should not be "collapsed" during WPT `cts.html` generation, + so that that cts.html "variants" can have individual test expectations + (i.e. marked as "expected to fail", "skip", etc.). -**Example:** `{ suite: 'webgpu', path: 'command_buffer/compute/basic' }` corresponds to -`src/webgpu/command_buffer/compute/basic.spec.ts`. +There are four types of `TestQuery`: -### Test Case ID +- `TestQueryMultiFile` represents any subtree of the file hierarchy: + - `suite:*` + - `suite:path,to,*` + - `suite:path,to,file,*` +- `TestQueryMultiTest` represents any subtree of the test hierarchy: + - `suite:path,to,file:*` + - `suite:path,to,file:path,to,*` + - `suite:path,to,file:path,to,test,*` +- `TestQueryMultiCase` represents any subtree of the case hierarchy: + - `suite:path,to,file:path,to,test:*` + - `suite:path,to,file:path,to,test:my=0;*` + - `suite:path,to,file:path,to,test:my=0;params="here";*` +- `TestQuerySingleCase` represents as single case: + - `suite:path,to,file:path,to,test:my=0;params="here"` -Uniquely identifies a single test case within a test spec. +Test Queries are a **weakly ordered set**: any query is +_Unordered_, _Equal_, _StrictSuperset_, or _StrictSubset_ relative to any other. +This property is used to construct the complete tree of test cases. +In the examples above, every example query is a StrictSubset of the previous one +(note: even `:*` is a subset of `,*`). -Comprised of test name (`test`) and the parameters for a case (`params`). -(If `params` is null, there is only one case for the test.) +In the WPT and standalone harnesses, the query is stored in the URL, e.g. +`index.html?q=q:u,e:r,y:*`. -**Type:** `TestCaseID` +Queries are selectively URL-encoded for readability and compatibility with browsers +(see `encodeURIComponentSelectively`). -**Example:** `{ test: '', params: { 'value': 1 } }` +**Type:** `TestQuery` ## Listing @@ -53,39 +101,35 @@ A listing of the **test spec files** in a suite. This can be generated only in Node, which has filesystem access (see `src/tools/crawl.ts`). As part of the build step, a _listing file_ is generated (see `src/tools/gen.ts`) so that the -test files can be discovered by the web runner (since it does not have filesystem access). +Test Spec Files can be discovered by the web runner (since it does not have filesystem access). **Type:** `TestSuiteListing` ### Listing File -**Example:** `out/webgpu/listing.js` +Each Suite has one Listing File (`suite/listing.[tj]s`), containing a list of the files +in the suite. -## Test Spec +In `src/suite/listing.ts`, this is computed dynamically. +In `out/suite/listing.js`, the listing has been pre-baked (by `tools/gen_listings`). -May be either a _test spec file_ or a _filtered test spec_. -It is identified by a `TestSpecID`. +**Type:** Once `import`ed, `ListingFile` -Always contains one `RunCaseIterable`. +**Example:** `out/webgpu/listing.js` -**Type:** `TestSpec` +## Test Spec File -### Test Spec File +A Test Spec File has a `description` and a Test Group (under which tests and cases are defined). -A single `.spec.ts` file. It always contains one _test group_. +**Type:** Once `import`ed, `SpecFile` **Example:** `src/webgpu/**/*.spec.ts` -### Filtered Test Spec - -A subset of the tests in a single test spec file. -It is created at runtime, via a filter. - -It contains one "virtual" test group, which has type `RunCaseIterable`. +## Test Group -## Test Group / Group +A subtree of tests. There is one Test Group per Test Spec File. -A collection of test cases. There is one per test spec file. +The Test Fixture used for tests is defined at TestGroup creation. **Type:** `TestGroup` @@ -93,18 +137,17 @@ A collection of test cases. There is one per test spec file. One test. It has a single _test function_. -It may represent multiple _test cases_, each of which runs the same test function with different **parameters**. +It may represent multiple _test cases_, each of which runs the same Test Function with different +Parameters. -It is created by `TestGroup.test()`. -At creation time, it can be parameterized via `Test.params()`. - -**Type:** `Test` +A test is named using `TestGroup.test()`, which returns a `TestBuilder`. +`TestBuilder.params()` can optionally be used to parameterize the test. +Then, `TestBuilder.fn()` provides the Test Function. ### Test Function -A test function is defined inline inside of a `TestGroup.test()` call. - -It receives an instance of the appropriate _test fixture_, through which it produce test results. +When a test case is run, the Test Function receives an instance of the +Test Fixture provided to the Test Group, producing test results. **Type:** `TestFn` @@ -116,9 +159,20 @@ A single case of a test. It is identified by a `TestCaseID`: a test name, and it ## Parameters / Params +Each Test Case has a (possibly empty) set of Parameters. +The parameters are available to the Test Function `f(t)` via `t.params`. + +A set of Public Parameters identifies a Test Case within a Test. + +There are also Private Paremeters: any parameter name beginning with an underscore (`_`). +These parameters are not part of the Test Case identification, but are still passed into +the Test Function. They can be used to manually specify expected results. + +**Type:** `CaseParams` + ## Test Fixture / Fixture -Test fixtures provide helpers for tests to use. +_Test Fixtures_ provide helpers for tests to use. A new instance of the fixture is created for every run of every test case. There is always one fixture class for a whole test group (though this may change). @@ -126,7 +180,7 @@ There is always one fixture class for a whole test group (though this may change The fixture is also how a test gets access to the _case recorder_, which allows it to produce test results. -They are also how tests produce results: `.log()`, `.fail()`, etc. +They are also how tests produce results: `.skip()`, `.fail()`, etc. **Type:** `Fixture` @@ -138,137 +192,61 @@ Provides basic fixture utilities most useful in the `unittests` suite. Provides utilities useful in WebGPU CTS tests. -# Running Tests - -- _Queries_ contain multiple: - - _Filters_ (positive or negative). - -## Query - -A query is a string which denotes a subset of a test suite to run. -It is comprised of a list of filters. -A case is included in the subset if it matches any of the filters. - -In the WPT and standalone harnesses, the query is stored in the URL. - -Queries are selectively URL-encoded for readability and compatibility with browsers. - -**Example:** `?q=unittests:param_helpers:combine/=` -**Example:** `?q=unittests:param_helpers:combine/mixed=` - -**Type:** None yet. TODO - -### Filter - -A filter matches a set of cases in a suite. - -Each filter may match one of: - -- `S:s` In one suite `S`, all specs whose paths start with `s` (which may be empty). -- `S:s:t` In one spec `S:s`, all tests whose names start with `t` (which may be empty). -- `S:s:t~c` In one test `S:s:t`, all cases whose params are a superset of `c`. -- `S:s:t=c` In one test `S:s:t`, the single case whose params equal `c` (empty string = `{}`). - -**Type:** `TestFilter` - -### Using filters to split expectations - -A set of cases can be split using negative filters. For example, imagine you have one WPT test variant: - -- `webgpu/cts.html?q=unittests:param_helpers:` - -But one of the cases is failing. To be able to suppress the failing test without losing test coverage, the WPT test variant can be split into two variants: - -- `webgpu/cts.html?q=unittests:param_helpers:¬=unittests:param_helpers:combine/mixed:` -- `webgpu/cts.html?q=unittests:param_helpers:combine/mixed:` - -This runs the same set of cases, but in two separate page loads. - # Test Results ## Logger A logger logs the results of a whole test run. -It saves an empty `LiveTestSpecResult` into its results array, then creates a +It saves an empty `LiveTestSpecResult` into its results map, then creates a _test spec recorder_, which records the results for a group into the `LiveTestSpecResult`. -### Test Spec Recorder - -Refers to a `LiveTestSpecResult` in the logger, and writes results into it. - -It saves an empty `LiveTestCaseResult` into its `LiveTestSpecResult`, then creates a -_test case recorder_, which records the results for a case into the `LiveTestCaseResult`. +**Type:** `Logger` ### Test Case Recorder -Records the actual results of running a test case (its pass-status, run time, and logs) -into its `LiveTestCaseResult`. +Refers to a `LiveTestCaseResult` created by the logger. +Records the results of running a test case (its pass-status, run time, and logs) into it. + +**Types:** `TestCaseRecorder`, `LiveTestCaseResult` #### Test Case Status The `status` of a `LiveTestCaseResult` can be one of: -- `'running'` -- `'fail'` -- `'warn'` +- `'running'` (only while still running) - `'pass'` +- `'skip'` +- `'warn'` +- `'fail'` + +The "worst" result from running a case is always reported (fail > warn > skip > pass). +Note this means a test can still fail if it's "skipped", if it failed before +`.skip()` was called. -The "worst" result from running a case is always reported. +**Type:** `Status` ## Results Format The results are returned in JSON format. -They are designed to be easily merged in JavaScript. -(TODO: Write a merge tool.) +They are designed to be easily merged in JavaScript: +the `"results"` can be passed into the constructor of `Map` and merged from there. -(TODO: Update these docs if the format changes.) +(TODO: Write a merge tool, if needed.) ```js { - "version": "e24c459b46c4815f93f0aed5261e28008d1f2882-dirty", + "version": "bf472c5698138cdf801006cd400f587e9b1910a5-dirty", "results": [ - // LiveTestSpecResult objects - { - "spec": "unittests:basic:", - "cases": [ - // LiveTestCaseResult objects - { - "test": "test/sync", - "params": null, - "status": "pass", - "timems": 145, - "logs": [] - }, - { - "test": "test/async", - "params": null, - "status": "pass", - "timems": 26, - "logs": [] - } - ] - }, - { - "spec": "unittests:test_group:", - "cases": [ - { - "test": "invalid test name", - "params": { "char": "\"" }, - "status": "pass", - "timems": 66, - "logs": ["OK: threw"] - }, - { - "test": "invalid test name", - "params": { "char": "`" }, - "status": "pass", - "timems": 15, - "logs": ["OK: threw"] - } - ] - } + [ + "unittests:async_mutex:basic:", + { "status": "pass", "timems": 0.286, "logs": [] } + ], + [ + "unittests:async_mutex:serial:", + { "status": "pass", "timems": 0.415, "logs": [] } + ] ] } ``` diff --git a/chromium/third_party/webgpu-cts/src/package-lock.json b/chromium/third_party/webgpu-cts/src/package-lock.json new file mode 100644 index 00000000000..2becb20ea92 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/package-lock.json @@ -0,0 +1,6674 @@ +{ + "name": "@webgpu/cts", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/cli": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.10.1.tgz", + "integrity": "sha512-cVB+dXeGhMOqViIaZs3A9OUAe4pKw4SBNdMw6yHJMYR7s4TB+Cei7ThquV/84O19PdIFWuwe03vxxES0BHUm5g==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + } + }, + "@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.1" + } + }, + "@babel/core": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", + "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.2", + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helpers": "^7.10.1", + "@babel/parser": "^7.10.2", + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", + "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.2", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.2.tgz", + "integrity": "sha512-5C/QhkGFh1vqcziq1vAL6SI9ymzUp8BCYjFpvYVhWP4DlATIb3u5q3iUd35mvlyGs8fO7hckkW7i0tmH+5+bvQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-member-expression-to-functions": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1" + } + }, + "@babel/helper-function-name": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", + "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", + "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", + "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-module-imports": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", + "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-module-transforms": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", + "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-simple-access": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", + "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz", + "integrity": "sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", + "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-simple-access": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", + "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", + "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", + "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "dev": true + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.1.tgz", + "integrity": "sha512-sqdGWgoXlnOdgMXU+9MbhzwFRgxVLeiGBqTrnuS7LC2IBU31wSsESbTUreT2O418obpfPdGUR2GbEufZF1bpqw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.1.tgz", + "integrity": "sha512-ypC4jwfIVF72og0dgvEcFRdOM2V9Qm1tu7RGmdZOlhsccyK0wisXmMObGuWEOd5jQ+K9wcIgSNftCpk2vkjUfQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.1.tgz", + "integrity": "sha512-X/d8glkrAtra7CaQGMiGs/OGa6XgUzqPcBXCIGFCpCqnfGlT0Wfbzo/B89xHhnInTaItPK8LALblVXcUOEh95Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.1.tgz", + "integrity": "sha512-v+QWKlmCnsaimLeqq9vyCsVRMViZG1k2SZTlcZvB+TqyH570Zsij8nvVUZzOASCRiQFUxkLrn9Wg/kH0zgy5OQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-typescript": "^7.10.1" + } + }, + "@babel/preset-typescript": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.1.tgz", + "integrity": "sha512-m6GV3y1ShiqxnyQj10600ZVOFrSSAa8HQ3qIUk2r+gcGtHTIRw0dJnFLt1WNXpKjtVw7yw1DAPU/6ma2ZvgJuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-transform-typescript": "^7.10.1" + } + }, + "@babel/template": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", + "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/traverse": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", + "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.1", + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", + "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/jquery": { + "version": "3.3.38", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.38.tgz", + "integrity": "sha512-nkDvmx7x/6kDM5guu/YpXkGZ/Xj/IwGiLDdKM99YA5Vag7pjGyTJ8BNUh/6hxEn/sEu5DKtyRgnONJ7EmOoKrA==", + "dev": true, + "requires": { + "@types/sizzle": "*" + } + }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", + "dev": true + }, + "@types/node": { + "version": "14.0.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.12.tgz", + "integrity": "sha512-/sjzehvjkkpvLpYtN6/2dv5kg41otMGuHQUt9T2aiAuIfleCQRQHXXzF1eAw/qkZTj5Kcf4JSTf7EIizHocy6Q==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/offscreencanvas": { + "version": "2019.6.2", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.6.2.tgz", + "integrity": "sha512-ndVeLKDF10p4hZswi0KKSUWAmNoTcgz8LUPiIIPeT3qD8bTaYe0pXyuyQ21+DmGRMkT8orxiISm4O+YpMLCDBw==", + "dev": true, + "requires": { + "@types/webgl2": "*" + } + }, + "@types/sizzle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "dev": true + }, + "@types/webgl2": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.5.tgz", + "integrity": "sha512-oGaKsBbxQOY5+aJFV3KECDhGaXt+yZJt2y/OZsnQGLRkH6Fvr7rv4pCt3SRH1somIHfej/c4u7NSpCyd9x+1Ow==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz", + "integrity": "sha512-iIC0Pb8qDaoit+m80Ln/aaeu9zKQdOLF4SHcGLarSeY1gurW6aU4JsOPMjKQwXlw70MvWKZQc6S2NamA8SJ/gg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.31.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz", + "integrity": "sha512-MI6IWkutLYQYTQgZ48IVnRXmLR/0Q6oAyJgiOror74arUMh7EWjJkADfirZhRsUMHeLJ85U2iySDwHTSnNi9vA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.31.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.31.0.tgz", + "integrity": "sha512-uph+w6xUOlyV2DLSC6o+fBDzZ5i7+3/TxAsH4h3eC64tlga57oMb96vVlXoMwjR/nN+xyWlsnxtbDkB46M2EPQ==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.31.0", + "@typescript-eslint/typescript-estree": "2.31.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz", + "integrity": "sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@webgpu/glslang": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==", + "dev": true + }, + "@webgpu/types": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.0.24.tgz", + "integrity": "sha512-g3axpnE8h42vzcl9Zi8jBjht9ts4Y2E8AI0DTktwsRh4yiIg+OmVjn49Kp/5atsAmsbAGNtROgrOj/lyxkftsA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", + "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "babel-plugin-add-header-comment": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/babel-plugin-add-header-comment/-/babel-plugin-add-header-comment-1.0.3.tgz", + "integrity": "sha1-URxJAQYmQNWkgLSsPt1pRBlYUOw=", + "dev": true + }, + "babel-plugin-const-enum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-const-enum/-/babel-plugin-const-enum-1.0.1.tgz", + "integrity": "sha512-6oGu63g1FS9psUPQyLCJM08ty6kGihGKTbzWGbAKHfUuCzCh7y9twh516cR6v0lM4d4NOoR+DgLb7uKVytyp6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-typescript": "^7.3.3" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "dev": true, + "requires": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "coffeescript": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz", + "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "csproj2ts": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/csproj2ts/-/csproj2ts-1.1.0.tgz", + "integrity": "sha512-sk0RTT51t4lUNQ7UfZrqjQx7q4g0m3iwNA6mvyh7gLsgQYvwKzfdyoAgicC9GqJvkoIkU0UmndV9c7VZ8pJ45Q==", + "dev": true, + "requires": { + "es6-promise": "^4.1.1", + "lodash": "^4.17.4", + "semver": "^5.4.1", + "xml2js": "^0.4.19" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + } + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "divhide": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/divhide/-/divhide-2.0.1.tgz", + "integrity": "sha1-jHsCb3/w6XWAPLuWWuyhFN6C2bs=", + "dev": true, + "requires": { + "lodash": "=3.9.3" + }, + "dependencies": { + "lodash": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.9.3.tgz", + "integrity": "sha1-AVnoaDL+/8bWHYUrEqlTuZSWvTI=", + "dev": true + } + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "requires": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "requires": { + "string-template": "~0.2.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-0.1.2.tgz", + "integrity": "sha1-8RLCn+paCZhTn8tqL9IUQ9KPBfc=", + "dev": true + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.2.0.tgz", + "integrity": "sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.2.0", + "espree": "^7.1.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + } + }, + "eslint-plugin-ban": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-ban/-/eslint-plugin-ban-1.5.1.tgz", + "integrity": "sha512-I15ptCK+Oy/6N0/Trd9+fXRW0DHivX2K3lQf6+XNK0mRRv5G/4PFuVs7YQa5VxIxui8HVgXnwoa1HGHJDQF/WQ==", + "dev": true, + "requires": { + "requireindex": "~1.2.0" + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.21.1.tgz", + "integrity": "sha512-qYOOsgUv63vHof7BqbzuD+Ud34bXHxFJxntuAC1ZappFZXYbRIek3aJ7jc9i2dHDGDyZ/0zlO0cpioES265Lsw==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz", + "integrity": "sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz", + "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==", + "dev": true + }, + "espree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz", + "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==", + "dev": true, + "requires": { + "acorn": "^7.2.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.2.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", + "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-sync-cmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", + "dev": true + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "requires": { + "glob": "~5.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "follow-redirects": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", + "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", + "dev": true, + "requires": { + "ini": "^1.3.5" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globule": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "grunt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.1.0.tgz", + "integrity": "sha512-+NGod0grmviZ7Nzdi9am7vuRS/h76PcWDsV635mEXF0PEQMUV6Kb+OjTdsVxbi0PZmfQOjCMKb3w8CVZcqsn1g==", + "dev": true, + "requires": { + "coffeescript": "~1.10.0", + "dateformat": "~1.0.12", + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.3.0", + "glob": "~7.0.0", + "grunt-cli": "~1.2.0", + "grunt-known-options": "~1.1.0", + "grunt-legacy-log": "~2.0.0", + "grunt-legacy-util": "~1.1.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.13.1", + "minimatch": "~3.0.2", + "mkdirp": "~1.0.3", + "nopt": "~3.0.6", + "path-is-absolute": "~1.0.0", + "rimraf": "~2.6.2" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "grunt-cli": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "dev": true, + "requires": { + "findup-sync": "~0.3.0", + "grunt-known-options": "~1.1.0", + "nopt": "~3.0.6", + "resolve": "~1.1.0" + } + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "grunt-contrib-clean": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-2.0.0.tgz", + "integrity": "sha512-g5ZD3ORk6gMa5ugZosLDQl3dZO7cI3R14U75hTM+dVLVxdMNJCPVmwf9OUt4v4eWgpKKWWoVK9DZc1amJp4nQw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "rimraf": "^2.6.2" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, + "grunt-contrib-copy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "grunt-contrib-watch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", + "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "dev": true, + "requires": { + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, + "grunt-http-server": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-http-server/-/grunt-http-server-2.1.0.tgz", + "integrity": "sha512-kv1qgucbRG0XthXu/uyoi15mYeF8W2QDODPurKE9zuRaJPhpuglOkHThGmqKdmJU38CEqc/Q49+Z51VhGFsN8g==", + "dev": true, + "requires": { + "divhide": "2.0.1", + "http-server": "0.11.1", + "lodash": "4.17.5", + "opener": "1.4.3", + "showdown": "1.8.6" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, + "http-server": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz", + "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", + "dev": true, + "requires": { + "colors": "1.0.3", + "corser": "~2.0.0", + "ecstatic": "^3.0.0", + "http-proxy": "^1.8.1", + "opener": "~1.4.0", + "optimist": "0.6.x", + "portfinder": "^1.0.13", + "union": "~0.4.3" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "opener": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", + "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "dev": true + }, + "qs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", + "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", + "dev": true + }, + "union": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz", + "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", + "dev": true, + "requires": { + "qs": "~2.3.3" + } + } + } + }, + "grunt-known-options": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", + "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", + "dev": true + }, + "grunt-legacy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz", + "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==", + "dev": true, + "requires": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.5" + } + }, + "grunt-legacy-log-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz", + "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==", + "dev": true, + "requires": { + "chalk": "~2.4.1", + "lodash": "~4.17.10" + } + }, + "grunt-legacy-util": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz", + "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==", + "dev": true, + "requires": { + "async": "~1.5.2", + "exit": "~0.1.1", + "getobject": "~0.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.10", + "underscore.string": "~3.3.4", + "which": "~1.3.0" + } + }, + "grunt-run": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/grunt-run/-/grunt-run-0.8.1.tgz", + "integrity": "sha512-+wvoOJevugcjMLldbVCyspRHHntwVIJiTGjx0HFq+UwXhVPe7AaAiUdY4135CS68pAoRLhd7pAILpL2ITe1tmA==", + "dev": true, + "requires": { + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "grunt-ts": { + "version": "6.0.0-beta.22", + "resolved": "https://registry.npmjs.org/grunt-ts/-/grunt-ts-6.0.0-beta.22.tgz", + "integrity": "sha512-g9e+ZImQ7W38dfpwhp0+GUltXWidy3YGPfIA/IyGL5HMv6wmVmMMoSgscI5swhs2HSPf8yAvXAAJbwrouijoRg==", + "dev": true, + "requires": { + "chokidar": "^2.0.4", + "csproj2ts": "^1.1.0", + "detect-indent": "^4.0.0", + "detect-newline": "^2.1.0", + "es6-promise": "~0.1.1", + "jsmin2": "^1.2.1", + "lodash": "~4.17.10", + "ncp": "0.5.1", + "rimraf": "2.2.6", + "semver": "^5.3.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "rimraf": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.6.tgz", + "integrity": "sha1-xZWXVpsU2VatKcrMQr3d9fDqT0w=", + "dev": true + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "gts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/gts/-/gts-2.0.2.tgz", + "integrity": "sha512-SLytzl2IqKXf6kGULwr07XQ9lVsvjrzFD3OAA7DEfIQYuD+lKBPt/cZ/RYGxaWerY4PTfmnXT7KdxEr9Ec8uHQ==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "2.31.0", + "@typescript-eslint/parser": "2.31.0", + "chalk": "^4.0.0", + "eslint": "^6.8.0", + "eslint-config-prettier": "^6.10.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^3.1.2", + "execa": "^4.0.0", + "inquirer": "^7.1.0", + "meow": "^7.0.0", + "ncp": "^2.0.0", + "prettier": "^2.0.4", + "rimraf": "^3.0.2", + "update-notifier": "^4.1.0", + "write-file-atomic": "^3.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", + "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "execa": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.2.tgz", + "integrity": "sha512-QI2zLa6CjGWdiQsmSkZoGtDx2N+cQIGb3yNolGTdjSQzydzLgYYf8LRuagp7S7fPimjcrzUDSUFd/MgzELMi4Q==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "dev": true + }, + "meow": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", + "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "arrify": "^2.0.1", + "camelcase": "^6.0.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "trim-newlines": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + } + } + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-parser-js": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", + "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "jsmin2": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jsmin2/-/jsmin2-1.2.1.tgz", + "integrity": "sha1-iPvi+/dfCpH2YCD9mBzWk/S/5X4=", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "ncp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.5.1.tgz", + "integrity": "sha1-dDmFMW49tFkoG1hxaehFc1oFQ58=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "portfinder": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz", + "integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "pupa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", + "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, + "quiet-grunt": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/quiet-grunt/-/quiet-grunt-0.2.3.tgz", + "integrity": "sha1-8JCJeal9JCrC2NbuvP5Vj1nAYYQ=", + "dev": true + }, + "raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "dev": true, + "requires": { + "bytes": "1", + "string_decoder": "0.10" + }, + "dependencies": { + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "registry-auth-token": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", + "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "showdown": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-1.8.6.tgz", + "integrity": "sha1-kepO47elRIqspoIKTifmkMatdxw=", + "dev": true, + "requires": { + "yargs": "^10.0.3" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "term-size": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", + "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "dev": true, + "requires": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", + "dev": true + }, + "underscore.string": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", + "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "dev": true, + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "update-notifier": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz", + "integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", + "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^8.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "yargs-parser": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/chromium/third_party/webgpu-cts/src/package.json b/chromium/third_party/webgpu-cts/src/package.json index ac33bc81f50..3d90cc714b4 100644 --- a/chromium/third_party/webgpu-cts/src/package.json +++ b/chromium/third_party/webgpu-cts/src/package.json @@ -5,6 +5,9 @@ "scripts": { "test": "grunt pre" }, + "engines": { + "node": ">=11.14.0" + }, "repository": { "type": "git", "url": "git+https://github.com/gpuweb/cts.git" @@ -17,34 +20,33 @@ }, "homepage": "https://github.com/gpuweb/cts#readme", "devDependencies": { - "@babel/cli": "^7.7.7", - "@babel/core": "^7.7.7", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-syntax-dynamic-import": "^7.7.4", - "@babel/plugin-syntax-import-meta": "^7.7.4", - "@babel/preset-typescript": "^7.7.7", - "@types/jquery": "^3.3.30", - "@types/node": "^13.1.2", - "@types/offscreencanvas": "^2019.6.1", + "@babel/cli": "^7.10.1", + "@babel/core": "^7.10.2", + "@babel/plugin-proposal-class-properties": "^7.10.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.10.1", + "@babel/preset-typescript": "^7.10.1", + "@types/jquery": "^3.3.38", + "@types/node": "^14.0.12", + "@types/offscreencanvas": "^2019.6.2", "@webgpu/glslang": "^0.0.15", - "@webgpu/types": "0.0.22", + "@webgpu/types": "0.0.24", "babel-plugin-add-header-comment": "^1.0.3", - "babel-plugin-const-enum": "^0.0.5", - "clang-format": "^1.3.0", - "fast-glob": "^3.1.1", - "grunt": "^1.0.4", - "grunt-babel": "^8.0.0", + "babel-plugin-const-enum": "^1.0.1", + "eslint": "^7.2.0", + "eslint-plugin-ban": "^1.5.1", + "eslint-plugin-import": "^2.21.1", + "fast-glob": "^3.2.2", + "grunt": "^1.1.0", "grunt-contrib-clean": "^2.0.0", "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-watch": "^1.1.0", "grunt-http-server": "^2.1.0", - "grunt-mkdir": "^1.0.0", "grunt-run": "^0.8.1", "grunt-ts": "^6.0.0-beta.22", - "gts": "^1.1.2", + "gts": "^2.0.2", "quiet-grunt": "^0.2.3", - "ts-node": "^8.5.4", - "tslint": "^6.1.1", - "typescript": "^3.8.3", - "typescript-formatter": "^7.2.2" + "ts-node": "^8.10.2", + "typescript": "^3.9.5" } } diff --git a/chromium/third_party/webgpu-cts/src/prettier.config.js b/chromium/third_party/webgpu-cts/src/prettier.config.js index 9aa538d6526..9f4053f719e 100644 --- a/chromium/third_party/webgpu-cts/src/prettier.config.js +++ b/chromium/third_party/webgpu-cts/src/prettier.config.js @@ -1,5 +1,6 @@ module.exports = { printWidth: 100, + arrowParens: 'avoid', bracketSpacing: true, singleQuote: true, diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/allowed_characters.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/allowed_characters.ts deleted file mode 100644 index bc54c2c7395..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/allowed_characters.ts +++ /dev/null @@ -1,2 +0,0 @@ -// It may be OK to add more allowed characters here. -export const allowedTestNameCharacters = 'a-zA-Z0-9/_'; diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/file_loader.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/file_loader.ts new file mode 100644 index 00000000000..27e39bccfd0 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/file_loader.ts @@ -0,0 +1,51 @@ +import { parseQuery } from './query/parseQuery.js'; +import { TestQuery } from './query/query.js'; +import { RunCaseIterable } from './test_group.js'; +import { TestSuiteListing } from './test_suite_listing.js'; +import { loadTreeForQuery, TestTree, TestTreeLeaf } from './tree.js'; + +// A listing file, e.g. either of: +// - `src/webgpu/listing.ts` (which is dynamically computed, has a Promise<TestSuiteListing>) +// - `out/webgpu/listing.js` (which is pre-baked, has a TestSuiteListing) +interface ListingFile { + listing: Promise<TestSuiteListing> | TestSuiteListing; +} + +// A .spec.ts file, as imported. +export interface SpecFile { + readonly description: string; + readonly g: RunCaseIterable; +} + +// Base class for DefaultTestFileLoader and FakeTestFileLoader. +export abstract class TestFileLoader { + abstract listing(suite: string): Promise<TestSuiteListing>; + protected abstract import(path: string): Promise<SpecFile>; + + importSpecFile(suite: string, path: string[]): Promise<SpecFile> { + return this.import(`${suite}/${path.join('/')}.spec.js`); + } + + async loadTree(query: TestQuery, subqueriesToExpand: string[] = []): Promise<TestTree> { + return loadTreeForQuery( + this, + query, + subqueriesToExpand.map(q => parseQuery(q)) + ); + } + + async loadCases(query: TestQuery): Promise<IterableIterator<TestTreeLeaf>> { + const tree = await this.loadTree(query); + return tree.iterateLeaves(); + } +} + +export class DefaultTestFileLoader extends TestFileLoader { + async listing(suite: string): Promise<TestSuiteListing> { + return ((await import(`../../${suite}/listing.js`)) as ListingFile).listing; + } + + import(path: string): Promise<SpecFile> { + return import(`../../${path}`); + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/fixture.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/fixture.ts index a592d4f4c97..0cf811704f2 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/fixture.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/fixture.ts @@ -1,5 +1,5 @@ -import { TestCaseRecorder } from './logger.js'; -import { ParamSpec } from './params_utils.js'; +import { TestCaseRecorder } from './logging/test_case_recorder.js'; +import { CaseParams } from './params_utils.js'; import { assert } from './util/util.js'; export class SkipTestCase extends Error {} @@ -8,12 +8,12 @@ export class SkipTestCase extends Error {} // A new instance of the Fixture is created for every single test case // (i.e. every time the test function is run). export class Fixture { - params: ParamSpec; + params: unknown; protected rec: TestCaseRecorder; private eventualExpectations: Array<Promise<unknown>> = []; private numOutstandingAsyncExpectations = 0; - constructor(rec: TestCaseRecorder, params: ParamSpec) { + constructor(rec: TestCaseRecorder, params: CaseParams) { this.rec = rec; this.params = params; } @@ -43,7 +43,7 @@ export class Fixture { } fail(msg?: string): void { - this.rec.fail(new Error(msg)); + this.rec.expectationFailed(new Error(msg)); } protected async immediateAsyncExpectation<T>(fn: () => Promise<T>): Promise<T> { @@ -61,16 +61,16 @@ export class Fixture { private expectErrorValue(expectedName: string, ex: unknown, niceStack: Error): void { if (!(ex instanceof Error)) { - niceStack.message = 'THREW non-error value, of type ' + typeof ex + niceStack.message; - this.rec.fail(niceStack); + niceStack.message = `THREW non-error value, of type ${typeof ex}: ${ex}`; + this.rec.expectationFailed(niceStack); return; } const actualName = ex.name; if (actualName !== expectedName) { - niceStack.message = `THREW ${actualName}, instead of ${expectedName}` + niceStack.message; - this.rec.fail(niceStack); + niceStack.message = `THREW ${actualName}, instead of ${expectedName}: ${ex}`; + this.rec.expectationFailed(niceStack); } else { - niceStack.message = 'OK: threw ' + actualName + niceStack.message; + niceStack.message = `OK: threw ${actualName}${ex.message}`; this.rec.debug(niceStack); } } @@ -80,8 +80,8 @@ export class Fixture { const m = msg ? ': ' + msg : ''; try { await p; - niceStack.message = 'DID NOT THROW' + m; - this.rec.fail(niceStack); + niceStack.message = 'DID NOT REJECT' + m; + this.rec.expectationFailed(niceStack); } catch (ex) { niceStack.message = m; this.expectErrorValue(expectedName, ex, niceStack); @@ -93,7 +93,7 @@ export class Fixture { const m = msg ? ': ' + msg : ''; try { fn(); - this.rec.fail(new Error('DID NOT THROW' + m)); + this.rec.expectationFailed(new Error('DID NOT THROW' + m)); } catch (ex) { this.expectErrorValue(expectedName, ex, new Error(m)); } @@ -104,7 +104,7 @@ export class Fixture { const m = msg ? ': ' + msg : ''; this.rec.debug(new Error('expect OK' + m)); } else { - this.rec.fail(new Error(msg)); + this.rec.expectationFailed(new Error(msg)); } return cond; } diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/generate_minimal_query_list.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/generate_minimal_query_list.ts deleted file mode 100644 index 32538bbe621..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/generate_minimal_query_list.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { TestSpecOrTestOrCaseID } from './id.js'; -import { Logger } from './logger.js'; -import { makeFilter } from './test_filter/load_filter.js'; -import { TestFilterResult } from './test_filter/test_filter_result.js'; -import { FilterResultTreeNode, treeFromFilterResults } from './tree.js'; - -interface QuerySplitterTreeNode { - needsSplit: boolean; - children?: Map<string, QuerySplitterTreeNode>; -} - -interface Expectation { - id: TestSpecOrTestOrCaseID; - line: string; - seen: boolean; -} - -function makeQuerySplitterTree( - caselist: TestFilterResult[], - expectationStrings: string[] -): QuerySplitterTreeNode { - const expectations: Expectation[] = []; - for (const e of expectationStrings) { - const filter = makeFilter(e); - const id = filter.idIfSingle(); - if (!id) { - throw new Error( - 'Can only handle expectations which cover one file, one test, or one case. ' + e - ); - } - expectations.push({ id, line: e, seen: false }); - } - - const convertToQuerySplitterTree = ( - tree: FilterResultTreeNode, - name?: string - ): QuerySplitterTreeNode => { - const children = tree.children; - let needsSplit = true; - - if (name !== undefined) { - const filter = makeFilter(name); - const moreThanOneFile = !filter.definitelyOneFile(); - const matchingExpectations = expectations.map(e => { - const matches = filter.matches(e.id); - if (matches) e.seen = true; - return matches; - }); - needsSplit = matchingExpectations.some(m => m) || moreThanOneFile; - } - - const queryNode: QuerySplitterTreeNode = { needsSplit }; - if (children) { - queryNode.children = new Map(); - for (const [k, v] of children) { - const subtree = convertToQuerySplitterTree(v, k); - queryNode.children.set(k, subtree); - } - } - return queryNode; - }; - - const log = new Logger(); - const tree = treeFromFilterResults(log, caselist.values()); - const queryTree = convertToQuerySplitterTree(tree)!; - - for (const e of expectations) { - if (!e.seen) throw new Error('expectation had no effect: ' + e.line); - } - - return queryTree; -} - -// Takes a TestFilterResultIterator enumerating every test case in the suite, and a list of -// expectation queries from a browser's expectations file. Creates a minimal list of queries -// (i.e. wpt variant lines) such that: -// -// - There is at least one query per spec file. -// - Each of those those input queries is in the output, so that it can have its own expectation. -// -// It does this by creating a tree from the list of cases (same tree as the standalone runner uses), -// then marking every node which is a parent of a node that matches an expectation. -export async function generateMinimalQueryList( - caselist: TestFilterResult[], - expectationStrings: string[] -): Promise<string[]> { - const unsplitNodes: string[] = []; - const findUnsplitNodes = (name: string, node: QuerySplitterTreeNode | undefined) => { - if (node === undefined) { - return; - } - if (node.needsSplit && node.children) { - for (const [k, v] of node.children) { - findUnsplitNodes(k, v); - } - } else { - unsplitNodes.push(name); - } - }; - - const queryTree = makeQuerySplitterTree(caselist, expectationStrings); - findUnsplitNodes('', queryTree); - - for (const exp of expectationStrings) { - if (!unsplitNodes.some(name => name === exp)) { - throw new Error( - 'Something went wrong: all expectation strings should always appear exactly: ' + exp - ); - } - } - return unsplitNodes; -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/gpu/device_pool.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/gpu/device_pool.ts new file mode 100644 index 00000000000..b008aa180c0 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/gpu/device_pool.ts @@ -0,0 +1,140 @@ +import { assert, raceWithRejectOnTimeout, unreachable, assertReject } from '../util/util.js'; + +import { getGPU } from './implementation.js'; + +interface DeviceHolder { + acquired: boolean; // whether the device is currently in use by a test + device: GPUDevice; + lostReason?: string; // initially undefined; becomes set when the device is lost +} + +class TestFailedButDeviceReusable extends Error {} +export class TestOOMedShouldAttemptGC extends Error {} + +const kPopErrorScopeTimeoutMS = 5000; + +export class DevicePool { + failed: boolean = false; // if device init failed once, never try again + holder?: DeviceHolder = undefined; // undefined if "uninitialized" (not yet initialized, or lost) + + async acquire(): Promise<GPUDevice> { + assert(!this.failed, 'WebGPU device previously failed to initialize; not retrying'); + + if (this.holder === undefined) { + try { + this.holder = await DevicePool.makeHolder(); + } catch (ex) { + this.failed = true; + throw ex; + } + } + assert(!this.holder.acquired, 'Device was in use on DevicePool.acquire'); + this.holder.acquired = true; + + this.beginErrorScopes(); + return this.holder.device; + } + + // When a test is done using a device, it's released back into the pool. + // This waits for error scopes, checks their results, and checks for various error conditions. + async release(device: GPUDevice): Promise<void> { + const holder = this.holder; + assert(holder !== undefined, 'trying to release a device while pool is uninitialized'); + assert(holder.acquired, 'trying to release a device while already released'); + assert(device === holder.device, 'Released device was the wrong device'); + + try { + // Time out if popErrorScope never completes. This could happen due to a browser bug - e.g., + // as of this writing, on Chrome GPU process crash, popErrorScope just hangs. + await raceWithRejectOnTimeout( + this.endErrorScopes(), + kPopErrorScopeTimeoutMS, + 'finalization popErrorScope timed out' + ); + + // (Hopefully if the device was lost, it has been reported by the time endErrorScopes() + // has finished (or timed out). If not, it could cause a finite number of extra test + // failures following this one (but should recover eventually).) + const lostReason = holder.lostReason; + if (lostReason !== undefined) { + // Fail the current test. + unreachable(`Device was lost: ${lostReason}`); + } + } catch (ex) { + // Any error that isn't explicitly TestFailedButDeviceReusable forces a new device to be + // created for the next test. + if (!(ex instanceof TestFailedButDeviceReusable)) { + this.holder = undefined; + } + throw ex; + } finally { + // TODO: device.destroy() + + // Mark the holder as free. (This only has an effect if the pool still has the holder.) + // This could be done at the top but is done here to guard against async-races during release. + holder.acquired = false; + } + } + + // Gets a device and creates a DeviceHolder. + // If the device is lost, DeviceHolder.lostReason gets set. + private static async makeHolder(): Promise<DeviceHolder> { + const gpu = getGPU(); + const adapter = await gpu.requestAdapter(); + + const holder: DeviceHolder = { + acquired: false, + device: await adapter.requestDevice(), + lostReason: undefined, + }; + holder.device.lost.then(ev => { + holder.lostReason = ev.message; + }); + return holder; + } + + // Create error scopes that wrap the entire test. + private beginErrorScopes(): void { + assert(this.holder !== undefined); + this.holder.device.pushErrorScope('out-of-memory'); + this.holder.device.pushErrorScope('validation'); + } + + // End the whole-test error scopes. Check that there are no extra error scopes, and that no + // otherwise-uncaptured errors occurred during the test. + private async endErrorScopes(): Promise<void> { + assert(this.holder !== undefined); + let gpuValidationError: GPUValidationError | GPUOutOfMemoryError | null; + let gpuOutOfMemoryError: GPUValidationError | GPUOutOfMemoryError | null; + + try { + // May reject if the device was lost. + gpuValidationError = await this.holder.device.popErrorScope(); + gpuOutOfMemoryError = await this.holder.device.popErrorScope(); + } catch (ex) { + assert( + this.holder.lostReason !== undefined, + "popErrorScope failed, but device.lost hasn't fired (yet)" + ); + throw ex; + } + + await assertReject( + this.holder.device.popErrorScope(), + 'There was an extra error scope on the stack after a test' + ); + + if (gpuValidationError !== null) { + assert(gpuValidationError instanceof GPUValidationError); + // Allow the device to be reused. + throw new TestFailedButDeviceReusable( + `Unexpected validation error occurred: ${gpuValidationError.message}` + ); + } + if (gpuOutOfMemoryError !== null) { + assert(gpuOutOfMemoryError instanceof GPUOutOfMemoryError); + // Don't allow the device to be reused; unexpected OOM could break the device. + throw new TestOOMedShouldAttemptGC('Unexpected out-of-memory error occurred'); + } + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/id.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/id.ts deleted file mode 100644 index 60d04da1598..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/id.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ParamSpec } from './params_utils.js'; - -// Identifies a test spec file. -export interface TestSpecID { - // The spec's suite name, e.g. 'webgpu'. - readonly suite: string; - // The spec's path within the suite, e.g. 'command_buffer/compute/basic'. - readonly path: string; -} - -export function testSpecEquals(x: TestSpecID, y: TestSpecID): boolean { - return x.suite === y.suite && x.path === y.path; -} - -// Identifies a test case (a specific parameterization of a test), within its spec file. -export interface TestCaseID { - readonly test: string; - readonly params: ParamSpec | null; -} - -export interface TestSpecOrTestOrCaseID { - readonly spec: TestSpecID; - readonly test?: string; - readonly params?: ParamSpec | null; -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/listing.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/listing.ts deleted file mode 100644 index bc5bedaf709..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/listing.ts +++ /dev/null @@ -1,9 +0,0 @@ -// A listing of all specs within a single suite. This is the (awaited) type of -// `groups` in '{cts,unittests}/listing.ts' and the auto-generated -// 'out/{cts,unittests}/listing.js' files (see tools/gen_listings). -export type TestSuiteListing = Iterable<TestSuiteListingEntry>; - -export interface TestSuiteListingEntry { - readonly path: string; - readonly description: string; -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/loader.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/loader.ts deleted file mode 100644 index 78f804ae2bc..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/loader.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { TestSuiteListing } from './listing.js'; -import { loadFilter } from './test_filter/load_filter.js'; -import { TestFilterResult } from './test_filter/test_filter_result.js'; -import { RunCaseIterable } from './test_group.js'; - -// One of the following: -// - An actual .spec.ts file, as imported. -// - A *filtered* list of cases from a single .spec.ts file. -export interface TestSpec { - readonly description: string; - readonly g: RunCaseIterable; -} - -// A shell object describing a directory (from its README.txt). -export interface ReadmeFile { - readonly description: string; -} - -export type TestSpecOrReadme = TestSpec | ReadmeFile; - -type TestFilterResultIterator = IterableIterator<TestFilterResult>; -function* concat(lists: TestFilterResult[][]): TestFilterResultIterator { - for (const specs of lists) { - yield* specs; - } -} - -export interface TestFileLoader { - listing(suite: string): Promise<TestSuiteListing>; - import(path: string): Promise<TestSpecOrReadme>; -} - -class DefaultTestFileLoader implements TestFileLoader { - async listing(suite: string): Promise<TestSuiteListing> { - return (await import(`../../${suite}/listing.js`)).listing; - } - - import(path: string): Promise<TestSpec> { - return import('../../' + path); - } -} - -export class TestLoader { - private fileLoader: TestFileLoader; - - constructor(fileLoader: TestFileLoader = new DefaultTestFileLoader()) { - this.fileLoader = fileLoader; - } - - // TODO: Test - async loadTestsFromQuery(query: string): Promise<TestFilterResultIterator> { - return this.loadTests(new URLSearchParams(query).getAll('q')); - } - - // TODO: Test - // TODO: Probably should actually not exist at all, just use queries on cmd line too. - async loadTestsFromCmdLine(filters: string[]): Promise<TestFilterResultIterator> { - return this.loadTests(filters); - } - - async loadTests(filters: string[]): Promise<TestFilterResultIterator> { - const loads = filters.map(f => loadFilter(this.fileLoader, f)); - return concat(await Promise.all(loads)); - } -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/logger.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/logger.ts deleted file mode 100644 index 0dc2eb1a161..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/logger.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { SkipTestCase } from './fixture.js'; -import { TestSpecID } from './id.js'; -import { ParamSpec, extractPublicParams } from './params_utils.js'; -import { makeQueryString } from './url_query.js'; -import { getStackTrace } from './util/stack.js'; -import { assert, now } from './util/util.js'; -import { version } from './version.js'; - -type Status = 'running' | 'pass' | 'skip' | 'warn' | 'fail'; -export interface LiveTestSpecResult { - readonly spec: string; - readonly cases: LiveTestCaseResult[]; -} - -interface TestCaseResult { - readonly test: string; - readonly params: ParamSpec | null; - status: Status; - timems: number; -} - -export interface LiveTestCaseResult extends TestCaseResult { - logs?: LogMessageWithStack[]; -} - -export interface TransferredTestCaseResult extends TestCaseResult { - // When transferred from a worker, a LogMessageWithStack turns into a generic Error - // (its prototype gets lost and replaced with Error). - logs?: Error[]; -} - -export class LogMessageWithStack extends Error { - constructor(name: string, ex: Error, includeStack: boolean = true) { - super(ex.message); - - this.name = name; - this.stack = includeStack ? ex.stack : undefined; - } - - toJSON(): string { - let m = this.name; - if (this.message) { - m += ': ' + this.message; - } - if (this.stack) { - m += '\n' + getStackTrace(this); - } - return m; - } -} - -export class Logger { - readonly results: LiveTestSpecResult[] = []; - - constructor() {} - - record(spec: TestSpecID): [TestSpecRecorder, LiveTestSpecResult] { - const result: LiveTestSpecResult = { spec: makeQueryString(spec), cases: [] }; - this.results.push(result); - return [new TestSpecRecorder(result), result]; - } - - asJSON(space?: number): string { - return JSON.stringify({ version, results: this.results }, undefined, space); - } -} - -export class TestSpecRecorder { - private result: LiveTestSpecResult; - - constructor(result: LiveTestSpecResult) { - this.result = result; - } - - record(test: string, params: ParamSpec | null): [TestCaseRecorder, LiveTestCaseResult] { - const result: LiveTestCaseResult = { - test, - params: params ? extractPublicParams(params) : null, - status: 'running', - timems: -1, - }; - this.result.cases.push(result); - return [new TestCaseRecorder(result), result]; - } -} - -enum PassState { - pass = 0, - skip = 1, - warn = 2, - fail = 3, -} - -export class TestCaseRecorder { - private result: LiveTestCaseResult; - private state = PassState.pass; - private startTime = -1; - private logs: LogMessageWithStack[] = []; - private debugging = false; - - constructor(result: LiveTestCaseResult) { - this.result = result; - } - - start(debug: boolean = false): void { - this.startTime = now(); - this.logs = []; - this.state = PassState.pass; - this.debugging = debug; - } - - finish(): void { - assert(this.startTime >= 0, 'finish() before start()'); - - const endTime = now(); - // Round to next microsecond to avoid storing useless .xxxx00000000000002 in results. - this.result.timems = Math.ceil((endTime - this.startTime) * 1000) / 1000; - this.result.status = PassState[this.state] as Status; - - this.result.logs = this.logs; - this.debugging = false; - } - - debug(ex: Error): void { - if (!this.debugging) { - return; - } - this.logs.push(new LogMessageWithStack('DEBUG', ex, false)); - } - - warn(ex: Error): void { - this.setState(PassState.warn); - this.logs.push(new LogMessageWithStack('WARN', ex)); - } - - fail(ex: Error): void { - this.setState(PassState.fail); - this.logs.push(new LogMessageWithStack('FAIL', ex)); - } - - skipped(ex: SkipTestCase): void { - this.setState(PassState.skip); - this.logs.push(new LogMessageWithStack('SKIP', ex)); - } - - threw(ex: Error): void { - if (ex instanceof SkipTestCase) { - this.skipped(ex); - return; - } - - this.setState(PassState.fail); - this.logs.push(new LogMessageWithStack('EXCEPTION', ex)); - } - - private setState(state: PassState): void { - this.state = Math.max(this.state, state); - } -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/logging/log_message.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/log_message.ts new file mode 100644 index 00000000000..5c5c0900357 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/log_message.ts @@ -0,0 +1,37 @@ +import { extractImportantStackTrace } from '../util/stack.js'; + +export class LogMessageWithStack extends Error { + private stackHidden: boolean = false; + private timesSeen: number = 1; + + constructor(name: string, ex: Error) { + super(ex.message); + + this.name = name; + this.stack = ex.stack; + } + + /** Set a flag so the stack is not printed in toJSON(). */ + setStackHidden() { + this.stackHidden = true; + } + + /** Increment the "seen x times" counter. */ + incrementTimesSeen() { + this.timesSeen++; + } + + toJSON(): string { + let m = this.name + ': '; + if (!this.stackHidden && this.stack) { + // this.message is already included in this.stack + m += extractImportantStackTrace(this); + } else { + m += this.message; + } + if (this.timesSeen > 1) { + m += `\n(seen ${this.timesSeen} times with identical stack)`; + } + return m; + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/logging/logger.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/logger.ts new file mode 100644 index 00000000000..4f4bc1c45e5 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/logger.ts @@ -0,0 +1,25 @@ +import { version } from '../version.js'; + +import { LiveTestCaseResult } from './result.js'; +import { TestCaseRecorder } from './test_case_recorder.js'; + +export type LogResults = Map<string, LiveTestCaseResult>; + +export class Logger { + readonly debug: boolean; + readonly results: LogResults = new Map(); + + constructor(debug: boolean) { + this.debug = debug; + } + + record(name: string): [TestCaseRecorder, LiveTestCaseResult] { + const result: LiveTestCaseResult = { status: 'running', timems: -1 }; + this.results.set(name, result); + return [new TestCaseRecorder(result, this.debug), result]; + } + + asJSON(space?: number): string { + return JSON.stringify({ version, results: Array.from(this.results) }, undefined, space); + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/logging/result.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/result.ts new file mode 100644 index 00000000000..ebdaf47642b --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/result.ts @@ -0,0 +1,18 @@ +import { LogMessageWithStack } from './log_message.js'; + +export type Status = 'running' | 'pass' | 'skip' | 'warn' | 'fail'; + +export interface TestCaseResult { + status: Status; + timems: number; +} + +export interface LiveTestCaseResult extends TestCaseResult { + logs?: LogMessageWithStack[]; +} + +export interface TransferredTestCaseResult extends TestCaseResult { + // When transferred from a worker, a LogMessageWithStack turns into a generic Error + // (its prototype gets lost and replaced with Error). + logs?: Error[]; +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/logging/test_case_recorder.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/test_case_recorder.ts new file mode 100644 index 00000000000..55dcd26b1d8 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/logging/test_case_recorder.ts @@ -0,0 +1,126 @@ +import { SkipTestCase } from '../fixture.js'; +import { now, assert } from '../util/util.js'; + +import { LogMessageWithStack } from './log_message.js'; +import { LiveTestCaseResult } from './result.js'; + +enum LogSeverity { + Pass = 0, + Skip = 1, + Warn = 2, + ExpectFailed = 3, + ValidationFailed = 4, + ThrewException = 5, +} + +const kMaxLogStacks = 2; + +/** Holds onto a LiveTestCaseResult owned by the Logger, and writes the results into it. */ +export class TestCaseRecorder { + private result: LiveTestCaseResult; + private maxLogSeverity = LogSeverity.Pass; + private startTime = -1; + private logs: LogMessageWithStack[] = []; + private logLinesAtCurrentSeverity = 0; + private debugging = false; + /** Used to dedup log messages which have identical stacks. */ + private messagesForPreviouslySeenStacks = new Map<string, LogMessageWithStack>(); + + constructor(result: LiveTestCaseResult, debugging: boolean) { + this.result = result; + this.debugging = debugging; + } + + start(): void { + assert(this.startTime < 0, 'TestCaseRecorder cannot be reused'); + this.startTime = now(); + } + + finish(): void { + assert(this.startTime >= 0, 'finish() before start()'); + + const timeMilliseconds = now() - this.startTime; + // Round to next microsecond to avoid storing useless .xxxx00000000000002 in results. + this.result.timems = Math.ceil(timeMilliseconds * 1000) / 1000; + + // Convert numeric enum back to string (but expose 'exception' as 'fail') + this.result.status = + this.maxLogSeverity === LogSeverity.Pass + ? 'pass' + : this.maxLogSeverity === LogSeverity.Skip + ? 'skip' + : this.maxLogSeverity === LogSeverity.Warn + ? 'warn' + : 'fail'; // Everything else is an error + + this.result.logs = this.logs; + } + + injectResult(injectedResult: LiveTestCaseResult): void { + Object.assign(this.result, injectedResult); + } + + debug(ex: Error): void { + if (!this.debugging) { + return; + } + const logMessage = new LogMessageWithStack('DEBUG', ex); + logMessage.setStackHidden(); + this.logImpl(LogSeverity.Pass, logMessage); + } + + skipped(ex: SkipTestCase): void { + this.logImpl(LogSeverity.Skip, new LogMessageWithStack('SKIP', ex)); + } + + warn(ex: Error): void { + this.logImpl(LogSeverity.Warn, new LogMessageWithStack('WARN', ex)); + } + + expectationFailed(ex: Error): void { + this.logImpl(LogSeverity.ExpectFailed, new LogMessageWithStack('EXPECTATION FAILED', ex)); + } + + validationFailed(ex: Error): void { + this.logImpl(LogSeverity.ValidationFailed, new LogMessageWithStack('VALIDATION FAILED', ex)); + } + + threw(ex: Error): void { + if (ex instanceof SkipTestCase) { + this.skipped(ex); + return; + } + this.logImpl(LogSeverity.ThrewException, new LogMessageWithStack('EXCEPTION', ex)); + } + + private logImpl(level: LogSeverity, logMessage: LogMessageWithStack): void { + // Deduplicate errors with the exact same stack + if (logMessage.stack) { + const seen = this.messagesForPreviouslySeenStacks.get(logMessage.stack); + if (seen) { + seen.incrementTimesSeen(); + return; + } + this.messagesForPreviouslySeenStacks.set(logMessage.stack, logMessage); + } + + // Mark printStack=false for all logs except 2 at the highest severity + if (level > this.maxLogSeverity) { + this.logLinesAtCurrentSeverity = 0; + this.maxLogSeverity = level; + if (!this.debugging) { + // Go back and turn off printStack for everything of a lower log level + for (const log of this.logs) { + log.setStackHidden(); + } + } + } + if (level < this.maxLogSeverity || this.logLinesAtCurrentSeverity >= kMaxLogStacks) { + if (!this.debugging) { + logMessage.setStackHidden(); + } + } + this.logs.push(logMessage); + this.logLinesAtCurrentSeverity++; + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/params.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/params.ts deleted file mode 100644 index b76279cd2aa..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/params.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - ParamArgument, - ParamSpec, - ParamSpecIterable, - ParamSpecIterator, - paramsEquals, -} from './params_utils.js'; -import { assert } from './util/util.js'; - -export function poptions(name: string, values: ParamArgument[]): POptions { - return new POptions(name, values); -} -export function pbool(name: string): POptions { - return new POptions(name, [false, true]); -} -export function pexclude(params: ParamSpecIterable, exclude: ParamSpecIterable): PExclude { - return new PExclude(params, exclude); -} -export function pfilter(cases: ParamSpecIterable, pred: Predicate): PFilter { - return new PFilter(cases, pred); -} -export function pcombine(...params: ParamSpecIterable[]): ParamSpecIterable { - return new PCombine(params); -} - -class POptions implements ParamSpecIterable { - private name: string; - private values: ParamArgument[]; - - constructor(name: string, values: ParamArgument[]) { - this.name = name; - this.values = values; - } - - *[Symbol.iterator](): ParamSpecIterator { - for (const value of this.values) { - yield { [this.name]: value }; - } - } -} - -class PExclude implements ParamSpecIterable { - private cases: ParamSpecIterable; - private exclude: ParamSpec[]; - - constructor(cases: ParamSpecIterable, exclude: ParamSpecIterable) { - this.cases = cases; - this.exclude = Array.from(exclude); - } - - *[Symbol.iterator](): ParamSpecIterator { - for (const p of this.cases) { - if (this.exclude.every(e => !paramsEquals(p, e))) { - yield p; - } - } - } -} - -type Predicate = (o: ParamSpec) => boolean; -class PFilter implements ParamSpecIterable { - private cases: ParamSpecIterable; - private pred: Predicate; - - constructor(cases: ParamSpecIterable, pred: Predicate) { - this.cases = cases; - this.pred = pred; - } - - *[Symbol.iterator](): ParamSpecIterator { - for (const p of this.cases) { - if (this.pred(p)) { - yield p; - } - } - } -} - -class PCombine implements ParamSpecIterable { - private params: ParamSpecIterable[]; - - constructor(params: ParamSpecIterable[]) { - this.params = params; - } - - [Symbol.iterator](): ParamSpecIterator { - return PCombine.cartesian(this.params); - } - - static merge(a: ParamSpec, b: ParamSpec): ParamSpec { - for (const key of Object.keys(a)) { - assert(!b.hasOwnProperty(key), 'Duplicate key: ' + key); - } - return { ...a, ...b }; - } - - static *cartesian(iters: ParamSpecIterable[]): ParamSpecIterator { - if (iters.length === 0) { - return; - } - if (iters.length === 1) { - yield* iters[0]; - return; - } - const [as, ...rest] = iters; - for (const a of as) { - for (const b of PCombine.cartesian(rest)) { - yield PCombine.merge(a, b); - } - } - } -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/params_builder.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/params_builder.ts new file mode 100644 index 00000000000..9b18c9f30d6 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/params_builder.ts @@ -0,0 +1,127 @@ +import { CaseParams, CaseParamsIterable, publicParamsEquals } from './params_utils.js'; +import { assert } from './util/util.js'; + +// https://stackoverflow.com/a/56375136 +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void + ? I + : never; +type CheckForUnion<T, TErr, TOk> = [T] extends [UnionToIntersection<T>] ? TOk : TErr; + +type CheckForStringLiteralType<T, TOk> = string extends T ? void : CheckForUnion<T, void, TOk>; + +export function poptions<Name extends string, V>( + name: Name, + values: Iterable<V> +): CheckForStringLiteralType<Name, Iterable<{ [name in Name]: V }>> { + const iter = makeReusableIterable(function* () { + for (const value of values) { + yield { [name]: value }; + } + }); + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + return iter as any; +} + +export function pbool<Name extends string>( + name: Name +): CheckForStringLiteralType<Name, Iterable<{ [name in Name]: boolean }>> { + return poptions(name, [false, true]); +} + +export function params(): ParamsBuilder<{}> { + return new ParamsBuilder(); +} + +export class ParamsBuilder<A extends {}> implements CaseParamsIterable { + private paramSpecs: CaseParamsIterable = [{}]; + + [Symbol.iterator](): Iterator<A> { + const iter: Iterator<CaseParams> = this.paramSpecs[Symbol.iterator](); + return iter as Iterator<A>; + } + + combine<B extends {}>(newParams: Iterable<B>): ParamsBuilder<Merged<A, B>> { + const paramSpecs = this.paramSpecs as Iterable<A>; + this.paramSpecs = makeReusableIterable(function* () { + for (const a of paramSpecs) { + for (const b of newParams) { + yield mergeParams(a, b); + } + } + }) as CaseParamsIterable; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + return this as any; + } + + expand<B extends {}>(expander: (_: A) => Iterable<B>): ParamsBuilder<Merged<A, B>> { + const paramSpecs = this.paramSpecs as Iterable<A>; + this.paramSpecs = makeReusableIterable(function* () { + for (const a of paramSpecs) { + for (const b of expander(a)) { + yield mergeParams(a, b); + } + } + }) as CaseParamsIterable; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + return this as any; + } + + filter(pred: (_: A) => boolean): ParamsBuilder<A> { + const paramSpecs = this.paramSpecs as Iterable<A>; + this.paramSpecs = makeReusableIterable(function* () { + for (const p of paramSpecs) { + if (pred(p)) { + yield p; + } + } + }); + return this; + } + + unless(pred: (_: A) => boolean): ParamsBuilder<A> { + return this.filter(x => !pred(x)); + } + + exclude(exclude: CaseParamsIterable): ParamsBuilder<A> { + const excludeArray = Array.from(exclude); + const paramSpecs = this.paramSpecs; + this.paramSpecs = makeReusableIterable(function* () { + for (const p of paramSpecs) { + if (excludeArray.every(e => !publicParamsEquals(p, e))) { + yield p; + } + } + }); + return this; + } +} + +// If you create an Iterable by calling a generator function (e.g. in IIFE), it is exhausted after +// one use. This just wraps a generator function in an object so it be iterated multiple times. +function makeReusableIterable<P>(generatorFn: () => Generator<P>): Iterable<P> { + return { [Symbol.iterator]: generatorFn }; +} + +type ValueTypeForKeyOfMergedType<A, B, Key extends keyof A | keyof B> = Key extends keyof A + ? Key extends keyof B + ? void // Key is in both types + : A[Key] // Key is only in A + : Key extends keyof B + ? B[Key] // Key is only in B + : void; // Key is in neither type (not possible) + +type Merged<A, B> = keyof A & keyof B extends never + ? string extends keyof A | keyof B + ? never // (keyof A | keyof B) == string, which is too broad + : { + [Key in keyof A | keyof B]: ValueTypeForKeyOfMergedType<A, B, Key>; + } + : never; // (keyof A & keyof B) is not empty, so they overlapped + +function mergeParams<A extends {}, B extends {}>(a: A, b: B): Merged<A, B> { + for (const key of Object.keys(a)) { + assert(!(key in b), 'Duplicate key: ' + key); + } + return { ...a, ...b } as Merged<A, B>; +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/params_utils.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/params_utils.ts index 4022f1d0d3a..e8c9f4cedda 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/params_utils.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/params_utils.ts @@ -1,69 +1,34 @@ -import { objectEquals } from './util/util.js'; +import { comparePublicParamsPaths, Ordering } from './query/compare.js'; +import { kWildcard, kParamSeparator, kParamKVSeparator } from './query/separators.js'; -// tslint:disable-next-line: no-any -export type ParamArgument = any; -export interface ParamSpec { +// Consider adding more types here if needed +export type ParamArgument = void | undefined | number | string | boolean | number[]; +export interface CaseParams { + readonly [k: string]: ParamArgument; +} +export interface CaseParamsRW { [k: string]: ParamArgument; } -export type ParamSpecIterable = Iterable<ParamSpec>; -export type ParamSpecIterator = IterableIterator<ParamSpec>; +export type CaseParamsIterable = Iterable<CaseParams>; + +export function paramKeyIsPublic(key: string): boolean { + return !key.startsWith('_'); +} -export function extractPublicParams(params: ParamSpec): ParamSpec { - const publicParams: ParamSpec = {}; +export function extractPublicParams(params: CaseParams): CaseParams { + const publicParams: CaseParamsRW = {}; for (const k of Object.keys(params)) { - if (!k.startsWith('_')) { + if (paramKeyIsPublic(k)) { publicParams[k] = params[k]; } } return publicParams; } -export function stringifyPublicParams(p: ParamSpec | null): string { - if (p === null || paramsEquals(p, {})) { - return ''; - } - return JSON.stringify(extractPublicParams(p)); -} +export const badParamValueChars = new RegExp( + '[' + kParamKVSeparator + kParamSeparator + kWildcard + ']' +); -export function paramsEquals(x: ParamSpec | null, y: ParamSpec | null): boolean { - if (x === y) { - return true; - } - if (x === null) { - x = {}; - } - if (y === null) { - y = {}; - } - - for (const xk of Object.keys(x)) { - if (x[xk] !== undefined && !y.hasOwnProperty(xk)) { - return false; - } - if (!objectEquals(x[xk], y[xk])) { - return false; - } - } - - for (const yk of Object.keys(y)) { - if (y[yk] !== undefined && !x.hasOwnProperty(yk)) { - return false; - } - } - return true; -} - -export function paramsSupersets(sup: ParamSpec | null, sub: ParamSpec | null): boolean { - if (sub === null) { - return true; - } - if (sup === null) { - sup = {}; - } - for (const k of Object.keys(sub)) { - if (!sup.hasOwnProperty(k) || sup[k] !== sub[k]) { - return false; - } - } - return true; +export function publicParamsEquals(x: CaseParams, y: CaseParams): boolean { + return comparePublicParamsPaths(x, y) === Ordering.Equal; } diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/compare.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/compare.ts new file mode 100644 index 00000000000..c823ec915a7 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/compare.ts @@ -0,0 +1,93 @@ +import { CaseParams, paramKeyIsPublic } from '../params_utils.js'; +import { assert, objectEquals } from '../util/util.js'; + +import { TestQuery } from './query.js'; + +export const enum Ordering { + Unordered, + StrictSuperset, + Equal, + StrictSubset, +} + +/** + * Compares two queries for their ordering (which is used to build the tree). + * + * See src/unittests/query_compare.spec.ts for examples. + */ +export function compareQueries(a: TestQuery, b: TestQuery): Ordering { + if (a.suite !== b.suite) { + return Ordering.Unordered; + } + + const filePathOrdering = comparePaths(a.filePathParts, b.filePathParts); + if (filePathOrdering !== Ordering.Equal || a.isMultiFile || b.isMultiFile) { + return compareOneLevel(filePathOrdering, a.isMultiFile, b.isMultiFile); + } + assert('testPathParts' in a && 'testPathParts' in b); + + const testPathOrdering = comparePaths(a.testPathParts, b.testPathParts); + if (testPathOrdering !== Ordering.Equal || a.isMultiTest || b.isMultiTest) { + return compareOneLevel(testPathOrdering, a.isMultiTest, b.isMultiTest); + } + assert('params' in a && 'params' in b); + + const paramsPathOrdering = comparePublicParamsPaths(a.params, b.params); + if (paramsPathOrdering !== Ordering.Equal || a.isMultiCase || b.isMultiCase) { + return compareOneLevel(paramsPathOrdering, a.isMultiCase, b.isMultiCase); + } + return Ordering.Equal; +} + +/** + * Compares a single level of a query. + * + * "IsBig" means the query is big relative to the level, e.g. for test-level: + * - Anything >= `suite:a,*` is big + * - Anything <= `suite:a:*` is small + */ +function compareOneLevel(ordering: Ordering, aIsBig: boolean, bIsBig: boolean): Ordering { + assert(ordering !== Ordering.Equal || aIsBig || bIsBig); + if (ordering === Ordering.Unordered) return Ordering.Unordered; + if (aIsBig && bIsBig) return ordering; + if (!aIsBig && !bIsBig) return Ordering.Unordered; // Equal case is already handled + // Exactly one of (a, b) is big. + if (aIsBig && ordering !== Ordering.StrictSubset) return Ordering.StrictSuperset; + if (bIsBig && ordering !== Ordering.StrictSuperset) return Ordering.StrictSubset; + return Ordering.Unordered; +} + +function comparePaths(a: readonly string[], b: readonly string[]): Ordering { + const shorter = Math.min(a.length, b.length); + + for (let i = 0; i < shorter; ++i) { + if (a[i] !== b[i]) { + return Ordering.Unordered; + } + } + if (a.length === b.length) { + return Ordering.Equal; + } else if (a.length < b.length) { + return Ordering.StrictSuperset; + } else { + return Ordering.StrictSubset; + } +} + +export function comparePublicParamsPaths(a: CaseParams, b: CaseParams): Ordering { + const aKeys = Object.keys(a).filter(k => paramKeyIsPublic(k)); + const commonKeys = new Set(aKeys.filter(k => k in b)); + + for (const k of commonKeys) { + if (!objectEquals(a[k], b[k])) { + return Ordering.Unordered; + } + } + const bKeys = Object.keys(b).filter(k => paramKeyIsPublic(k)); + const aRemainingKeys = aKeys.length - commonKeys.size; + const bRemainingKeys = bKeys.length - commonKeys.size; + if (aRemainingKeys === 0 && bRemainingKeys === 0) return Ordering.Equal; + if (aRemainingKeys === 0) return Ordering.StrictSuperset; + if (bRemainingKeys === 0) return Ordering.StrictSubset; + return Ordering.Unordered; +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/encode_selectively.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/encode_selectively.ts new file mode 100644 index 00000000000..cc25e2dc739 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/encode_selectively.ts @@ -0,0 +1,20 @@ +/** + * Encodes a stringified TestQuery so that it can be placed in a `?q=` parameter in a URL. + * + * `encodeURIComponent` encodes in accordance with `application/x-www-form-urlencoded`, + * but URLs don't actually have to be as strict as HTML form encoding + * (we interpret this purely from JavaScript). + * So we encode the component, then selectively convert some %-encoded escape codes + * back to their original form for readability/copyability. + */ +export function encodeURIComponentSelectively(s: string): string { + let ret = encodeURIComponent(s); + ret = ret.replace(/%22/g, '"'); // for JSON strings + ret = ret.replace(/%2C/g, ','); // for path separator, and JSON arrays + ret = ret.replace(/%3A/g, ':'); // for big separator + ret = ret.replace(/%3B/g, ';'); // for param separator + ret = ret.replace(/%3D/g, '='); // for params (k=v) + ret = ret.replace(/%5B/g, '['); // for JSON arrays + ret = ret.replace(/%5D/g, ']'); // for JSON arrays + return ret; +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/parseQuery.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/parseQuery.ts new file mode 100644 index 00000000000..029ad4fc4fc --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/parseQuery.ts @@ -0,0 +1,132 @@ +import { + CaseParamsRW, + ParamArgument, + badParamValueChars, + paramKeyIsPublic, +} from '../params_utils.js'; +import { assert } from '../util/util.js'; + +import { + TestQuery, + TestQueryMultiFile, + TestQueryMultiTest, + TestQueryMultiCase, + TestQuerySingleCase, +} from './query.js'; +import { kBigSeparator, kWildcard, kPathSeparator, kParamSeparator } from './separators.js'; +import { validQueryPart } from './validQueryPart.js'; + +export function parseQuery(s: string): TestQuery { + try { + return parseQueryImpl(s); + } catch (ex) { + ex.message += '\n on: ' + s; + throw ex; + } +} + +function parseQueryImpl(s: string): TestQuery { + // Undo encodeURIComponentSelectively + s = decodeURIComponent(s); + + // bigParts are: suite, group, test, params (note kBigSeparator could appear in params) + const [suite, fileString, testString, paramsString] = s.split(kBigSeparator, 4); + assert(fileString !== undefined, `filter string must have at least one ${kBigSeparator}`); + + const { parts: file, wildcard: filePathHasWildcard } = parseBigPart(fileString, kPathSeparator); + + if (testString === undefined) { + // Query is file-level + assert( + filePathHasWildcard, + `File-level query without wildcard ${kWildcard}. Did you want a file-level query \ +(append ${kPathSeparator}${kWildcard}) or test-level query (append ${kBigSeparator}${kWildcard})?` + ); + return new TestQueryMultiFile(suite, file); + } + assert(!filePathHasWildcard, `Wildcard ${kWildcard} must be at the end of the query string`); + + const { parts: test, wildcard: testPathHasWildcard } = parseBigPart(testString, kPathSeparator); + + if (paramsString === undefined) { + // Query is test-level + assert( + testPathHasWildcard, + `Test-level query without wildcard ${kWildcard}; did you want a test-level query \ +(append ${kPathSeparator}${kWildcard}) or case-level query (append ${kBigSeparator}${kWildcard})?` + ); + assert(file.length > 0, 'File part of test-level query was empty (::)'); + return new TestQueryMultiTest(suite, file, test); + } + + // Query is case-level + assert(!testPathHasWildcard, `Wildcard ${kWildcard} must be at the end of the query string`); + + const { parts: paramsParts, wildcard: paramsHasWildcard } = parseBigPart( + paramsString, + kParamSeparator + ); + + assert(test.length > 0, 'Test part of case-level query was empty (::)'); + + const params: CaseParamsRW = {}; + for (const paramPart of paramsParts) { + const [k, v] = parseSingleParam(paramPart); + assert(validQueryPart.test(k), 'param key names must match ' + validQueryPart); + params[k] = v; + } + if (paramsHasWildcard) { + return new TestQueryMultiCase(suite, file, test, params); + } else { + return new TestQuerySingleCase(suite, file, test, params); + } +} + +// webgpu:a,b,* or webgpu:a,b,c:* +const kExampleQueries = `\ +webgpu${kBigSeparator}a${kPathSeparator}b${kPathSeparator}${kWildcard} or \ +webgpu${kBigSeparator}a${kPathSeparator}b${kPathSeparator}c${kBigSeparator}${kWildcard}`; + +function parseBigPart( + s: string, + separator: typeof kParamSeparator | typeof kPathSeparator +): { parts: string[]; wildcard: boolean } { + if (s === '') { + return { parts: [], wildcard: false }; + } + const parts = s.split(separator); + + let endsWithWildcard = false; + for (const [i, part] of parts.entries()) { + if (i === parts.length - 1) { + endsWithWildcard = part === kWildcard; + } + assert( + part.indexOf(kWildcard) === -1 || endsWithWildcard, + `Wildcard ${kWildcard} must be complete last part of a path (e.g. ${kExampleQueries})` + ); + } + if (endsWithWildcard) { + // Remove the last element of the array (which is just the wildcard). + parts.length = parts.length - 1; + } + return { parts, wildcard: endsWithWildcard }; +} + +function parseSingleParam(paramSubstring: string): [string, ParamArgument] { + assert(paramSubstring !== '', 'Param in a query must not be blank (is there a trailing comma?)'); + const i = paramSubstring.indexOf('='); + assert(i !== -1, 'Param in a query must be of form key=value'); + const k = paramSubstring.substring(0, i); + assert(paramKeyIsPublic(k), 'Param in a query must not be private (start with _)'); + const v = paramSubstring.substring(i + 1); + return [k, parseSingleParamValue(v)]; +} + +function parseSingleParamValue(s: string): ParamArgument { + assert( + !badParamValueChars.test(s), + `param value must not match ${badParamValueChars} - was ${s}` + ); + return s === 'undefined' ? undefined : JSON.parse(s); +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/query.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/query.ts new file mode 100644 index 00000000000..9b951fe69d9 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/query.ts @@ -0,0 +1,123 @@ +import { CaseParams } from '../params_utils.js'; +import { assert } from '../util/util.js'; + +import { encodeURIComponentSelectively } from './encode_selectively.js'; +import { kBigSeparator, kPathSeparator, kWildcard, kParamSeparator } from './separators.js'; +import { stringifyPublicParams } from './stringify_params.js'; + +/** + * Represents a test query of some level. + * + * TestQuery types are immutable. + */ +export type TestQuery = + | TestQuerySingleCase + | TestQueryMultiCase + | TestQueryMultiTest + | TestQueryMultiFile; + +export type TestQueryLevel = + | 1 // MultiFile + | 2 // MultiTest + | 3 // MultiCase + | 4; // SingleCase + +/** + * A multi-file test query, like `s:*` or `s:a,b,*`. + * + * Immutable (makes copies of constructor args). + */ +export class TestQueryMultiFile { + readonly level: TestQueryLevel = 1; + readonly isMultiFile: boolean = true; + readonly suite: string; + readonly filePathParts: readonly string[]; + + constructor(suite: string, file: readonly string[]) { + this.suite = suite; + this.filePathParts = [...file]; + } + + toString(): string { + return encodeURIComponentSelectively(this.toStringHelper().join(kBigSeparator)); + } + + protected toStringHelper(): string[] { + return [this.suite, [...this.filePathParts, kWildcard].join(kPathSeparator)]; + } +} + +/** + * A multi-test test query, like `s:f:*` or `s:f:a,b,*`. + * + * Immutable (makes copies of constructor args). + */ +export class TestQueryMultiTest extends TestQueryMultiFile { + readonly level: TestQueryLevel = 2; + readonly isMultiFile: false = false; + readonly isMultiTest: boolean = true; + readonly testPathParts: readonly string[]; + + constructor(suite: string, file: readonly string[], test: readonly string[]) { + super(suite, file); + assert(file.length > 0, 'multi-test (or finer) query must have file-path'); + this.testPathParts = [...test]; + } + + protected toStringHelper(): string[] { + return [ + this.suite, + this.filePathParts.join(kPathSeparator), + [...this.testPathParts, kWildcard].join(kPathSeparator), + ]; + } +} + +/** + * A multi-case test query, like `s:f:t:*` or `s:f:t:a,b,*`. + * + * Immutable (makes copies of constructor args), except for param values + * (which aren't normally supposed to change; they're marked readonly in CaseParams). + */ +export class TestQueryMultiCase extends TestQueryMultiTest { + readonly level: TestQueryLevel = 3; + readonly isMultiTest: false = false; + readonly isMultiCase: boolean = true; + readonly params: CaseParams; + + constructor(suite: string, file: readonly string[], test: readonly string[], params: CaseParams) { + super(suite, file, test); + assert(test.length > 0, 'multi-case (or finer) query must have test-path'); + this.params = { ...params }; + } + + protected toStringHelper(): string[] { + const paramsParts = stringifyPublicParams(this.params); + return [ + this.suite, + this.filePathParts.join(kPathSeparator), + this.testPathParts.join(kPathSeparator), + [...paramsParts, kWildcard].join(kParamSeparator), + ]; + } +} + +/** + * A multi-case test query, like `s:f:t:` or `s:f:t:a=1,b=1`. + * + * Immutable (makes copies of constructor args). + */ +export class TestQuerySingleCase extends TestQueryMultiCase { + readonly level: TestQueryLevel = 4; + readonly isMultiCase: false = false; + + protected toStringHelper(): string[] { + const paramsParts = stringifyPublicParams(this.params); + return [ + this.suite, + this.filePathParts.join(kPathSeparator), + this.testPathParts.join(kPathSeparator), + paramsParts.join(kParamSeparator), + ]; + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/separators.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/separators.ts new file mode 100644 index 00000000000..0c8f6ea9a94 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/separators.ts @@ -0,0 +1,14 @@ +/** Separator between big parts: suite:file:test:case */ +export const kBigSeparator = ':'; + +/** Separator between path,to,file or path,to,test */ +export const kPathSeparator = ','; + +/** Separator between k=v;k=v */ +export const kParamSeparator = ';'; + +/** Separator between key and value in k=v */ +export const kParamKVSeparator = '='; + +/** Final wildcard, if query is not single-case */ +export const kWildcard = '*'; diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/stringify_params.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/stringify_params.ts new file mode 100644 index 00000000000..921667aceae --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/stringify_params.ts @@ -0,0 +1,28 @@ +import { + CaseParams, + ParamArgument, + badParamValueChars, + paramKeyIsPublic, +} from '../params_utils.js'; +import { assert } from '../util/util.js'; + +import { kParamKVSeparator } from './separators.js'; + +export function stringifyPublicParams(p: CaseParams): string[] { + return Object.keys(p) + .filter(k => paramKeyIsPublic(k)) + .map(k => stringifySingleParam(k, p[k])); +} + +export function stringifySingleParam(k: string, v: ParamArgument) { + return `${k}${kParamKVSeparator}${stringifySingleParamValue(v)}`; +} + +function stringifySingleParamValue(v: ParamArgument): string { + const s = v === undefined ? 'undefined' : JSON.stringify(v); + assert( + !badParamValueChars.test(s), + `JSON.stringified param value must not match ${badParamValueChars} - was ${s}` + ); + return s; +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/query/validQueryPart.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/query/validQueryPart.ts new file mode 100644 index 00000000000..62184adb625 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/query/validQueryPart.ts @@ -0,0 +1,2 @@ +/** Applies to group parts, test parts, params keys. */ +export const validQueryPart = /^[a-zA-Z0-9_]+$/; diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/filter_by_group.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/filter_by_group.ts deleted file mode 100644 index 021c4078ae2..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/filter_by_group.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { TestSpecOrTestOrCaseID } from '../id.js'; -import { ReadmeFile, TestFileLoader, TestSpec } from '../loader.js'; - -import { TestFilter } from './internal.js'; -import { TestFilterResult } from './test_filter_result.js'; - -export class FilterByGroup implements TestFilter { - private readonly suite: string; - private readonly specPathPrefix: string; - - constructor(suite: string, groupPrefix: string) { - this.suite = suite; - this.specPathPrefix = groupPrefix; - } - - matches(id: TestSpecOrTestOrCaseID): boolean { - return id.spec.suite === this.suite && this.pathMatches(id.spec.path); - } - - async iterate(loader: TestFileLoader): Promise<TestFilterResult[]> { - const specs = await loader.listing(this.suite); - const entries: TestFilterResult[] = []; - - const suite = this.suite; - for (const { path, description } of specs) { - if (this.pathMatches(path)) { - const isReadme = path === '' || path.endsWith('/'); - const spec = isReadme - ? ({ description } as ReadmeFile) - : ((await loader.import(`${suite}/${path}.spec.js`)) as TestSpec); - entries.push({ id: { suite, path }, spec }); - } - } - - return entries; - } - - definitelyOneFile(): boolean { - // FilterByGroup could always possibly match multiple files, because it represents a prefix, - // e.g. "a:b" not "a:b:". - return false; - } - - idIfSingle(): undefined { - // FilterByGroup could be one whole suite, but we only want whole files, tests, or cases. - return undefined; - } - - private pathMatches(path: string): boolean { - return path.startsWith(this.specPathPrefix); - } -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/filter_one_file.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/filter_one_file.ts deleted file mode 100644 index c6cc9969458..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/filter_one_file.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { TestCaseID, TestSpecID, TestSpecOrTestOrCaseID, testSpecEquals } from '../id.js'; -import { TestFileLoader, TestSpec } from '../loader.js'; -import { TestSpecRecorder } from '../logger.js'; -import { ParamSpec, paramsEquals, paramsSupersets } from '../params_utils.js'; -import { RunCase, RunCaseIterable } from '../test_group.js'; - -import { TestFilter } from './internal.js'; -import { TestFilterResult } from './test_filter_result.js'; - -abstract class FilterOneFile implements TestFilter { - protected readonly specId: TestSpecID; - - constructor(specId: TestSpecID) { - this.specId = specId; - } - - abstract getCases(spec: TestSpec): RunCaseIterable; - - async iterate(loader: TestFileLoader): Promise<TestFilterResult[]> { - const spec = (await loader.import( - `${this.specId.suite}/${this.specId.path}.spec.js` - )) as TestSpec; - return [ - { - id: this.specId, - spec: { - description: spec.description, - g: this.getCases(spec), - }, - }, - ]; - } - - definitelyOneFile(): true { - return true; - } - - abstract idIfSingle(): TestSpecOrTestOrCaseID | undefined; - abstract matches(id: TestSpecOrTestOrCaseID): boolean; -} - -type TestGroupFilter = (testcase: TestCaseID) => boolean; -function filterTestGroup(group: RunCaseIterable, filter: TestGroupFilter): RunCaseIterable { - return { - *iterate(log: TestSpecRecorder): Iterable<RunCase> { - for (const rc of group.iterate(log)) { - if (filter(rc.id)) { - yield rc; - } - } - }, - }; -} - -export class FilterByTestMatch extends FilterOneFile { - private readonly testPrefix: string; - - constructor(specId: TestSpecID, testPrefix: string) { - super(specId); - this.testPrefix = testPrefix; - } - - getCases(spec: TestSpec): RunCaseIterable { - return filterTestGroup(spec.g, testcase => this.testMatches(testcase.test)); - } - - idIfSingle(): TestSpecOrTestOrCaseID | undefined { - if (this.testPrefix.length !== 0) { - return undefined; - } - // This is one whole spec file. - return { spec: this.specId }; - } - - matches(id: TestSpecOrTestOrCaseID): boolean { - if (id.test === undefined) { - return false; - } - return testSpecEquals(id.spec, this.specId) && this.testMatches(id.test); - } - - private testMatches(test: string): boolean { - return test.startsWith(this.testPrefix); - } -} - -export class FilterByParamsMatch extends FilterOneFile { - private readonly test: string; - private readonly params: ParamSpec | null; - - constructor(specId: TestSpecID, test: string, params: ParamSpec | null) { - super(specId); - this.test = test; - this.params = params; - } - - getCases(spec: TestSpec): RunCaseIterable { - return filterTestGroup(spec.g, testcase => this.caseMatches(testcase.test, testcase.params)); - } - - idIfSingle(): TestSpecOrTestOrCaseID | undefined { - if (this.params !== null) { - return undefined; - } - // This is one whole test. - return { spec: this.specId, test: this.test }; - } - - matches(id: TestSpecOrTestOrCaseID): boolean { - if (id.test === undefined) { - return false; - } - return testSpecEquals(id.spec, this.specId) && this.caseMatches(id.test, id.params); - } - - private caseMatches(test: string, params: ParamSpec | null | undefined): boolean { - if (params === undefined) { - return false; - } - return test === this.test && paramsSupersets(params, this.params); - } -} - -export class FilterByParamsExact extends FilterOneFile { - private readonly test: string; - private readonly params: ParamSpec | null; - - constructor(specId: TestSpecID, test: string, params: ParamSpec | null) { - super(specId); - this.test = test; - this.params = params; - } - - getCases(spec: TestSpec): RunCaseIterable { - return filterTestGroup(spec.g, testcase => this.caseMatches(testcase.test, testcase.params)); - } - - idIfSingle(): TestSpecOrTestOrCaseID | undefined { - // This is one single test case. - return { spec: this.specId, test: this.test, params: this.params }; - } - - matches(id: TestSpecOrTestOrCaseID): boolean { - if (id.test === undefined || id.params === undefined) { - return false; - } - return testSpecEquals(id.spec, this.specId) && this.caseMatches(id.test, id.params); - } - - private caseMatches(test: string, params: ParamSpec | null): boolean { - return test === this.test && paramsEquals(params, this.params); - } -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/internal.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/internal.ts deleted file mode 100644 index 5f22b4d763a..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/internal.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { TestSpecOrTestOrCaseID } from '../id.js'; -import { TestFileLoader } from '../loader.js'; - -import { TestFilterResult } from './test_filter_result.js'; - -export interface TestFilter { - // Iterates over the test cases matched by the filter. - iterate(loader: TestFileLoader): Promise<TestFilterResult[]>; - - // Iff the filter could not possibly match multiple files, returns true. - definitelyOneFile(): boolean; - - // If the filter can accept one spec, one test, or one case, returns its ID. - idIfSingle(): TestSpecOrTestOrCaseID | undefined; - - matches(id: TestSpecOrTestOrCaseID): boolean; -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/load_filter.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/load_filter.ts deleted file mode 100644 index 08096ffd056..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/load_filter.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { allowedTestNameCharacters } from '../allowed_characters.js'; -import { TestFileLoader } from '../loader.js'; -import { ParamSpec } from '../params_utils.js'; -import { assert, unreachable } from '../util/util.js'; - -import { FilterByGroup } from './filter_by_group.js'; -import { FilterByParamsExact, FilterByParamsMatch, FilterByTestMatch } from './filter_one_file.js'; -import { TestFilter } from './internal.js'; -import { TestFilterResult } from './test_filter_result.js'; - -// Each filter is of one of the forms below (urlencoded). -export function makeFilter(filter: string): TestFilter { - const i1 = filter.indexOf(':'); - assert(i1 !== -1, 'Test queries must fully specify their suite name (e.g. "webgpu:")'); - - const suite = filter.substring(0, i1); - const i2 = filter.indexOf(':', i1 + 1); - if (i2 === -1) { - // - webgpu: - // - webgpu:buf - // - webgpu:buffers/ - // - webgpu:buffers/map - const groupPrefix = filter.substring(i1 + 1); - return new FilterByGroup(suite, groupPrefix); - } - - const path = filter.substring(i1 + 1, i2); - const endOfTestName = new RegExp('[^' + allowedTestNameCharacters + ']'); - const i3sub = filter.substring(i2 + 1).search(endOfTestName); - if (i3sub === -1) { - // - webgpu:buffers/mapWriteAsync: - // - webgpu:buffers/mapWriteAsync:b - const testPrefix = filter.substring(i2 + 1); - return new FilterByTestMatch({ suite, path }, testPrefix); - } - - const i3 = i2 + 1 + i3sub; - const test = filter.substring(i2 + 1, i3); - const token = filter.charAt(i3); - - let params = null; - if (i3 + 1 < filter.length) { - params = JSON.parse(filter.substring(i3 + 1)) as ParamSpec; - } - - if (token === '~') { - // - webgpu:buffers/mapWriteAsync:basic~ - // - webgpu:buffers/mapWriteAsync:basic~{} - // - webgpu:buffers/mapWriteAsync:basic~{filter:"params"} - return new FilterByParamsMatch({ suite, path }, test, params); - } else if (token === '=') { - // - webgpu:buffers/mapWriteAsync:basic= - // - webgpu:buffers/mapWriteAsync:basic={} - // - webgpu:buffers/mapWriteAsync:basic={exact:"params"} - return new FilterByParamsExact({ suite, path }, test, params); - } else { - unreachable("invalid character after test name; must be '~' or '='"); - } -} - -export function loadFilter(loader: TestFileLoader, filter: string): Promise<TestFilterResult[]> { - return makeFilter(filter).iterate(loader); -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/test_filter_result.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/test_filter_result.ts deleted file mode 100644 index 934d94eb331..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/test_filter/test_filter_result.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { TestSpecID } from '../id.js'; -import { TestSpecOrReadme } from '../loader.js'; - -// Result of iterating a test filter. Contains a loaded spec (.spec.ts) file and its id. -export interface TestFilterResult { - readonly id: TestSpecID; - readonly spec: TestSpecOrReadme; -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_group.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_group.ts index 1bf00efdbc0..706a2334f33 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/test_group.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/test_group.ts @@ -1,43 +1,66 @@ -import { allowedTestNameCharacters } from './allowed_characters.js'; import { Fixture } from './fixture.js'; -import { TestCaseID } from './id.js'; -import { LiveTestCaseResult, TestCaseRecorder, TestSpecRecorder } from './logger.js'; -import { ParamSpec, ParamSpecIterable, extractPublicParams, paramsEquals } from './params_utils.js'; -import { checkPublicParamType } from './url_query.js'; +import { TestCaseRecorder } from './logging/test_case_recorder.js'; +import { + CaseParams, + CaseParamsIterable, + extractPublicParams, + publicParamsEquals, +} from './params_utils.js'; +import { kPathSeparator } from './query/separators.js'; +import { stringifyPublicParams } from './query/stringify_params.js'; +import { validQueryPart } from './query/validQueryPart.js'; import { assert } from './util/util.js'; +export type RunFn = (rec: TestCaseRecorder) => Promise<void>; + +export interface TestCaseID { + readonly test: readonly string[]; + readonly params: CaseParams; +} + export interface RunCase { readonly id: TestCaseID; - run(debug?: boolean): Promise<LiveTestCaseResult>; - injectResult(result: LiveTestCaseResult): void; + run: RunFn; } -export interface RunCaseIterable { - iterate(rec: TestSpecRecorder): Iterable<RunCase>; +// Interface for defining tests +export interface TestGroupBuilder<F extends Fixture> { + test(name: string): TestBuilderWithName<F, never>; +} +export function makeTestGroup<F extends Fixture>(fixture: FixtureClass<F>): TestGroupBuilder<F> { + return new TestGroup(fixture); } -type FixtureClass<F extends Fixture> = new (log: TestCaseRecorder, params: ParamSpec) => F; -type TestFn<F extends Fixture> = (t: F) => Promise<void> | void; +// Interface for running tests +export interface RunCaseIterable { + iterate(): Iterable<RunCase>; + checkCaseNamesAndDuplicates(): void; +} +export function makeTestGroupForUnitTesting<F extends Fixture>( + fixture: FixtureClass<F> +): TestGroup<F> { + return new TestGroup(fixture); +} -const validNames = new RegExp('^[' + allowedTestNameCharacters + ']+$'); +type FixtureClass<F extends Fixture> = new (log: TestCaseRecorder, params: CaseParams) => F; +type TestFn<F extends Fixture, P extends {}> = (t: F & { params: P }) => Promise<void> | void; -export class TestGroup<F extends Fixture> implements RunCaseIterable { +class TestGroup<F extends Fixture> implements RunCaseIterable, TestGroupBuilder<F> { private fixture: FixtureClass<F>; private seen: Set<string> = new Set(); - private tests: Array<Test<F>> = []; + private tests: Array<TestBuilder<F, never>> = []; constructor(fixture: FixtureClass<F>) { this.fixture = fixture; } - *iterate(log: TestSpecRecorder): Iterable<RunCase> { + *iterate(): Iterable<RunCase> { for (const test of this.tests) { - yield* test.iterate(log); + yield* test.iterate(); } } private checkName(name: string): void { - assert(validNames.test(name), `Invalid test name ${name}; must match [${validNames}]+`); assert( // Shouldn't happen due to the rule above. Just makes sure that treated // unencoded strings as encoded strings is OK. @@ -50,90 +73,110 @@ export class TestGroup<F extends Fixture> implements RunCaseIterable { } // TODO: This could take a fixture, too, to override the one for the group. - test(name: string, fn: TestFn<F>): Test<F> { - // Replace spaces with underscores for readability. - assert(name.indexOf('_') === -1, 'Invalid test name ${name}: contains underscore (use space)'); - name = name.replace(/ /g, '_'); - + test(name: string): TestBuilderWithName<F, never> { this.checkName(name); - const test = new Test<F>(name, this.fixture, fn); + const parts = name.split(kPathSeparator); + for (const p of parts) { + assert(validQueryPart.test(p), `Invalid test name part ${p}; must match ${validQueryPart}`); + } + + const test = new TestBuilder<F, never>(parts, this.fixture); this.tests.push(test); return test; } + + checkCaseNamesAndDuplicates(): void { + for (const test of this.tests) { + test.checkCaseNamesAndDuplicates(); + } + } +} + +interface TestBuilderWithName<F extends Fixture, P extends {}> extends TestBuilderWithParams<F, P> { + params<NewP extends {}>(specs: Iterable<NewP>): TestBuilderWithParams<F, NewP>; } -// This test is created when it's inserted, but may be parameterized afterward (.params()). -class Test<F extends Fixture> { - readonly name: string; - readonly fixture: FixtureClass<F>; - readonly fn: TestFn<F>; - private cases: ParamSpecIterable | null = null; +interface TestBuilderWithParams<F extends Fixture, P extends {}> { + fn(fn: TestFn<F, P>): void; +} + +class TestBuilder<F extends Fixture, P extends {}> { + private readonly testPath: string[]; + private readonly fixture: FixtureClass<F>; + private testFn: TestFn<F, P> | undefined; + private cases?: CaseParamsIterable = undefined; - constructor(name: string, fixture: FixtureClass<F>, fn: TestFn<F>) { - this.name = name; + constructor(testPath: string[], fixture: FixtureClass<F>) { + this.testPath = testPath; this.fixture = fixture; - this.fn = fn; } - params(specs: ParamSpecIterable): void { - assert(this.cases === null, 'test case is already parameterized'); - const cases = Array.from(specs); - const seen: ParamSpec[] = []; - // This is n^2. - for (const spec of cases) { - const publicParams = extractPublicParams(spec); + fn(fn: TestFn<F, P>): void { + this.testFn = fn; + } - // Check type of public params: can only be (currently): - // number, string, boolean, undefined, number[] - for (const v of Object.values(publicParams)) { - checkPublicParamType(v); - } + checkCaseNamesAndDuplicates(): void { + if (this.cases === undefined) { + return; + } - assert(!seen.some(x => paramsEquals(x, publicParams)), 'Duplicate test case params'); - seen.push(publicParams); + // This is n^2. + const seen: CaseParams[] = []; + for (const testcase of this.cases) { + // stringifyPublicParams also checks for invalid params values + const testcaseString = stringifyPublicParams(testcase); + assert( + !seen.some(x => publicParamsEquals(x, testcase)), + `Duplicate public test case params: ${testcaseString}` + ); + seen.push(testcase); } - this.cases = cases; } - *iterate(rec: TestSpecRecorder): IterableIterator<RunCase> { - for (const params of this.cases || [null]) { - yield new RunCaseSpecific(rec, this.name, params, this.fixture, this.fn); + params<NewP extends {}>(casesIterable: Iterable<NewP>): TestBuilderWithParams<F, NewP> { + assert(this.cases === undefined, 'test case is already parameterized'); + this.cases = Array.from(casesIterable); + + return (this as unknown) as TestBuilderWithParams<F, NewP>; + } + + *iterate(): IterableIterator<RunCase> { + assert(this.testFn !== undefined, 'No test function (.fn()) for test'); + for (const params of this.cases || [{}]) { + yield new RunCaseSpecific(this.testPath, params, this.fixture, this.testFn); } } } class RunCaseSpecific<F extends Fixture> implements RunCase { readonly id: TestCaseID; - private readonly params: ParamSpec | null; - private readonly recorder: TestSpecRecorder; + + private readonly params: CaseParams | null; private readonly fixture: FixtureClass<F>; - private readonly fn: TestFn<F>; + private readonly fn: TestFn<F, never>; constructor( - recorder: TestSpecRecorder, - test: string, - params: ParamSpec | null, + testPath: string[], + params: CaseParams, fixture: FixtureClass<F>, - fn: TestFn<F> + fn: TestFn<F, never> ) { - this.id = { test, params: params ? extractPublicParams(params) : null }; + this.id = { test: testPath, params: extractPublicParams(params) }; this.params = params; - this.recorder = recorder; this.fixture = fixture; this.fn = fn; } - async run(debug: boolean): Promise<LiveTestCaseResult> { - const [rec, res] = this.recorder.record(this.id.test, this.id.params); - rec.start(debug); - + async run(rec: TestCaseRecorder): Promise<void> { + rec.start(); try { const inst = new this.fixture(rec, this.params || {}); try { await inst.init(); - await this.fn(inst); + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + await this.fn(inst as any); } finally { // Runs as long as constructor succeeded, even if initialization or the test failed. await inst.finalize(); @@ -141,16 +184,10 @@ class RunCaseSpecific<F extends Fixture> implements RunCase { } catch (ex) { // There was an exception from constructor, init, test, or finalize. // An error from init or test may have been a SkipTestCase. - // An error from finalize may have been an eventualAsyncExpectation failure. + // An error from finalize may have been an eventualAsyncExpectation failure + // or unexpected validation/OOM error from the GPUDevice. rec.threw(ex); } - rec.finish(); - return res; - } - - injectResult(result: LiveTestCaseResult): void { - const [, res] = this.recorder.record(this.id.test, this.id.params); - Object.assign(res, result); } } diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/test_suite_listing.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/test_suite_listing.ts new file mode 100644 index 00000000000..c3c6896229a --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/test_suite_listing.ts @@ -0,0 +1,16 @@ +// A listing of all specs within a single suite. This is the (awaited) type of +// `groups` in '{cts,unittests}/listing.ts' and `listing` in the auto-generated +// 'out/{cts,unittests}/listing.js' files (see tools/gen_listings). +export type TestSuiteListing = TestSuiteListingEntry[]; + +export type TestSuiteListingEntry = TestSuiteListingEntrySpec | TestSuiteListingEntryReadme; + +interface TestSuiteListingEntrySpec { + readonly file: string[]; + readonly description: string; +} + +interface TestSuiteListingEntryReadme { + readonly file: string[]; + readonly readme: string; +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/tree.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/tree.ts index 514fc505a55..9b74afb10b4 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/tree.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/tree.ts @@ -1,82 +1,437 @@ -import { Logger } from './logger.js'; -import { stringifyPublicParams } from './params_utils.js'; -import { TestFilterResult } from './test_filter/test_filter_result.js'; -import { RunCase } from './test_group.js'; +import { TestFileLoader } from './file_loader.js'; +import { TestCaseRecorder } from './logging/test_case_recorder.js'; +import { CaseParamsRW } from './params_utils.js'; +import { compareQueries, Ordering } from './query/compare.js'; +import { + TestQuery, + TestQueryMultiCase, + TestQuerySingleCase, + TestQueryMultiFile, + TestQueryMultiTest, +} from './query/query.js'; +import { kBigSeparator, kWildcard, kPathSeparator, kParamSeparator } from './query/separators.js'; +import { stringifySingleParam } from './query/stringify_params.js'; +import { RunCase, RunFn } from './test_group.js'; +import { assert } from './util/util.js'; -export interface FilterResultTreeNode { +// `loadTreeForQuery()` loads a TestTree for a given queryToLoad. +// The resulting tree is a linked-list all the way from `suite:*` to queryToLoad, +// and under queryToLoad is a tree containing every case matched by queryToLoad. +// +// `subqueriesToExpand` influences the `collapsible` flag on nodes in the resulting tree. +// A node is considered "collapsible" if none of the subqueriesToExpand is a StrictSubset +// of that node. +// +// In WebKit/Blink-style web_tests, an expectation file marks individual cts.html "variants" as +// "Failure", "Crash", etc. +// By passing in the list of expectations as the subqueriesToExpand, we can programmatically +// subdivide the cts.html "variants" list to be able to implement arbitrarily-fine suppressions +// (instead of having to suppress entire test files, which would lose a lot of coverage). +// +// `iterateCollapsedQueries()` produces the list of queries for the variants list. +// +// Though somewhat complicated, this system has important benefits: +// - Avoids having to suppress entire test files, which would cause large test coverage loss. +// - Minimizes the number of page loads needed for fine-grained suppressions. +// (In the naive case, we could do one page load per test case - but the test suite would +// take impossibly long to run.) +// - Enables developers to put any number of tests in one file as appropriate, without worrying +// about expectation granularity. + +export interface TestSubtree<T extends TestQuery = TestQuery> { + /** + * Readable "relative" name for display in standalone runner. + * Not always the exact relative name, because sometimes there isn't + * one (e.g. s:f:* relative to s:f,*), but something that is readable. + */ + readonly readableRelativeName: string; + readonly query: T; + readonly children: Map<string, TestTreeNode>; + readonly collapsible: boolean; description?: string; - runCase?: RunCase; - children?: Map<string, FilterResultTreeNode>; } -// e.g. iteratePath('a/b/c/d', ':') yields ['a/', 'a/b/', 'a/b/c/', 'a/b/c/d:'] -function* iteratePath(path: string, terminator: string): IterableIterator<string> { - const parts = path.split('/'); - if (parts.length > 1) { - let partial = parts[0] + '/'; - yield partial; - for (let i = 1; i < parts.length - 1; ++i) { - partial += parts[i] + '/'; - yield partial; +export interface TestTreeLeaf { + /** + * Readable "relative" name for display in standalone runner. + */ + readonly readableRelativeName: string; + readonly query: TestQuerySingleCase; + readonly run: RunFn; +} + +export type TestTreeNode = TestSubtree | TestTreeLeaf; + +export class TestTree { + readonly root: TestSubtree; + + constructor(root: TestSubtree) { + this.root = root; + } + + iterateCollapsedQueries(): IterableIterator<TestQuery> { + return TestTree.iterateSubtreeCollapsedQueries(this.root); + } + + iterateLeaves(): IterableIterator<TestTreeLeaf> { + return TestTree.iterateSubtreeLeaves(this.root); + } + + /** + * If a parent and its child are at different levels, then + * generally the parent has only one child, i.e.: + * a,* { a,b,* { a,b:* { ... } } } + * Collapse that down into: + * a,* { a,b:* { ... } } + * which is less needlessly verbose when displaying the tree in the standalone runner. + */ + dissolveLevelBoundaries(): void { + const newRoot = dissolveLevelBoundaries(this.root); + assert(newRoot === this.root); + } + + toString(): string { + return TestTree.subtreeToString('(root)', this.root, ''); + } + + static *iterateSubtreeCollapsedQueries(subtree: TestSubtree): IterableIterator<TestQuery> { + for (const [, child] of subtree.children) { + if ('children' in child && !child.collapsible) { + yield* TestTree.iterateSubtreeCollapsedQueries(child); + } else { + yield child.query; + } } - // Path ends in '/' (so is a README). - if (parts[parts.length - 1] === '') { - return; + } + + static *iterateSubtreeLeaves(subtree: TestSubtree): IterableIterator<TestTreeLeaf> { + for (const [, child] of subtree.children) { + if ('children' in child) { + yield* TestTree.iterateSubtreeLeaves(child); + } else { + yield child; + } } } - yield path + terminator; -} -export function treeFromFilterResults( - log: Logger, - listing: IterableIterator<TestFilterResult> -): FilterResultTreeNode { - function getOrInsert(n: FilterResultTreeNode, k: string): FilterResultTreeNode { - const children = n.children!; - if (children.has(k)) { - return children.get(k)!; + static subtreeToString(name: string, tree: TestTreeNode, indent: string): string { + const collapsible = 'run' in tree ? '>' : tree.collapsible ? '+' : '-'; + let s = indent + `${collapsible} ${JSON.stringify(name)} => ${tree.query}`; + if ('children' in tree) { + if (tree.description !== undefined) { + s += `\n${indent} | ${JSON.stringify(tree.description)}`; + } + + for (const [name, child] of tree.children) { + s += '\n' + TestTree.subtreeToString(name, child, indent + ' '); + } } - const v = { children: new Map() }; - children.set(k, v); - return v; + return s; } +} + +// TODO: Consider having subqueriesToExpand actually impact the depth-order of params in the tree. +export async function loadTreeForQuery( + loader: TestFileLoader, + queryToLoad: TestQuery, + subqueriesToExpand: TestQuery[] +): Promise<TestTree> { + const suite = queryToLoad.suite; + const specs = await loader.listing(suite); + + const subqueriesToExpandEntries = Array.from(subqueriesToExpand.entries()); + const seenSubqueriesToExpand: boolean[] = new Array(subqueriesToExpand.length); + seenSubqueriesToExpand.fill(false); + + const isCollapsible = (subquery: TestQuery) => + subqueriesToExpandEntries.every(([i, toExpand]) => { + const ordering = compareQueries(toExpand, subquery); - const tree = { children: new Map() }; - for (const f of listing) { - const files = getOrInsert(tree, f.id.suite + ':'); - if (f.id.path === '') { - // This is a suite README. - files.description = f.spec.description.trim(); + // If toExpand == subquery, no expansion is needed (but it's still "seen"). + if (ordering === Ordering.Equal) seenSubqueriesToExpand[i] = true; + return ordering !== Ordering.StrictSubset; + }); + + // L0 = suite-level, e.g. suite:* + // L1 = file-level, e.g. suite:a,b:* + // L2 = test-level, e.g. suite:a,b:c,d:* + // L3 = case-level, e.g. suite:a,b:c,d: + let foundCase = false; + // L0 is suite:* + const subtreeL0 = makeTreeForSuite(suite); + isCollapsible(subtreeL0.query); // mark seenSubqueriesToExpand + for (const entry of specs) { + if (entry.file.length === 0 && 'readme' in entry) { + // Suite-level readme. + assert(subtreeL0.description === undefined); + subtreeL0.description = entry.readme.trim(); continue; } - let tests = files; - for (const path of iteratePath(f.id.path, ':')) { - tests = getOrInsert(tests, f.id.suite + ':' + path); - } - if (f.spec.description) { - // This is a directory README or spec file. - tests.description = f.spec.description.trim(); + { + const queryL1 = new TestQueryMultiFile(suite, entry.file); + const orderingL1 = compareQueries(queryL1, queryToLoad); + if (orderingL1 === Ordering.Unordered) { + // File path is not matched by this query. + continue; + } } - if (!('g' in f.spec)) { - // This is a directory README. + if ('readme' in entry) { + // Entry is a README that is an ancestor or descendant of the query. + // (It's included for display in the standalone runner.) + + // readmeSubtree is suite:a,b,* + // (This is always going to dedup with a file path, if there are any test spec files under + // the directory that has the README). + const readmeSubtree: TestSubtree<TestQueryMultiFile> = addSubtreeForDirPath( + subtreeL0, + entry.file + ); + assert(readmeSubtree.description === undefined); + readmeSubtree.description = entry.readme.trim(); continue; } + // Entry is a spec file. + + const spec = await loader.importSpecFile(queryToLoad.suite, entry.file); + const description = spec.description.trim(); + // subtreeL1 is suite:a,b:* + const subtreeL1: TestSubtree<TestQueryMultiTest> = addSubtreeForFilePath( + subtreeL0, + entry.file, + description, + isCollapsible + ); - const [tRec] = log.record(f.id); - const fId = f.id.suite + ':' + f.id.path; - for (const t of f.spec.g.iterate(tRec)) { - let cases = tests; - for (const path of iteratePath(t.id.test, '~')) { - cases = getOrInsert(cases, fId + ':' + path); + // TODO: If tree generation gets too slow, avoid actually iterating the cases in a file + // if there's no need to (based on the subqueriesToExpand). + for (const t of spec.g.iterate()) { + { + const queryL3 = new TestQuerySingleCase(suite, entry.file, t.id.test, t.id.params); + const orderingL3 = compareQueries(queryL3, queryToLoad); + if (orderingL3 === Ordering.Unordered || orderingL3 === Ordering.StrictSuperset) { + // Case is not matched by this query. + continue; + } } - const p = stringifyPublicParams(t.id.params); - cases.children!.set(fId + ':' + t.id.test + '=' + p, { - runCase: t, - }); + // subtreeL2 is suite:a,b:c,d:* + const subtreeL2: TestSubtree<TestQueryMultiCase> = addSubtreeForTestPath( + subtreeL1, + t.id.test, + isCollapsible + ); + + // Leaf for case is suite:a,b:c,d:x=1;y=2 + addLeafForCase(subtreeL2, t, isCollapsible); + + foundCase = true; } } + + for (const [i, sq] of subqueriesToExpandEntries) { + const seen = seenSubqueriesToExpand[i]; + assert( + seen, + `subqueriesToExpand entry did not match anything \ +(can happen due to overlap with another subquery): ${sq.toString()}` + ); + } + assert(foundCase, 'Query does not match any cases'); + + return new TestTree(subtreeL0); +} + +function makeTreeForSuite(suite: string): TestSubtree<TestQueryMultiFile> { + return { + readableRelativeName: suite + kBigSeparator, + query: new TestQueryMultiFile(suite, []), + children: new Map(), + collapsible: false, + }; +} + +function addSubtreeForDirPath( + tree: TestSubtree<TestQueryMultiFile>, + file: string[] +): TestSubtree<TestQueryMultiFile> { + const subqueryFile: string[] = []; + // To start, tree is suite:* + // This loop goes from that -> suite:a,* -> suite:a,b,* + for (const part of file) { + subqueryFile.push(part); + tree = getOrInsertSubtree(part, tree, () => { + const query = new TestQueryMultiFile(tree.query.suite, subqueryFile); + return { readableRelativeName: part + kPathSeparator + kWildcard, query, collapsible: false }; + }); + } return tree; } + +function addSubtreeForFilePath( + tree: TestSubtree<TestQueryMultiFile>, + file: string[], + description: string, + checkCollapsible: (sq: TestQuery) => boolean +): TestSubtree<TestQueryMultiTest> { + // To start, tree is suite:* + // This goes from that -> suite:a,* -> suite:a,b,* + tree = addSubtreeForDirPath(tree, file); + // This goes from that -> suite:a,b:* + const subtree = getOrInsertSubtree('', tree, () => { + const query = new TestQueryMultiTest(tree.query.suite, tree.query.filePathParts, []); + assert(file.length > 0, 'file path is empty'); + return { + readableRelativeName: file[file.length - 1] + kBigSeparator + kWildcard, + query, + description, + collapsible: checkCollapsible(query), + }; + }); + return subtree; +} + +function addSubtreeForTestPath( + tree: TestSubtree<TestQueryMultiTest>, + test: readonly string[], + isCollapsible: (sq: TestQuery) => boolean +): TestSubtree<TestQueryMultiCase> { + const subqueryTest: string[] = []; + // To start, tree is suite:a,b:* + // This loop goes from that -> suite:a,b:c,* -> suite:a,b:c,d,* + for (const part of test) { + subqueryTest.push(part); + tree = getOrInsertSubtree(part, tree, () => { + const query = new TestQueryMultiTest( + tree.query.suite, + tree.query.filePathParts, + subqueryTest + ); + return { + readableRelativeName: part + kPathSeparator + kWildcard, + query, + collapsible: isCollapsible(query), + }; + }); + } + // This goes from that -> suite:a,b:c,d:* + return getOrInsertSubtree('', tree, () => { + const query = new TestQueryMultiCase( + tree.query.suite, + tree.query.filePathParts, + subqueryTest, + {} + ); + assert(subqueryTest.length > 0, 'subqueryTest is empty'); + return { + readableRelativeName: subqueryTest[subqueryTest.length - 1] + kBigSeparator + kWildcard, + kWildcard, + query, + collapsible: isCollapsible(query), + }; + }); +} + +function addLeafForCase( + tree: TestSubtree<TestQueryMultiTest>, + t: RunCase, + checkCollapsible: (sq: TestQuery) => boolean +): void { + const query = tree.query; + let name: string = ''; + const subqueryParams: CaseParamsRW = {}; + + // To start, tree is suite:a,b:c,d:* + // This loop goes from that -> suite:a,b:c,d:x=1;* -> suite:a,b:c,d:x=1;y=2;* + for (const [k, v] of Object.entries(t.id.params)) { + name = stringifySingleParam(k, v); + subqueryParams[k] = v; + + tree = getOrInsertSubtree(name, tree, () => { + const subquery = new TestQueryMultiCase( + query.suite, + query.filePathParts, + query.testPathParts, + subqueryParams + ); + return { + readableRelativeName: name + kParamSeparator + kWildcard, + query: subquery, + collapsible: checkCollapsible(subquery), + }; + }); + } + + // This goes from that -> suite:a,b:c,d:x=1;y=2 + const subquery = new TestQuerySingleCase( + query.suite, + query.filePathParts, + query.testPathParts, + subqueryParams + ); + checkCollapsible(subquery); // mark seenSubqueriesToExpand + insertLeaf(tree, subquery, t); +} + +function getOrInsertSubtree<T extends TestQuery>( + key: string, + parent: TestSubtree, + createSubtree: () => Omit<TestSubtree<T>, 'children'> +): TestSubtree<T> { + let v: TestSubtree<T>; + const child = parent.children.get(key); + if (child !== undefined) { + assert('children' in child); // Make sure cached subtree is not actually a leaf + v = child as TestSubtree<T>; + } else { + v = { ...createSubtree(), children: new Map() }; + parent.children.set(key, v); + } + return v; +} + +function insertLeaf(parent: TestSubtree, query: TestQuerySingleCase, t: RunCase) { + const key = ''; + const leaf: TestTreeLeaf = { + readableRelativeName: readableNameForCase(query), + query, + run: (rec: TestCaseRecorder) => t.run(rec), + }; + assert(!parent.children.has(key)); + parent.children.set(key, leaf); +} + +function dissolveLevelBoundaries(tree: TestTreeNode): TestTreeNode { + if ('children' in tree) { + if (tree.children.size === 1 && tree.description === undefined) { + // Loops exactly once + for (const [, child] of tree.children) { + if (child.query.level > tree.query.level) { + const newtree = dissolveLevelBoundaries(child); + + return newtree; + } + } + } + + for (const [k, child] of tree.children) { + const newChild = dissolveLevelBoundaries(child); + if (newChild !== child) { + tree.children.set(k, newChild); + } + } + } + return tree; +} + +/** Generate a readable relative name for a case (used in standalone). */ +function readableNameForCase(query: TestQuerySingleCase): string { + const paramsKeys = Object.keys(query.params); + if (paramsKeys.length === 0) { + return query.testPathParts[query.testPathParts.length - 1] + kBigSeparator; + } else { + const lastKey = paramsKeys[paramsKeys.length - 1]; + return stringifySingleParam(lastKey, query.params[lastKey]); + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/url_query.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/url_query.ts deleted file mode 100644 index b963ce3277c..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/url_query.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { TestCaseID, TestSpecID } from './id.js'; -import { ParamArgument, stringifyPublicParams } from './params_utils.js'; -import { unreachable } from './util/util.js'; - -export function encodeSelectively(s: string): string { - let ret = encodeURIComponent(s); - ret = ret.replace(/%22/g, '"'); - ret = ret.replace(/%2C/g, ','); - ret = ret.replace(/%2F/g, '/'); - ret = ret.replace(/%3A/g, ':'); - ret = ret.replace(/%3D/g, '='); - ret = ret.replace(/%5B/g, '['); - ret = ret.replace(/%5D/g, ']'); - ret = ret.replace(/%7B/g, '{'); - ret = ret.replace(/%7D/g, '}'); - return ret; -} - -export function checkPublicParamType(v: ParamArgument): void { - if (typeof v === 'number' || typeof v === 'string' || typeof v === 'boolean' || v === undefined) { - return; - } - if (v instanceof Array) { - for (const x of v) { - if (typeof x !== 'number') { - break; - } - } - return; - } - unreachable('Invalid type for test case params ' + v); -} - -export function makeQueryString(spec: TestSpecID, testcase?: TestCaseID): string { - let s = spec.suite + ':'; - s += spec.path + ':'; - if (testcase !== undefined) { - s += testcase.test + '='; - s += stringifyPublicParams(testcase.params); - } - return encodeSelectively(s); -} diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/collect_garbage.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/util/collect_garbage.ts index d1978315000..3cffa03a43e 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/collect_garbage.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/util/collect_garbage.ts @@ -1,8 +1,10 @@ -// tslint:disable-next-line: no-any +import { resolveOnTimeout } from './util.js'; + +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ declare const Components: any; -export function attemptGarbageCollection(): void { - // tslint:disable-next-line: no-any +export async function attemptGarbageCollection(): Promise<void> { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const w: any = self; if (w.GCController) { w.GCController.collect(); @@ -19,6 +21,7 @@ export function attemptGarbageCollection(): void { .getInterface(Components.interfaces.nsIDOMWindowUtils) .garbageCollect(); return; + /* eslint-disable-next-line no-empty */ } catch (e) {} if (w.gc) { @@ -34,12 +37,14 @@ export function attemptGarbageCollection(): void { let i: number; function gcRec(n: number): void { if (n < 1) return; - // tslint:disable-next-line: no-any - let temp: any = { i: 'ab' + i + i / 100000 }; + let temp: object | string = { i: 'ab' + i + i / 100000 }; temp = temp + 'foo'; + temp; // dummy use of unused variable gcRec(n - 1); } for (i = 0; i < 1000; i++) { gcRec(10); } + + return resolveOnTimeout(35); // Let the event loop run a few frames in case it helps. } diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/util/stack.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/util/stack.ts index b0591f00aab..583ea4b811c 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/util/stack.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/util/stack.ts @@ -1,33 +1,17 @@ -// Takes a stack trace, and extracts only the first continuous range of lines -// containing '/(webgpu|unittests)/', which should provide only the useful part -// of the stack to the caller (for logging). -export function getStackTrace(e: Error): string { +// Returns the stack trace of an Error, but without the extra boilerplate at the bottom +// (e.g. RunCaseSpecific, processTicksAndRejections, etc.), for logging. +export function extractImportantStackTrace(e: Error): string { if (!e.stack) { return ''; } - - const parts = e.stack.split('\n'); - - const stack = []; - const moreStack = []; - let found = false; - const commonRegex = /[\/\\](webgpu|unittests)[\/\\]/; - for (let i = 0; i < parts.length; ++i) { - const part = parts[i].trim(); - const isSuites = commonRegex.test(part); // approximate - if (found && !isSuites) { - moreStack.push(part); - } - if (isSuites) { - if (moreStack.length) { - stack.push(...moreStack); - moreStack.length = 0; - } - stack.push(part); - found = true; + const lines = e.stack.split('\n'); + for (let i = lines.length - 1; i >= 0; --i) { + const line = lines[i]; + if (line.indexOf('.spec.') !== -1) { + return lines.slice(0, i + 1).join('\n'); } } - return stack.join('\n'); + return e.stack; } // *** Examples *** diff --git a/chromium/third_party/webgpu-cts/src/src/common/framework/util/util.ts b/chromium/third_party/webgpu-cts/src/src/common/framework/util/util.ts index 3695fc0e0df..1d42d86ffcc 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/framework/util/util.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/framework/util/util.ts @@ -1,8 +1,17 @@ import { timeout } from './timeout.js'; -export function assert(condition: boolean, msg?: string): asserts condition { +export function assert(condition: boolean, msg?: string | (() => string)): asserts condition { if (!condition) { - throw new Error(msg); + throw new Error(msg && (typeof msg === 'string' ? msg : msg())); + } +} + +export async function assertReject(p: Promise<unknown>, msg?: string): Promise<void> { + try { + await p; + unreachable(msg); + } catch (ex) { + // Assertion OK } } @@ -11,17 +20,26 @@ export function unreachable(msg?: string): never { } // performance.now() is available in all browsers, but not in scope by default in Node. -// tslint:disable-next-line no-var-requires const perf = typeof performance !== 'undefined' ? performance : require('perf_hooks').performance; export function now(): number { return perf.now(); } +export function resolveOnTimeout(ms: number): Promise<void> { + return new Promise(resolve => { + timeout(() => { + resolve(); + }, ms); + }); +} + +export class PromiseTimeoutError extends Error {} + export function rejectOnTimeout(ms: number, msg: string): Promise<never> { - return new Promise((resolve, reject) => { + return new Promise((_resolve, reject) => { timeout(() => { - reject(new Error(msg)); + reject(new PromiseTimeoutError(msg)); }, ms); }); } diff --git a/chromium/third_party/webgpu-cts/src/src/common/runtime/cmdline.ts b/chromium/third_party/webgpu-cts/src/src/common/runtime/cmdline.ts index 3934df3f6bc..45ca87425eb 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/runtime/cmdline.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/runtime/cmdline.ts @@ -1,12 +1,13 @@ -// tslint:disable: no-console +/* eslint no-console: "off" */ +/* eslint no-process-exit: "off" */ import * as fs from 'fs'; import * as process from 'process'; -import { TestSpecID } from '../framework/id.js'; -import { TestLoader } from '../framework/loader.js'; -import { LiveTestCaseResult, Logger } from '../framework/logger.js'; -import { makeQueryString } from '../framework/url_query.js'; +import { DefaultTestFileLoader } from '../framework/file_loader.js'; +import { Logger } from '../framework/logging/logger.js'; +import { LiveTestCaseResult } from '../framework/logging/result.js'; +import { parseQuery } from '../framework/query/parseQuery.js'; import { assert, unreachable } from '../framework/util/util.js'; function usage(rc: number): never { @@ -28,7 +29,7 @@ if (!fs.existsSync('src/common/runtime/cmdline.ts')) { let verbose = false; let debug = false; let printJSON = false; -const filterArgs = []; +const queries: string[] = []; for (const a of process.argv.slice(2)) { if (a.startsWith('-')) { if (a === '--verbose') { @@ -41,49 +42,52 @@ for (const a of process.argv.slice(2)) { usage(1); } } else { - filterArgs.push(a); + queries.push(a); } } -if (filterArgs.length === 0) { +if (queries.length === 0) { usage(0); } (async () => { try { - const loader = new TestLoader(); - const files = await loader.loadTestsFromCmdLine(filterArgs); + const loader = new DefaultTestFileLoader(); + assert(queries.length === 1, 'currently, there must be exactly one query on the cmd line'); + const testcases = await loader.loadCases(parseQuery(queries[0])); - const log = new Logger(); + const log = new Logger(debug); - const failed: Array<[TestSpecID, LiveTestCaseResult]> = []; - const warned: Array<[TestSpecID, LiveTestCaseResult]> = []; - const skipped: Array<[TestSpecID, LiveTestCaseResult]> = []; + const failed: Array<[string, LiveTestCaseResult]> = []; + const warned: Array<[string, LiveTestCaseResult]> = []; + const skipped: Array<[string, LiveTestCaseResult]> = []; let total = 0; - for (const f of files) { - if (!('g' in f.spec)) { - continue; + + for (const testcase of testcases) { + const name = testcase.query.toString(); + const [rec, res] = log.record(name); + await testcase.run(rec); + + if (verbose) { + printResults([[name, res]]); } - const [rec] = log.record(f.id); - for (const t of f.spec.g.iterate(rec)) { - const res = await t.run(debug); - if (verbose) { - printResults([[f.id, res]]); - } - - total++; - if (res.status === 'pass') { - } else if (res.status === 'fail') { - failed.push([f.id, res]); - } else if (res.status === 'warn') { - warned.push([f.id, res]); - } else if (res.status === 'skip') { - skipped.push([f.id, res]); - } else { + total++; + switch (res.status) { + case 'pass': + break; + case 'fail': + failed.push([name, res]); + break; + case 'warn': + warned.push([name, res]); + break; + case 'skip': + skipped.push([name, res]); + break; + default: unreachable('unrecognized status'); - } } } @@ -111,13 +115,11 @@ if (filterArgs.length === 0) { } const passed = total - warned.length - failed.length - skipped.length; - function pct(x: number): string { - return ((100 * x) / total).toFixed(2); - } - function rpt(x: number): string { + const pct = (x: number) => ((100 * x) / total).toFixed(2); + const rpt = (x: number) => { const xs = x.toString().padStart(1 + Math.log10(total), ' '); return `${xs} / ${total} = ${pct(x).padStart(6, ' ')}%`; - } + }; console.log(''); console.log(`** Summary ** Passed w/o warnings = ${rpt(passed)} @@ -134,9 +136,9 @@ Failed = ${rpt(failed.length)}`); } })(); -function printResults(results: Array<[TestSpecID, LiveTestCaseResult]>): void { - for (const [id, r] of results) { - console.log(`[${r.status}] ${makeQueryString(id, r)} (${r.timems}ms). Log:`); +function printResults(results: Array<[string, LiveTestCaseResult]>): void { + for (const [name, r] of results) { + console.log(`[${r.status}] ${name} (${r.timems}ms). Log:`); if (r.logs) { for (const l of r.logs) { console.log(' - ' + l.toJSON().replace(/\n/g, '\n ')); diff --git a/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker-worker.ts b/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker-worker.ts index 19e4d623b22..62c66849b29 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker-worker.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker-worker.ts @@ -1,28 +1,25 @@ -import { TestLoader } from '../../framework/loader.js'; -import { Logger } from '../../framework/logger.js'; +import { DefaultTestFileLoader } from '../../framework/file_loader.js'; +import { Logger } from '../../framework/logging/logger.js'; +import { parseQuery } from '../../framework/query/parseQuery.js'; import { assert } from '../../framework/util/util.js'; -// tslint:disable-next-line: no-any -declare var self: any; // should be DedicatedWorkerGlobalScope +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +declare const self: any; // should be DedicatedWorkerGlobalScope -const log = new Logger(); -const loader = new TestLoader(); +const loader = new DefaultTestFileLoader(); self.onmessage = async (ev: MessageEvent) => { - const { query, debug } = ev.data; + const query: string = ev.data.query; + const debug: boolean = ev.data.debug; - const files = Array.from(await loader.loadTests([query])); - assert(files.length === 1, 'worker query resulted in != 1 files'); + const log = new Logger(debug); - const f = files[0]; - const [rec] = log.record(f.id); - assert('g' in f.spec, 'worker query resulted in README'); + const testcases = Array.from(await loader.loadCases(parseQuery(query))); + assert(testcases.length === 1, 'worker query resulted in != 1 cases'); - const cases = Array.from(f.spec.g.iterate(rec)); - assert(cases.length === 1, 'worker query resulted in != 1 cases'); - const c = cases[0]; - - const result = await c.run(debug); + const testcase = testcases[0]; + const [rec, result] = log.record(testcase.query.toString()); + await testcase.run(rec); self.postMessage({ query, result }); }; diff --git a/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker.ts b/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker.ts index 251a405ed73..cb526a0b43d 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/runtime/helper/test_worker.ts @@ -1,14 +1,15 @@ -import { - LiveTestCaseResult, - LogMessageWithStack, - TransferredTestCaseResult, -} from '../../framework/logger.js'; +import { LogMessageWithStack } from '../../framework/logging/log_message.js'; +import { TransferredTestCaseResult, LiveTestCaseResult } from '../../framework/logging/result.js'; +import { TestCaseRecorder } from '../../framework/logging/test_case_recorder.js'; export class TestWorker { - private worker: Worker; - private resolvers = new Map<string, (result: LiveTestCaseResult) => void>(); + private readonly debug: boolean; + private readonly worker: Worker; + private readonly resolvers = new Map<string, (result: LiveTestCaseResult) => void>(); + + constructor(debug: boolean) { + this.debug = debug; - constructor() { const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/test_worker-worker.js'; @@ -28,10 +29,11 @@ export class TestWorker { }; } - run(query: string, debug: boolean = false): Promise<LiveTestCaseResult> { - this.worker.postMessage({ query, debug }); - return new Promise(resolve => { + async run(rec: TestCaseRecorder, query: string): Promise<void> { + this.worker.postMessage({ query, debug: this.debug }); + const workerResult = await new Promise<LiveTestCaseResult>(resolve => { this.resolvers.set(query, resolve); }); + rec.injectResult(workerResult); } } diff --git a/chromium/third_party/webgpu-cts/src/src/common/runtime/standalone.ts b/chromium/third_party/webgpu-cts/src/src/common/runtime/standalone.ts index 578418b4017..1af0e63474d 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/runtime/standalone.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/runtime/standalone.ts @@ -1,10 +1,11 @@ // Implements the standalone test runner (see also: /standalone/index.html). -import { TestLoader } from '../framework/loader.js'; -import { LiveTestCaseResult, Logger } from '../framework/logger.js'; -import { RunCase } from '../framework/test_group.js'; -import { FilterResultTreeNode, treeFromFilterResults } from '../framework/tree.js'; -import { encodeSelectively } from '../framework/url_query.js'; +import { DefaultTestFileLoader } from '../framework/file_loader.js'; +import { Logger } from '../framework/logging/logger.js'; +import { parseQuery } from '../framework/query/parseQuery.js'; +import { TestQueryLevel } from '../framework/query/query.js'; +import { TestTreeNode, TestSubtree, TestTreeLeaf } from '../framework/tree.js'; +import { assert } from '../framework/util/util.js'; import { optionEnabled } from './helper/options.js'; import { TestWorker } from './helper/test_worker.js'; @@ -15,12 +16,13 @@ window.onbeforeunload = () => { }; let haveSomeResults = false; -const log = new Logger(); const runnow = optionEnabled('runnow'); const debug = optionEnabled('debug'); -const worker = optionEnabled('worker') ? new TestWorker() : undefined; +const logger = new Logger(debug); + +const worker = optionEnabled('worker') ? new TestWorker(debug) : undefined; const resultsVis = document.getElementById('resultsVis')!; const resultsJSON = document.getElementById('resultsJSON')!; @@ -29,25 +31,28 @@ type RunSubtree = () => Promise<void>; // DOM generation -function makeTreeNodeHTML(name: string, tree: FilterResultTreeNode): [HTMLElement, RunSubtree] { - if (tree.children) { - return makeSubtreeHTML(name, tree); +function makeTreeNodeHTML( + tree: TestTreeNode, + parentLevel: TestQueryLevel +): [HTMLElement, RunSubtree] { + if ('children' in tree) { + return makeSubtreeHTML(tree, parentLevel); } else { - return makeCaseHTML(name, tree.runCase!); + return makeCaseHTML(tree); } } -function makeCaseHTML(name: string, t: RunCase): [HTMLElement, RunSubtree] { +function makeCaseHTML(t: TestTreeLeaf): [HTMLElement, RunSubtree] { const div = $('<div>').addClass('testcase'); + const name = t.query.toString(); const runSubtree = async () => { haveSomeResults = true; - let res: LiveTestCaseResult; + const [rec, res] = logger.record(name); if (worker) { - res = await worker.run(name, debug); - t.injectResult(res); + await worker.run(rec, name); } else { - res = await t.run(debug); + await t.run(rec); } casetime.text(res.timems.toFixed(4) + ' ms'); @@ -57,62 +62,58 @@ function makeCaseHTML(name: string, t: RunCase): [HTMLElement, RunSubtree] { if (res.logs) { caselogs.empty(); for (const l of res.logs) { - const caselog = $('<div>') - .addClass('testcaselog') - .appendTo(caselogs); + const caselog = $('<div>').addClass('testcaselog').appendTo(caselogs); $('<button>') .addClass('testcaselogbtn') .attr('alt', 'Log stack to console') .attr('title', 'Log stack to console') .appendTo(caselog) .on('click', () => { - // tslint:disable-next-line: no-console + /* eslint-disable-next-line no-console */ console.log(l); }); - $('<pre>') - .addClass('testcaselogtext') - .appendTo(caselog) - .text(l.toJSON()); + $('<pre>').addClass('testcaselogtext').appendTo(caselog).text(l.toJSON()); } } }; - const casehead = makeTreeNodeHeaderHTML(name, undefined, runSubtree); + const caselogs = $('<div>').addClass('testcaselogs'); + const casehead = makeTreeNodeHeaderHTML(t, runSubtree, 2, checked => { + checked ? caselogs.show() : caselogs.hide(); + }); div.append(casehead); - const casetime = $('<div>') - .addClass('testcasetime') - .html('ms') - .appendTo(casehead); - const caselogs = $('<div>') - .addClass('testcaselogs') - .appendTo(div); + const casetime = $('<div>').addClass('testcasetime').html('ms').appendTo(casehead); + caselogs.appendTo(div); return [div[0], runSubtree]; } -function makeSubtreeHTML(name: string, subtree: FilterResultTreeNode): [HTMLElement, RunSubtree] { +function makeSubtreeHTML(n: TestSubtree, parentLevel: TestQueryLevel): [HTMLElement, RunSubtree] { const div = $('<div>').addClass('subtree'); - const header = makeTreeNodeHeaderHTML(name, subtree.description, () => { - return runSubtree(); + const subtreeHTML = $('<div>').addClass('subtreechildren'); + const runSubtree = makeSubtreeChildrenHTML(subtreeHTML[0], n.children.values(), n.query.level); + + const header = makeTreeNodeHeaderHTML(n, runSubtree, parentLevel, checked => { + checked ? subtreeHTML.show() : subtreeHTML.hide(); }); + div.append(header); + div.append(subtreeHTML); - const subtreeHTML = $('<div>') - .addClass('subtreechildren') - .appendTo(div); - const runSubtree = makeSubtreeChildrenHTML(subtreeHTML[0], subtree.children!); + div[0].classList.add(['', 'multifile', 'multitest', 'multicase'][n.query.level]); return [div[0], runSubtree]; } function makeSubtreeChildrenHTML( div: HTMLElement, - children: Map<string, FilterResultTreeNode> + children: Iterable<TestTreeNode>, + parentLevel: TestQueryLevel ): RunSubtree { const runSubtreeFns: RunSubtree[] = []; - for (const [name, subtree] of children) { - const [subtreeHTML, runSubtree] = makeTreeNodeHTML(name, subtree); + for (const subtree of children) { + const [subtreeHTML, runSubtree] = makeTreeNodeHTML(subtree, parentLevel); div.append(subtreeHTML); runSubtreeFns.push(runSubtree); } @@ -125,26 +126,38 @@ function makeSubtreeChildrenHTML( } function makeTreeNodeHeaderHTML( - name: string, - description: string | undefined, - runSubtree: RunSubtree + n: TestTreeNode, + runSubtree: RunSubtree, + parentLevel: TestQueryLevel, + onChange: (checked: boolean) => void ): HTMLElement { + const isLeaf = 'run' in n; const div = $('<div>').addClass('nodeheader'); - const nameEncoded = encodeSelectively(name); - let nameHTML; - { - const i = nameEncoded.indexOf('{'); - const n1 = i === -1 ? nameEncoded : nameEncoded.slice(0, i + 1); - const n2 = i === -1 ? '' : nameEncoded.slice(i + 1); - nameHTML = n1.replace(/:/g, ':<wbr>') + '<wbr>' + n2.replace(/,/g, ',<wbr>'); + const href = `?${worker ? 'worker&' : ''}${debug ? 'debug&' : ''}q=${n.query.toString()}`; + if (onChange) { + const checkbox = $('<input>') + .attr('type', 'checkbox') + .addClass('collapsebtn') + .change(function (this) { + onChange((this as HTMLInputElement).checked); + }) + .attr('alt', 'Expand') + .attr('title', 'Expand') + .appendTo(div); + + // Collapse s:f:* or s:f:t:* or s:f:t:c by default. + if (n.query.level > rootQueryLevel && n.query.level > parentLevel) { + onChange(false); + } else { + checkbox.prop('checked', true); // (does not fire onChange) + } } - - const href = `?${worker ? 'worker&' : ''}${debug ? 'debug&' : ''}q=${nameEncoded}`; + const runtext = isLeaf ? 'Run case' : 'Run subtree'; $('<button>') - .addClass('noderun') - .attr('alt', 'Run subtree') - .attr('title', 'Run subtree') + .addClass(isLeaf ? 'leafrun' : 'subtreerun') + .attr('alt', runtext) + .attr('title', runtext) .on('click', async () => { await runSubtree(); updateJSON(); @@ -156,35 +169,73 @@ function makeTreeNodeHeaderHTML( .attr('alt', 'Open') .attr('title', 'Open') .appendTo(div); - const nodetitle = $('<div>') - .addClass('nodetitle') - .appendTo(div); - $('<span>') + const nodetitle = $('<div>').addClass('nodetitle').appendTo(div); + const nodename = $('<span>') .addClass('nodename') - .html(nameHTML) + .text(n.readableRelativeName) .appendTo(nodetitle); - if (description) { + if ('run' in n) { + nodename.addClass('leafname'); + } + $('<input>') + .attr('type', 'text') + .prop('readonly', true) + .addClass('nodequery') + .val(n.query.toString()) + .appendTo(nodetitle); + if ('description' in n && n.description) { $('<div>') .addClass('nodedescription') - .html(description.replace(/\n/g, '<br>')) + .html(n.description.replace(/\n\n/g, '<br><br>')) .appendTo(nodetitle); } return div[0]; } function updateJSON(): void { - resultsJSON.textContent = log.asJSON(2); + resultsJSON.textContent = logger.asJSON(2); } +let rootQueryLevel: TestQueryLevel = 1; + (async () => { - const loader = new TestLoader(); + const loader = new DefaultTestFileLoader(); - // TODO: everything after this point is very similar across the three runtimes. // TODO: start populating page before waiting for everything to load? - const files = await loader.loadTestsFromQuery(window.location.search); - const tree = treeFromFilterResults(log, files); + const qs = new URLSearchParams(window.location.search).getAll('q'); + if (qs.length === 0) { + qs.push('webgpu:*'); + } - const runSubtree = makeSubtreeChildrenHTML(resultsVis, tree.children!); + // Update the URL bar to match the exact current options. + { + let url = window.location.protocol + '//' + window.location.host + window.location.pathname; + url += + '?' + + new URLSearchParams([ + ['runnow', runnow ? '1' : '0'], + ['worker', worker ? '1' : '0'], + ['debug', debug ? '1' : '0'], + ]).toString() + + '&' + + qs.map(q => 'q=' + q).join('&'); + window.history.replaceState(null, '', url); + } + + assert(qs.length === 1, 'currently, there must be exactly one ?q='); + const rootQuery = parseQuery(qs[0]); + rootQueryLevel = rootQuery.level; + const tree = await loader.loadTree(rootQuery); + + tree.dissolveLevelBoundaries(); + + const [el, runSubtree] = makeSubtreeHTML(tree.root, 1); + resultsVis.append(el); + + $('#expandall').change(function (this) { + const checked = (this as HTMLInputElement).checked; + $('.collapsebtn').prop('checked', checked).trigger('change'); + }); if (runnow) { runSubtree(); diff --git a/chromium/third_party/webgpu-cts/src/src/common/runtime/wpt.ts b/chromium/third_party/webgpu-cts/src/src/common/runtime/wpt.ts index bc2ac7b8f06..5600b7e9cd3 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/runtime/wpt.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/runtime/wpt.ts @@ -1,7 +1,9 @@ -import { TestLoader } from '../framework/loader.js'; -import { LiveTestCaseResult, Logger } from '../framework/logger.js'; -import { makeQueryString } from '../framework/url_query.js'; +import { DefaultTestFileLoader } from '../framework/file_loader.js'; +import { Logger } from '../framework/logging/logger.js'; +import { parseQuery } from '../framework/query/parseQuery.js'; +import { TestTreeLeaf } from '../framework/tree.js'; import { AsyncMutex } from '../framework/util/async_mutex.js'; +import { assert } from '../framework/util/util.js'; import { optionEnabled } from './helper/options.js'; import { TestWorker } from './helper/test_worker.js'; @@ -15,51 +17,48 @@ declare interface WptTestObject { declare function async_test(f: (this: WptTestObject) => Promise<void>, name: string): void; (async () => { - const loader = new TestLoader(); - const files = await loader.loadTestsFromQuery(window.location.search); + const loader = new DefaultTestFileLoader(); + const qs = new URLSearchParams(window.location.search).getAll('q'); + assert(qs.length === 1, 'currently, there must be exactly one ?q='); + const testcases = await loader.loadCases(parseQuery(qs[0])); - const worker = optionEnabled('worker') ? new TestWorker() : undefined; + await addWPTTests(testcases); +})(); + +// Note: `async_test`s must ALL be added within the same task. This function *must not* be async. +function addWPTTests(testcases: IterableIterator<TestTreeLeaf>): Promise<Logger> { + const worker = optionEnabled('worker') ? new TestWorker(false) : undefined; - const log = new Logger(); + const log = new Logger(false); const mutex = new AsyncMutex(); const running: Array<Promise<void>> = []; - for (const f of files) { - if (!('g' in f.spec)) { - continue; - } + for (const testcase of testcases) { + const name = testcase.query.toString(); + const wpt_fn = function (this: WptTestObject): Promise<void> { + const p = mutex.with(async () => { + const [rec, res] = log.record(name); + if (worker) { + await worker.run(rec, name); + } else { + await testcase.run(rec); + } - const [rec] = log.record(f.id); - for (const t of f.spec.g.iterate(rec)) { - const name = makeQueryString(f.id, t.id); - - // Note: apparently, async_tests must ALL be added within the same task. - async_test(function(this: WptTestObject): Promise<void> { - const p = mutex.with(async () => { - let r: LiveTestCaseResult; - if (worker) { - r = await worker.run(name); - t.injectResult(r); - } else { - r = await t.run(); + this.step(() => { + // Unfortunately, it seems not possible to surface any logs for warn/skip. + if (res.status === 'fail') { + throw (res.logs || []).map(s => s.toJSON()).join('\n\n'); } - - this.step(() => { - // Unfortunately, it seems not possible to surface any logs for warn/skip. - if (r.status === 'fail') { - throw (r.logs || []).map(s => s.toJSON()).join('\n\n'); - } - }); - this.done(); }); + this.done(); + }); - running.push(p); - return p; - }, name); - } + running.push(p); + return p; + }; + + async_test(wpt_fn, name); } - await Promise.all(running); - const resultsElem = document.getElementById('results') as HTMLElement; - resultsElem.textContent = log.asJSON(2); -})(); + return Promise.all(running).then(() => log); +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/templates/cts.html b/chromium/third_party/webgpu-cts/src/src/common/templates/cts.html index a4169922466..3c37875fe3b 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/templates/cts.html +++ b/chromium/third_party/webgpu-cts/src/src/common/templates/cts.html @@ -25,24 +25,4 @@ <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> -<style> -#results { - font-family: monospace; - width: 100%; - height: 15em; -} - -/* Test Name column */ -#results > tbody > tr > td:nth-child(2) { - word-break: break-word; -} - -/* Message column */ -#results > tbody > tr > td:nth-child(3) { - white-space: pre-wrap; - word-break: break-word; -} -</style> - -<textarea id=results></textarea> <script type=module src=/webgpu/common/runtime/wpt.js></script> diff --git a/chromium/third_party/webgpu-cts/src/src/common/tools/.eslintrc.json b/chromium/third_party/webgpu-cts/src/src/common/tools/.eslintrc.json new file mode 100644 index 00000000000..0a79eae4c5b --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/common/tools/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "rules": { + "no-console": "off", + "no-process-exit": "off", + "node/no-unpublished-require": "off", + "@typescript-eslint/no-var-requires": "off" + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/common/tools/crawl.ts b/chromium/third_party/webgpu-cts/src/src/common/tools/crawl.ts index d6d3edbe4ce..6e7ffc61fc6 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/tools/crawl.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/tools/crawl.ts @@ -2,59 +2,58 @@ // This crawls the file tree under src/suites/${suite} to generate a (non-hierarchical) static // listing file that can then be used in the browser to load the modules containing the tests. -// tslint:disable: no-console - import * as fs from 'fs'; import * as path from 'path'; -const fg = require('fast-glob'); +import { SpecFile } from '../framework/file_loader.js'; +import { TestSuiteListingEntry, TestSuiteListing } from '../framework/test_suite_listing.js'; +import { assert, unreachable } from '../framework/util/util.js'; -import { TestSuiteListingEntry } from '../framework/listing.js'; -import { TestSpec } from '../framework/loader.js'; -import { assert } from '../framework/util/util.js'; +const fg = require('fast-glob'); -const specSuffix = '.spec.ts'; +const specFileSuffix = '.spec.ts'; export async function crawl(suite: string): Promise<TestSuiteListingEntry[]> { - const specDir = 'src/' + suite; - if (!fs.existsSync(specDir)) { - console.error(`Could not find ${specDir}`); + const suiteDir = 'src/' + suite; + if (!fs.existsSync(suiteDir)) { + console.error(`Could not find ${suiteDir}`); process.exit(1); } - const specFiles = await fg(`${specDir}/**/{README.txt,*${specSuffix}}`, { onlyFiles: true }); - specFiles.sort(); + const glob = `${suiteDir}/**/{README.txt,*${specFileSuffix}}`; + const filesToEnumerate: string[] = await fg(glob, { onlyFiles: true }); + filesToEnumerate.sort(); + + const entries: TestSuiteListingEntry[] = []; + for (const file of filesToEnumerate) { + const f = file.substring((suiteDir + '/').length); // Suite-relative file path + if (f.endsWith(specFileSuffix)) { + const filepathWithoutExtension = f.substring(0, f.length - specFileSuffix.length); + const filename = `../../../${suiteDir}/${filepathWithoutExtension}.spec.js`; - const groups: TestSuiteListingEntry[] = []; - for (const file of specFiles) { - const f = file.substring((specDir + '/').length); - if (f.endsWith(specSuffix)) { - const testPath = f.substring(0, f.length - specSuffix.length); - const filename = `../../../${specDir}/${testPath}.spec.js`; - const mod = (await import(filename)) as TestSpec; + const mod = (await import(filename)) as SpecFile; assert(mod.description !== undefined, 'Test spec file missing description: ' + filename); assert(mod.g !== undefined, 'Test spec file missing TestGroup definition: ' + filename); - groups.push({ - path: testPath, - description: mod.description.trim(), - }); + + mod.g.checkCaseNamesAndDuplicates(); + + const path = filepathWithoutExtension.split('/'); + entries.push({ file: path, description: mod.description.trim() }); } else if (path.basename(file) === 'README.txt') { - const group = f.substring(0, f.length - 'README.txt'.length); - const description = fs.readFileSync(file, 'utf8').trim(); - groups.push({ - path: group, - description, - }); + const filepathWithoutExtension = f.substring(0, f.length - '/README.txt'.length); + const readme = fs.readFileSync(file, 'utf8').trim(); + + const path = filepathWithoutExtension ? filepathWithoutExtension.split('/') : []; + entries.push({ file: path, readme }); } else { - console.error('Unrecognized file: ' + file); - process.exit(1); + unreachable(`glob ${glob} matched an unrecognized filename ${file}`); } } - return groups; + return entries; } -export function makeListing(filename: string): Promise<TestSuiteListingEntry[]> { +export function makeListing(filename: string): Promise<TestSuiteListing> { const suite = path.basename(path.dirname(filename)); return crawl(suite); } diff --git a/chromium/third_party/webgpu-cts/src/src/common/tools/gen_listings.ts b/chromium/third_party/webgpu-cts/src/src/common/tools/gen_listings.ts index f24cfd45c7d..0aff1e4f505 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/tools/gen_listings.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/tools/gen_listings.ts @@ -1,5 +1,3 @@ -// tslint:disable: no-console - import * as fs from 'fs'; import * as path from 'path'; import * as process from 'process'; @@ -38,6 +36,7 @@ export const listing = ${JSON.stringify(listing, undefined, 2)}; ); try { fs.unlinkSync(outFile + '.map'); + /* eslint-disable-next-line no-empty */ } catch (ex) {} } })(); diff --git a/chromium/third_party/webgpu-cts/src/src/common/tools/gen_wpt_cts_html.ts b/chromium/third_party/webgpu-cts/src/src/common/tools/gen_wpt_cts_html.ts index c669871a352..4f74f9b15b9 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/tools/gen_wpt_cts_html.ts +++ b/chromium/third_party/webgpu-cts/src/src/common/tools/gen_wpt_cts_html.ts @@ -1,11 +1,8 @@ -// tslint:disable: no-console - import { promises as fs } from 'fs'; -import { listing } from '../../webgpu/listing.js'; -import { generateMinimalQueryList } from '../framework/generate_minimal_query_list.js'; -import { TestSuiteListingEntry } from '../framework/listing.js'; -import { TestLoader } from '../framework/loader.js'; +import { DefaultTestFileLoader } from '../framework/file_loader.js'; +import { TestQueryMultiTest, TestQueryMultiFile } from '../framework/query/query.js'; +import { assert } from '../framework/util/util.js'; function printUsageAndExit(rc: number): void { console.error(`\ @@ -48,11 +45,11 @@ const [ (async () => { if (process.argv.length === 4) { - const entries = (await listing) as TestSuiteListingEntry[]; + const entries = await (await import('../../webgpu/listing.js')).listing; const lines = entries // Exclude READMEs. - .filter(l => l.path.length !== 0 && !l.path.endsWith('/')) - .map(l => '?q=webgpu:' + l.path); + .filter(l => !('readme' in l)) + .map(l => '?q=' + new TestQueryMultiTest('webgpu', l.file, []).toString()); await generateFile(lines); } else { // Prefixes sorted from longest to shortest @@ -60,9 +57,9 @@ const [ .split('\n') .filter(a => a.length) .sort((a, b) => b.length - a.length); - const expectationLines = (await fs.readFile(expectationsFile, 'utf8')) - .split('\n') - .filter(l => l.length); + const expectationLines = new Set( + (await fs.readFile(expectationsFile, 'utf8')).split('\n').filter(l => l.length) + ); const expectations: Map<string, string[]> = new Map(); for (const prefix of argsPrefixes) { @@ -78,17 +75,28 @@ const [ continue expLoop; } } - throw new Error('All input lines must start with one of the prefixes. ' + exp); + console.log('note: ignored expectation: ' + exp); } - const loader = new TestLoader(); - const files = Array.from(await loader.loadTestsFromCmdLine([suite + ':'])); - - const lines = []; + const loader = new DefaultTestFileLoader(); + const lines: Array<string | undefined> = []; for (const prefix of argsPrefixes) { - lines.push(undefined); - for (const q of await generateMinimalQueryList(files, expectations.get(prefix)!)) { - lines.push(prefix + q); + const rootQuery = new TestQueryMultiFile(suite, []); + const tree = await loader.loadTree(rootQuery, expectations.get(prefix)!); + + lines.push(undefined); // output blank line between prefixes + for (const q of tree.iterateCollapsedQueries()) { + const urlQueryString = prefix + q.toString(); // "?worker=0&q=..." + // Check for a safe-ish path length limit. Filename must be <= 255, and on Windows the whole + // path must be <= 259. Leave room for e.g.: + // 'c:\b\s\w\xxxxxxxx\layout-test-results\external\wpt\webgpu\cts_worker=0_q=...-actual.txt' + assert( + urlQueryString.length < 185, + 'Generated test variant would produce too-long -actual.txt filename. \ +Try broadening suppressions to avoid long test variant names. ' + + urlQueryString + ); + lines.push(urlQueryString); } } await generateFile(lines); diff --git a/chromium/third_party/webgpu-cts/src/src/common/tools/setup-ts-in-node.js b/chromium/third_party/webgpu-cts/src/src/common/tools/setup-ts-in-node.js index 0616dab35db..d5f773140e6 100644 --- a/chromium/third_party/webgpu-cts/src/src/common/tools/setup-ts-in-node.js +++ b/chromium/third_party/webgpu-cts/src/src/common/tools/setup-ts-in-node.js @@ -4,7 +4,7 @@ require('ts-node').register({ module: 'commonjs', }, transpileOnly: true, -}) +}); // Redirect imports of .js files to .ts files const Module = require('module'); diff --git a/chromium/third_party/webgpu-cts/src/src/demo/README.txt b/chromium/third_party/webgpu-cts/src/src/demo/README.txt new file mode 100644 index 00000000000..3b5654080ec --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/README.txt @@ -0,0 +1 @@ +Demo test suite for manually testing test runners. diff --git a/chromium/third_party/webgpu-cts/src/src/demo/a.spec.ts b/chromium/third_party/webgpu-cts/src/src/demo/a.spec.ts new file mode 100644 index 00000000000..82160c3c1a5 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/a.spec.ts @@ -0,0 +1,6 @@ +export const description = 'Description for a.spec.ts'; + +import { makeTestGroup } from '../common/framework/test_group.js'; +import { UnitTest } from '../unittests/unit_test.js'; + +export const g = makeTestGroup(UnitTest); diff --git a/chromium/third_party/webgpu-cts/src/src/demo/a/README.txt b/chromium/third_party/webgpu-cts/src/src/demo/a/README.txt new file mode 100644 index 00000000000..62c18e3cc36 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/a/README.txt @@ -0,0 +1 @@ +README for a/ diff --git a/chromium/third_party/webgpu-cts/src/src/demo/a/b.spec.ts b/chromium/third_party/webgpu-cts/src/src/demo/a/b.spec.ts new file mode 100644 index 00000000000..7e066591dd5 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/a/b.spec.ts @@ -0,0 +1,6 @@ +export const description = 'Description for b.spec.ts'; + +import { makeTestGroup } from '../../common/framework/test_group.js'; +import { UnitTest } from '../../unittests/unit_test.js'; + +export const g = makeTestGroup(UnitTest); diff --git a/chromium/third_party/webgpu-cts/src/src/demo/a/b/README.txt b/chromium/third_party/webgpu-cts/src/src/demo/a/b/README.txt new file mode 100644 index 00000000000..eed2f44bbd7 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/a/b/README.txt @@ -0,0 +1 @@ +README for a/b/ diff --git a/chromium/third_party/webgpu-cts/src/src/demo/a/b/c.spec.ts b/chromium/third_party/webgpu-cts/src/src/demo/a/b/c.spec.ts new file mode 100644 index 00000000000..5358a11c381 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/a/b/c.spec.ts @@ -0,0 +1,39 @@ +export const description = 'Description for c.spec.ts'; + +import { makeTestGroup } from '../../../common/framework/test_group.js'; +import { unreachable } from '../../../common/framework/util/util.js'; +import { UnitTest } from '../../../unittests/unit_test.js'; + +export const g = makeTestGroup(UnitTest); + +g.test('f').fn(() => {}); + +g.test('f,g').fn(() => {}); + +g.test('f,g,h') + .params([{}, { x: 0 }, { x: 0, y: 0 }]) + .fn(() => {}); + +g.test('case_depth_2_in_single_child_test') + .params([{ x: 0, y: 0 }]) + .fn(() => {}); + +g.test('statuses,debug').fn(t => { + t.debug('debug'); +}); + +g.test('statuses,skip').fn(t => { + t.skip('skip'); +}); + +g.test('statuses,warn').fn(t => { + t.warn('warn'); +}); + +g.test('statuses,fail').fn(t => { + t.fail('fail'); +}); + +g.test('statuses,throw').fn(() => { + unreachable('unreachable'); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/demo/a/b/d.spec.ts b/chromium/third_party/webgpu-cts/src/src/demo/a/b/d.spec.ts new file mode 100644 index 00000000000..1412e53baf1 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/a/b/d.spec.ts @@ -0,0 +1,8 @@ +export const description = 'Description for d.spec.ts'; + +import { makeTestGroup } from '../../../common/framework/test_group.js'; +import { UnitTest } from '../../../unittests/unit_test.js'; + +export const g = makeTestGroup(UnitTest); + +g.test('test_depth_2,in_single_child_file').fn(() => {}); diff --git a/chromium/third_party/webgpu-cts/src/src/demo/file_depth_2/in_single_child_dir/r.spec.ts b/chromium/third_party/webgpu-cts/src/src/demo/file_depth_2/in_single_child_dir/r.spec.ts new file mode 100644 index 00000000000..2a1adc6f507 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/demo/file_depth_2/in_single_child_dir/r.spec.ts @@ -0,0 +1,6 @@ +export const description = 'Description for r.spec.ts'; + +import { makeTestGroup } from '../../../common/framework/test_group.js'; +import { UnitTest } from '../../../unittests/unit_test.js'; + +export const g = makeTestGroup(UnitTest); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/async_mutex.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/async_mutex.spec.ts index e663bd40224..dc1bb0d1657 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/async_mutex.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/async_mutex.spec.ts @@ -2,27 +2,30 @@ export const description = ` Tests for AsyncMutex. `; -import { TestGroup } from '../common/framework/test_group.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; import { AsyncMutex } from '../common/framework/util/async_mutex.js'; import { objectEquals } from '../common/framework/util/util.js'; import { UnitTest } from './unit_test.js'; -export const g = new TestGroup(UnitTest); +export const g = makeTestGroup(UnitTest); -g.test('basic', async t => { +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +g.test('basic').fn(async t => { const mutex = new AsyncMutex(); await mutex.with(async () => {}); }); -g.test('serial', async t => { +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +g.test('serial').fn(async t => { const mutex = new AsyncMutex(); await mutex.with(async () => {}); await mutex.with(async () => {}); await mutex.with(async () => {}); }); -g.test('parallel', async t => { +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +g.test('parallel').fn(async t => { const mutex = new AsyncMutex(); await Promise.all([ mutex.with(async () => {}), @@ -31,7 +34,7 @@ g.test('parallel', async t => { ]); }); -g.test('parallel/many', async t => { +g.test('parallel,many').fn(async t => { const mutex = new AsyncMutex(); const actual: number[] = []; const expected = []; @@ -45,13 +48,13 @@ g.test('parallel/many', async t => { t.expect(objectEquals(actual, expected)); }); -g.test('return', async t => { +g.test('return').fn(async t => { const mutex = new AsyncMutex(); const ret = await mutex.with(async () => 123); t.expect(ret === 123); }); -g.test('return/parallel', async t => { +g.test('return,parallel').fn(async t => { const mutex = new AsyncMutex(); const ret = await Promise.all([ mutex.with(async () => 1), diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/basic.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/basic.spec.ts index f8cb768b641..fc4a75d7bbf 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/basic.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/basic.spec.ts @@ -2,28 +2,36 @@ export const description = ` Basic unit tests for test framework. `; -import { TestGroup } from '../common/framework/test_group.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; import { UnitTest } from './unit_test.js'; -export const g = new TestGroup(UnitTest); - -g.test('test/sync', t => {}); - -g.test('test/async', async t => {}); - -g.test('testp/sync', t => { - t.debug(JSON.stringify(t.params)); -}).params([{}]); - -g.test('testp/async', async t => { - t.debug(JSON.stringify(t.params)); -}).params([{}]); - -g.test('testp/private', t => { - const { a, b, _result } = t.params; - t.expect(a + b === _result); -}).params([ - { a: 1, b: 2, _result: 3 }, // - { a: 4, b: -3, _result: 1 }, -]); +export const g = makeTestGroup(UnitTest); + +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +g.test('test,sync').fn(t => {}); + +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +g.test('test,async').fn(async t => {}); + +g.test('test_with_params,sync') + .params([{}]) + .fn(t => { + t.debug(JSON.stringify(t.params)); + }); + +g.test('test_with_params,async') + .params([{}]) + .fn(async t => { + t.debug(JSON.stringify(t.params)); + }); + +g.test('test_with_params,private_params') + .params([ + { a: 1, b: 2, _result: 3 }, // + { a: 4, b: -3, _result: 1 }, + ]) + .fn(t => { + const { a, b, _result } = t.params; + t.expect(a + b === _result); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/getStackTrace.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/getStackTrace.spec.ts index 2966e640f7f..532a10ce7b0 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/getStackTrace.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/getStackTrace.spec.ts @@ -2,51 +2,38 @@ export const description = ` Tests for getStackTrace. `; -import { TestGroup } from '../common/framework/test_group.js'; -import { getStackTrace } from '../common/framework/util/stack.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; +import { extractImportantStackTrace } from '../common/framework/util/stack.js'; import { UnitTest } from './unit_test.js'; -export const g = new TestGroup(UnitTest); +export const g = makeTestGroup(UnitTest); -g.test('stacks', t => { - const lines: number = t.params._expectedLines; - - const ex = new Error(); - ex.stack = t.params._stack; - t.expect(ex.stack === t.params._stack); - const stringified = getStackTrace(ex); - const parts = stringified.split('\n'); - - t.expect(parts.length === lines); - const fst = parts[0]; - const lst = parts[parts.length - 1]; - t.expect(fst.indexOf('/unittests/') !== -1 || fst.indexOf('\\unittests\\') !== -1); - t.expect(lst.indexOf('/unittests/') !== -1 || lst.indexOf('\\unittests\\') !== -1); -}).params([ - { - case: 'node_fail', - _expectedLines: 1, - _stack: `Error: +g.test('stacks') + .params([ + { + case: 'node_fail', + _expectedLines: 3, + _stack: `Error: at CaseRecorder.fail (/Users/kainino/src/cts/src/common/framework/logger.ts:99:30) at RunCaseSpecific.exports.g.test.t [as fn] (/Users/kainino/src/cts/src/unittests/logger.spec.ts:80:7) at RunCaseSpecific.run (/Users/kainino/src/cts/src/common/framework/test_group.ts:121:18) at processTicksAndRejections (internal/process/task_queues.js:86:5)`, - }, - { - // TODO: make sure this test case actually matches what happens on windows - case: 'node_fail_backslash', - _expectedLines: 1, - _stack: `Error: + }, + { + // TODO: make sure this test case actually matches what happens on windows + case: 'node_fail_backslash', + _expectedLines: 3, + _stack: `Error: at CaseRecorder.fail (C:\\Users\\kainino\\src\\cts\\src\\common\\framework\\logger.ts:99:30) at RunCaseSpecific.exports.g.test.t [as fn] (C:\\Users\\kainino\\src\\cts\\src\\unittests\\logger.spec.ts:80:7) at RunCaseSpecific.run (C:\\Users\\kainino\\src\\cts\\src\\common\\framework\\test_group.ts:121:18) at processTicksAndRejections (internal\\process\\task_queues.js:86:5)`, - }, - { - case: 'node_fail_processTicksAndRejections', - _expectedLines: 3, - _stack: `Error: expectation had no effect: suite1:foo: + }, + { + case: 'node_fail_processTicksAndRejections', + _expectedLines: 5, + _stack: `Error: expectation had no effect: suite1:foo: at Object.generateMinimalQueryList (/Users/kainino/src/cts/src/common/framework/generate_minimal_query_list.ts:72:24) at testGenerateMinimalQueryList (/Users/kainino/src/cts/src/unittests/loading.spec.ts:289:25) at processTicksAndRejections (internal/process/task_queues.js:93:5) @@ -55,64 +42,64 @@ g.test('stacks', t => { at /Users/kainino/src/cts/src/common/runtime/cmdline.ts:62:25 at async Promise.all (index 29) at /Users/kainino/src/cts/src/common/runtime/cmdline.ts:78:5`, - }, - { - case: 'node_throw', - _expectedLines: 1, - _stack: `Error: hello + }, + { + case: 'node_throw', + _expectedLines: 2, + _stack: `Error: hello at RunCaseSpecific.g.test.t [as fn] (/Users/kainino/src/cts/src/unittests/test_group.spec.ts:51:11) at RunCaseSpecific.run (/Users/kainino/src/cts/src/common/framework/test_group.ts:121:18) at processTicksAndRejections (internal/process/task_queues.js:86:5)`, - }, - { - case: 'firefox_fail', - _expectedLines: 1, - _stack: `fail@http://localhost:8080/out/common/framework/logger.js:104:30 + }, + { + case: 'firefox_fail', + _expectedLines: 3, + _stack: `fail@http://localhost:8080/out/common/framework/logger.js:104:30 expect@http://localhost:8080/out/common/framework/default_fixture.js:59:16 @http://localhost:8080/out/unittests/util.spec.js:35:5 run@http://localhost:8080/out/common/framework/test_group.js:119:18`, - }, - { - case: 'firefox_throw', - _expectedLines: 1, - _stack: `@http://localhost:8080/out/unittests/test_group.spec.js:48:11 + }, + { + case: 'firefox_throw', + _expectedLines: 1, + _stack: `@http://localhost:8080/out/unittests/test_group.spec.js:48:11 run@http://localhost:8080/out/common/framework/test_group.js:119:18`, - }, - { - case: 'safari_fail', - _expectedLines: 1, - _stack: `fail@http://localhost:8080/out/common/framework/logger.js:104:39 + }, + { + case: 'safari_fail', + _expectedLines: 3, + _stack: `fail@http://localhost:8080/out/common/framework/logger.js:104:39 expect@http://localhost:8080/out/common/framework/default_fixture.js:59:20 http://localhost:8080/out/unittests/util.spec.js:35:11 http://localhost:8080/out/common/framework/test_group.js:119:20 asyncFunctionResume@[native code] [native code] promiseReactionJob@[native code]`, - }, - { - case: 'safari_throw', - _expectedLines: 1, - _stack: `http://localhost:8080/out/unittests/test_group.spec.js:48:20 + }, + { + case: 'safari_throw', + _expectedLines: 1, + _stack: `http://localhost:8080/out/unittests/test_group.spec.js:48:20 http://localhost:8080/out/common/framework/test_group.js:119:20 asyncFunctionResume@[native code] [native code] promiseReactionJob@[native code]`, - }, - { - case: 'chrome_fail', - _expectedLines: 1, - _stack: `Error + }, + { + case: 'chrome_fail', + _expectedLines: 4, + _stack: `Error at CaseRecorder.fail (http://localhost:8080/out/common/framework/logger.js:104:30) at DefaultFixture.expect (http://localhost:8080/out/common/framework/default_fixture.js:59:16) at RunCaseSpecific.fn (http://localhost:8080/out/unittests/util.spec.js:35:5) at RunCaseSpecific.run (http://localhost:8080/out/common/framework/test_group.js:119:18) at async runCase (http://localhost:8080/out/common/runtime/standalone.js:37:17) at async http://localhost:8080/out/common/runtime/standalone.js:102:7`, - }, - { - case: 'chrome_throw', - _expectedLines: 5, - _stack: `Error: hello + }, + { + case: 'chrome_throw', + _expectedLines: 6, + _stack: `Error: hello at RunCaseSpecific.fn (http://localhost:8080/out/unittests/test_group.spec.js:48:11) at RunCaseSpecific.run (http://localhost:8080/out/common/framework/test_group.js:119:18)" at async Promise.all (index 0) @@ -121,11 +108,11 @@ promiseReactionJob@[native code]`, at async RunCaseSpecific.run (http://localhost:8080/out/common/framework/test_group.js:119:7) at async runCase (http://localhost:8080/out/common/runtime/standalone.js:37:17) at async http://localhost:8080/out/common/runtime/standalone.js:102:7`, - }, - { - case: 'multiple_lines', - _expectedLines: 7, - _stack: `Error: hello + }, + { + case: 'multiple_lines', + _expectedLines: 8, + _stack: `Error: hello at RunCaseSpecific.fn (http://localhost:8080/out/unittests/test_group.spec.js:48:11) at RunCaseSpecific.fn (http://localhost:8080/out/unittests/test_group.spec.js:48:11) at RunCaseSpecific.fn (http://localhost:8080/out/unittests/test_group.spec.js:48:11) @@ -136,5 +123,16 @@ promiseReactionJob@[native code]`, at async RunCaseSpecific.run (http://localhost:8080/out/common/framework/test_group.js:119:7) at async runCase (http://localhost:8080/out/common/runtime/standalone.js:37:17) at async http://localhost:8080/out/common/runtime/standalone.js:102:7`, - }, -]); + }, + ]) + .fn(t => { + const ex = new Error(); + ex.stack = t.params._stack; + t.expect(ex.stack === t.params._stack); + const stringified = extractImportantStackTrace(ex); + const parts = stringified.split('\n'); + + t.expect(parts.length === t.params._expectedLines); + const last = parts[parts.length - 1]; + t.expect(last.indexOf('/unittests/') !== -1 || last.indexOf('\\unittests\\') !== -1); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/listing.ts b/chromium/third_party/webgpu-cts/src/src/unittests/listing.ts index ba26ed77bd4..2d6f4cf8ecf 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/listing.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/listing.ts @@ -1,4 +1,4 @@ -import { TestSuiteListing } from '../common/framework/listing.js'; +import { TestSuiteListing } from '../common/framework/test_suite_listing.js'; import { makeListing } from '../common/tools/crawl.js'; export const listing: Promise<TestSuiteListing> = makeListing(__filename); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/loaders_and_trees.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/loaders_and_trees.spec.ts new file mode 100644 index 00000000000..5ca7e7e5d3b --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/unittests/loaders_and_trees.spec.ts @@ -0,0 +1,360 @@ +export const description = ` +Tests for queries/filtering, loading, and running. +`; + +import { TestFileLoader, SpecFile } from '../common/framework/file_loader.js'; +import { Logger } from '../common/framework/logging/logger.js'; +import { Status } from '../common/framework/logging/result.js'; +import { parseQuery } from '../common/framework/query/parseQuery.js'; +import { + TestQuery, + TestQuerySingleCase, + TestQueryMultiCase, + TestQueryMultiTest, + TestQueryMultiFile, +} from '../common/framework/query/query.js'; +import { makeTestGroup, makeTestGroupForUnitTesting } from '../common/framework/test_group.js'; +import { TestSuiteListing, TestSuiteListingEntry } from '../common/framework/test_suite_listing.js'; +import { TestTreeLeaf } from '../common/framework/tree.js'; +import { assert, objectEquals } from '../common/framework/util/util.js'; + +import { UnitTest } from './unit_test.js'; + +const listingData: { [k: string]: TestSuiteListingEntry[] } = { + suite1: [ + { file: [], readme: 'desc 1a' }, + { file: ['foo'], description: 'desc 1b' }, + { file: ['bar'], readme: 'desc 1c' }, + { file: ['bar', 'buzz', 'buzz'], description: 'desc 1d' }, + { file: ['baz'], description: 'desc 1e' }, + ], + suite2: [ + { file: [], readme: 'desc 2a' }, + { file: ['foof'], description: 'desc 2b' }, + ], +}; + +const specsData: { [k: string]: SpecFile } = { + 'suite1/foo.spec.js': { + description: 'desc 1b', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('hello').fn(() => {}); + g.test('bonjour').fn(() => {}); + g.test('hola').fn(() => {}); + return g; + })(), + }, + 'suite1/bar/biz.spec.js': { + description: 'desc 1f', + g: makeTestGroupForUnitTesting(UnitTest), + }, + 'suite1/bar/bez.spec.js': { + description: 'desc 1g', + g: makeTestGroupForUnitTesting(UnitTest), + }, + 'suite1/bar/buzz/buzz.spec.js': { + description: 'desc 1d', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('zap').fn(() => {}); + return g; + })(), + }, + 'suite1/baz.spec.js': { + description: 'desc 1e', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('wye') + .params([{}, { x: 1 }]) + .fn(() => {}); + g.test('zed') + .params([ + { a: 1, b: 2, _c: 0 }, + { b: 3, a: 1, _c: 0 }, + ]) + .fn(() => {}); + return g; + })(), + }, + 'suite2/foof.spec.js': { + description: 'desc 2b', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('blah').fn(t => { + t.debug('OK'); + }); + g.test('bleh') + .params([{ a: 1 }]) + .fn(t => { + t.debug('OK'); + t.debug('OK'); + }); + g.test('bluh,a').fn(t => { + t.fail('bye'); + }); + return g; + })(), + }, +}; + +class FakeTestFileLoader extends TestFileLoader { + async listing(suite: string): Promise<TestSuiteListing> { + return listingData[suite]; + } + + async import(path: string): Promise<SpecFile> { + assert(path in specsData, '[test] mock file ' + path + ' does not exist'); + return specsData[path]; + } +} + +class LoadingTest extends UnitTest { + static readonly loader = new FakeTestFileLoader(); + + async load(query: string): Promise<TestTreeLeaf[]> { + return Array.from(await LoadingTest.loader.loadCases(parseQuery(query))); + } + + async loadNames(query: string): Promise<string[]> { + return (await this.load(query)).map(c => c.query.toString()); + } +} + +export const g = makeTestGroup(LoadingTest); + +g.test('suite').fn(async t => { + t.shouldReject('Error', t.load('suite1')); + t.shouldReject('Error', t.load('suite1:')); +}); + +g.test('group').fn(async t => { + t.expect((await t.load('suite1:*')).length === 8); + t.expect((await t.load('suite1:foo,*')).length === 3); // x:foo,* matches x:foo: + t.expect((await t.load('suite1:bar,*')).length === 1); + t.expect((await t.load('suite1:bar,buzz,buzz,*')).length === 1); + + t.shouldReject('Error', t.load('suite1:f*')); + + { + const s = new TestQueryMultiFile('suite1', ['bar', 'buzz']).toString(); + t.expect((await t.load(s)).length === 1); + } +}); + +g.test('test').fn(async t => { + t.shouldReject('Error', t.load('suite1::')); + t.shouldReject('Error', t.load('suite1:bar:')); + t.shouldReject('Error', t.load('suite1:bar,:')); + + t.shouldReject('Error', t.load('suite1::*')); + t.shouldReject('Error', t.load('suite1:bar,:*')); + t.shouldReject('Error', t.load('suite1:bar:*')); + + t.expect((await t.load('suite1:foo:*')).length === 3); + t.expect((await t.load('suite1:bar,buzz,buzz:*')).length === 1); + t.expect((await t.load('suite1:baz:*')).length === 4); + + t.expect((await t.load('suite2:foof:bluh,*')).length === 1); + t.expect((await t.load('suite2:foof:bluh,a,*')).length === 1); + + { + const s = new TestQueryMultiTest('suite2', ['foof'], ['bluh']).toString(); + t.expect((await t.load(s)).length === 1); + } +}); + +g.test('case').fn(async t => { + t.shouldReject('Error', t.load('suite1:foo::')); + t.shouldReject('Error', t.load('suite1:bar:zed,:')); + + t.shouldReject('Error', t.load('suite1:foo:h*')); + + t.shouldReject('Error', t.load('suite1:foo::*')); + t.shouldReject('Error', t.load('suite1:baz::*')); + t.shouldReject('Error', t.load('suite1:baz:zed,:*')); + + t.shouldReject('Error', t.load('suite1:baz:zed:')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1;b=2*')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1;b=2;')); + t.shouldReject('SyntaxError', t.load('suite1:baz:zed:a=1;b=2,')); // tries to parse '2,' as JSON + t.shouldReject('Error', t.load('suite1:baz:zed:a=1,b=2')); // '=' not allowed in value '1,b=2' + t.shouldReject('Error', t.load('suite1:baz:zed:b=2*')); + t.shouldReject('Error', t.load('suite1:baz:zed:b=2;a=1;_c=0')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1,*')); + + t.expect((await t.load('suite1:baz:zed:*')).length === 2); + t.expect((await t.load('suite1:baz:zed:a=1;*')).length === 2); + t.expect((await t.load('suite1:baz:zed:a=1;b=2')).length === 1); + t.expect((await t.load('suite1:baz:zed:a=1;b=2;*')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=2;*')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=2;a=1')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=2;a=1;*')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=3;a=1')).length === 1); + t.expect((await t.load('suite1:baz:zed:a=1;b=3')).length === 1); + t.expect((await t.load('suite1:foo:hello:')).length === 1); + + { + const s = new TestQueryMultiCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }).toString(); + t.expect((await t.load(s)).length === 1); + } + { + const s = new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }).toString(); + t.expect((await t.load(s)).length === 1); + } +}); + +g.test('end2end').fn(async t => { + const l = await t.load('suite2:foof:*'); + assert(l.length === 3, 'listing length'); + + const log = new Logger(true); + + const exp = async ( + i: number, + query: TestQuery, + status: Status, + logs: (s: string[]) => boolean + ) => { + t.expect(objectEquals(l[i].query, query)); + const name = l[i].query.toString(); + const [rec, res] = log.record(name); + await l[i].run(rec); + + t.expect(log.results.get(name) === res); + t.expect(res.status === status); + t.expect(res.timems > 0); + assert(res.logs !== undefined); // only undefined while pending + t.expect(logs(res.logs.map(l => JSON.stringify(l)))); + }; + + await exp(0, new TestQuerySingleCase('suite2', ['foof'], ['blah'], {}), 'pass', logs => + objectEquals(logs, ['"DEBUG: OK"']) + ); + await exp(1, new TestQuerySingleCase('suite2', ['foof'], ['bleh'], { a: 1 }), 'pass', logs => + objectEquals(logs, ['"DEBUG: OK"', '"DEBUG: OK"']) + ); + await exp( + 2, + new TestQuerySingleCase('suite2', ['foof'], ['bluh', 'a'], {}), + 'fail', + logs => + logs.length === 1 && + logs[0].startsWith('"EXPECTATION FAILED: Error: bye\\n') && + logs[0].indexOf('loaders_and_trees.spec.') !== -1 + ); +}); + +async function testIterateCollapsed( + t: LoadingTest, + expectations: string[], + expectedResult: 'throws' | string[] +) { + const treePromise = LoadingTest.loader.loadTree( + new TestQueryMultiFile('suite1', []), + expectations + ); + if (expectedResult === 'throws') { + t.shouldReject('Error', treePromise, 'loadTree should have thrown Error'); + return; + } + const tree = await treePromise; + const actual = Array.from(tree.iterateCollapsedQueries(), q => q.toString()); + if (!objectEquals(actual, expectedResult)) { + t.fail( + `iterateCollapsed failed: + got [${actual.join(', ')}] + exp [${expectedResult.join(', ')}] +${tree.toString()}` + ); + } +} + +g.test('print').fn(async () => { + const tree = await LoadingTest.loader.loadTree(new TestQueryMultiFile('suite1', [])); + tree.toString(); +}); + +g.test('iterateCollapsed').fn(async t => { + // Expectations have no effect + await testIterateCollapsed(t, [], ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:*']); + await testIterateCollapsed( + t, + ['suite1:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:*'] + ); + await testIterateCollapsed( + t, + ['suite1:foo:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:*'] + ); + await testIterateCollapsed( + t, + ['suite1:bar,buzz,buzz:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:*'] + ); + + // Expectations have some effect + await testIterateCollapsed( + t, + ['suite1:baz:wye:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:wye:*', 'suite1:baz:zed,*'] + ); + await testIterateCollapsed( + t, + ['suite1:baz:zed:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:wye,*', 'suite1:baz:zed:*'] + ); + await testIterateCollapsed( + t, + ['suite1:baz:wye:*', 'suite1:baz:zed:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:wye:*', 'suite1:baz:zed:*'] + ); + await testIterateCollapsed( + t, + ['suite1:baz:wye:'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1;*', + 'suite1:baz:zed,*', + ] + ); + await testIterateCollapsed( + t, + ['suite1:baz:wye:x=1'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1', + 'suite1:baz:zed,*', + ] + ); + await testIterateCollapsed( + t, + ['suite1:foo:*', 'suite1:baz:wye:'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1;*', + 'suite1:baz:zed,*', + ] + ); + + // Invalid expectation queries + await testIterateCollapsed(t, ['garbage'], 'throws'); + await testIterateCollapsed(t, ['garbage*'], 'throws'); + await testIterateCollapsed(t, ['suite1*'], 'throws'); + await testIterateCollapsed(t, ['suite1:foo*'], 'throws'); + await testIterateCollapsed(t, ['suite1:foo:ba*'], 'throws'); + + // Valid expectation queries but they don't match anything + await testIterateCollapsed(t, ['garbage:*'], 'throws'); + await testIterateCollapsed(t, ['suite1:doesntexist:*'], 'throws'); + await testIterateCollapsed(t, ['suite2:foo:*'], 'throws'); + // Doesn't match anything because we collapse this unnecessary node into just 'suite1:foo:*' + await testIterateCollapsed(t, ['suite1:foo,*'], 'throws'); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/loading.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/loading.spec.ts deleted file mode 100644 index c66728a3df2..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/unittests/loading.spec.ts +++ /dev/null @@ -1,348 +0,0 @@ -export const description = ` -Tests for queries/filtering, loading, and running. -`; - -import { generateMinimalQueryList } from '../common/framework/generate_minimal_query_list.js'; -import { TestSuiteListing, TestSuiteListingEntry } from '../common/framework/listing.js'; -import { TestFileLoader, TestLoader, TestSpecOrReadme } from '../common/framework/loader.js'; -import { Logger } from '../common/framework/logger.js'; -import { paramsEquals } from '../common/framework/params_utils.js'; -import { TestFilterResult } from '../common/framework/test_filter/test_filter_result.js'; -import { RunCase, TestGroup } from '../common/framework/test_group.js'; -import { makeQueryString } from '../common/framework/url_query.js'; -import { assert, objectEquals } from '../common/framework/util/util.js'; - -import { UnitTest } from './unit_test.js'; - -const listingData: { [k: string]: TestSuiteListingEntry[] } = { - suite1: [ - { path: '', description: 'desc 1a' }, - { path: 'foo', description: 'desc 1b' }, - { path: 'bar/', description: 'desc 1c' }, - { path: 'bar/buzz', description: 'desc 1d' }, - { path: 'baz', description: 'desc 1e' }, - ], - suite2: [ - { path: '', description: 'desc 2a' }, - { path: 'foof', description: 'desc 2b' }, - ], -}; - -const specsData: { [k: string]: TestSpecOrReadme } = { - 'suite1/README.txt': { description: 'desc 1a' }, - 'suite1/foo.spec.js': { - description: 'desc 1b', - g: (() => { - const g = new TestGroup(UnitTest); - g.test('hello', () => {}); - g.test('bonjour', () => {}); - g.test('hola', () => {}); - return g; - })(), - }, - 'suite1/bar/README.txt': { description: 'desc 1c' }, - 'suite1/bar/biz.spec.js': { - description: 'desc 1f', - g: new TestGroup(UnitTest), - }, - 'suite1/bar/bez.spec.js': { - description: 'desc 1g', - g: new TestGroup(UnitTest), - }, - 'suite1/bar/buzz.spec.js': { - description: 'desc 1d', - g: (() => { - const g = new TestGroup(UnitTest); - g.test('zap', () => {}); - return g; - })(), - }, - 'suite1/baz.spec.js': { - description: 'desc 1e', - g: (() => { - const g = new TestGroup(UnitTest); - g.test('wye', () => {}).params([ - {}, // - { x: 1 }, - ]); - g.test('zed', () => {}).params([ - { a: 1, b: 2, _c: 0 }, // - { a: 1, b: 3, _c: 0 }, - ]); - return g; - })(), - }, - 'suite2/foof.spec.js': { - description: 'desc 2b', - g: (() => { - const g = new TestGroup(UnitTest); - g.test('blah', t => { - t.debug('OK'); - }); - g.test('bleh', t => { - t.debug('OK'); - t.debug('OK'); - }).params([{}]); - g.test('bluh', t => { - t.fail('bye'); - }); - return g; - })(), - }, -}; - -class FakeTestFileLoader implements TestFileLoader { - async listing(suite: string): Promise<TestSuiteListing> { - return listingData[suite]; - } - - async import(path: string): Promise<TestSpecOrReadme> { - assert(specsData.hasOwnProperty(path), '[test] mock file ' + path + ' does not exist'); - return specsData[path]; - } -} - -class LoadingTest extends UnitTest { - static readonly loader: TestLoader = new TestLoader(new FakeTestFileLoader()); - - async load(filters: string[]): Promise<TestFilterResult[]> { - return Array.from(await LoadingTest.loader.loadTestsFromCmdLine(filters)); - } - - async singleGroup(query: string): Promise<RunCase[]> { - const [rec] = new Logger().record({ suite: '', path: '' }); - const a = await this.load([query]); - assert(a.length === 1, 'more than one group'); - const spec = a[0].spec; - assert('g' in spec, 'group undefined'); - return Array.from(spec.g.iterate(rec)); - } -} - -export const g = new TestGroup(LoadingTest); - -g.test('whole suite', async t => { - t.shouldReject('Error', t.load(['suite1'])); - t.expect((await t.load(['suite1:'])).length === 5); -}); - -g.test('partial suite', async t => { - t.expect((await t.load(['suite1:f'])).length === 1); - t.expect((await t.load(['suite1:fo'])).length === 1); - t.expect((await t.load(['suite1:foo'])).length === 1); - t.expect((await t.load(['suite1:foof'])).length === 0); - t.expect((await t.load(['suite1:ba'])).length === 3); - t.expect((await t.load(['suite1:bar'])).length === 2); - t.expect((await t.load(['suite1:bar/'])).length === 2); - t.expect((await t.load(['suite1:bar/b'])).length === 1); -}); - -g.test('whole group', async t => { - t.shouldReject('Error', t.load(['suite1::'])); - t.shouldReject('Error', t.load(['suite1:bar:'])); - t.shouldReject('Error', t.load(['suite1:bar/:'])); - t.expect((await t.singleGroup('suite1:bar/buzz:')).length === 1); - t.expect((await t.singleGroup('suite1:baz:')).length === 4); - - { - const foo = (await t.load(['suite1:foo:']))[0]; - t.expect(foo.id.suite === 'suite1'); - t.expect(foo.id.path === 'foo'); - assert('g' in foo.spec, 'foo group'); - const [rec] = new Logger().record({ suite: '', path: '' }); - t.expect(Array.from(foo.spec.g.iterate(rec)).length === 3); - } -}); - -g.test('partial group', async t => { - t.expect((await t.singleGroup('suite1:foo:h')).length === 2); - t.expect((await t.singleGroup('suite1:foo:he')).length === 1); - t.expect((await t.singleGroup('suite1:foo:hello')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed')).length === 2); -}); - -g.test('partial test/exact', async t => { - t.expect((await t.singleGroup('suite1:foo:hello=')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed=')).length === 0); - t.expect((await t.singleGroup('suite1:baz:zed=')).length === 0); - t.expect((await t.singleGroup('suite1:baz:zed={}')).length === 0); - t.expect((await t.singleGroup('suite1:baz:zed={"a":1,"b":2}')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed={"b":2,"a":1}')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed={"a":1,"b":2,"_c":0}')).length === 0); -}); - -g.test('partial test/makeQueryString', async t => { - const s = makeQueryString( - { suite: 'suite1', path: 'baz' }, - { test: 'zed', params: { a: 1, b: 2 } } - ); - t.expect((await t.singleGroup(s)).length === 1); -}); - -g.test('partial test/match', async t => { - t.expect((await t.singleGroup('suite1:baz:zed~')).length === 2); - t.expect((await t.singleGroup('suite1:baz:zed~{}')).length === 2); - t.expect((await t.singleGroup('suite1:baz:zed~{"a":1}')).length === 2); - t.expect((await t.singleGroup('suite1:baz:zed~{"a":1,"b":2}')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed~{"b":2,"a":1}')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed~{"b":2}')).length === 1); - t.expect((await t.singleGroup('suite1:baz:zed~{"a":2}')).length === 0); - t.expect((await t.singleGroup('suite1:baz:zed~{"c":0}')).length === 0); - t.expect((await t.singleGroup('suite1:baz:zed~{"_c":0}')).length === 0); -}); - -g.test('end2end', async t => { - const l = await t.load(['suite2:foof']); - assert(l.length === 1, 'listing length'); - - t.expect(l[0].id.suite === 'suite2'); - t.expect(l[0].id.path === 'foof'); - t.expect(l[0].spec.description === 'desc 2b'); - assert('g' in l[0].spec); - t.expect(l[0].spec.g.iterate instanceof Function); - - const log = new Logger(); - const [rec, res] = log.record(l[0].id); - const rcs = Array.from(l[0].spec.g.iterate(rec)); - assert(rcs.length === 3, 'iterate length'); - - t.expect(rcs[0].id.test === 'blah'); - t.expect(rcs[0].id.params === null); - - t.expect(rcs[1].id.test === 'bleh'); - t.expect(paramsEquals(rcs[1].id.params, {})); - - t.expect(log.results[0] === res); - t.expect(res.spec === 'suite2:foof:'); - t.expect(res.cases.length === 0); - - { - const cases = res.cases; - const res0 = await rcs[0].run(true); - assert(cases.length === 1, 'results cases length'); - t.expect(res.cases[0] === res0); - t.expect(res0.test === 'blah'); - t.expect(res0.params === null); - t.expect(res0.status === 'pass'); - t.expect(res0.timems >= 0); - assert(res0.logs !== undefined, 'results case logs'); - t.expect(objectEquals(JSON.stringify(res0.logs), '["DEBUG: OK"]')); - } - { - // Store cases off to a separate variable due to a typescript bug - // where it can't detect that res.cases.length might change between - // above and here. - const cases = res.cases; - const res1 = await rcs[1].run(true); - assert(cases.length === 2, 'results cases length'); - t.expect(res.cases[1] === res1); - t.expect(res1.test === 'bleh'); - t.expect(paramsEquals(res1.params, {})); - t.expect(res1.status === 'pass'); - t.expect(res1.timems >= 0); - assert(res1.logs !== undefined, 'results case logs'); - t.expect(objectEquals(JSON.stringify(res1.logs), '["DEBUG: OK","DEBUG: OK"]')); - } - { - // Store cases off to a separate variable due to a typescript bug - // where it can't detect that res.cases.length might change between - // above and here. - const cases = res.cases; - const res2 = await rcs[2].run(true); - assert(cases.length === 3, 'results cases length'); - t.expect(res.cases[2] === res2); - t.expect(res2.test === 'bluh'); - t.expect(res2.params === null); - t.expect(res2.status === 'fail'); - t.expect(res2.timems >= 0); - assert(res2.logs !== undefined, 'results case logs'); - t.expect(res2.logs.length === 1); - const l = res2.logs[0].toJSON(); - t.expect(l.startsWith('FAIL: bye\n')); - t.expect(l.indexOf('loading.spec.') !== -1); - } -}); - -const testGenerateMinimalQueryList = async ( - t: LoadingTest, - expectations: string[], - result: string[] -) => { - const l = await t.load(['suite1:']); - const queries = await generateMinimalQueryList(l, expectations); - t.expect(objectEquals(queries, result)); -}; - -g.test('generateMinimalQueryList/errors', async t => { - t.shouldReject('Error', testGenerateMinimalQueryList(t, ['garbage'], [])); - t.shouldReject('Error', testGenerateMinimalQueryList(t, ['suite1:'], [])); - t.shouldReject('Error', testGenerateMinimalQueryList(t, ['suite1:foo'], [])); - t.shouldReject('Error', testGenerateMinimalQueryList(t, ['suite1:foo:ba'], [])); - t.shouldReject('Error', testGenerateMinimalQueryList(t, ['suite2:foo:'], [])); -}); - -g.test('generateMinimalQueryList', async t => { - await testGenerateMinimalQueryList( - t, // - [], - ['suite1:foo:', 'suite1:bar/buzz:', 'suite1:baz:'] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:foo:'], - ['suite1:foo:', 'suite1:bar/buzz:', 'suite1:baz:'] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:bar/buzz:'], - ['suite1:foo:', 'suite1:bar/buzz:', 'suite1:baz:'] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:baz:wye~'], - ['suite1:foo:', 'suite1:bar/buzz:', 'suite1:baz:wye~', 'suite1:baz:zed~'] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:baz:zed~'], - ['suite1:foo:', 'suite1:bar/buzz:', 'suite1:baz:wye~', 'suite1:baz:zed~'] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:baz:wye~', 'suite1:baz:zed~'], - ['suite1:foo:', 'suite1:bar/buzz:', 'suite1:baz:wye~', 'suite1:baz:zed~'] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:baz:wye='], - [ - 'suite1:foo:', - 'suite1:bar/buzz:', - 'suite1:baz:wye=', - 'suite1:baz:wye={"x":1}', - 'suite1:baz:zed~', - ] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:baz:wye={"x":1}'], - [ - 'suite1:foo:', - 'suite1:bar/buzz:', - 'suite1:baz:wye=', - 'suite1:baz:wye={"x":1}', - 'suite1:baz:zed~', - ] - ); - await testGenerateMinimalQueryList( - t, // - ['suite1:foo:', 'suite1:baz:wye='], - [ - 'suite1:foo:', - 'suite1:bar/buzz:', - 'suite1:baz:wye=', - 'suite1:baz:wye={"x":1}', - 'suite1:baz:zed~', - ] - ); -}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/logger.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/logger.spec.ts index cc284b16d61..de1b02fbe47 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/logger.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/logger.spec.ts @@ -5,139 +5,143 @@ Also serves as a larger test of async test functions, and of the logging system. `; import { SkipTestCase } from '../common/framework/fixture.js'; -import { Logger } from '../common/framework/logger.js'; -import { paramsEquals } from '../common/framework/params_utils.js'; -import { TestGroup } from '../common/framework/test_group.js'; +import { Logger } from '../common/framework/logging/logger.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; +import { assert } from '../common/framework/util/util.js'; import { UnitTest } from './unit_test.js'; -export const g = new TestGroup(UnitTest); - -g.test('construct', t => { - const mylog = new Logger(); - const [testrec, testres] = mylog.record({ suite: 'a', path: 'foo/bar' }); - const [, res1] = testrec.record('baz', null); - const params2 = {}; - const [, res2] = testrec.record('qux', params2); - - t.expect(testres.spec === 'a:foo/bar:'); - t.expect(testres.cases.length === 2); - t.expect(testres.cases[0] === res1); - t.expect(testres.cases[1] === res2); - t.expect(res1.test === 'baz'); - t.expect(res1.params === null); +export const g = makeTestGroup(UnitTest); + +g.test('construct').fn(t => { + const mylog = new Logger(true); + const [, res1] = mylog.record('one'); + const [, res2] = mylog.record('two'); + + t.expect(mylog.results.get('one') === res1); + t.expect(mylog.results.get('two') === res2); t.expect(res1.logs === undefined); t.expect(res1.status === 'running'); t.expect(res1.timems < 0); - t.expect(res2.test === 'qux'); - t.expect(paramsEquals(res2.params, params2)); t.expect(res2.logs === undefined); t.expect(res2.status === 'running'); t.expect(res2.timems < 0); }); -g.test('private params', t => { - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: 'a', path: 'foo/bar' }); - const [, res] = testrec.record('baz', { a: 1, _b: 2 }); - - t.expect(paramsEquals(res.params, { a: 1 })); -}); - -g.test('empty', t => { - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: '', path: '' }); - const [rec, res] = testrec.record('baz', null); +g.test('empty').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); rec.start(); t.expect(res.status === 'running'); rec.finish(); + t.expect(res.status === 'pass'); t.expect(res.timems >= 0); }); -g.test('pass', t => { - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: '', path: '' }); - const [rec, res] = testrec.record('baz', null); +g.test('pass').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); rec.start(); rec.debug(new Error('hello')); t.expect(res.status === 'running'); rec.finish(); + t.expect(res.status === 'pass'); t.expect(res.timems >= 0); }); -g.test('skip', t => { - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: '', path: '' }); - const [rec, res] = testrec.record('baz', null); +g.test('skip').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); rec.start(); - t.expect(res.status === 'running'); - rec.skipped(new SkipTestCase()); rec.debug(new Error('hello')); - - t.expect(res.status === 'running'); rec.finish(); t.expect(res.status === 'skip'); t.expect(res.timems >= 0); }); -g.test('warn', t => { - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: '', path: '' }); - const [rec, res] = testrec.record('baz', null); +g.test('warn').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); rec.start(); - t.expect(res.status === 'running'); - - rec.warn(new Error()); + rec.warn(new Error('hello')); rec.skipped(new SkipTestCase()); - - t.expect(res.status === 'running'); rec.finish(); t.expect(res.status === 'warn'); t.expect(res.timems >= 0); }); -g.test('fail', t => { - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: '', path: '' }); - const [rec, res] = testrec.record('baz', null); +g.test('fail,expectationFailed').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); rec.start(); - t.expect(res.status === 'running'); - - rec.fail(new Error('bye')); + rec.expectationFailed(new Error('bye')); rec.warn(new Error()); rec.skipped(new SkipTestCase()); - - t.expect(res.status === 'running'); rec.finish(); t.expect(res.status === 'fail'); t.expect(res.timems >= 0); }); -g.test('debug', t => { - const { debug, _logsCount } = t.params; +g.test('fail,validationFailed').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); + + rec.start(); + rec.validationFailed(new Error('bye')); + rec.warn(new Error()); + rec.skipped(new SkipTestCase()); + rec.finish(); - const mylog = new Logger(); - const [testrec] = mylog.record({ suite: '', path: '' }); - const [rec, res] = testrec.record('baz', null); + t.expect(res.status === 'fail'); + t.expect(res.timems >= 0); +}); - rec.start(debug); - rec.debug(new Error('hello')); +g.test('fail,threw').fn(t => { + const mylog = new Logger(true); + const [rec, res] = mylog.record('one'); + + rec.start(); + rec.threw(new Error('bye')); + rec.warn(new Error()); + rec.skipped(new SkipTestCase()); rec.finish(); - t.expect(res.status === 'pass'); + + t.expect(res.status === 'fail'); t.expect(res.timems >= 0); - t.expect(res.logs!.length === _logsCount); -}).params([ - { debug: true, _logsCount: 1 }, // - { debug: false, _logsCount: 0 }, -]); +}); + +g.test('debug') + .params([ + { debug: true, _logsCount: 5 }, // + { debug: false, _logsCount: 3 }, + ]) + .fn(t => { + const { debug, _logsCount } = t.params; + + const mylog = new Logger(debug); + const [rec, res] = mylog.record('one'); + + rec.start(); + rec.debug(new Error('hello')); + rec.expectationFailed(new Error('bye')); + rec.warn(new Error()); + rec.skipped(new SkipTestCase()); + rec.debug(new Error('foo')); + rec.finish(); + + t.expect(res.status === 'fail'); + t.expect(res.timems >= 0); + assert(res.logs !== undefined); + t.expect(res.logs.length === _logsCount); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/make_filter.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/make_filter.spec.ts deleted file mode 100644 index d7769d6cf35..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/unittests/make_filter.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const description = ` -Unit tests for makeFilter. -`; - -import { TestGroup } from '../common/framework/test_group.js'; - -import { UnitTest } from './unit_test.js'; - -export const g = new TestGroup(UnitTest); - -// TODO: tests for makeFilter, in particular idIfSingle() diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/param_helpers.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/param_helpers.spec.ts deleted file mode 100644 index ba2dbf4593e..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/unittests/param_helpers.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -export const description = ` -Unit tests for parameterization helpers. -`; - -import { pcombine, pexclude, pfilter, poptions } from '../common/framework/params.js'; -import { ParamSpec, ParamSpecIterable, paramsEquals } from '../common/framework/params_utils.js'; -import { TestGroup } from '../common/framework/test_group.js'; - -import { UnitTest } from './unit_test.js'; - -class ParamsTest extends UnitTest { - expectSpecEqual(act: ParamSpecIterable, exp: ParamSpec[]): void { - const a = Array.from(act); - this.expect(a.length === exp.length && a.every((x, i) => paramsEquals(x, exp[i]))); - } -} - -export const g = new TestGroup(ParamsTest); - -g.test('options', t => { - t.expectSpecEqual(poptions('hello', [1, 2, 3]), [{ hello: 1 }, { hello: 2 }, { hello: 3 }]); -}); - -g.test('combine/none', t => { - t.expectSpecEqual(pcombine(), []); -}); - -g.test('combine/zeroes and ones', t => { - t.expectSpecEqual(pcombine([], []), []); - t.expectSpecEqual(pcombine([], [{}]), []); - t.expectSpecEqual(pcombine([{}], []), []); - t.expectSpecEqual(pcombine([{}], [{}]), [{}]); -}); - -g.test('combine/mixed', t => { - t.expectSpecEqual( - pcombine(poptions('x', [1, 2]), poptions('y', ['a', 'b']), [{ p: 4 }, { q: 5 }], [{}]), - [ - { x: 1, y: 'a', p: 4 }, - { x: 1, y: 'a', q: 5 }, - { x: 1, y: 'b', p: 4 }, - { x: 1, y: 'b', q: 5 }, - { x: 2, y: 'a', p: 4 }, - { x: 2, y: 'a', q: 5 }, - { x: 2, y: 'b', p: 4 }, - { x: 2, y: 'b', q: 5 }, - ] - ); -}); - -g.test('filter', t => { - t.expectSpecEqual( - pfilter( - [ - { a: true, x: 1 }, - { a: false, y: 2 }, - ], - p => p.a - ), - [{ a: true, x: 1 }] - ); -}); - -g.test('exclude', t => { - t.expectSpecEqual( - pexclude( - [ - { a: true, x: 1 }, - { a: false, y: 2 }, - ], - [{ a: true }, { a: false, y: 2 }] - ), - [{ a: true, x: 1 }] - ); -}); - -g.test('undefined', t => { - t.expectSpecEqual([{ a: undefined }], [{}]); - t.expectSpecEqual([{}], [{ a: undefined }]); -}); - -g.test('arrays', t => { - t.expectSpecEqual([{ a: [1, 2] }], [{ a: [1, 2] }]); -}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/params.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/params.spec.ts deleted file mode 100644 index 65c486f9a09..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/unittests/params.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -export const description = ` -Unit tests for parameterization. -`; - -import { pcombine, pexclude, pfilter } from '../common/framework/params.js'; -import { ParamSpec } from '../common/framework/params_utils.js'; -import { TestGroup } from '../common/framework/test_group.js'; - -import { TestGroupTest } from './test_group_test.js'; -import { UnitTest } from './unit_test.js'; - -export const g = new TestGroup(TestGroupTest); - -g.test('none', t => { - t.fail("this test shouldn't run"); -}).params([]); - -g.test('combine none', t => { - t.fail("this test shouldn't run"); -}).params(pcombine([])); - -g.test('filter', t => { - t.expect(t.params.a); -}).params( - pfilter( - [ - { a: true, x: 1 }, // - { a: false, y: 2 }, - ], - p => p.a - ) -); - -g.test('exclude', t => { - t.expect(t.params.a); -}).params( - pexclude( - [ - { a: true, x: 1 }, // - { a: false, y: 2 }, - ], - [ - { a: true }, // - { a: false, y: 2 }, - ] - ) -); - -g.test('generator', t0 => { - const g = new TestGroup(UnitTest); - - const ran: ParamSpec[] = []; - - g.test('generator', t => { - ran.push(t.params); - }).params( - (function*(): IterableIterator<ParamSpec> { - for (let x = 0; x < 3; ++x) { - for (let y = 0; y < 2; ++y) { - yield { x, y }; - } - } - })() - ); - - t0.expectCases(g, [ - { test: 'generator', params: { x: 0, y: 0 } }, - { test: 'generator', params: { x: 0, y: 1 } }, - { test: 'generator', params: { x: 1, y: 0 } }, - { test: 'generator', params: { x: 1, y: 1 } }, - { test: 'generator', params: { x: 2, y: 0 } }, - { test: 'generator', params: { x: 2, y: 1 } }, - ]); -}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/params_builder_and_utils.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/params_builder_and_utils.spec.ts new file mode 100644 index 00000000000..086162f1228 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/unittests/params_builder_and_utils.spec.ts @@ -0,0 +1,140 @@ +export const description = ` +Unit tests for parameterization helpers. +`; + +import { poptions, params } from '../common/framework/params_builder.js'; +import { + CaseParams, + CaseParamsIterable, + publicParamsEquals, +} from '../common/framework/params_utils.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; + +import { UnitTest } from './unit_test.js'; + +class ParamsTest extends UnitTest { + expectSpecEqual(act: CaseParamsIterable, exp: CaseParams[]): void { + const a = Array.from(act); + this.expect(a.length === exp.length && a.every((x, i) => publicParamsEquals(x, exp[i]))); + } +} + +export const g = makeTestGroup(ParamsTest); + +g.test('options').fn(t => { + t.expectSpecEqual(poptions('hello', [1, 2, 3]), [{ hello: 1 }, { hello: 2 }, { hello: 3 }]); +}); + +g.test('params').fn(t => { + t.expectSpecEqual(params(), [{}]); +}); + +g.test('combine,zeroes_and_ones').fn(t => { + t.expectSpecEqual(params().combine([]).combine([]), []); + t.expectSpecEqual(params().combine([]).combine([{}]), []); + t.expectSpecEqual(params().combine([{}]).combine([]), []); + t.expectSpecEqual(params().combine([{}]).combine([{}]), [{}]); +}); + +g.test('combine,mixed').fn(t => { + t.expectSpecEqual( + params() + .combine(poptions('x', [1, 2])) + .combine(poptions('y', ['a', 'b'])) + .combine([{ p: 4 }, { q: 5 }]) + .combine([{}]), + [ + { x: 1, y: 'a', p: 4 }, + { x: 1, y: 'a', q: 5 }, + { x: 1, y: 'b', p: 4 }, + { x: 1, y: 'b', q: 5 }, + { x: 2, y: 'a', p: 4 }, + { x: 2, y: 'a', q: 5 }, + { x: 2, y: 'b', p: 4 }, + { x: 2, y: 'b', q: 5 }, + ] + ); +}); + +g.test('filter').fn(t => { + t.expectSpecEqual( + params() + .combine([ + { a: true, x: 1 }, + { a: false, y: 2 }, + ]) + .filter(p => p.a), + [{ a: true, x: 1 }] + ); +}); + +g.test('unless').fn(t => { + t.expectSpecEqual( + params() + .combine([ + { a: true, x: 1 }, + { a: false, y: 2 }, + ]) + .unless(p => p.a), + [{ a: false, y: 2 }] + ); +}); + +g.test('exclude').fn(t => { + t.expectSpecEqual( + params() + .combine([ + { a: true, x: 1 }, + { a: false, y: 2 }, + ]) + .exclude([{ a: true }, { a: false, y: 2 }]), + [{ a: true, x: 1 }] + ); +}); + +g.test('expand').fn(t => { + t.expectSpecEqual( + params() + .combine([ + { a: true, x: 1 }, + { a: false, y: 2 }, + ]) + .expand(function* (p) { + if (p.a) { + yield* poptions('z', [3, 4]); + } else { + yield { w: 5 }; + } + }), + [ + { a: true, x: 1, z: 3 }, + { a: true, x: 1, z: 4 }, + { a: false, y: 2, w: 5 }, + ] + ); +}); + +g.test('expand,invalid').fn(t => { + const p = params() + .combine([{ x: 1 }]) + .expand(function* (p) { + yield p; // causes key 'x' to be duplicated + }); + t.shouldThrow('Error', () => { + Array.from(p); + }); +}); + +g.test('undefined').fn(t => { + t.expect(!publicParamsEquals({ a: undefined }, {})); + t.expect(!publicParamsEquals({}, { a: undefined })); +}); + +g.test('private').fn(t => { + t.expect(publicParamsEquals({ _a: 0 }, {})); + t.expect(publicParamsEquals({}, { _a: 0 })); +}); + +g.test('arrays').fn(t => { + t.expectSpecEqual([{ a: [1, 2] }], [{ a: [1, 2] }]); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/params_builder_toplevel.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/params_builder_toplevel.spec.ts new file mode 100644 index 00000000000..aebbfb673cf --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/unittests/params_builder_toplevel.spec.ts @@ -0,0 +1,95 @@ +export const description = ` +Unit tests for parameterization. +`; + +import { params } from '../common/framework/params_builder.js'; +import { CaseParams } from '../common/framework/params_utils.js'; +import { makeTestGroup, makeTestGroupForUnitTesting } from '../common/framework/test_group.js'; + +import { TestGroupTest } from './test_group_test.js'; +import { UnitTest } from './unit_test.js'; + +export const g = makeTestGroup(TestGroupTest); + +g.test('none') + .params([]) + .fn(t => { + t.fail("this test shouldn't run"); + }); + +g.test('combine_none') + .params(params().combine([])) + .fn(t => { + t.fail("this test shouldn't run"); + }); + +g.test('filter') + .params( + params() + .combine([ + { a: true, x: 1 }, // + { a: false, y: 2 }, + ]) + .filter(p => p.a) + ) + .fn(t => { + t.expect(t.params.a); + }); + +g.test('unless') + .params( + params() + .combine([ + { a: true, x: 1 }, // + { a: false, y: 2 }, + ]) + .unless(p => p.a) + ) + .fn(t => { + t.expect(!t.params.a); + }); + +g.test('exclude') + .params( + params() + .combine([ + { a: true, x: 1 }, + { a: false, y: 2 }, + ]) + .exclude([ + { a: true }, // + { a: false, y: 2 }, + ]) + ) + .fn(t => { + t.expect(t.params.a); + }); + +g.test('generator').fn(t0 => { + const g = makeTestGroupForUnitTesting(UnitTest); + + const ran: CaseParams[] = []; + + g.test('generator') + .params( + (function* (): IterableIterator<CaseParams> { + for (let x = 0; x < 3; ++x) { + for (let y = 0; y < 2; ++y) { + yield { x, y }; + } + } + })() + ) + .fn(t => { + ran.push(t.params); + }); + + t0.expectCases(g, [ + { test: ['generator'], params: { x: 0, y: 0 } }, + { test: ['generator'], params: { x: 0, y: 1 } }, + { test: ['generator'], params: { x: 1, y: 0 } }, + { test: ['generator'], params: { x: 1, y: 1 } }, + { test: ['generator'], params: { x: 2, y: 0 } }, + { test: ['generator'], params: { x: 2, y: 1 } }, + ]); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/query_compare.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/query_compare.spec.ts new file mode 100644 index 00000000000..f3e35753ea0 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/unittests/query_compare.spec.ts @@ -0,0 +1,133 @@ +export const description = ` +Tests for TestQuery comparison +`; + +import { compareQueries, Ordering } from '../common/framework/query/compare.js'; +import { + TestQuery, + TestQuerySingleCase, + TestQueryMultiFile, + TestQueryMultiTest, + TestQueryMultiCase, +} from '../common/framework/query/query.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; + +import { UnitTest } from './unit_test.js'; + +class F extends UnitTest { + expectQ(a: TestQuery, exp: '<' | '=' | '>' | '!', b: TestQuery) { + const [expOrdering, expInvOrdering] = + exp === '<' + ? [Ordering.StrictSubset, Ordering.StrictSuperset] + : exp === '=' + ? [Ordering.Equal, Ordering.Equal] + : exp === '>' + ? [Ordering.StrictSuperset, Ordering.StrictSubset] + : [Ordering.Unordered, Ordering.Unordered]; + { + const act = compareQueries(a, b); + this.expect(act === expOrdering, `${a} ${b} got ${act}, exp ${expOrdering}`); + } + { + const act = compareQueries(a, b); + this.expect(act === expOrdering, `${b} ${a} got ${act}, exp ${expInvOrdering}`); + } + } + + expectWellOrdered(...qs: TestQuery[]) { + for (let i = 0; i < qs.length; ++i) { + this.expectQ(qs[i], '=', qs[i]); + for (let j = i + 1; j < qs.length; ++j) { + this.expectQ(qs[i], '>', qs[j]); + } + } + } + + expectUnordered(...qs: TestQuery[]) { + for (let i = 0; i < qs.length; ++i) { + this.expectQ(qs[i], '=', qs[i]); + for (let j = i + 1; j < qs.length; ++j) { + this.expectQ(qs[i], '!', qs[j]); + } + } + } +} + +export const g = makeTestGroup(F); + +// suite:* > suite:a,* > suite:a,b,* > suite:a,b:* +// suite:a,b:* > suite:a,b:c,* > suite:a,b:c,d,* > suite:a,b:c,d:* +// suite:a,b:c,d:* > suite:a,b:c,d:x=1;* > suite:a,b:c,d:x=1;y=2;* > suite:a,b:c,d:x=1;y=2 +// suite:a;* (unordered) suite:b;* +g.test('well_ordered').fn(t => { + t.expectWellOrdered( + new TestQueryMultiFile('suite', []), + new TestQueryMultiFile('suite', ['a']), + new TestQueryMultiFile('suite', ['a', 'b']), + new TestQueryMultiTest('suite', ['a', 'b'], []), + new TestQueryMultiTest('suite', ['a', 'b'], ['c']), + new TestQueryMultiTest('suite', ['a', 'b'], ['c', 'd']), + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], {}), + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], { x: 1 }), + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], { x: 1, y: 2 }), + new TestQuerySingleCase('suite', ['a', 'b'], ['c', 'd'], { x: 1, y: 2 }) + ); + t.expectWellOrdered( + new TestQueryMultiFile('suite', []), + new TestQueryMultiFile('suite', ['a']), + new TestQueryMultiFile('suite', ['a', 'b']), + new TestQueryMultiTest('suite', ['a', 'b'], []), + new TestQueryMultiTest('suite', ['a', 'b'], ['c']), + new TestQueryMultiTest('suite', ['a', 'b'], ['c', 'd']), + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], {}), + new TestQuerySingleCase('suite', ['a', 'b'], ['c', 'd'], {}) + ); +}); + +g.test('unordered').fn(t => { + t.expectUnordered( + new TestQueryMultiFile('suite', ['a']), // + new TestQueryMultiFile('suite', ['x']) + ); + t.expectUnordered( + new TestQueryMultiFile('suite', ['a', 'b']), + new TestQueryMultiFile('suite', ['a', 'x']) + ); + t.expectUnordered( + new TestQueryMultiTest('suite', ['a', 'b'], ['c']), + new TestQueryMultiTest('suite', ['a', 'b'], ['x']), + new TestQueryMultiTest('suite', ['a'], []), + new TestQueryMultiTest('suite', ['a', 'x'], []) + ); + t.expectUnordered( + new TestQueryMultiTest('suite', ['a', 'b'], ['c', 'd']), + new TestQueryMultiTest('suite', ['a', 'b'], ['c', 'x']), + new TestQueryMultiTest('suite', ['a'], []), + new TestQueryMultiTest('suite', ['a', 'x'], []) + ); + t.expectUnordered( + new TestQueryMultiTest('suite', ['a', 'b'], ['c', 'd']), + new TestQueryMultiTest('suite', ['a', 'b'], ['c', 'x']), + new TestQueryMultiTest('suite', ['a'], []), + new TestQueryMultiTest('suite', ['a', 'x'], ['c']) + ); + t.expectUnordered( + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], { x: 1 }), + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], { x: 9 }), + new TestQueryMultiCase('suite', ['a', 'b'], ['c'], { x: 9 }) + ); + t.expectUnordered( + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], { x: 1, y: 2 }), + new TestQueryMultiCase('suite', ['a', 'b'], ['c', 'd'], { x: 1, y: 8 }), + new TestQueryMultiCase('suite', ['a', 'b'], ['c'], { x: 1, y: 8 }) + ); + t.expectUnordered( + new TestQuerySingleCase('suite', ['a', 'b'], ['c', 'd'], { x: 1, y: 2 }), + new TestQuerySingleCase('suite', ['a', 'b'], ['c', 'd'], { x: 1, y: 8 }), + new TestQuerySingleCase('suite', ['a', 'b'], ['c'], { x: 1, y: 8 }) + ); + t.expectUnordered( + new TestQuerySingleCase('suite1', ['bar', 'buzz', 'buzz'], ['zap'], {}), + new TestQueryMultiTest('suite1', ['bar'], []) + ); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/test_filter.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/test_filter.spec.ts deleted file mode 100644 index 4b752a66f82..00000000000 --- a/chromium/third_party/webgpu-cts/src/src/unittests/test_filter.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -export const description = ` -Unit tests for test_filter .matches() methods. -`; - -import { FilterByGroup } from '../common/framework/test_filter/filter_by_group.js'; -import { - FilterByParamsExact, - FilterByParamsMatch, - FilterByTestMatch, -} from '../common/framework/test_filter/filter_one_file.js'; -import { TestGroup } from '../common/framework/test_group.js'; - -import { UnitTest } from './unit_test.js'; - -export const g = new TestGroup(UnitTest); - -g.test('FilterByGroup/matches', t => { - { - const f = new FilterByGroup('ab', 'de/f'); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/fg' } })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'x' })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'x', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'x', params: {} })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/fg/' }, test: 'x', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f/g' }, test: 'x', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f/g/' }, test: 'x', params: null })); - } - { - const f = new FilterByGroup('ab', 'de/f/'); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/fg' } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'x' })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'x', params: null })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'x', params: {} })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/fg/' }, test: 'x', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f/g' }, test: 'x', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f/g/' }, test: 'x', params: null })); - } -}); - -g.test('FilterByTestMatch/matches', t => { - const f = new FilterByTestMatch({ suite: 'ab', path: 'de/f' }, 'xy'); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy' })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xyz', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xyz', params: {} })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xyz', params: { z: 1 } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f/' }, test: 'xyz', params: null })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/fg' }, test: 'xyz', params: null })); -}); - -g.test('FilterByParamsMatch/matches', t => { - { - const f = new FilterByParamsMatch({ suite: 'ab', path: 'de/f' }, 'xy', null); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: {} })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: { z: 1 } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy' })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: undefined })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xyz', params: {} })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f/' }, test: 'xy', params: {} })); - } - { - const f = new FilterByParamsMatch({ suite: 'ab', path: 'de/f' }, 'xy', {}); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: {} })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy' })); - } -}); - -g.test('FilterByParamsExact', t => { - const f = new FilterByParamsExact({ suite: 'ab', path: 'de/f' }, 'xy', {}); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: null })); - t.expect(f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: {} })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy', params: { z: 1 } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xyz', params: {} })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f/' }, test: 'xy', params: {} })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' } })); - t.expect(!f.matches({ spec: { suite: 'ab', path: 'de/f' }, test: 'xy' })); -}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/test_group.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/test_group.spec.ts index 018a90360ef..f9dbb549442 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/test_group.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/test_group.spec.ts @@ -3,31 +3,33 @@ Unit tests for TestGroup. `; import { Fixture } from '../common/framework/fixture.js'; -import { poptions } from '../common/framework/params.js'; -import { TestGroup } from '../common/framework/test_group.js'; +import { makeTestGroup, makeTestGroupForUnitTesting } from '../common/framework/test_group.js'; import { assert } from '../common/framework/util/util.js'; import { TestGroupTest } from './test_group_test.js'; import { UnitTest } from './unit_test.js'; -export const g = new TestGroup(TestGroupTest); +export const g = makeTestGroup(TestGroupTest); -g.test('UnitTest fixture', async t0 => { +g.test('UnitTest_fixture').fn(async t0 => { let seen = 0; + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function count(t: Fixture): void { seen++; } - const g = new TestGroup(UnitTest); + const g = makeTestGroupForUnitTesting(UnitTest); - g.test('test', count); - g.test('testp', count).params([{ a: 1 }]); + g.test('test').fn(count); + g.test('testp') + .params([{ a: 1 }]) + .fn(count); await t0.run(g); t0.expect(seen === 2); }); -g.test('custom fixture', async t0 => { +g.test('custom_fixture').fn(async t0 => { let seen = 0; class Counter extends UnitTest { count(): void { @@ -35,21 +37,23 @@ g.test('custom fixture', async t0 => { } } - const g = new TestGroup(Counter); + const g = makeTestGroupForUnitTesting(Counter); - g.test('test', t => { + g.test('test').fn(t => { t.count(); }); - g.test('testp', t => { - t.count(); - }).params([{ a: 1 }]); + g.test('testp') + .params([{ a: 1 }]) + .fn(t => { + t.count(); + }); await t0.run(g); t0.expect(seen === 2); }); -g.test('stack', async t0 => { - const g = new TestGroup(UnitTest); +g.test('stack').fn(async t0 => { + const g = makeTestGroupForUnitTesting(UnitTest); const doNestedThrow1 = () => { throw new Error('goodbye'); @@ -57,101 +61,169 @@ g.test('stack', async t0 => { const doNestedThrow2 = () => doNestedThrow1(); - g.test('fail', t => { + g.test('fail').fn(t => { t.fail(); }); - g.test('throw', t => { + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + g.test('throw').fn(t => { throw new Error('hello'); }); - g.test('throw nested', t => { + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + g.test('throw_nested').fn(t => { doNestedThrow2(); }); const res = await t0.run(g); - const search = /unittests[\/\\]test_group\.spec\.[tj]s|suites[\/\\]unittests[\/\\]unit_test\.[tj]s/; - for (const { logs } of res.cases) { + const search = /unittests[/\\]test_group\.spec\.[tj]s/; + t0.expect(res.size > 0); + for (const { logs } of res.values()) { assert(logs !== undefined, 'expected logs'); - const l = logs[0].toJSON(); - t0.expect(search.test(l)); - const st = l.split('\n'); - t0.expect(search.test(st[st.length - 1])); + t0.expect(logs.some(l => search.test(l.toJSON()))); + t0.expect(search.test(logs[logs.length - 1].toJSON())); } }); -g.test('duplicate test name', t => { - const g = new TestGroup(UnitTest); - g.test('abc', () => {}); +g.test('duplicate_test_name').fn(t => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc').fn(() => {}); t.shouldThrow('Error', () => { - g.test('abc', () => {}); + g.test('abc').fn(() => {}); }); }); -g.test('duplicate test params', t => { - const g = new TestGroup(UnitTest); +g.test('duplicate_test_params,none').fn(() => { + { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc') + .params([]) + .fn(() => {}); + g.checkCaseNamesAndDuplicates(); + } - t.shouldThrow('Error', () => { - g.test('abc', () => { - // - }).params([ - { a: 1 }, // - { a: 1 }, - ]); - }); + { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc').fn(() => {}); + g.checkCaseNamesAndDuplicates(); + } + + { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc') + .params([ + { a: 1 }, // + ]) + .fn(() => {}); + g.checkCaseNamesAndDuplicates(); + } }); -g.test('duplicate test params/with different private params', t => { - const g = new TestGroup(UnitTest); +g.test('duplicate_test_params,basic').fn(t => { + { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc') + .params([ + { a: 1 }, // + { a: 1 }, + ]) + .fn(() => {}); + t.shouldThrow('Error', () => { + g.checkCaseNamesAndDuplicates(); + }); + } + { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc') + .params([ + { a: 1, b: 3 }, // + { b: 3, a: 1 }, + ]) + .fn(() => {}); + t.shouldThrow('Error', () => { + g.checkCaseNamesAndDuplicates(); + }); + } +}); - t.shouldThrow('Error', () => { - g.test('abc', () => { - // - }).params([ +g.test('duplicate_test_params,with_different_private_params').fn(t => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('abc') + .params([ { a: 1, _b: 1 }, // { a: 1, _b: 2 }, - ]); + ]) + .fn(() => {}); + t.shouldThrow('Error', () => { + g.checkCaseNamesAndDuplicates(); }); }); -const badChars = Array.from('"`~@#$+=\\|!^&*[]<>{}-\'.,'); -g.test('invalid test name', t => { - const g = new TestGroup(UnitTest); +g.test('invalid_test_name').fn(t => { + const g = makeTestGroupForUnitTesting(UnitTest); - t.shouldThrow('Error', () => { - g.test('a' + t.params.char + 'b', () => {}); - }); -}).params(poptions('char', badChars)); + const badChars = Array.from('"`~@#$+=\\|!^&*[]<>{}-\'. '); + for (const char of badChars) { + const name = 'a' + char + 'b'; + t.shouldThrow( + 'Error', + () => { + g.test(name).fn(() => {}); + }, + name + ); + } +}); + +g.test('param_value,valid').fn(() => { + const g = makeTestGroup(UnitTest); + g.test('a').params([{ x: JSON.stringify({ a: 1, b: 2 }) }]); +}); + +g.test('param_value,invalid').fn(t => { + for (const badChar of ';=*') { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('a').params([{ badChar }]); + t.shouldThrow('Error', () => { + g.checkCaseNamesAndDuplicates(); + }); + } +}); -g.test('throws', async t0 => { - const g = new TestGroup(UnitTest); +g.test('throws').fn(async t0 => { + const g = makeTestGroupForUnitTesting(UnitTest); - g.test('a', t => { + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + g.test('a').fn(t => { throw new Error(); }); const result = await t0.run(g); - t0.expect(result.cases[0].status === 'fail'); + const values = Array.from(result.values()); + t0.expect(values.length === 1); + t0.expect(values[0].status === 'fail'); }); -g.test('shouldThrow', async t0 => { +g.test('shouldThrow').fn(async t0 => { t0.shouldThrow('TypeError', () => { throw new TypeError(); }); - const g = new TestGroup(UnitTest); + const g = makeTestGroupForUnitTesting(UnitTest); - g.test('a', t => { + g.test('a').fn(t => { t.shouldThrow('Error', () => { throw new TypeError(); }); }); const result = await t0.run(g); - t0.expect(result.cases[0].status === 'fail'); + const values = Array.from(result.values()); + t0.expect(values.length === 1); + t0.expect(values[0].status === 'fail'); }); -g.test('shouldReject', async t0 => { +g.test('shouldReject').fn(async t0 => { t0.shouldReject( 'TypeError', (async () => { @@ -159,9 +231,9 @@ g.test('shouldReject', async t0 => { })() ); - const g = new TestGroup(UnitTest); + const g = makeTestGroupForUnitTesting(UnitTest); - g.test('a', async t => { + g.test('a').fn(async t => { t.shouldReject( 'Error', (async () => { @@ -172,5 +244,7 @@ g.test('shouldReject', async t0 => { const result = await t0.run(g); // Fails even though shouldReject doesn't fail until after the test function ends - t0.expect(result.cases[0].status === 'fail'); + const values = Array.from(result.values()); + t0.expect(values.length === 1); + t0.expect(values[0].status === 'fail'); }); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/test_group_test.ts b/chromium/third_party/webgpu-cts/src/src/unittests/test_group_test.ts index 0572740e434..b4129583e12 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/test_group_test.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/test_group_test.ts @@ -1,35 +1,23 @@ -import { Fixture } from '../common/framework/fixture.js'; -import { TestCaseID } from '../common/framework/id.js'; -import { LiveTestSpecResult, Logger } from '../common/framework/logger.js'; -import { paramsEquals } from '../common/framework/params_utils.js'; -import { TestGroup } from '../common/framework/test_group.js'; +import { Logger, LogResults } from '../common/framework/logging/logger.js'; +import { TestQuerySingleCase } from '../common/framework/query/query.js'; +import { RunCaseIterable, TestCaseID } from '../common/framework/test_group.js'; +import { objectEquals } from '../common/framework/util/util.js'; import { UnitTest } from './unit_test.js'; export class TestGroupTest extends UnitTest { - async run<F extends Fixture>(g: TestGroup<F>): Promise<LiveTestSpecResult> { - const [rec, res] = new Logger().record({ suite: '', path: '' }); - await Promise.all(Array.from(g.iterate(rec)).map(test => test.run())); - return res; - } - - enumerate<F extends Fixture>(g: TestGroup<F>): TestCaseID[] { - const cases = []; - const [rec] = new Logger().record({ suite: '', path: '' }); - for (const test of g.iterate(rec)) { - cases.push(test.id); + async run(g: RunCaseIterable): Promise<LogResults> { + const logger = new Logger(true); + for (const rc of await Promise.all(g.iterate())) { + const query = new TestQuerySingleCase('xx', ['yy'], rc.id.test, rc.id.params); + const [rec] = logger.record(query.toString()); + await rc.run(rec); } - return cases; + return logger.results; } - expectCases<F extends Fixture>(g: TestGroup<F>, cases: TestCaseID[]): void { - const gcases = this.enumerate(g); - - if (this.expect(gcases.length === cases.length)) { - for (let i = 0; i < cases.length; ++i) { - this.expect(gcases[i].test === cases[i].test); - this.expect(paramsEquals(gcases[i].params, cases[i].params)); - } - } + expectCases(g: RunCaseIterable, cases: TestCaseID[]): void { + const gcases = Array.from(g.iterate()).map(rc => rc.id); + this.expect(objectEquals(gcases, cases)); } } diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/test_query.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/test_query.spec.ts new file mode 100644 index 00000000000..7f5e6d01801 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/unittests/test_query.spec.ts @@ -0,0 +1,56 @@ +export const description = ` +Tests for TestQuery +`; +import { + TestQueryMultiFile, + TestQueryMultiTest, + TestQueryMultiCase, + TestQuerySingleCase, + TestQuery, +} from '../common/framework/query/query.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; + +import { UnitTest } from './unit_test.js'; + +class F extends UnitTest { + expectToString(q: TestQuery, exp: string) { + this.expect(q.toString() === exp); + } +} + +export const g = makeTestGroup(F); + +g.test('constructor').fn(t => { + t.shouldThrow('Error', () => new TestQueryMultiTest('suite', [], [])); + + t.shouldThrow('Error', () => new TestQueryMultiCase('suite', ['a'], [], {})); + t.shouldThrow('Error', () => new TestQueryMultiCase('suite', [], ['c'], {})); + t.shouldThrow('Error', () => new TestQueryMultiCase('suite', [], [], {})); + + t.shouldThrow('Error', () => new TestQuerySingleCase('suite', ['a'], [], {})); + t.shouldThrow('Error', () => new TestQuerySingleCase('suite', [], ['c'], {})); + t.shouldThrow('Error', () => new TestQuerySingleCase('suite', [], [], {})); +}); + +g.test('toString').fn(t => { + t.expectToString(new TestQueryMultiFile('s', []), 's:*'); + t.expectToString(new TestQueryMultiFile('s', ['a']), 's:a,*'); + t.expectToString(new TestQueryMultiFile('s', ['a', 'b']), 's:a,b,*'); + t.expectToString(new TestQueryMultiTest('s', ['a', 'b'], []), 's:a,b:*'); + t.expectToString(new TestQueryMultiTest('s', ['a', 'b'], ['c']), 's:a,b:c,*'); + t.expectToString(new TestQueryMultiTest('s', ['a', 'b'], ['c', 'd']), 's:a,b:c,d,*'); + t.expectToString(new TestQueryMultiCase('s', ['a', 'b'], ['c', 'd'], {}), 's:a,b:c,d:*'); + t.expectToString( + new TestQueryMultiCase('s', ['a', 'b'], ['c', 'd'], { x: 1 }), + 's:a,b:c,d:x=1;*' + ); + t.expectToString( + new TestQueryMultiCase('s', ['a', 'b'], ['c', 'd'], { x: 1, y: 2 }), + 's:a,b:c,d:x=1;y=2;*' + ); + t.expectToString( + new TestQuerySingleCase('s', ['a', 'b'], ['c', 'd'], { x: 1, y: 2 }), + 's:a,b:c,d:x=1;y=2' + ); + t.expectToString(new TestQuerySingleCase('s', ['a', 'b'], ['c', 'd'], {}), 's:a,b:c,d:'); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/unittests/url_query.spec.ts b/chromium/third_party/webgpu-cts/src/src/unittests/url_query.spec.ts index 9d47cf8d2f6..1a9e8fc3aaf 100644 --- a/chromium/third_party/webgpu-cts/src/src/unittests/url_query.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/unittests/url_query.spec.ts @@ -2,27 +2,75 @@ export const description = ` Unit tests for URL queries. `; -import { TestGroup } from '../common/framework/test_group.js'; -import { makeQueryString } from '../common/framework/url_query.js'; +import { + TestQuery, + TestQuerySingleCase, + TestQueryMultiCase, + TestQueryMultiTest, + TestQueryMultiFile, +} from '../common/framework/query/query.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; import { UnitTest } from './unit_test.js'; -export const g = new TestGroup(UnitTest); +class T extends UnitTest { + expectQueryString(q: TestQuery, exp: string): void { + const s = q.toString(); + this.expect(s === exp, `got ${s} expected ${exp}`); + } +} -g.test('makeQueryString', t => { - const s = makeQueryString({ suite: 'a', path: 'b/c' }, { test: 'd/e', params: { f: 'g', h: 3 } }); - t.expect(s === 'a:b/c:d/e={"f":"g","h":3}'); +export const g = makeTestGroup(T); + +g.test('stringifyQuery,single_case').fn(t => { + t.expectQueryString( + new TestQuerySingleCase('a', ['b_1', '2_c'], ['d_3', '4_e'], { + f: 'g', + _pri1: 0, + a: 3, + _pri2: 1, + }), + 'a:b_1,2_c:d_3,4_e:f="g";a=3' + ); +}); + +g.test('stringifyQuery,multi_case').fn(t => { + t.expectQueryString( + new TestQueryMultiCase('a', ['b_1', '2_c'], ['d_3', '4_e'], { + f: 'g', + _pri1: 0, + a: 3, + _pri2: 1, + }), + 'a:b_1,2_c:d_3,4_e:f="g";a=3;*' + ); + + t.expectQueryString( + new TestQueryMultiCase('a', ['b_1', '2_c'], ['d_3', '4_e'], {}), + 'a:b_1,2_c:d_3,4_e:*' + ); }); -g.test('makeQueryString/private', t => { - const s = makeQueryString({ suite: 'a', path: 'b' }, { test: 'c', params: { pub: 2, _pri: 3 } }); - t.expect(s === 'a:b:c={"pub":2}'); +g.test('stringifyQuery,multi_test').fn(t => { + t.expectQueryString( + new TestQueryMultiTest('a', ['b_1', '2_c'], ['d_3', '4_e']), + 'a:b_1,2_c:d_3,4_e,*' + ); + + t.expectQueryString( + new TestQueryMultiTest('a', ['b_1', '2_c'], []), // + 'a:b_1,2_c:*' + ); }); -g.test('makeQueryString/undefined', t => { - const s = makeQueryString( - { suite: 'a', path: 'b' }, - { test: 'c', params: { f: undefined, h: 3 } } +g.test('stringifyQuery,multi_file').fn(t => { + t.expectQueryString( + new TestQueryMultiFile('a', ['b_1', '2_c']), // + 'a:b_1,2_c,*' + ); + + t.expectQueryString( + new TestQueryMultiFile('a', []), // + 'a:*' ); - t.expect(s === 'a:b:c={"h":3}'); }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/create_mapped.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/create_mapped.spec.ts index 546abfff508..d99b7f50ae6 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/create_mapped.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/create_mapped.spec.ts @@ -1,22 +1,23 @@ -export const description = ``; +export const description = ''; -import { pbool, pcombine, poptions } from '../../../../common/framework/params.js'; -import { TestGroup } from '../../../../common/framework/test_group.js'; +import { params, pbool, poptions } from '../../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { MappingTest } from './mapping_test.js'; -export const g = new TestGroup(MappingTest); +export const g = makeTestGroup(MappingTest); -g.test('createBufferMapped', async t => { - const size = t.params.size; - const [buffer, arrayBuffer] = t.device.createBufferMapped({ - size, - usage: GPUBufferUsage.COPY_SRC | (t.params.mappable ? GPUBufferUsage.MAP_WRITE : 0), - }); - t.checkMapWrite(buffer, arrayBuffer, size); -}).params( - pcombine( - poptions('size', [12, 512 * 1024]), // - pbool('mappable') +g.test('createBufferMapped') + .params( + params() + .combine(poptions('size', [12, 512 * 1024])) + .combine(pbool('mappable')) ) -); + .fn(t => { + const { size, mappable } = t.params; + const [buffer, arrayBuffer] = t.device.createBufferMapped({ + size, + usage: GPUBufferUsage.COPY_SRC | (mappable ? GPUBufferUsage.MAP_WRITE : 0), + }); + t.checkMapWrite(buffer, arrayBuffer, size); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map.spec.ts index 34817452240..562de03d741 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map.spec.ts @@ -1,52 +1,57 @@ -export const description = ``; +export const description = ''; -import { pbool, pcombine, poptions } from '../../../../common/framework/params.js'; -import { TestGroup } from '../../../../common/framework/test_group.js'; +import { pbool, poptions, params } from '../../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { MappingTest } from './mapping_test.js'; -export const g = new TestGroup(MappingTest); +export const g = makeTestGroup(MappingTest); -g.test('mapWriteAsync', async t => { - const size = t.params.size; - const buffer = t.device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.MAP_WRITE, - }); - - const arrayBuffer = await buffer.mapWriteAsync(); - t.checkMapWrite(buffer, arrayBuffer, size); -}).params(poptions('size', [12, 512 * 1024])); - -g.test('mapReadAsync', async t => { - const size = t.params.size; +g.test('mapWriteAsync') + .params(poptions('size', [12, 512 * 1024])) + .fn(async t => { + const { size } = t.params; + const buffer = t.device.createBuffer({ + size, + usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.MAP_WRITE, + }); - const [buffer, init] = t.device.createBufferMapped({ - size, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, + const arrayBuffer = await buffer.mapWriteAsync(); + t.checkMapWrite(buffer, arrayBuffer, size); }); - const expected = new Uint32Array(new ArrayBuffer(size)); - const data = new Uint32Array(init); - for (let i = 0; i < data.length; ++i) { - data[i] = expected[i] = i + 1; - } - buffer.unmap(); - - const actual = new Uint8Array(await buffer.mapReadAsync()); - t.expectBuffer(actual, new Uint8Array(expected.buffer)); -}).params(poptions('size', [12, 512 * 1024])); - -g.test('createBufferMapped', async t => { - const size = t.params.size; - const [buffer, arrayBuffer] = t.device.createBufferMapped({ - size, - usage: GPUBufferUsage.COPY_SRC | (t.params.mappable ? GPUBufferUsage.MAP_WRITE : 0), +g.test('mapReadAsync') + .params(poptions('size', [12, 512 * 1024])) + .fn(async t => { + const { size } = t.params; + + const [buffer, init] = t.device.createBufferMapped({ + size, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, + }); + + const expected = new Uint32Array(new ArrayBuffer(size)); + const data = new Uint32Array(init); + for (let i = 0; i < data.length; ++i) { + data[i] = expected[i] = i + 1; + } + buffer.unmap(); + + const actual = new Uint8Array(await buffer.mapReadAsync()); + t.expectBuffer(actual, new Uint8Array(expected.buffer)); }); - t.checkMapWrite(buffer, arrayBuffer, size); -}).params( - pcombine( - poptions('size', [12, 512 * 1024]), // - pbool('mappable') + +g.test('createBufferMapped') + .params( + params() + .combine(poptions('size', [12, 512 * 1024])) + .combine(pbool('mappable')) ) -); + .fn(async t => { + const { size, mappable } = t.params; + const [buffer, arrayBuffer] = t.device.createBufferMapped({ + size, + usage: GPUBufferUsage.COPY_SRC | (mappable ? GPUBufferUsage.MAP_WRITE : 0), + }); + t.checkMapWrite(buffer, arrayBuffer, size); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_detach.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_detach.spec.ts index 8835a379e19..5cad48e7303 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_detach.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_detach.spec.ts @@ -1,6 +1,6 @@ -export const description = ``; +export const description = ''; -import { TestGroup } from '../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { GPUTest } from '../../../gpu_test.js'; class F extends GPUTest { @@ -17,45 +17,51 @@ class F extends GPUTest { } } -export const g = new TestGroup(F); - -g.test('mapWriteAsync', async t => { - const buffer = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.MAP_WRITE }); - const arrayBuffer = await buffer.mapWriteAsync(); - t.checkDetach(buffer, arrayBuffer, t.params.unmap, t.params.destroy); -}).params([ - { unmap: true, destroy: false }, // - { unmap: false, destroy: true }, - { unmap: true, destroy: true }, -]); - -g.test('mapReadAsync', async t => { - const buffer = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.MAP_READ }); - const arrayBuffer = await buffer.mapReadAsync(); - t.checkDetach(buffer, arrayBuffer, t.params.unmap, t.params.destroy); -}).params([ - { unmap: true, destroy: false }, // - { unmap: false, destroy: true }, - { unmap: true, destroy: true }, -]); - -g.test('create mapped', async t => { - const desc = { - size: 4, - usage: GPUBufferUsage.MAP_WRITE, - }; - const [buffer, arrayBuffer] = t.device.createBufferMapped(desc); - - const view = new Uint8Array(arrayBuffer); - t.expect(arrayBuffer.byteLength === 4); - t.expect(view.length === 4); - - if (t.params.unmap) buffer.unmap(); - if (t.params.destroy) buffer.destroy(); - t.expect(arrayBuffer.byteLength === 0, 'ArrayBuffer should be detached'); - t.expect(view.byteLength === 0, 'ArrayBufferView should be detached'); -}).params([ - { unmap: true, destroy: false }, - { unmap: false, destroy: true }, - { unmap: true, destroy: true }, -]); +export const g = makeTestGroup(F); + +g.test('mapWriteAsync') + .params([ + { unmap: true, destroy: false }, // + { unmap: false, destroy: true }, + { unmap: true, destroy: true }, + ]) + .fn(async t => { + const buffer = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.MAP_WRITE }); + const arrayBuffer = await buffer.mapWriteAsync(); + t.checkDetach(buffer, arrayBuffer, t.params.unmap, t.params.destroy); + }); + +g.test('mapReadAsync') + .params([ + { unmap: true, destroy: false }, // + { unmap: false, destroy: true }, + { unmap: true, destroy: true }, + ]) + .fn(async t => { + const buffer = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.MAP_READ }); + const arrayBuffer = await buffer.mapReadAsync(); + t.checkDetach(buffer, arrayBuffer, t.params.unmap, t.params.destroy); + }); + +g.test('create_mapped') + .params([ + { unmap: true, destroy: false }, + { unmap: false, destroy: true }, + { unmap: true, destroy: true }, + ]) + .fn(async t => { + const desc = { + size: 4, + usage: GPUBufferUsage.MAP_WRITE, + }; + const [buffer, arrayBuffer] = t.device.createBufferMapped(desc); + + const view = new Uint8Array(arrayBuffer); + t.expect(arrayBuffer.byteLength === 4); + t.expect(view.length === 4); + + if (t.params.unmap) buffer.unmap(); + if (t.params.destroy) buffer.destroy(); + t.expect(arrayBuffer.byteLength === 0, 'ArrayBuffer should be detached'); + t.expect(view.byteLength === 0, 'ArrayBufferView should be detached'); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_oom.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_oom.spec.ts index 3ea113677b4..cbc19d10090 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_oom.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/buffers/map_oom.spec.ts @@ -1,29 +1,33 @@ -export const description = ``; +export const description = ''; -import { TestGroup } from '../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { GPUTest } from '../../../gpu_test.js'; -function getBufferDesc(): GPUBufferDescriptor { +function getBufferDesc(usage: GPUBufferUsageFlags): GPUBufferDescriptor { return { size: Number.MAX_SAFE_INTEGER, - usage: GPUBufferUsage.MAP_WRITE, + usage, }; } -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('mapWriteAsync', async t => { - const buffer = t.device.createBuffer(getBufferDesc()); - t.shouldReject('RangeError', buffer.mapWriteAsync()); +g.test('mapWriteAsync').fn(async t => { + const buffer = t.expectGPUError('out-of-memory', () => { + return t.device.createBuffer(getBufferDesc(GPUBufferUsage.MAP_WRITE)); + }); + t.shouldReject('OperationError', buffer.mapWriteAsync()); }); -g.test('mapReadAsync', async t => { - const buffer = t.device.createBuffer(getBufferDesc()); - t.shouldReject('RangeError', buffer.mapReadAsync()); +g.test('mapReadAsync').fn(async t => { + const buffer = t.expectGPUError('out-of-memory', () => { + return t.device.createBuffer(getBufferDesc(GPUBufferUsage.MAP_READ)); + }); + t.shouldReject('OperationError', buffer.mapReadAsync()); }); -g.test('createBufferMapped', async t => { +g.test('createBufferMapped').fn(async t => { t.shouldThrow('RangeError', () => { - t.device.createBufferMapped(getBufferDesc()); + t.device.createBufferMapped(getBufferDesc(GPUBufferUsage.COPY_SRC)); }); }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/basic.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/basic.spec.ts index 1a9eec72703..54927a5e6ee 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/basic.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/basic.spec.ts @@ -2,12 +2,12 @@ export const description = ` Basic tests. `; -import { TestGroup } from '../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { GPUTest } from '../../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('empty', async t => { +g.test('empty').fn(async t => { const encoder = t.device.createCommandEncoder(); const cmd = encoder.finish(); t.device.defaultQueue.submit([cmd]); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/compute/basic.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/compute/basic.spec.ts index 00357959d33..856794f7fb6 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/compute/basic.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/compute/basic.spec.ts @@ -2,12 +2,12 @@ export const description = ` Basic command buffer compute tests. `; -import { TestGroup } from '../../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('memcpy', async t => { +g.test('memcpy').fn(async t => { const data = new Uint32Array([0x01020304]); const [src, srcData] = t.device.createBufferMapped({ diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/copies.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/copies.spec.ts index 3b11273ccc1..d794dfc60c8 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/copies.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/copies.spec.ts @@ -2,12 +2,12 @@ export const description = ` copy{Buffer,Texture}To{Buffer,Texture} tests. `; -import { TestGroup } from '../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { GPUTest } from '../../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('b2b', async t => { +g.test('b2b').fn(async t => { const data = new Uint32Array([0x01020304]); const [src, map] = t.device.createBufferMapped({ @@ -29,7 +29,7 @@ g.test('b2b', async t => { t.expectContents(dst, data); }); -g.test('b2t2b', async t => { +g.test('b2t2b').fn(async t => { const data = new Uint32Array([0x01020304]); const [src, map] = t.device.createBufferMapped({ @@ -66,7 +66,7 @@ g.test('b2t2b', async t => { t.expectContents(dst, data); }); -g.test('b2t2t2b', async t => { +g.test('b2t2t2b').fn(async t => { const data = new Uint32Array([0x01020304]); const [src, map] = t.device.createBufferMapped({ diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/basic.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/basic.spec.ts index ca837240e10..eb86f02188c 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/basic.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/basic.spec.ts @@ -2,12 +2,12 @@ export const description = ` Basic command buffer rendering tests. `; -import { TestGroup } from '../../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('clear', async t => { +g.test('clear').fn(async t => { const dst = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/rendering.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/rendering.spec.ts index 76d71cbdc45..8952dcdf4a8 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/rendering.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/rendering.spec.ts @@ -1,11 +1,11 @@ -export const description = ``; +export const description = ''; -import { TestGroup } from '../../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('fullscreen quad', async t => { +g.test('fullscreen_quad').fn(async t => { const dst = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/storeop.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/storeop.spec.ts index 704054b2ca5..6418f6cd88c 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/storeop.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/command_buffer/render/storeop.spec.ts @@ -1,79 +1,74 @@ export const description = ` renderPass store op test that drawn quad is either stored or cleared based on storeop`; -import { TestGroup } from '../../../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('storeOp controls whether 1x1 drawn quad is stored', async t => { - const renderTexture = t.device.createTexture({ - size: { width: 1, height: 1, depth: 1 }, - format: 'r8unorm', - usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT, - }); +g.test('storeOp_controls_whether_1x1_drawn_quad_is_stored') + .params([ + { storeOp: 'store', _expected: 1 }, // + { storeOp: 'clear', _expected: 0 }, + ] as const) + .fn(async t => { + const renderTexture = t.device.createTexture({ + size: { width: 1, height: 1, depth: 1 }, + format: 'r8unorm', + usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT, + }); - // create render pipeline - const vertexModule = t.makeShaderModule('vertex', { - glsl: ` - #version 450 - const vec2 pos[3] = vec2[3]( - vec2( 1.0f, -1.0f), - vec2( 1.0f, 1.0f), - vec2(-1.0f, 1.0f) - ); + // create render pipeline + const vertexModule = t.makeShaderModule('vertex', { + glsl: ` + #version 450 + const vec2 pos[3] = vec2[3]( + vec2( 1.0f, -1.0f), + vec2( 1.0f, 1.0f), + vec2(-1.0f, 1.0f) + ); - void main() { - gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0); - } - `, - }); - const fragmentModule = t.makeShaderModule('fragment', { - glsl: ` + void main() { + gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0); + } + `, + }); + const fragmentModule = t.makeShaderModule('fragment', { + glsl: ` #version 450 layout(location = 0) out vec4 fragColor; void main() { fragColor = vec4(1.0, 0.0, 0.0, 1.0); } `, - }); - const renderPipeline = t.device.createRenderPipeline({ - vertexStage: { module: vertexModule, entryPoint: 'main' }, - fragmentStage: { module: fragmentModule, entryPoint: 'main' }, - layout: t.device.createPipelineLayout({ bindGroupLayouts: [] }), - primitiveTopology: 'triangle-list', - colorStates: [{ format: 'r8unorm' }], - }); + }); + const renderPipeline = t.device.createRenderPipeline({ + vertexStage: { module: vertexModule, entryPoint: 'main' }, + fragmentStage: { module: fragmentModule, entryPoint: 'main' }, + layout: t.device.createPipelineLayout({ bindGroupLayouts: [] }), + primitiveTopology: 'triangle-list', + colorStates: [{ format: 'r8unorm' }], + }); - // encode pass and submit - const encoder = t.device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [ - { - attachment: renderTexture.createView(), - storeOp: t.params.storeOp, - loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }, - }, - ], - }); - pass.setPipeline(renderPipeline); - pass.draw(3, 1, 0, 0); - pass.endPass(); - const dstBuffer = t.device.createBuffer({ - size: 4, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, - }); - encoder.copyTextureToBuffer( - { texture: renderTexture }, - { buffer: dstBuffer, bytesPerRow: 256 }, - { width: 1, height: 1, depth: 1 } - ); - t.device.defaultQueue.submit([encoder.finish()]); + // encode pass and submit + const encoder = t.device.createCommandEncoder(); + const pass = encoder.beginRenderPass({ + colorAttachments: [ + { + attachment: renderTexture.createView(), + storeOp: t.params.storeOp, + loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }, + }, + ], + }); + pass.setPipeline(renderPipeline); + pass.draw(3, 1, 0, 0); + pass.endPass(); + t.device.defaultQueue.submit([encoder.finish()]); - // expect the buffer to be clear - const expectedContent = new Uint32Array([t.params._expected]); - t.expectContents(dstBuffer, expectedContent); -}).params([ - { storeOp: 'store', _expected: 255 }, // - { storeOp: 'clear', _expected: 0 }, -]); + // expect the buffer to be clear + t.expectSingleColor(renderTexture, 'r8unorm', { + size: [1, 1, 1], + exp: { R: t.params._expected }, + }); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/fences.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/fences.spec.ts index 698cbce33cb..7b9dbf9d05d 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/fences.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/fences.spec.ts @@ -1,29 +1,29 @@ -export const description = ``; +export const description = ''; -import { attemptGarbageCollection } from '../../../common/framework/collect_garbage.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; +import { attemptGarbageCollection } from '../../../common/framework/util/collect_garbage.js'; import { raceWithRejectOnTimeout } from '../../../common/framework/util/util.js'; import { GPUTest } from '../../gpu_test.js'; -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); -g.test('initial/no descriptor', t => { +g.test('initial,no_descriptor').fn(t => { const fence = t.queue.createFence(); t.expect(fence.getCompletedValue() === 0); }); -g.test('initial/empty descriptor', t => { +g.test('initial,empty_descriptor').fn(t => { const fence = t.queue.createFence({}); t.expect(fence.getCompletedValue() === 0); }); -g.test('initial/descriptor with initialValue', t => { +g.test('initial,descriptor_with_initialValue').fn(t => { const fence = t.queue.createFence({ initialValue: 2 }); t.expect(fence.getCompletedValue() === 2); }); // Promise resolves when onCompletion value is less than signal value. -g.test('wait/less than signaled', async t => { +g.test('wait,less_than_signaled').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); await fence.onCompletion(1); @@ -31,7 +31,7 @@ g.test('wait/less than signaled', async t => { }); // Promise resolves when onCompletion value is equal to signal value. -g.test('wait/equal to signaled', async t => { +g.test('wait,equal_to_signaled').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); await fence.onCompletion(2); @@ -39,7 +39,7 @@ g.test('wait/equal to signaled', async t => { }); // All promises resolve when signal is called once. -g.test('wait/signaled once', async t => { +g.test('wait,signaled_once').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 20); const promises = []; @@ -54,7 +54,7 @@ g.test('wait/signaled once', async t => { }); // Promise resolves when signal is called multiple times. -g.test('wait/signaled multiple times', async t => { +g.test('wait,signaled_multiple_times').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 1); t.queue.signal(fence, 2); @@ -63,7 +63,7 @@ g.test('wait/signaled multiple times', async t => { }); // Promise resolves if fence has already completed. -g.test('wait/already completed', async t => { +g.test('wait,already_completed').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); @@ -81,7 +81,7 @@ g.test('wait/already completed', async t => { }); // Test many calls to signal and wait on fence values one at a time. -g.test('wait/many/serially', async t => { +g.test('wait,many,serially').fn(async t => { const fence = t.queue.createFence(); for (let i = 1; i <= 20; ++i) { t.queue.signal(fence, i); @@ -91,7 +91,7 @@ g.test('wait/many/serially', async t => { }); // Test many calls to signal and wait on all fence values. -g.test('wait/many/parallel', async t => { +g.test('wait,many,parallel').fn(async t => { const fence = t.queue.createFence(); const promises = []; for (let i = 1; i <= 20; ++i) { @@ -107,7 +107,7 @@ g.test('wait/many/parallel', async t => { }); // Test onCompletion promise resolves within a time limit. -g.test('wait/resolves within timeout', t => { +g.test('wait,resolves_within_timeout').fn(t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); @@ -122,23 +122,23 @@ g.test('wait/resolves within timeout', t => { }); // Test dropping references to the fence and onCompletion promise does not crash. -g.test('drop/fence and promise', t => { +g.test('drop,fence_and_promise').fn(async t => { { const fence = t.queue.createFence(); t.queue.signal(fence, 2); fence.onCompletion(2); } - attemptGarbageCollection(); + await attemptGarbageCollection(); }); // Test dropping references to the fence and holding the promise does not crash. -g.test('drop/promise', async t => { +g.test('drop,promise').fn(async t => { let promise; { const fence = t.queue.createFence(); t.queue.signal(fence, 2); promise = fence.onCompletion(2); } - attemptGarbageCollection(); + await attemptGarbageCollection(); await promise; }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/copied_texture_clear.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/copied_texture_clear.spec.ts new file mode 100644 index 00000000000..5e81506d710 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/copied_texture_clear.spec.ts @@ -0,0 +1,86 @@ +export const description = 'Test uninitialized textures are initialized to zero when copied.'; + +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { assert, unreachable } from '../../../../common/framework/util/util.js'; +import { SubresourceRange } from '../../../util/texture/subresource.js'; + +import { InitializedState, ReadMethod, TextureZeroInitTest } from './texture_zero_init_test.js'; + +class CopiedTextureClearTest extends TextureZeroInitTest { + private checkContentsByBufferCopy( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + for (const { level: mipLevel, slice } of subresourceRange.each()) { + assert(this.params.dimension === '2d'); + + this.expectSingleColor(texture, this.params.format, { + size: [this.textureWidth, this.textureHeight, 1], + dimension: this.params.dimension, + slice, + layout: { mipLevel }, + exp: this.stateToTexelComponents[state], + }); + } + } + + private checkContentsByTextureCopy( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + for (const { level, slice } of subresourceRange.each()) { + assert(this.params.dimension === '2d'); + + const width = this.textureWidth >> level; + const height = this.textureHeight >> level; + + const dst = this.device.createTexture({ + size: [width, height, 1], + format: this.params.format, + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, + }); + + const commandEncoder = this.device.createCommandEncoder(); + commandEncoder.copyTextureToTexture( + { texture, mipLevel: level, arrayLayer: slice }, + { texture: dst, mipLevel: 0, arrayLayer: 0 }, + { width, height, depth: 1 } + ); + this.queue.submit([commandEncoder.finish()]); + + this.expectSingleColor(dst, this.params.format, { + size: [width, height, 1], + exp: this.stateToTexelComponents[state], + }); + } + } + + checkContents( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + switch (this.params.readMethod) { + case ReadMethod.CopyToBuffer: + this.checkContentsByBufferCopy(texture, state, subresourceRange); + break; + + case ReadMethod.CopyToTexture: + this.checkContentsByTextureCopy(texture, state, subresourceRange); + break; + + default: + unreachable(); + } + } +} + +export const g = makeTestGroup(CopiedTextureClearTest); + +g.test('uninitialized_texture_is_zero') + .params(TextureZeroInitTest.generateParams([ReadMethod.CopyToBuffer, ReadMethod.CopyToTexture])) + .fn(t => { + t.run(); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/depth_stencil_attachment_clear.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/depth_stencil_attachment_clear.spec.ts new file mode 100644 index 00000000000..ef316a9119e --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/depth_stencil_attachment_clear.spec.ts @@ -0,0 +1,211 @@ +export const description = + 'Test uninitialized textures are initialized to zero when used as a depth/stencil attachment.'; + +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { unreachable } from '../../../../common/framework/util/util.js'; +import { SubresourceRange } from '../../../util/texture/subresource.js'; + +import { + InitializedState, + ReadMethod, + TextureZeroInitTest, + initializedStateAsDepth, + initializedStateAsStencil, +} from './texture_zero_init_test.js'; + +class DepthStencilAttachmentClearTest extends TextureZeroInitTest { + // Construct a pipeline which will render a single triangle with depth + // equal to |initializeStateAsDepth(state)|. The depth compare function + // is set to "equal" so the fragment shader will only write 1.0 to the + // R8Unorm output if the depth buffer contains exactly the expected value. + private getDepthTestReadbackPipeline( + state: InitializedState, + format: GPUTextureFormat, + sampleCount: number + ): GPURenderPipeline { + return this.device.createRenderPipeline({ + vertexStage: { + entryPoint: 'main', + module: this.makeShaderModule('vertex', { + glsl: `#version 310 es + void main() { + const vec2 pos[3] = vec2[3]( + vec2(-1.f, -3.f), vec2(3.f, 1.f), vec2(-1.f, 1.f)); + gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f); + } + `, + }), + }, + fragmentStage: { + entryPoint: 'main', + module: this.makeShaderModule('fragment', { + glsl: `#version 310 es + precision highp float; + layout(location = 0) out float outSuccess; + + void main() { + gl_FragDepth = float(${initializedStateAsDepth(state)}); + outSuccess = 1.0; + } + `, + }), + }, + colorStates: [ + { + format: 'r8unorm', + }, + ], + depthStencilState: { + format, + depthCompare: 'equal', + }, + primitiveTopology: 'triangle-list', + sampleCount, + }); + } + + // Construct a pipeline which will render a single triangle. + // The stencil compare function is set to "equal" so the fragment shader + // will only write 1.0 to the R8Unorm output if the stencil buffer contains + // exactly the stencil reference value. + private getStencilTestReadbackPipeline( + format: GPUTextureFormat, + sampleCount: number + ): GPURenderPipeline { + return this.device.createRenderPipeline({ + vertexStage: { + entryPoint: 'main', + module: this.makeShaderModule('vertex', { + glsl: `#version 310 es + void main() { + const vec2 pos[3] = vec2[3]( + vec2(-1.f, -3.f), vec2(3.f, 1.f), vec2(-1.f, 1.f)); + gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f); + } + `, + }), + }, + fragmentStage: { + entryPoint: 'main', + module: this.makeShaderModule('fragment', { + glsl: `#version 310 es + precision highp float; + layout(location = 0) out float outSuccess; + + void main() { + outSuccess = 1.0; + } + `, + }), + }, + colorStates: [ + { + format: 'r8unorm', + }, + ], + depthStencilState: { + format, + stencilFront: { + compare: 'equal', + }, + stencilBack: { + compare: 'equal', + }, + }, + primitiveTopology: 'triangle-list', + sampleCount, + }); + } + + // Check the contents by running either a depth or stencil test. The test will + // render 1.0 to an R8Unorm texture if the depth/stencil buffer is equal to the expected + // value. This is done by using a depth compare function and explicitly setting the depth + // value with gl_FragDepth in the shader, or by using a stencil compare function and + // setting the stencil reference value in the render pass. + checkContents( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + for (const viewDescriptor of this.generateTextureViewDescriptorsForRendering( + this.params.aspect, + subresourceRange + )) { + const width = this.textureWidth >> viewDescriptor.baseMipLevel!; + const height = this.textureHeight >> viewDescriptor.baseMipLevel!; + + const renderTexture = this.device.createTexture({ + size: [width, height, 1], + format: 'r8unorm', + usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.COPY_SRC, + sampleCount: this.params.sampleCount, + }); + + let resolveTexture = undefined; + let resolveTarget = undefined; + if (this.params.sampleCount > 1) { + resolveTexture = this.device.createTexture({ + size: [width, height, 1], + format: 'r8unorm', + usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.COPY_SRC, + }); + resolveTarget = resolveTexture.createView(); + } + + const commandEncoder = this.device.createCommandEncoder(); + const pass = commandEncoder.beginRenderPass({ + colorAttachments: [ + { + attachment: renderTexture.createView(), + resolveTarget, + loadValue: [0, 0, 0, 0], + storeOp: 'store', + }, + ], + depthStencilAttachment: { + attachment: texture.createView(viewDescriptor), + depthStoreOp: 'store', + depthLoadValue: 'load', + stencilStoreOp: 'store', + stencilLoadValue: 'load', + }, + }); + + switch (this.params.readMethod) { + case ReadMethod.DepthTest: + pass.setPipeline( + this.getDepthTestReadbackPipeline(state, this.params.format, this.params.sampleCount) + ); + break; + + case ReadMethod.StencilTest: + pass.setPipeline( + this.getStencilTestReadbackPipeline(this.params.format, this.params.sampleCount) + ); + // Set the stencil reference. The rendering pipeline uses stencil compare function "equal" + // so this pass will write 1.0 to the output only if the stencil buffer is equal to this + // reference value. + pass.setStencilReference(initializedStateAsStencil(state)); + break; + + default: + unreachable(); + } + pass.draw(3, 1, 0, 0); + pass.endPass(); + + this.queue.submit([commandEncoder.finish()]); + + this.expectSingleColor(resolveTexture || renderTexture, 'r8unorm', { + size: [width, height, 1], + exp: { R: 1 }, + }); + } + } +} + +export const g = makeTestGroup(DepthStencilAttachmentClearTest); + +g.test('uninitialized_texture_is_zero') + .params(TextureZeroInitTest.generateParams([ReadMethod.DepthTest, ReadMethod.StencilTest])) + .fn(t => t.run()); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/sampled_texture_clear.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/sampled_texture_clear.spec.ts index ca889f023cd..3463222a90a 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/sampled_texture_clear.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/sampled_texture_clear.spec.ts @@ -1,73 +1,207 @@ -export const description = ` -computePass test that sampled texture is cleared`; - -import { TestGroup } from '../../../../common/framework/test_group.js'; -import { GPUTest } from '../../../gpu_test.js'; - -export const g = new TestGroup(GPUTest); - -g.test('compute pass test that sampled texture is cleared', async t => { - const texture = t.device.createTexture({ - size: { width: 256, height: 256, depth: 1 }, - format: 'r8unorm', - usage: GPUTextureUsage.SAMPLED, - }); - - const bufferTex = t.device.createBuffer({ - size: 4 * 256 * 256, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, - }); - - const sampler = t.device.createSampler(); - - const bindGroupLayout = t.device.createBindGroupLayout({ - entries: [ - { binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'sampled-texture' }, - { binding: 1, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }, - { binding: 2, visibility: GPUShaderStage.COMPUTE, type: 'sampler' }, - ], - }); - - // create compute pipeline - const computeModule = t.makeShaderModule('compute', { - glsl: ` - #version 450 - layout(binding = 0) uniform texture2D sampleTex; - layout(std430, binding = 1) buffer BufferTex { - vec4 result; - } bufferTex; - layout(binding = 2) uniform sampler sampler0; +export const description = 'Test uninitialized textures are initialized to zero when sampled.'; + +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { assert } from '../../../../common/framework/util/util.js'; +import { SubresourceRange } from '../../../util/texture/subresource.js'; +import { getTexelDataRepresentation } from '../../../util/texture/texelData.js'; + +import { + InitializedState, + ReadMethod, + TextureZeroInitTest, + initializedStateAsFloat, + initializedStateAsSint, + initializedStateAsUint, +} from './texture_zero_init_test.js'; + +class SampledTextureClearTest extends TextureZeroInitTest { + private getSamplingReadbackPipeline( + prefix: string, + sampleCount: number, + dimension: GPUTextureDimension + ): GPUComputePipeline { + const componentOrder = getTexelDataRepresentation(this.params.format).componentOrder; + const MS = sampleCount > 1 ? 'MS' : ''; + const XD = dimension.toUpperCase(); + const componentCount = componentOrder.length; + const indexExpression = + componentCount === 1 + ? componentOrder[0].toLowerCase() + : componentOrder.map(c => c.toLowerCase()).join('') + '[i]'; + + const glsl = `#version 310 es + precision highp float; + precision highp ${prefix}texture${XD}${MS}; + precision highp sampler; + + layout(set = 0, binding = 0, std140) uniform Constants { + int level; + }; + + layout(set = 0, binding = 1) uniform ${prefix}texture${XD}${MS} myTexture; + layout(set = 0, binding = 2) uniform sampler mySampler; + layout(set = 0, binding = 3, std430) writeonly buffer Result { + uint result[]; + }; + + void writeResult(uint flatIndex, uvec4 texel) { + for (uint i = flatIndex; i < flatIndex + ${componentCount}u; ++i) { + result[i] = texel.${indexExpression}; + } + } + + void writeResult(uint flatIndex, ivec4 texel) { + for (uint i = flatIndex; i < flatIndex + ${componentCount}u; ++i) { + result[i] = uint(texel.${indexExpression}); + } + } + + void writeResult(uint flatIndex, vec4 texel) { + for (uint i = flatIndex; i < flatIndex + ${componentCount}u; ++i) { + result[i] = floatBitsToUint(texel.${indexExpression}); + } + } + void main() { - bufferTex.result = - texelFetch(sampler2D(sampleTex, sampler0), ivec2(0,0), 0); + uint flatIndex = gl_NumWorkGroups.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x; + flatIndex = flatIndex * ${componentCount}u; + + writeResult(flatIndex, texelFetch( + ${prefix}sampler${XD}${MS}(myTexture, mySampler), + ivec2(gl_GlobalInvocationID.xy), level)); + } + `; + + return this.device.createComputePipeline({ + layout: undefined, + computeStage: { + entryPoint: 'main', + module: this.makeShaderModule('compute', { glsl }), + }, + }); + } + + checkContents( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + assert(this.params.dimension === '2d'); + + const sampler = this.device.createSampler(); + + for (const { level, slices } of subresourceRange.mipLevels()) { + const width = this.textureWidth >> level; + const height = this.textureHeight >> level; + + let readbackTypedArray: + | Float32ArrayConstructor + | Int32ArrayConstructor + | Uint32ArrayConstructor = Float32Array; + let prefix = ''; + let expectedShaderValue = initializedStateAsFloat(state); + if (this.params.format.indexOf('sint') !== -1) { + prefix = 'i'; + expectedShaderValue = initializedStateAsSint(state); + readbackTypedArray = Int32Array; + } else if (this.params.format.indexOf('uint') !== -1) { + prefix = 'u'; + expectedShaderValue = initializedStateAsUint(state); + readbackTypedArray = Uint32Array; + } + + const computePipeline = this.getSamplingReadbackPipeline( + prefix, + this.params.sampleCount, + this.params.dimension + ); + + for (const slice of slices) { + const [ubo, uboMapping] = this.device.createBufferMapped({ + size: 4, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + new Int32Array(uboMapping, 0, 1)[0] = level; + ubo.unmap(); + + const byteLength = + width * + height * + Uint32Array.BYTES_PER_ELEMENT * + getTexelDataRepresentation(this.params.format).componentOrder.length; + const resultBuffer = this.device.createBuffer({ + size: byteLength, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, + }); + + const bindGroup = this.device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: { buffer: ubo }, + }, + { + binding: 1, + resource: texture.createView({ + baseMipLevel: 0, + mipLevelCount: this.params.mipLevelCount, + baseArrayLayer: slice, + arrayLayerCount: 1, + }), + }, + { binding: 2, resource: sampler }, + { + binding: 3, + resource: { + buffer: resultBuffer, + }, + }, + ], + }); + + const commandEncoder = this.device.createCommandEncoder(); + const pass = commandEncoder.beginComputePass(); + pass.setPipeline(computePipeline); + pass.setBindGroup(0, bindGroup); + pass.dispatch(width, height); + pass.endPass(); + this.queue.submit([commandEncoder.finish()]); + ubo.destroy(); + + const mappedResultBuffer = this.createCopyForMapRead(resultBuffer, 0, byteLength); + resultBuffer.destroy(); + + this.eventualAsyncExpectation(async niceStack => { + const actual = await mappedResultBuffer.mapReadAsync(); + const expected = new readbackTypedArray(new ArrayBuffer(actual.byteLength)); + expected.fill(expectedShaderValue); + + // TODO: Have a better way to determine approximately equal, maybe in ULPs. + let tolerance; + if (this.params.format === 'rgb10a2unorm') { + tolerance = (i: number) => { + // The alpha component is only two bits. Use a generous tolerance. + return i % 4 === 3 ? 0.18 : 0.01; + }; + } else { + tolerance = 0.01; + } + + const check = this.checkBuffer(new readbackTypedArray(actual), expected, tolerance); + if (check !== undefined) { + niceStack.message = check; + this.rec.expectationFailed(niceStack); + } + mappedResultBuffer.destroy(); + }); } - `, - }); - const pipelineLayout = t.device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }); - const computePipeline = t.device.createComputePipeline({ - computeStage: { module: computeModule, entryPoint: 'main' }, - layout: pipelineLayout, - }); - - // create bindgroup - const bindGroup = t.device.createBindGroup({ - layout: bindGroupLayout, - entries: [ - { binding: 0, resource: texture.createView() }, - { binding: 1, resource: { buffer: bufferTex, offset: 0, size: 4 * 256 * 256 } }, - { binding: 2, resource: sampler }, - ], - }); - - // encode the pass and submit - const encoder = t.device.createCommandEncoder(); - const pass = encoder.beginComputePass(); - pass.setPipeline(computePipeline); - pass.setBindGroup(0, bindGroup); - pass.dispatch(256, 256, 1); - pass.endPass(); - const commands = encoder.finish(); - t.device.defaultQueue.submit([commands]); - - await t.expectContents(bufferTex, new Uint32Array([0])); -}); + } + } +} + +export const g = makeTestGroup(SampledTextureClearTest); + +g.test('uninitialized_texture_is_zero') + .params(TextureZeroInitTest.generateParams([ReadMethod.Sample])) + .fn(t => t.run()); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/texture_zero_init_test.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/texture_zero_init_test.ts new file mode 100644 index 00000000000..c5119e23ade --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/operation/resource_init/texture_zero_init_test.ts @@ -0,0 +1,581 @@ +import { TextureUsage } from '../../../../common/constants.js'; +import { TestCaseRecorder } from '../../../../common/framework/logging/test_case_recorder.js'; +import { params, poptions, pbool } from '../../../../common/framework/params_builder.js'; +import { CaseParams } from '../../../../common/framework/params_utils.js'; +import { assert, unreachable } from '../../../../common/framework/util/util.js'; +import { kTextureAspects, kTextureFormatInfo, kTextureFormats } from '../../../capability_info.js'; +import { GPUTest } from '../../../gpu_test.js'; +import { createTextureUploadBuffer } from '../../../util/texture/layout.js'; +import { BeginEndRange, SubresourceRange } from '../../../util/texture/subresource.js'; +import { PerTexelComponent, getTexelDataRepresentation } from '../../../util/texture/texelData.js'; + +enum UninitializeMethod { + Creation = 'Creation', // The texture was just created. It is uninitialized. + StoreOpClear = 'StoreOpClear', // The texture was rendered to with GPUStoreOp "clear" +} +const kUninitializeMethods = Object.keys(UninitializeMethod) as UninitializeMethod[]; + +export enum ReadMethod { + Sample = 'Sample', // The texture is sampled from + CopyToBuffer = 'CopyToBuffer', // The texture is copied to a buffer + CopyToTexture = 'CopyToTexture', // The texture is copied to another texture + DepthTest = 'DepthTest', // The texture is read as a depth buffer + StencilTest = 'StencilTest', // The texture is read as a stencil buffer + ColorBlending = 'ColorBlending', // Read the texture by blending as a color attachment + Storage = 'Storage', // Read the texture as a storage texture +} + +// Test with these mip level counts +type MipLevels = 1 | 5; +const kMipLevelCounts: MipLevels[] = [1, 5]; + +// For each mip level count, define the mip ranges to leave uninitialized. +const kUninitializedMipRangesToTest: { [k in MipLevels]: BeginEndRange[] } = { + 1: [{ begin: 0, end: 1 }], // Test the only mip + 5: [ + { begin: 0, end: 2 }, + { begin: 3, end: 4 }, + ], // Test a range and a single mip +}; + +// Test with these sample counts. +type SampleCounts = 1 | 4; +const kSampleCounts: SampleCounts[] = [1, 4]; + +// Test with these slice counts. This means the depth of a 3d texture or the number +// or layers in a 2D or a 1D texture array. +type SliceCounts = 1 | 7; + +// For each slice count, define the slices to leave uninitialized. +const kUninitializedSliceRangesToTest: { [k in SliceCounts]: BeginEndRange[] } = { + 1: [{ begin: 0, end: 1 }], // Test the only slice + 7: [ + { begin: 2, end: 4 }, + { begin: 6, end: 7 }, + ], // Test a range and a single slice +}; + +// Test with these combinations of texture dimension and sliceCount. +const kCreationSizes: Array<{ + dimension: GPUTextureDimension; + sliceCount: SliceCounts; +}> = [ + // { dimension: '1d', sliceCount: 7 }, // TODO: 1d textures + { dimension: '2d', sliceCount: 1 }, // 2d textures + { dimension: '2d', sliceCount: 7 }, // 2d array textures + // { dimension: '3d', sliceCount: 7 }, // TODO: 3d textures +]; + +// Enums to abstract over color / depth / stencil values in textures. Depending on the texture format, +// the data for each value may have a different representation. These enums are converted to a +// representation such that their values can be compared. ex.) An integer is needed to upload to an +// unsigned normalized format, but its value is read as a float in the shader. +export const enum InitializedState { + Canary, // Set on initialized subresources. It should stay the same. On discarded resources, we should observe zero. + Zero, // We check that uninitialized subresources are in this state when read back. +} + +export function initializedStateAsFloat(state: InitializedState): number { + switch (state) { + case InitializedState.Zero: + return 0; + case InitializedState.Canary: + return 1; + default: + unreachable(); + } +} + +export function initializedStateAsUint(state: InitializedState): number { + switch (state) { + case InitializedState.Zero: + return 0; + case InitializedState.Canary: + return 255; + default: + unreachable(); + } +} + +export function initializedStateAsSint(state: InitializedState): number { + switch (state) { + case InitializedState.Zero: + return 0; + case InitializedState.Canary: + return -1; + default: + unreachable(); + } +} + +export function initializedStateAsColor( + state: InitializedState, + format: GPUTextureFormat +): [number, number, number, number] { + let value; + if (format.indexOf('uint') !== -1) { + value = initializedStateAsUint(state); + } else if (format.indexOf('sint') !== -1) { + value = initializedStateAsSint(state); + } else { + value = initializedStateAsFloat(state); + } + return [value, value, value, value]; +} + +export function initializedStateAsDepth(state: InitializedState): number { + switch (state) { + case InitializedState.Zero: + return 0; + case InitializedState.Canary: + return 1; + default: + unreachable(); + } +} + +export function initializedStateAsStencil(state: InitializedState): number { + switch (state) { + case InitializedState.Zero: + return 0; + case InitializedState.Canary: + return 42; + default: + unreachable(); + } +} + +interface TestParams { + format: GPUTextureFormat; + aspect: GPUTextureAspect; + dimension: GPUTextureDimension; + sliceCount: SliceCounts; + mipLevelCount: MipLevels; + sampleCount: SampleCounts; + uninitializeMethod: UninitializeMethod; + readMethod: ReadMethod; + nonPowerOfTwo: boolean; +} + +function getRequiredTextureUsage( + format: GPUTextureFormat, + sampleCount: SampleCounts, + uninitializeMethod: UninitializeMethod, + readMethod: ReadMethod +): GPUTextureUsageFlags { + let usage: GPUTextureUsageFlags = TextureUsage.CopyDst; + + switch (uninitializeMethod) { + case UninitializeMethod.Creation: + break; + case UninitializeMethod.StoreOpClear: + usage |= TextureUsage.OutputAttachment; + break; + default: + unreachable(); + } + + switch (readMethod) { + case ReadMethod.CopyToBuffer: + case ReadMethod.CopyToTexture: + usage |= TextureUsage.CopySrc; + break; + case ReadMethod.Sample: + usage |= TextureUsage.Sampled; + break; + case ReadMethod.Storage: + usage |= TextureUsage.Storage; + break; + case ReadMethod.DepthTest: + case ReadMethod.StencilTest: + case ReadMethod.ColorBlending: + usage |= TextureUsage.OutputAttachment; + break; + default: + unreachable(); + } + + if (sampleCount > 1) { + // Copies to multisampled textures are not allowed. We need OutputAttachment to initialize + // canary data in multisampled textures. + usage |= TextureUsage.OutputAttachment; + } + + if (!kTextureFormatInfo[format].copyable) { + // Copies are not possible. We need OutputAttachment to initialize + // canary data. + assert(kTextureFormatInfo[format].renderable); + usage |= TextureUsage.OutputAttachment; + } + + return usage; +} + +export abstract class TextureZeroInitTest extends GPUTest { + protected stateToTexelComponents: { [k in InitializedState]: PerTexelComponent<number> }; + + constructor(rec: TestCaseRecorder, params: CaseParams) { + super(rec, params); + + const stateToTexelComponents = (state: InitializedState) => { + const [R, G, B, A] = initializedStateAsColor(state, this.params.format); + return { + R, + G, + B, + A, + Depth: initializedStateAsDepth(state), + Stencil: initializedStateAsStencil(state), + }; + }; + + this.stateToTexelComponents = { + [InitializedState.Zero]: stateToTexelComponents(InitializedState.Zero), + [InitializedState.Canary]: stateToTexelComponents(InitializedState.Canary), + }; + } + + get params(): TestParams { + return super.params as TestParams; + } + + get textureWidth(): number { + let width = 1 << this.params.mipLevelCount; + if (this.params.nonPowerOfTwo) { + width = 2 * width - 1; + } + return width; + } + + get textureHeight(): number { + let height = 1 << this.params.mipLevelCount; + if (this.params.nonPowerOfTwo) { + height = 2 * height - 1; + } + return height; + } + + // Used to iterate subresources and check that their uninitialized contents are zero when accessed + *iterateUninitializedSubresources(): Generator<SubresourceRange> { + for (const mipRange of kUninitializedMipRangesToTest[this.params.mipLevelCount]) { + for (const sliceRange of kUninitializedSliceRangesToTest[this.params.sliceCount]) { + yield new SubresourceRange({ mipRange, sliceRange }); + } + } + } + + // Used to iterate and initialize other subresources not checked for zero-initialization. + // Zero-initialization of uninitialized subresources should not have side effects on already + // initialized subresources. + *iterateInitializedSubresources(): Generator<SubresourceRange> { + const uninitialized: boolean[][] = new Array(this.params.mipLevelCount); + for (let level = 0; level < uninitialized.length; ++level) { + uninitialized[level] = new Array(this.params.sliceCount); + } + for (const subresources of this.iterateUninitializedSubresources()) { + for (const { level, slice } of subresources.each()) { + uninitialized[level][slice] = true; + } + } + for (let level = 0; level < uninitialized.length; ++level) { + for (let slice = 0; slice < uninitialized[level].length; ++slice) { + if (!uninitialized[level][slice]) { + yield new SubresourceRange({ + mipRange: { begin: level, count: 1 }, + sliceRange: { begin: slice, count: 1 }, + }); + } + } + } + } + + *generateTextureViewDescriptorsForRendering( + aspect: GPUTextureAspect, + subresourceRange?: SubresourceRange + ): Generator<GPUTextureViewDescriptor> { + const viewDescriptor: GPUTextureViewDescriptor = { + dimension: '2d', + aspect, + }; + + if (subresourceRange === undefined) { + return viewDescriptor; + } + + for (const { level, slice } of subresourceRange.each()) { + yield { + ...viewDescriptor, + baseMipLevel: level, + mipLevelCount: 1, + baseArrayLayer: slice, + arrayLayerCount: 1, + }; + } + } + + abstract checkContents( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void; + + private initializeWithStoreOp( + state: InitializedState, + texture: GPUTexture, + subresourceRange?: SubresourceRange + ): void { + const commandEncoder = this.device.createCommandEncoder(); + for (const viewDescriptor of this.generateTextureViewDescriptorsForRendering( + this.params.aspect, + subresourceRange + )) { + if (kTextureFormatInfo[this.params.format].color) { + commandEncoder + .beginRenderPass({ + colorAttachments: [ + { + attachment: texture.createView(viewDescriptor), + storeOp: 'store', + loadValue: initializedStateAsColor(state, this.params.format), + }, + ], + }) + .endPass(); + } else { + commandEncoder + .beginRenderPass({ + colorAttachments: [], + depthStencilAttachment: { + attachment: texture.createView(viewDescriptor), + depthStoreOp: 'store', + depthLoadValue: initializedStateAsDepth(state), + stencilStoreOp: 'store', + stencilLoadValue: initializedStateAsStencil(state), + }, + }) + .endPass(); + } + } + this.queue.submit([commandEncoder.finish()]); + } + + private initializeWithCopy( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + if (this.params.dimension === '1d' || this.params.dimension === '3d') { + // TODO: https://github.com/gpuweb/gpuweb/issues/69 + // Copies with 1D and 3D textures are not yet specified + unreachable(); + } + + const firstSubresource = subresourceRange.each().next().value; + assert(typeof firstSubresource !== 'undefined'); + + const largestWidth = this.textureWidth >> firstSubresource.level; + const largestHeight = this.textureHeight >> firstSubresource.level; + + const texelData = new Uint8Array( + getTexelDataRepresentation(this.params.format).getBytes(this.stateToTexelComponents[state]) + ); + const { buffer, bytesPerRow, rowsPerImage } = createTextureUploadBuffer( + texelData, + this.device, + this.params.format, + this.params.dimension, + [largestWidth, largestHeight, 1] + ); + + const commandEncoder = this.device.createCommandEncoder(); + + for (const { level, slice } of subresourceRange.each()) { + const width = this.textureWidth >> level; + const height = this.textureHeight >> level; + + commandEncoder.copyBufferToTexture( + { + buffer, + bytesPerRow, + rowsPerImage, + }, + { texture, mipLevel: level, arrayLayer: slice }, + { width, height, depth: 1 } + ); + } + this.queue.submit([commandEncoder.finish()]); + buffer.destroy(); + } + + initializeTexture( + texture: GPUTexture, + state: InitializedState, + subresourceRange: SubresourceRange + ): void { + if (this.params.sampleCount > 1 || !kTextureFormatInfo[this.params.format].copyable) { + // Copies to multisampled textures not yet specified. + // Use a storeOp for now. + assert(kTextureFormatInfo[this.params.format].renderable); + this.initializeWithStoreOp(state, texture, subresourceRange); + } else { + this.initializeWithCopy(texture, state, subresourceRange); + } + } + + discardTexture(texture: GPUTexture, subresourceRange: SubresourceRange): void { + const commandEncoder = this.device.createCommandEncoder(); + + for (const desc of this.generateTextureViewDescriptorsForRendering( + this.params.aspect, + subresourceRange + )) { + if (kTextureFormatInfo[this.params.format].color) { + commandEncoder + .beginRenderPass({ + colorAttachments: [ + { + attachment: texture.createView(desc), + storeOp: 'clear', + loadValue: 'load', + }, + ], + }) + .endPass(); + } else { + commandEncoder + .beginRenderPass({ + colorAttachments: [], + depthStencilAttachment: { + attachment: texture.createView(desc), + depthStoreOp: 'clear', + depthLoadValue: 'load', + stencilStoreOp: 'clear', + stencilLoadValue: 'load', + }, + }) + .endPass(); + } + } + this.queue.submit([commandEncoder.finish()]); + } + + static generateParams(readMethods: ReadMethod[]) { + return ( + // TODO: Consider making a list of "valid" texture descriptors in capability_info. + params() + .combine(poptions('format', kTextureFormats)) + .combine(poptions('aspect', kTextureAspects)) + .unless( + ({ format, aspect }) => + (aspect === 'depth-only' && !kTextureFormatInfo[format].depth) || + (aspect === 'stencil-only' && !kTextureFormatInfo[format].stencil) + ) + .combine(poptions('mipLevelCount', kMipLevelCounts)) + .combine(poptions('sampleCount', kSampleCounts)) + // Multisampled textures may only have one mip + .unless(({ sampleCount, mipLevelCount }) => sampleCount > 1 && mipLevelCount > 1) + .combine(poptions('uninitializeMethod', kUninitializeMethods)) + .combine(poptions('readMethod', readMethods)) + .unless( + ({ readMethod, format }) => + // It doesn't make sense to copy from a packed depth format. + // This is not specified yet, but it will probably be disallowed as the bits may + // be vendor-specific. + // TODO: Test copying out of the stencil aspect. + (readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture) && + (format === 'depth24plus' || format === 'depth24plus-stencil8') + ) + .unless( + ({ readMethod, format }) => + (readMethod === ReadMethod.DepthTest && !kTextureFormatInfo[format].depth) || + (readMethod === ReadMethod.StencilTest && !kTextureFormatInfo[format].stencil) || + (readMethod === ReadMethod.ColorBlending && !kTextureFormatInfo[format].color) || + // TODO: Test with depth sampling + (readMethod === ReadMethod.Sample && kTextureFormatInfo[format].depth) + ) + .unless( + ({ readMethod, sampleCount }) => + // We can only read from multisampled textures by sampling. + sampleCount > 1 && + (readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture) + ) + .combine(kCreationSizes) + // Multisampled 3D / 2D array textures not supported. + .unless(({ sampleCount, sliceCount }) => sampleCount > 1 && sliceCount > 1) + .filter(({ format, sampleCount, uninitializeMethod, readMethod }) => { + const usage = getRequiredTextureUsage( + format, + sampleCount, + uninitializeMethod, + readMethod + ); + + if (usage & TextureUsage.OutputAttachment && !kTextureFormatInfo[format].renderable) { + return false; + } + + if (usage & TextureUsage.Storage && !kTextureFormatInfo[format].storage) { + return false; + } + + return true; + }) + .combine(pbool('nonPowerOfTwo')) + ); + } + + run(): void { + const { + format, + dimension, + mipLevelCount, + sliceCount, + sampleCount, + uninitializeMethod, + readMethod, + } = this.params; + + const usage = getRequiredTextureUsage(format, sampleCount, uninitializeMethod, readMethod); + + const texture = this.device.createTexture({ + size: [this.textureWidth, this.textureHeight, sliceCount], + format, + dimension, + usage, + mipLevelCount, + sampleCount, + }); + + // Initialize some subresources with canary values + for (const subresourceRange of this.iterateInitializedSubresources()) { + this.initializeTexture(texture, InitializedState.Canary, subresourceRange); + } + + switch (uninitializeMethod) { + case UninitializeMethod.Creation: + break; + case UninitializeMethod.StoreOpClear: + // Initialize the rest of the resources. + for (const subresourceRange of this.iterateUninitializedSubresources()) { + this.initializeTexture(texture, InitializedState.Canary, subresourceRange); + } + // Then use a store op to discard their contents. + for (const subresourceRange of this.iterateUninitializedSubresources()) { + this.discardTexture(texture, subresourceRange); + } + break; + default: + unreachable(); + } + + // Check that all uninitialized resources are zero. + for (const subresourceRange of this.iterateUninitializedSubresources()) { + this.checkContents(texture, InitializedState.Zero, subresourceRange); + } + + // Check the all other resources are unchanged. + for (const subresourceRange of this.iterateInitializedSubresources()) { + this.checkContents(texture, InitializedState.Canary, subresourceRange); + } + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroup.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroup.spec.ts index 0825405b939..61ff346027c 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroup.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroup.spec.ts @@ -2,21 +2,27 @@ export const description = ` createBindGroup validation tests. `; -import * as C from '../../../common/constants.js'; -import { pcombine, poptions } from '../../../common/framework/params.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { poptions, params } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { unreachable } from '../../../common/framework/util/util.js'; -import { kBindingTypes } from '../../capability_info.js'; +import { + kBindingTypes, + kBindingTypeInfo, + kBindableResources, + kTextureUsages, + kTextureBindingTypes, + kTextureBindingTypeInfo, +} from '../../capability_info.js'; -import { BindingResourceType, ValidationTest, resourceBindingMatches } from './validation_test.js'; +import { ValidationTest } from './validation_test.js'; function clone<T extends GPUTextureDescriptor>(descriptor: T): T { return JSON.parse(JSON.stringify(descriptor)); } -export const g = new TestGroup(ValidationTest); +export const g = makeTestGroup(ValidationTest); -g.test('binding count mismatch', async t => { +g.test('binding_count_mismatch').fn(async t => { const bindGroupLayout = t.device.createBindGroupLayout({ entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }], }); @@ -44,7 +50,7 @@ g.test('binding count mismatch', async t => { }); }); -g.test('binding must be present in layout', async t => { +g.test('binding_must_be_present_in_layout').fn(async t => { const bindGroupLayout = t.device.createBindGroupLayout({ entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }], }); @@ -68,147 +74,134 @@ g.test('binding must be present in layout', async t => { }); }); -g.test('buffer binding must contain exactly one buffer of its type', t => { - const bindingType: GPUBindingType = t.params.bindingType; - const resourceType: BindingResourceType = t.params.resourceType; - - const layout = t.device.createBindGroupLayout({ - entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: bindingType }], - }); - - const resource = t.getBindingResource(resourceType); - - const shouldError = !resourceBindingMatches(bindingType, resourceType); - t.expectValidationError(() => { - t.device.createBindGroup({ layout, entries: [{ binding: 0, resource }] }); - }, shouldError); -}).params( - pcombine( - poptions('bindingType', kBindingTypes), - poptions('resourceType', Object.keys(BindingResourceType)) +g.test('buffer_binding_must_contain_exactly_one_buffer_of_its_type') + .params( + params() + .combine(poptions('bindingType', kBindingTypes)) + .combine(poptions('resourceType', kBindableResources)) ) -); + .fn(t => { + const { bindingType, resourceType } = t.params; + const info = kBindingTypeInfo[bindingType]; + + const storageTextureFormat = info.resource === 'storageTex' ? 'rgba8unorm' : undefined; + const layout = t.device.createBindGroupLayout({ + entries: [ + { binding: 0, visibility: GPUShaderStage.COMPUTE, type: bindingType, storageTextureFormat }, + ], + }); -g.test('texture binding must have correct usage', async t => { - const type: GPUBindingType = t.params.type; - const usage: GPUTextureUsageFlags = t.params._usage; + const resource = t.getBindingResource(resourceType); - const bindGroupLayout = t.device.createBindGroupLayout({ - entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type }], + const resourceBindingMatches = info.resource === resourceType; + t.expectValidationError(() => { + t.device.createBindGroup({ layout, entries: [{ binding: 0, resource }] }); + }, !resourceBindingMatches); }); - const goodDescriptor = { - size: { width: 16, height: 16, depth: 1 }, - format: C.TextureFormat.R8Unorm, - usage, - }; - - // Control case - t.device.createBindGroup({ - entries: [{ binding: 0, resource: t.device.createTexture(goodDescriptor).createView() }], - layout: bindGroupLayout, - }); +g.test('texture_binding_must_have_correct_usage') + .params( + params() + .combine(poptions('type', kTextureBindingTypes)) + .combine(poptions('usage', kTextureUsages)) + ) + .fn(async t => { + const { type, usage } = t.params; + const info = kTextureBindingTypeInfo[type]; - function* mismatchedTextureUsages(): Iterable<GPUTextureUsageFlags> { - yield GPUTextureUsage.COPY_SRC; - yield GPUTextureUsage.COPY_DST; - if (type !== 'sampled-texture') { - yield GPUTextureUsage.SAMPLED; - } - if (type !== 'readonly-storage-texture' && type !== 'writeonly-storage-texture') { - yield GPUTextureUsage.STORAGE; - } - yield GPUTextureUsage.OUTPUT_ATTACHMENT; - } + const storageTextureFormat = info.resource === 'storageTex' ? 'rgba8unorm' : undefined; + const bindGroupLayout = t.device.createBindGroupLayout({ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type, storageTextureFormat }], + }); - // Mismatched texture binding usages are not valid. - for (const mismatchedTextureUsage of mismatchedTextureUsages()) { - const badDescriptor = clone(goodDescriptor); - badDescriptor.usage = mismatchedTextureUsage; + const descriptor = { + size: { width: 16, height: 16, depth: 1 }, + format: 'rgba8unorm' as const, + usage, + }; + const shouldError = usage !== info.usage; t.expectValidationError(() => { t.device.createBindGroup({ - entries: [{ binding: 0, resource: t.device.createTexture(badDescriptor).createView() }], + entries: [{ binding: 0, resource: t.device.createTexture(descriptor).createView() }], layout: bindGroupLayout, }); - }); - } -}).params([ - { type: 'sampled-texture', _usage: C.TextureUsage.Sampled }, - { type: 'storage-texture', _usage: C.TextureUsage.Storage }, -]); - -g.test('texture must have correct component type', async t => { - const { textureComponentType } = t.params; - - const bindGroupLayout = t.device.createBindGroupLayout({ - entries: [ - { - binding: 0, - visibility: GPUShaderStage.FRAGMENT, - type: 'sampled-texture', - textureComponentType, - }, - ], + }, shouldError); }); - // TODO: Test more texture component types. - let format: GPUTextureFormat; - if (textureComponentType === 'float') { - format = 'r8unorm'; - } else if (textureComponentType === 'sint') { - format = 'r8sint'; - } else if (textureComponentType === 'uint') { - format = 'r8uint'; - } else { - unreachable('Unexpected texture component type'); - } +g.test('texture_must_have_correct_component_type') + .params(poptions('textureComponentType', ['float', 'sint', 'uint'] as const)) + .fn(async t => { + const { textureComponentType } = t.params; + + const bindGroupLayout = t.device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type: 'sampled-texture', + textureComponentType, + }, + ], + }); - const goodDescriptor = { - size: { width: 16, height: 16, depth: 1 }, - format, - usage: GPUTextureUsage.SAMPLED, - }; + // TODO: Test more texture component types. + let format: GPUTextureFormat; + if (textureComponentType === 'float') { + format = 'r8unorm'; + } else if (textureComponentType === 'sint') { + format = 'r8sint'; + } else if (textureComponentType === 'uint') { + format = 'r8uint'; + } else { + unreachable('Unexpected texture component type'); + } - // Control case - t.device.createBindGroup({ - entries: [ - { - binding: 0, - resource: t.device.createTexture(goodDescriptor).createView(), - }, - ], - layout: bindGroupLayout, - }); + const goodDescriptor = { + size: { width: 16, height: 16, depth: 1 }, + format, + usage: GPUTextureUsage.SAMPLED, + }; - function* mismatchedTextureFormats(): Iterable<GPUTextureFormat> { - if (textureComponentType !== 'float') { - yield 'r8unorm'; - } - if (textureComponentType !== 'sint') { - yield 'r8sint'; - } - if (textureComponentType !== 'uint') { - yield 'r8uint'; + // Control case + t.device.createBindGroup({ + entries: [ + { + binding: 0, + resource: t.device.createTexture(goodDescriptor).createView(), + }, + ], + layout: bindGroupLayout, + }); + + function* mismatchedTextureFormats(): Iterable<GPUTextureFormat> { + if (textureComponentType !== 'float') { + yield 'r8unorm'; + } + if (textureComponentType !== 'sint') { + yield 'r8sint'; + } + if (textureComponentType !== 'uint') { + yield 'r8uint'; + } } - } - // Mismatched texture binding formats are not valid. - for (const mismatchedTextureFormat of mismatchedTextureFormats()) { - const badDescriptor: GPUTextureDescriptor = clone(goodDescriptor); - badDescriptor.format = mismatchedTextureFormat; + // Mismatched texture binding formats are not valid. + for (const mismatchedTextureFormat of mismatchedTextureFormats()) { + const badDescriptor: GPUTextureDescriptor = clone(goodDescriptor); + badDescriptor.format = mismatchedTextureFormat; - t.expectValidationError(() => { - t.device.createBindGroup({ - entries: [{ binding: 0, resource: t.device.createTexture(badDescriptor).createView() }], - layout: bindGroupLayout, + t.expectValidationError(() => { + t.device.createBindGroup({ + entries: [{ binding: 0, resource: t.device.createTexture(badDescriptor).createView() }], + layout: bindGroupLayout, + }); }); - }); - } -}).params(poptions('textureComponentType', ['float', 'sint', 'uint'])); + } + }); // TODO: Write test for all dimensions. -g.test('texture must have correct dimension', async t => { +g.test('texture_must_have_correct_dimension').fn(async t => { const bindGroupLayout = t.device.createBindGroupLayout({ entries: [ { @@ -222,7 +215,7 @@ g.test('texture must have correct dimension', async t => { const goodDescriptor = { size: { width: 16, height: 16, depth: 1 }, - format: C.TextureFormat.RGBA8Unorm, + format: 'rgba8unorm' as const, usage: GPUTextureUsage.SAMPLED, }; @@ -244,61 +237,63 @@ g.test('texture must have correct dimension', async t => { }); }); -g.test('buffer offset and size for bind groups match', async t => { - const { offset, size, _success } = t.params; - - const bindGroupLayout = t.device.createBindGroupLayout({ - entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }], - }); +g.test('buffer_offset_and_size_for_bind_groups_match') + .params([ + { offset: 0, size: 512, _success: true }, // offset 0 is valid + { offset: 256, size: 256, _success: true }, // offset 256 (aligned) is valid + + // Touching the end of the buffer + { offset: 0, size: 1024, _success: true }, + { offset: 0, size: undefined, _success: true }, + { offset: 256 * 3, size: 256, _success: true }, + { offset: 256 * 3, size: undefined, _success: true }, + + // Zero-sized bindings + { offset: 0, size: 0, _success: true }, + { offset: 256, size: 0, _success: true }, + { offset: 1024, size: 0, _success: true }, + { offset: 1024, size: undefined, _success: true }, + + // Unaligned buffer offset is invalid + { offset: 1, size: 256, _success: false }, + { offset: 1, size: undefined, _success: false }, + { offset: 128, size: 256, _success: false }, + { offset: 255, size: 256, _success: false }, + + // Out-of-bounds + { offset: 256 * 5, size: 0, _success: false }, // offset is OOB + { offset: 0, size: 256 * 5, _success: false }, // size is OOB + { offset: 1024, size: 1, _success: false }, // offset+size is OOB + ]) + .fn(async t => { + const { offset, size, _success } = t.params; + + const bindGroupLayout = t.device.createBindGroupLayout({ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }], + }); - const buffer = t.device.createBuffer({ - size: 1024, - usage: GPUBufferUsage.STORAGE, - }); + const buffer = t.device.createBuffer({ + size: 1024, + usage: GPUBufferUsage.STORAGE, + }); - const descriptor = { - entries: [ - { - binding: 0, - resource: { buffer, offset, size }, - }, - ], - layout: bindGroupLayout, - }; + const descriptor = { + entries: [ + { + binding: 0, + resource: { buffer, offset, size }, + }, + ], + layout: bindGroupLayout, + }; - if (_success) { - // Control case - t.device.createBindGroup(descriptor); - } else { - // Buffer offset and/or size don't match in bind groups. - t.expectValidationError(() => { + if (_success) { + // Control case t.device.createBindGroup(descriptor); - }); - } -}).params([ - { offset: 0, size: 512, _success: true }, // offset 0 is valid - { offset: 256, size: 256, _success: true }, // offset 256 (aligned) is valid - - // Touching the end of the buffer - { offset: 0, size: 1024, _success: true }, - { offset: 0, size: undefined, _success: true }, - { offset: 256 * 3, size: 256, _success: true }, - { offset: 256 * 3, size: undefined, _success: true }, - - // Zero-sized bindings - { offset: 0, size: 0, _success: true }, - { offset: 256, size: 0, _success: true }, - { offset: 1024, size: 0, _success: true }, - { offset: 1024, size: undefined, _success: true }, - - // Unaligned buffer offset is invalid - { offset: 1, size: 256, _success: false }, - { offset: 1, size: undefined, _success: false }, - { offset: 128, size: 256, _success: false }, - { offset: 255, size: 256, _success: false }, - - // Out-of-bounds - { offset: 256 * 5, size: 0, _success: false }, // offset is OOB - { offset: 0, size: 256 * 5, _success: false }, // size is OOB - { offset: 1024, size: 1, _success: false }, // offset+size is OOB -]); + } else { + // Buffer offset and/or size don't match in bind groups. + t.expectValidationError(() => { + t.device.createBindGroup(descriptor); + }); + } + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroupLayout.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroupLayout.spec.ts index 2ab8b5e6465..5aa5dae448d 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroupLayout.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createBindGroupLayout.spec.ts @@ -2,15 +2,12 @@ export const description = ` createBindGroupLayout validation tests. `; -import * as C from '../../../common/constants.js'; -import { poptions } from '../../../common/framework/params.js'; -import { ParamSpec } from '../../../common/framework/params_utils.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { poptions, params } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { kBindingTypeInfo, kBindingTypes, kMaxBindingsPerBindGroup, - kPerStageBindingLimits, kShaderStages, } from '../../capability_info.js'; @@ -20,13 +17,13 @@ function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T { return JSON.parse(JSON.stringify(descriptor)); } -export const g = new TestGroup(ValidationTest); +export const g = makeTestGroup(ValidationTest); -g.test('some binding index was specified more than once', async t => { +g.test('some_binding_index_was_specified_more_than_once').fn(async t => { const goodDescriptor = { entries: [ - { binding: 0, visibility: GPUShaderStage.COMPUTE, type: C.BindingType.StorageBuffer }, - { binding: 1, visibility: GPUShaderStage.COMPUTE, type: C.BindingType.StorageBuffer }, + { binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' as const }, + { binding: 1, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' as const }, ], }; @@ -42,185 +39,192 @@ g.test('some binding index was specified more than once', async t => { }); }); -g.test('Visibility of bindings can be 0', async t => { +g.test('visibility_of_bindings_can_be_0').fn(async t => { t.device.createBindGroupLayout({ entries: [{ binding: 0, visibility: 0, type: 'storage-buffer' }], }); }); -g.test('number of dynamic buffers exceeds the maximum value', async t => { - const { type, maxDynamicBufferCount } = t.params; - - const maxDynamicBufferBindings: GPUBindGroupLayoutEntry[] = []; - for (let i = 0; i < maxDynamicBufferCount; i++) { - maxDynamicBufferBindings.push({ - binding: i, - visibility: GPUShaderStage.COMPUTE, - type, - hasDynamicOffset: true, - }); - } - - const goodDescriptor = { - entries: [ - ...maxDynamicBufferBindings, - { - binding: maxDynamicBufferBindings.length, +g.test('number_of_dynamic_buffers_exceeds_the_maximum_value') + .params([ + { type: 'storage-buffer' as const, maxDynamicBufferCount: 4 }, + { type: 'uniform-buffer' as const, maxDynamicBufferCount: 8 }, + ]) + .fn(async t => { + const { type, maxDynamicBufferCount } = t.params; + + const maxDynamicBufferBindings: GPUBindGroupLayoutEntry[] = []; + for (let i = 0; i < maxDynamicBufferCount; i++) { + maxDynamicBufferBindings.push({ + binding: i, visibility: GPUShaderStage.COMPUTE, type, - hasDynamicOffset: false, - }, - ], - }; - - // Control case - t.device.createBindGroupLayout(goodDescriptor); - - // Dynamic buffers exceed maximum in a bind group layout. - const badDescriptor = clone(goodDescriptor); - badDescriptor.entries[maxDynamicBufferCount].hasDynamicOffset = true; + hasDynamicOffset: true, + }); + } - t.expectValidationError(() => { - t.device.createBindGroupLayout(badDescriptor); + const goodDescriptor = { + entries: [ + ...maxDynamicBufferBindings, + { + binding: maxDynamicBufferBindings.length, + visibility: GPUShaderStage.COMPUTE, + type, + hasDynamicOffset: false, + }, + ], + }; + + // Control case + t.device.createBindGroupLayout(goodDescriptor); + + // Dynamic buffers exceed maximum in a bind group layout. + const badDescriptor = clone(goodDescriptor); + badDescriptor.entries[maxDynamicBufferCount].hasDynamicOffset = true; + + t.expectValidationError(() => { + t.device.createBindGroupLayout(badDescriptor); + }); }); -}).params([ - { type: C.BindingType.StorageBuffer, maxDynamicBufferCount: 4 }, - { type: C.BindingType.UniformBuffer, maxDynamicBufferCount: 8 }, -]); -g.test('dynamic set to true is allowed only for buffers', async t => { - const type: GPUBindingType = t.params.type; - const success = kBindingTypeInfo[type].type === 'buffer'; +g.test('dynamic_set_to_true_is_allowed_only_for_buffers') + .params(poptions('type', kBindingTypes)) + .fn(async t => { + const { type } = t.params; + const success = kBindingTypeInfo[type].perPipelineLimitClass.maxDynamic > 0; - const descriptor = { - entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type, hasDynamicOffset: true }], - }; + const descriptor = { + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type, hasDynamicOffset: true }], + }; - t.expectValidationError(() => { - t.device.createBindGroupLayout(descriptor); - }, !success); -}).params(poptions('type', kBindingTypes)); - -let kCasesForMaxResourcesPerStageTests: ParamSpec[]; -{ - // One bind group layout will be filled with kPerStageBindingLimit[...] of the type |type|. - // For each item in the array returned here, a case will be generated which tests a pipeline - // layout with one extra bind group layout with one extra binding. That extra binding will have: - // - // - If extraTypeSame, any of the binding types which counts toward the same limit as |type|. - // (i.e. 'storage-buffer' <-> 'readonly-storage-buffer'). - // - Otherwise, an arbitrary other type. - function* pickExtraBindingTypes( - bindingType: GPUBindingType, - extraTypeSame: boolean - ): IterableIterator<GPUBindingType> { - const info = kBindingTypeInfo[bindingType]; - if (extraTypeSame) { - for (const extraBindingType of kBindingTypes) { - if (info.perStageLimitType === kBindingTypeInfo[extraBindingType].perStageLimitType) { - yield extraBindingType; - } - } - } else { - yield info.perStageLimitType === 'sampler' ? 'sampled-texture' : 'sampler'; - } - } + t.expectValidationError(() => { + t.device.createBindGroupLayout(descriptor); + }, !success); + }); - kCasesForMaxResourcesPerStageTests = []; - for (const maxedType of kBindingTypes) { - for (const maxedVisibility of kShaderStages) { - // Don't generate a case where maxedType isn't valid in maxedVisibility. - if (!(kBindingTypeInfo[maxedType].validStages & maxedVisibility)) continue; - - for (const extraTypeSame of [true, false]) { - for (const extraType of pickExtraBindingTypes(maxedType, extraTypeSame)) { - for (const extraVisibility of kShaderStages) { - // Don't generate a case where extraType isn't valid in extraVisibility. - if (!(kBindingTypeInfo[extraType].validStages & extraVisibility)) continue; - - kCasesForMaxResourcesPerStageTests.push({ - maxedType, - maxedVisibility, - extraType, - extraVisibility, - }); - } - } +// One bind group layout will be filled with kPerStageBindingLimit[...] of the type |type|. +// For each item in the array returned here, a case will be generated which tests a pipeline +// layout with one extra bind group layout with one extra binding. That extra binding will have: +// +// - If extraTypeSame, any of the binding types which counts toward the same limit as |type|. +// (i.e. 'storage-buffer' <-> 'readonly-storage-buffer'). +// - Otherwise, an arbitrary other type. +function* pickExtraBindingTypes( + bindingType: GPUBindingType, + extraTypeSame: boolean +): IterableIterator<GPUBindingType> { + const info = kBindingTypeInfo[bindingType]; + if (extraTypeSame) { + for (const extraBindingType of kBindingTypes) { + if ( + info.perStageLimitClass.class === + kBindingTypeInfo[extraBindingType].perStageLimitClass.class + ) { + yield extraBindingType; } } + } else { + yield info.perStageLimitClass.class === 'sampler' ? 'sampled-texture' : 'sampler'; } } +const kCasesForMaxResourcesPerStageTests = params() + .combine(poptions('maxedType', kBindingTypes)) + .combine(poptions('maxedVisibility', kShaderStages)) + .filter(p => (kBindingTypeInfo[p.maxedType].validStages & p.maxedVisibility) !== 0) + .expand(function* (p) { + for (const extraTypeSame of [true, false]) { + yield* poptions('extraType', pickExtraBindingTypes(p.maxedType, extraTypeSame)); + } + }) + .combine(poptions('extraVisibility', kShaderStages)) + .filter(p => (kBindingTypeInfo[p.extraType].validStages & p.extraVisibility) !== 0); + // Should never fail unless kMaxBindingsPerBindGroup is exceeded, because the validation for // resources-of-type-per-stage is in pipeline layout creation. -g.test('max resources per stage/in bind group layout', async t => { - const maxedType: GPUBindingType = t.params.maxedType; - const extraType: GPUBindingType = t.params.extraType; - const { maxedVisibility, extraVisibility } = t.params; - const maxedCount = kPerStageBindingLimits[kBindingTypeInfo[maxedType].perStageLimitType]; - - const maxResourceBindings: GPUBindGroupLayoutEntry[] = []; - for (let i = 0; i < maxedCount; i++) { - maxResourceBindings.push({ - binding: i, - visibility: maxedVisibility, - type: maxedType, - }); - } +g.test('max_resources_per_stage,in_bind_group_layout') + .params(kCasesForMaxResourcesPerStageTests) + .fn(async t => { + const { maxedType, extraType, maxedVisibility, extraVisibility } = t.params; + const maxedTypeInfo = kBindingTypeInfo[maxedType]; + const maxedCount = maxedTypeInfo.perStageLimitClass.max; + const extraTypeInfo = kBindingTypeInfo[extraType]; + + const maxResourceBindings: GPUBindGroupLayoutEntry[] = []; + for (let i = 0; i < maxedCount; i++) { + maxResourceBindings.push({ + binding: i, + visibility: maxedVisibility, + type: maxedType, + storageTextureFormat: maxedTypeInfo.resource === 'storageTex' ? 'rgba8unorm' : undefined, + }); + } - const goodDescriptor = { entries: maxResourceBindings }; + const goodDescriptor = { entries: maxResourceBindings }; - // Control - t.device.createBindGroupLayout(goodDescriptor); + // Control + t.device.createBindGroupLayout(goodDescriptor); - const newDescriptor = clone(goodDescriptor); - newDescriptor.entries.push({ - binding: maxedCount, - visibility: extraVisibility, - type: extraType, - }); + const newDescriptor = clone(goodDescriptor); + newDescriptor.entries.push({ + binding: maxedCount, + visibility: extraVisibility, + type: extraType, + storageTextureFormat: extraTypeInfo.resource === 'storageTex' ? 'rgba8unorm' : undefined, + }); - const shouldError = maxedCount >= kMaxBindingsPerBindGroup; + const shouldError = maxedCount >= kMaxBindingsPerBindGroup; - t.expectValidationError(() => { - t.device.createBindGroupLayout(newDescriptor); - }, shouldError); -}).params(kCasesForMaxResourcesPerStageTests); + t.expectValidationError(() => { + t.device.createBindGroupLayout(newDescriptor); + }, shouldError); + }); // One pipeline layout can have a maximum number of each type of binding *per stage* (which is // different for each type). Test that the max works, then add one more binding of same-or-different // type and same-or-different visibility. -g.test('max resources per stage/in pipeline layout', async t => { - const maxedType: GPUBindingType = t.params.maxedType; - const extraType: GPUBindingType = t.params.extraType; - const { maxedVisibility, extraVisibility } = t.params; - const maxedCount = kPerStageBindingLimits[kBindingTypeInfo[maxedType].perStageLimitType]; - - const maxResourceBindings: GPUBindGroupLayoutEntry[] = []; - for (let i = 0; i < maxedCount; i++) { - maxResourceBindings.push({ - binding: i, - visibility: maxedVisibility, - type: maxedType, - }); - } +g.test('max_resources_per_stage,in_pipeline_layout') + .params(kCasesForMaxResourcesPerStageTests) + .fn(async t => { + const { maxedType, extraType, maxedVisibility, extraVisibility } = t.params; + const maxedTypeInfo = kBindingTypeInfo[maxedType]; + const maxedCount = maxedTypeInfo.perStageLimitClass.max; + const extraTypeInfo = kBindingTypeInfo[extraType]; + + const maxResourceBindings: GPUBindGroupLayoutEntry[] = []; + for (let i = 0; i < maxedCount; i++) { + maxResourceBindings.push({ + binding: i, + visibility: maxedVisibility, + type: maxedType, + storageTextureFormat: maxedTypeInfo.resource === 'storageTex' ? 'rgba8unorm' : undefined, + }); + } - const goodLayout = t.device.createBindGroupLayout({ entries: maxResourceBindings }); + const goodLayout = t.device.createBindGroupLayout({ entries: maxResourceBindings }); - // Control - t.device.createPipelineLayout({ bindGroupLayouts: [goodLayout] }); + // Control + t.device.createPipelineLayout({ bindGroupLayouts: [goodLayout] }); - const extraLayout = t.device.createBindGroupLayout({ - entries: [{ binding: 0, visibility: extraVisibility, type: extraType }], - }); + const extraLayout = t.device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: extraVisibility, + type: extraType, + storageTextureFormat: extraTypeInfo.resource === 'storageTex' ? 'rgba8unorm' : undefined, + }, + ], + }); - // Some binding types use the same limit, e.g. 'storage-buffer' and 'readonly-storage-buffer'. - const newBindingCountsTowardSamePerStageLimit = - (maxedVisibility & extraVisibility) !== 0 && - kBindingTypeInfo[maxedType].perStageLimitType === kBindingTypeInfo[extraType].perStageLimitType; - const layoutExceedsPerStageLimit = newBindingCountsTowardSamePerStageLimit; + // Some binding types use the same limit, e.g. 'storage-buffer' and 'readonly-storage-buffer'. + const newBindingCountsTowardSamePerStageLimit = + (maxedVisibility & extraVisibility) !== 0 && + kBindingTypeInfo[maxedType].perStageLimitClass.class === + kBindingTypeInfo[extraType].perStageLimitClass.class; + const layoutExceedsPerStageLimit = newBindingCountsTowardSamePerStageLimit; - t.expectValidationError(() => { - t.device.createPipelineLayout({ bindGroupLayouts: [goodLayout, extraLayout] }); - }, layoutExceedsPerStageLimit); -}).params(kCasesForMaxResourcesPerStageTests); + t.expectValidationError(() => { + t.device.createPipelineLayout({ bindGroupLayouts: [goodLayout, extraLayout] }); + }, layoutExceedsPerStageLimit); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createPipelineLayout.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createPipelineLayout.spec.ts index 9d8116cc517..cc466482991 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createPipelineLayout.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createPipelineLayout.spec.ts @@ -2,8 +2,8 @@ export const description = ` createPipelineLayout validation tests. `; -import { pbool, pcombine, poptions } from '../../../common/framework/params.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { pbool, poptions, params } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { kBindingTypeInfo, kBindingTypes, @@ -16,84 +16,88 @@ function clone<T extends GPUBindGroupLayoutDescriptor>(descriptor: T): T { return JSON.parse(JSON.stringify(descriptor)); } -export const g = new TestGroup(ValidationTest); +export const g = makeTestGroup(ValidationTest); -g.test('number of dynamic buffers exceeds the maximum value', async t => { - const { type, visibility } = t.params; - const maxDynamicCount = kBindingTypeInfo[type as GPUBindingType].maxDynamicCount; - - const maxDynamicBufferBindings: GPUBindGroupLayoutEntry[] = []; - for (let binding = 0; binding < maxDynamicCount; binding++) { - maxDynamicBufferBindings.push({ binding, visibility, type, hasDynamicOffset: true }); - } - - const maxDynamicBufferBindGroupLayout = t.device.createBindGroupLayout({ - entries: maxDynamicBufferBindings, - }); - - const goodDescriptor = { - entries: [{ binding: 0, visibility, type, hasDynamicOffset: false }], - }; - - const goodPipelineLayoutDescriptor = { - bindGroupLayouts: [ - maxDynamicBufferBindGroupLayout, - t.device.createBindGroupLayout(goodDescriptor), - ], - }; - - // Control case - t.device.createPipelineLayout(goodPipelineLayoutDescriptor); - - // Check dynamic buffers exceed maximum in pipeline layout. - const badDescriptor = clone(goodDescriptor); - badDescriptor.entries[0].hasDynamicOffset = true; - - const badPipelineLayoutDescriptor = { - bindGroupLayouts: [ - maxDynamicBufferBindGroupLayout, - t.device.createBindGroupLayout(badDescriptor), - ], - }; - - t.expectValidationError(() => { - t.device.createPipelineLayout(badPipelineLayoutDescriptor); - }); -}).params( - pcombine( - poptions('visibility', [0, 2, 4, 6]), // - poptions('type', ['uniform-buffer', 'storage-buffer', 'readonly-storage-buffer']) +g.test('number_of_dynamic_buffers_exceeds_the_maximum_value') + .params( + params() + .combine(poptions('visibility', [0, 2, 4, 6])) + .combine( + poptions('type', ['uniform-buffer', 'storage-buffer', 'readonly-storage-buffer'] as const) + ) ) -); + .fn(async t => { + const { type, visibility } = t.params; + const { maxDynamic } = kBindingTypeInfo[type].perPipelineLimitClass; -g.test('visibility and dynamic offsets', t => { - const hasDynamicOffset: boolean = t.params.hasDynamicOffset; - const type: GPUBindingType = t.params.type; - const visibility: GPUShaderStageFlags = t.params.visibility; - const info = kBindingTypeInfo[type as GPUBindingType]; + const maxDynamicBufferBindings: GPUBindGroupLayoutEntry[] = []; + for (let binding = 0; binding < maxDynamic; binding++) { + maxDynamicBufferBindings.push({ binding, visibility, type, hasDynamicOffset: true }); + } - const descriptor = { - entries: [{ binding: 0, visibility, type, hasDynamicOffset }], - }; - - let success = true; - if (info.type !== 'buffer' && hasDynamicOffset) success = false; - if ((visibility & ~info.validStages) !== 0) success = false; + const maxDynamicBufferBindGroupLayout = t.device.createBindGroupLayout({ + entries: maxDynamicBufferBindings, + }); - t.expectValidationError(() => { - t.device.createPipelineLayout({ - bindGroupLayouts: [t.device.createBindGroupLayout(descriptor)], + const goodDescriptor = { + entries: [{ binding: 0, visibility, type, hasDynamicOffset: false }], + }; + + const goodPipelineLayoutDescriptor = { + bindGroupLayouts: [ + maxDynamicBufferBindGroupLayout, + t.device.createBindGroupLayout(goodDescriptor), + ], + }; + + // Control case + t.device.createPipelineLayout(goodPipelineLayoutDescriptor); + + // Check dynamic buffers exceed maximum in pipeline layout. + const badDescriptor = clone(goodDescriptor); + badDescriptor.entries[0].hasDynamicOffset = true; + + const badPipelineLayoutDescriptor = { + bindGroupLayouts: [ + maxDynamicBufferBindGroupLayout, + t.device.createBindGroupLayout(badDescriptor), + ], + }; + + t.expectValidationError(() => { + t.device.createPipelineLayout(badPipelineLayoutDescriptor); }); - }, !success); -}).params( - pcombine( - poptions('type', kBindingTypes), // - pbool('hasDynamicOffset'), - poptions('visibility', kShaderStageCombinations) + }); + +g.test('visibility_and_dynamic_offsets') + .params( + params() + .combine(poptions('type', kBindingTypes)) + .combine(pbool('hasDynamicOffset')) + .combine(poptions('visibility', kShaderStageCombinations)) ) -); + .fn(t => { + const { type, hasDynamicOffset, visibility } = t.params; + const info = kBindingTypeInfo[type as GPUBindingType]; + + const storageTextureFormat = info.resource === 'storageTex' ? ('r32uint' as const) : undefined; + const descriptor = { + entries: [{ binding: 0, visibility, type, hasDynamicOffset, storageTextureFormat }], + }; + + const supportsDynamicOffset = kBindingTypeInfo[type].perPipelineLimitClass.maxDynamic > 0; + let success = true; + if (!supportsDynamicOffset && hasDynamicOffset) success = false; + if ((visibility & ~info.validStages) !== 0) success = false; + + t.expectValidationError(() => { + t.device.createPipelineLayout({ + bindGroupLayouts: [t.device.createBindGroupLayout(descriptor)], + }); + }, !success); + }); -g.test('number of bind group layouts exceeds the maximum value', async t => { +g.test('number_of_bind_group_layouts_exceeds_the_maximum_value').fn(async t => { const bindGroupLayoutDescriptor: GPUBindGroupLayoutDescriptor = { entries: [], }; diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createRenderPipeline.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createRenderPipeline.spec.ts index 9560bb940c8..b5ac9e8070c 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createRenderPipeline.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createRenderPipeline.spec.ts @@ -2,8 +2,8 @@ export const description = ` createRenderPipeline validation tests. `; -import { poptions } from '../../../common/framework/params.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { poptions } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { kTextureFormatInfo, kTextureFormats } from '../../capability_info.js'; import { ValidationTest } from './validation_test.js'; @@ -92,15 +92,15 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('basic use of createRenderPipeline', t => { +g.test('basic_use_of_createRenderPipeline').fn(t => { const descriptor = t.getDescriptor(); t.device.createRenderPipeline(descriptor); }); -g.test('at least one color state is required', async t => { +g.test('at_least_one_color_state_is_required').fn(async t => { const goodDescriptor = t.getDescriptor({ colorStates: [{ format: 'rgba8unorm' }], }); @@ -118,111 +118,117 @@ g.test('at least one color state is required', async t => { }); }); -g.test('color formats must be renderable', async t => { - const format: GPUTextureFormat = t.params.format; - const info = kTextureFormatInfo[format]; +g.test('color_formats_must_be_renderable') + .params(poptions('format', kTextureFormats)) + .fn(async t => { + const format: GPUTextureFormat = t.params.format; + const info = kTextureFormatInfo[format]; - const descriptor = t.getDescriptor({ colorStates: [{ format }] }); + const descriptor = t.getDescriptor({ colorStates: [{ format }] }); - if (info.renderable && info.color) { - // Succeeds when color format is renderable - t.device.createRenderPipeline(descriptor); - } else { - // Fails because when format is non-renderable - t.expectValidationError(() => { + if (info.renderable && info.color) { + // Succeeds when color format is renderable t.device.createRenderPipeline(descriptor); - }); - } -}).params(poptions('format', kTextureFormats)); - -g.test('sample count must be valid', async t => { - const { sampleCount, _success } = t.params; - - const descriptor = t.getDescriptor({ sampleCount }); + } else { + // Fails because when format is non-renderable + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + }); - if (_success) { - // Succeeds when sample count is valid - t.device.createRenderPipeline(descriptor); - } else { - // Fails when sample count is not 4 or 1 - t.expectValidationError(() => { +g.test('sample_count_must_be_valid') + .params([ + { sampleCount: 0, _success: false }, + { sampleCount: 1, _success: true }, + { sampleCount: 2, _success: false }, + { sampleCount: 3, _success: false }, + { sampleCount: 4, _success: true }, + { sampleCount: 8, _success: false }, + { sampleCount: 16, _success: false }, + ]) + .fn(async t => { + const { sampleCount, _success } = t.params; + + const descriptor = t.getDescriptor({ sampleCount }); + + if (_success) { + // Succeeds when sample count is valid t.device.createRenderPipeline(descriptor); - }); - } -}).params([ - { sampleCount: 0, _success: false }, - { sampleCount: 1, _success: true }, - { sampleCount: 2, _success: false }, - { sampleCount: 3, _success: false }, - { sampleCount: 4, _success: true }, - { sampleCount: 8, _success: false }, - { sampleCount: 16, _success: false }, -]); - -g.test('sample count must be equal to the one of every attachment in the render pass', async t => { - const { attachmentSamples, pipelineSamples, _success } = t.params; - - const colorTexture = t.createTexture({ - format: 'rgba8unorm', - sampleCount: attachmentSamples, - }); - const depthStencilTexture = t.createTexture({ - format: 'depth24plus-stencil8', - sampleCount: attachmentSamples, + } else { + // Fails when sample count is not 4 or 1 + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } }); - const renderPassDescriptorWithoutDepthStencil = { - colorAttachments: [ + +g.test('sample_count_must_be_equal_to_the_one_of_every_attachment_in_the_render_pass') + .params([ + { attachmentSamples: 4, pipelineSamples: 4, _success: true }, // It is allowed to use multisampled render pass and multisampled render pipeline. + { attachmentSamples: 4, pipelineSamples: 1, _success: false }, // It is not allowed to use multisampled render pass and non-multisampled render pipeline. + { attachmentSamples: 1, pipelineSamples: 4, _success: false }, // It is not allowed to use non-multisampled render pass and multisampled render pipeline. + ]) + .fn(async t => { + const { attachmentSamples, pipelineSamples, _success } = t.params; + + const colorTexture = t.createTexture({ + format: 'rgba8unorm', + sampleCount: attachmentSamples, + }); + const depthStencilTexture = t.createTexture({ + format: 'depth24plus-stencil8', + sampleCount: attachmentSamples, + }); + const renderPassDescriptorWithoutDepthStencil = { + colorAttachments: [ + { + attachment: colorTexture.createView(), + loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, + }, + ], + }; + const renderPassDescriptorWithDepthStencilOnly = { + colorAttachments: [], + depthStencilAttachment: { + attachment: depthStencilTexture.createView(), + depthLoadValue: 1.0, + depthStoreOp: 'store', + stencilLoadValue: 0, + stencilStoreOp: 'store', + }, + }; + + const pipelineWithoutDepthStencil = t.device.createRenderPipeline( + t.getDescriptor({ + sampleCount: pipelineSamples, + }) + ); + const pipelineWithDepthStencilOnly = t.device.createRenderPipeline( + t.getDescriptor({ + colorStates: [], + depthStencilState: { format: 'depth24plus-stencil8' }, + sampleCount: pipelineSamples, + }) + ); + + for (const { renderPassDescriptor, pipeline } of [ { - attachment: colorTexture.createView(), - loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, + renderPassDescriptor: renderPassDescriptorWithoutDepthStencil, + pipeline: pipelineWithoutDepthStencil, }, - ], - }; - const renderPassDescriptorWithDepthStencilOnly = { - colorAttachments: [], - depthStencilAttachment: { - attachment: depthStencilTexture.createView(), - depthLoadValue: 1.0, - depthStoreOp: 'store', - stencilLoadValue: 0, - stencilStoreOp: 'store', - }, - }; - - const pipelineWithoutDepthStencil = t.device.createRenderPipeline( - t.getDescriptor({ - sampleCount: pipelineSamples, - }) - ); - const pipelineWithDepthStencilOnly = t.device.createRenderPipeline( - t.getDescriptor({ - colorStates: [], - depthStencilState: { format: 'depth24plus-stencil8' }, - sampleCount: pipelineSamples, - }) - ); - - for (const { renderPassDescriptor, pipeline } of [ - { - renderPassDescriptor: renderPassDescriptorWithoutDepthStencil, - pipeline: pipelineWithoutDepthStencil, - }, - { - renderPassDescriptor: renderPassDescriptorWithDepthStencilOnly, - pipeline: pipelineWithDepthStencilOnly, - }, - ]) { - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor); - renderPass.setPipeline(pipeline); - renderPass.endPass(); - - t.expectValidationError(() => { - commandEncoder.finish(); - }, !_success); - } -}).params([ - { attachmentSamples: 4, pipelineSamples: 4, _success: true }, // It is allowed to use multisampled render pass and multisampled render pipeline. - { attachmentSamples: 4, pipelineSamples: 1, _success: false }, // It is not allowed to use multisampled render pass and non-multisampled render pipeline. - { attachmentSamples: 1, pipelineSamples: 4, _success: false }, // It is not allowed to use non-multisampled render pass and multisampled render pipeline. -]); + { + renderPassDescriptor: renderPassDescriptorWithDepthStencilOnly, + pipeline: pipelineWithDepthStencilOnly, + }, + ]) { + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor); + renderPass.setPipeline(pipeline); + renderPass.endPass(); + + t.expectValidationError(() => { + commandEncoder.finish(); + }, !_success); + } + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createTexture.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createTexture.spec.ts index b34cf77e0bf..46ff763e6f4 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createTexture.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createTexture.spec.ts @@ -2,8 +2,8 @@ export const description = ` createTexture validation tests. `; -import { poptions } from '../../../common/framework/params.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { poptions } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { kTextureFormatInfo, kTextureFormats } from '../../capability_info.js'; import { ValidationTest } from './validation_test.js'; @@ -38,106 +38,115 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); - -g.test('validation of sampleCount', async t => { - const { sampleCount, mipLevelCount, arrayLayerCount, _success } = t.params; - - const descriptor = t.getDescriptor({ sampleCount, mipLevelCount, arrayLayerCount }); - - t.expectValidationError(() => { - t.device.createTexture(descriptor); - }, !_success); -}).params([ - { sampleCount: 0, _success: false }, // sampleCount of 0 is not allowed - { sampleCount: 1, _success: true }, // sampleCount of 1 is allowed - { sampleCount: 2, _success: false }, // sampleCount of 2 is not allowed - { sampleCount: 3, _success: false }, // sampleCount of 3 is not allowed - { sampleCount: 4, _success: true }, // sampleCount of 4 is allowed - { sampleCount: 8, _success: false }, // sampleCount of 8 is not allowed - { sampleCount: 16, _success: false }, // sampleCount of 16 is not allowed - { sampleCount: 4, mipLevelCount: 2, _success: false }, // it is an error to create a multisampled texture with mipLevelCount > 1 - { sampleCount: 4, arrayLayerCount: 2, _success: true }, // multisampled 2D array texture is supported -]); - -g.test('validation of mipLevelCount', async t => { - const { width, height, mipLevelCount, _success } = t.params; - - const descriptor = t.getDescriptor({ width, height, mipLevelCount }); - - t.expectValidationError(() => { - t.device.createTexture(descriptor); - }, !_success); -}).params([ - { width: 32, height: 32, mipLevelCount: 1, _success: true }, // mipLevelCount of 1 is allowed - { width: 32, height: 32, mipLevelCount: 0, _success: false }, // mipLevelCount of 0 is not allowed - { width: 32, height: 32, mipLevelCount: 6, _success: true }, // full mip chains are allowed (Mip level sizes: 32, 16, 8, 4, 2, 1) - { width: 31, height: 32, mipLevelCount: 6, _success: true }, // full mip chains are allowed (Mip level sizes: 31x32, 15x16, 7x8, 3x4, 1x2, 1x1) - { width: 32, height: 31, mipLevelCount: 6, _success: true }, // full mip chains are allowed (Mip level sizes: 32x31, 16x15, 8x7, 4x3, 2x1, 1x1) - { width: 31, height: 32, mipLevelCount: 7, _success: false }, // too big mip chains on width are disallowed (Mip level sizes: 31x32, 15x16, 7x8, 3x4, 1x2, 1x1, ?x?) - { width: 32, height: 31, mipLevelCount: 7, _success: false }, // too big mip chains on height are disallowed (Mip level sizes: 32x31, 16x15, 8x7, 4x3, 2x1, 1x1, ?x?) - { width: 32, height: 32, mipLevelCount: 100, _success: false }, // undefined shift check if miplevel is bigger than the integer bit width - { width: 32, height: 8, mipLevelCount: 6, _success: true }, // non square mip map halves the resolution until a 1x1 dimension. (Mip maps: 32 * 8, 16 * 4, 8 * 2, 4 * 1, 2 * 1, 1 * 1) -]); - -g.test('it is valid to destroy a texture', t => { +export const g = makeTestGroup(F); + +g.test('validation_of_sampleCount') + .params([ + // TODO: Consider making a list of "valid"+"invalid" texture descriptors in capability_info. + { sampleCount: 0, _success: false }, // sampleCount of 0 is not allowed + { sampleCount: 1, _success: true }, // sampleCount of 1 is allowed + { sampleCount: 2, _success: false }, // sampleCount of 2 is not allowed + { sampleCount: 3, _success: false }, // sampleCount of 3 is not allowed + { sampleCount: 4, _success: true }, // sampleCount of 4 is allowed + { sampleCount: 8, _success: false }, // sampleCount of 8 is not allowed + { sampleCount: 16, _success: false }, // sampleCount of 16 is not allowed + { sampleCount: 4, mipLevelCount: 2, _success: false }, // multisampled multi-level not allowed + { sampleCount: 4, arrayLayerCount: 2, _success: false }, // multisampled multi-layer is not allowed + ]) + .fn(async t => { + const { sampleCount, mipLevelCount, arrayLayerCount, _success } = t.params; + + const descriptor = t.getDescriptor({ sampleCount, mipLevelCount, arrayLayerCount }); + + t.expectValidationError(() => { + t.device.createTexture(descriptor); + }, !_success); + }); + +g.test('validation_of_mipLevelCount') + .params([ + { width: 32, height: 32, mipLevelCount: 1, _success: true }, // mipLevelCount of 1 is allowed + { width: 32, height: 32, mipLevelCount: 0, _success: false }, // mipLevelCount of 0 is not allowed + { width: 32, height: 32, mipLevelCount: 6, _success: true }, // full mip chains are allowed (Mip level sizes: 32, 16, 8, 4, 2, 1) + { width: 31, height: 32, mipLevelCount: 6, _success: true }, // full mip chains are allowed (Mip level sizes: 31x32, 15x16, 7x8, 3x4, 1x2, 1x1) + { width: 32, height: 31, mipLevelCount: 6, _success: true }, // full mip chains are allowed (Mip level sizes: 32x31, 16x15, 8x7, 4x3, 2x1, 1x1) + { width: 31, height: 32, mipLevelCount: 7, _success: false }, // too big mip chains on width are disallowed (Mip level sizes: 31x32, 15x16, 7x8, 3x4, 1x2, 1x1, ?x?) + { width: 32, height: 31, mipLevelCount: 7, _success: false }, // too big mip chains on height are disallowed (Mip level sizes: 32x31, 16x15, 8x7, 4x3, 2x1, 1x1, ?x?) + { width: 32, height: 32, mipLevelCount: 100, _success: false }, // undefined shift check if miplevel is bigger than the integer bit width + { width: 32, height: 8, mipLevelCount: 6, _success: true }, // non square mip map halves the resolution until a 1x1 dimension. (Mip maps: 32 * 8, 16 * 4, 8 * 2, 4 * 1, 2 * 1, 1 * 1) + ]) + .fn(async t => { + const { width, height, mipLevelCount, _success } = t.params; + + const descriptor = t.getDescriptor({ width, height, mipLevelCount }); + + t.expectValidationError(() => { + t.device.createTexture(descriptor); + }, !_success); + }); + +g.test('it_is_valid_to_destroy_a_texture').fn(t => { const descriptor = t.getDescriptor(); const texture = t.device.createTexture(descriptor); texture.destroy(); }); -g.test('it is valid to destroy a destroyed texture', t => { +g.test('it_is_valid_to_destroy_a_destroyed_texture').fn(t => { const descriptor = t.getDescriptor(); const texture = t.device.createTexture(descriptor); texture.destroy(); texture.destroy(); }); -g.test('it is invalid to submit a destroyed texture before and after encode', async t => { - const { destroyBeforeEncode, destroyAfterEncode, _success } = t.params; +g.test('it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode') + .params([ + { destroyBeforeEncode: false, destroyAfterEncode: false, _success: true }, + { destroyBeforeEncode: true, destroyAfterEncode: false, _success: false }, + { destroyBeforeEncode: false, destroyAfterEncode: true, _success: false }, + ]) + .fn(async t => { + const { destroyBeforeEncode, destroyAfterEncode, _success } = t.params; + + const descriptor = t.getDescriptor(); + const texture = t.device.createTexture(descriptor); + const textureView = texture.createView(); + + if (destroyBeforeEncode) { + texture.destroy(); + } + + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass({ + colorAttachments: [ + { + attachment: textureView, + loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, + }, + ], + }); + renderPass.endPass(); + const commandBuffer = commandEncoder.finish(); + + if (destroyAfterEncode) { + texture.destroy(); + } + + t.expectValidationError(() => { + t.queue.submit([commandBuffer]); + }, !_success); + }); - const descriptor = t.getDescriptor(); - const texture = t.device.createTexture(descriptor); - const textureView = texture.createView(); +g.test('it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format') + .params(poptions('format', kTextureFormats)) + .fn(async t => { + const format: GPUTextureFormat = t.params.format; + const info = kTextureFormatInfo[format]; - if (destroyBeforeEncode) { - texture.destroy(); - } + const descriptor = t.getDescriptor({ width: 1, height: 1, format }); - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = commandEncoder.beginRenderPass({ - colorAttachments: [ - { - attachment: textureView, - loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, - }, - ], + t.expectValidationError(() => { + t.device.createTexture(descriptor); + }, !info.renderable); }); - renderPass.endPass(); - const commandBuffer = commandEncoder.finish(); - - if (destroyAfterEncode) { - texture.destroy(); - } - - t.expectValidationError(() => { - t.queue.submit([commandBuffer]); - }, !_success); -}).params([ - { destroyBeforeEncode: false, destroyAfterEncode: false, _success: true }, - { destroyBeforeEncode: true, destroyAfterEncode: false, _success: false }, - { destroyBeforeEncode: false, destroyAfterEncode: true, _success: false }, -]); - -g.test('it is invalid to have an output attachment texture with non renderable format', async t => { - const format: GPUTextureFormat = t.params.format; - const info = kTextureFormatInfo[format]; - - const descriptor = t.getDescriptor({ width: 1, height: 1, format }); - - t.expectValidationError(() => { - t.device.createTexture(descriptor); - }, !info.renderable); -}).params(poptions('format', kTextureFormats)); // TODO: Add tests for compressed texture formats diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createView.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createView.spec.ts index 695a9737de4..18033f17384 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createView.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/createView.spec.ts @@ -2,7 +2,7 @@ export const description = ` createView validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -67,76 +67,94 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); + +g.test('creating_texture_view_on_a_2D_non_array_texture') + .params([ + { _success: true }, // default view works + { arrayLayerCount: 1, _success: true }, // it is OK to create a 2D texture view on a 2D texture + { arrayLayerCount: 2, _success: false }, // it is an error to view a layer past the end of the texture + { dimension: '2d-array' as const, arrayLayerCount: 1, _success: true }, // it is OK to create a 1-layer 2D array texture view on a 2D texture + // mip level is in range + { mipLevelCount: 1, baseMipLevel: MIP_LEVEL_COUNT - 1, _success: true }, + { mipLevelCount: 2, baseMipLevel: MIP_LEVEL_COUNT - 2, _success: true }, + // baseMipLevel == k && mipLevelCount == 0 means to use levels k..end + { mipLevelCount: 0, baseMipLevel: 0, _success: true }, + { mipLevelCount: 0, baseMipLevel: 1, _success: true }, + { mipLevelCount: 0, baseMipLevel: MIP_LEVEL_COUNT - 1, _success: true }, + { mipLevelCount: 0, baseMipLevel: MIP_LEVEL_COUNT, _success: false }, + // it is an error to make the mip level out of range + { mipLevelCount: MIP_LEVEL_COUNT + 1, baseMipLevel: 0, _success: false }, + { mipLevelCount: MIP_LEVEL_COUNT, baseMipLevel: 1, _success: false }, + { mipLevelCount: 2, baseMipLevel: MIP_LEVEL_COUNT - 1, _success: false }, + { mipLevelCount: 1, baseMipLevel: MIP_LEVEL_COUNT, _success: false }, + ]) + .fn(async t => { + const { dimension = '2d', arrayLayerCount, mipLevelCount, baseMipLevel, _success } = t.params; + + const texture = t.createTexture({ arrayLayerCount: 1 }); + + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount, + mipLevelCount, + baseMipLevel, + }); -g.test('creating texture view on a 2D non array texture', async t => { - const { dimension = '2d', arrayLayerCount, mipLevelCount, baseMipLevel, _success } = t.params; + t.expectValidationError(() => { + texture.createView(descriptor); + }, !_success); + }); - const texture = t.createTexture({ arrayLayerCount: 1 }); +g.test('creating_texture_view_on_a_2D_array_texture') + .params([ + { _success: true }, // default view works + { dimension: '2d' as const, arrayLayerCount: 1, _success: true }, // it is OK to create a 2D texture view on a 2D array texture + { arrayLayerCount: ARRAY_LAYER_COUNT_2D, _success: true }, // it is OK to create a 2D array texture view on a 2D array texture + // baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end. + { arrayLayerCount: 0, baseArrayLayer: 0, _success: true }, + { arrayLayerCount: 0, baseArrayLayer: 1, _success: true }, + { arrayLayerCount: 0, baseArrayLayer: ARRAY_LAYER_COUNT_2D - 1, _success: true }, + { arrayLayerCount: 0, baseArrayLayer: ARRAY_LAYER_COUNT_2D, _success: false }, + // It is an error for the array layer range of the view to exceed that of the texture + { arrayLayerCount: ARRAY_LAYER_COUNT_2D + 1, baseArrayLayer: 0, _success: false }, + { arrayLayerCount: ARRAY_LAYER_COUNT_2D, baseArrayLayer: 1, _success: false }, + { arrayLayerCount: 2, baseArrayLayer: ARRAY_LAYER_COUNT_2D - 1, _success: false }, + { arrayLayerCount: 1, baseArrayLayer: ARRAY_LAYER_COUNT_2D, _success: false }, + ]) + .fn(async t => { + const { dimension = '2d-array', arrayLayerCount, baseArrayLayer, _success } = t.params; - const descriptor = t.getDescriptor({ - dimension, - arrayLayerCount, - mipLevelCount, - baseMipLevel, - }); + const texture = t.createTexture({ arrayLayerCount: ARRAY_LAYER_COUNT_2D }); - t.expectValidationError(() => { - texture.createView(descriptor); - }, !_success); -}).params([ - { _success: true }, // default view works - { arrayLayerCount: 1, _success: true }, // it is OK to create a 2D texture view on a 2D texture - { arrayLayerCount: 2, _success: false }, // it is an error to view a layer past the end of the texture - { dimension: '2d-array', arrayLayerCount: 1, _success: true }, // it is OK to create a 1-layer 2D array texture view on a 2D texture - // mip level is in range - { mipLevelCount: 1, baseMipLevel: MIP_LEVEL_COUNT - 1, _success: true }, - { mipLevelCount: 2, baseMipLevel: MIP_LEVEL_COUNT - 2, _success: true }, - // baseMipLevel == k && mipLevelCount == 0 means to use levels k..end - { mipLevelCount: 0, baseMipLevel: 0, _success: true }, - { mipLevelCount: 0, baseMipLevel: 1, _success: true }, - { mipLevelCount: 0, baseMipLevel: MIP_LEVEL_COUNT - 1, _success: true }, - { mipLevelCount: 0, baseMipLevel: MIP_LEVEL_COUNT, _success: false }, - // it is an error to make the mip level out of range - { mipLevelCount: MIP_LEVEL_COUNT + 1, baseMipLevel: 0, _success: false }, - { mipLevelCount: MIP_LEVEL_COUNT, baseMipLevel: 1, _success: false }, - { mipLevelCount: 2, baseMipLevel: MIP_LEVEL_COUNT - 1, _success: false }, - { mipLevelCount: 1, baseMipLevel: MIP_LEVEL_COUNT, _success: false }, -]); - -g.test('creating texture view on a 2D array texture', async t => { - const { dimension = '2d-array', arrayLayerCount, baseArrayLayer, _success } = t.params; - - const texture = t.createTexture({ arrayLayerCount: ARRAY_LAYER_COUNT_2D }); + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount, + baseArrayLayer, + }); - const descriptor = t.getDescriptor({ - dimension, - arrayLayerCount, - baseArrayLayer, + t.expectValidationError(() => { + texture.createView(descriptor); + }, !_success); }); - t.expectValidationError(() => { - texture.createView(descriptor); - }, !_success); -}).params([ - { _success: true }, // default view works - { dimension: '2d', arrayLayerCount: 1, _success: true }, // it is OK to create a 2D texture view on a 2D array texture - { arrayLayerCount: ARRAY_LAYER_COUNT_2D, _success: true }, // it is OK to create a 2D array texture view on a 2D array texture - // baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end. - { arrayLayerCount: 0, baseArrayLayer: 0, _success: true }, - { arrayLayerCount: 0, baseArrayLayer: 1, _success: true }, - { arrayLayerCount: 0, baseArrayLayer: ARRAY_LAYER_COUNT_2D - 1, _success: true }, - { arrayLayerCount: 0, baseArrayLayer: ARRAY_LAYER_COUNT_2D, _success: false }, - // It is an error for the array layer range of the view to exceed that of the texture - { arrayLayerCount: ARRAY_LAYER_COUNT_2D + 1, baseArrayLayer: 0, _success: false }, - { arrayLayerCount: ARRAY_LAYER_COUNT_2D, baseArrayLayer: 1, _success: false }, - { arrayLayerCount: 2, baseArrayLayer: ARRAY_LAYER_COUNT_2D - 1, _success: false }, - { arrayLayerCount: 1, baseArrayLayer: ARRAY_LAYER_COUNT_2D, _success: false }, -]); - -g.test( - 'Using defaults validates the same as setting values for more than 1 array layer', - async t => { +g.test('Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer') + .params([ + { _success: true }, + { format: 'rgba8unorm', _success: true }, + { format: 'r8unorm', _success: false }, + { dimension: '2d-array', _success: true }, + { dimension: '2d', _success: false }, + { arrayLayerCount: ARRAY_LAYER_COUNT_2D, _success: false }, // setting array layers to non-0 means the dimensionality will default to 2D so by itself it causes an error. + { arrayLayerCount: ARRAY_LAYER_COUNT_2D, dimension: '2d-array', _success: true }, + { + arrayLayerCount: ARRAY_LAYER_COUNT_2D, + dimension: '2d-array', + mipLevelCount: MIP_LEVEL_COUNT, + _success: true, + }, + ] as const) + .fn(async t => { const { format, dimension, arrayLayerCount, mipLevelCount, _success } = t.params; const texture = t.createTexture({ arrayLayerCount: ARRAY_LAYER_COUNT_2D }); @@ -146,97 +164,88 @@ g.test( t.expectValidationError(() => { texture.createView(descriptor); }, !_success); - } -).params([ - { _success: true }, - { format: 'rgba8unorm', _success: true }, - { format: 'r8unorm', _success: false }, - { dimension: '2d-array', _success: true }, - { dimension: '2d', _success: false }, - { arrayLayerCount: ARRAY_LAYER_COUNT_2D, _success: false }, // setting array layers to non-0 means the dimensionality will default to 2D so by itself it causes an error. - { arrayLayerCount: ARRAY_LAYER_COUNT_2D, dimension: '2d-array', _success: true }, - { - arrayLayerCount: ARRAY_LAYER_COUNT_2D, - dimension: '2d-array', - mipLevelCount: MIP_LEVEL_COUNT, - _success: true, - }, -]); - -g.test('Using defaults validates the same as setting values for only 1 array layer', async t => { - const { format, dimension, arrayLayerCount, mipLevelCount, _success } = t.params; + }); - const texture = t.createTexture({ arrayLayerCount: 1 }); +g.test('Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer') + .params([ + { _success: true }, + { format: 'rgba8unorm', _success: true }, + { format: 'r8unorm', _success: false }, + { dimension: '2d-array', _success: true }, + { dimension: '2d', _success: true }, + { arrayLayerCount: 0, _success: true }, + { arrayLayerCount: 1, _success: true }, + { arrayLayerCount: 2, _success: false }, + { mipLevelCount: MIP_LEVEL_COUNT, _success: true }, + { mipLevelCount: 1, _success: true }, + ] as const) + .fn(async t => { + const { format, dimension, arrayLayerCount, mipLevelCount, _success } = t.params; - const descriptor = { format, dimension, arrayLayerCount, mipLevelCount }; + const texture = t.createTexture({ arrayLayerCount: 1 }); - t.expectValidationError(() => { - texture.createView(descriptor); - }, !_success); -}).params([ - { _success: true }, - { format: 'rgba8unorm', _success: true }, - { format: 'r8unorm', _success: false }, - { dimension: '2d-array', _success: true }, - { dimension: '2d', _success: true }, - { arrayLayerCount: 0, _success: true }, - { arrayLayerCount: 1, _success: true }, - { arrayLayerCount: 2, _success: false }, - { mipLevelCount: MIP_LEVEL_COUNT, _success: true }, - { mipLevelCount: 1, _success: true }, -]); - -g.test('creating cube map texture view', async t => { - const { dimension = '2d-array', arrayLayerCount, _success } = t.params; - - const texture = t.createTexture({ arrayLayerCount: 16 }); + const descriptor = { format, dimension, arrayLayerCount, mipLevelCount }; - const descriptor = t.getDescriptor({ - dimension, - arrayLayerCount, + t.expectValidationError(() => { + texture.createView(descriptor); + }, !_success); }); - t.expectValidationError(() => { - texture.createView(descriptor); - }, !_success); -}).params([ - { dimension: 'cube', arrayLayerCount: 6, _success: true }, // it is OK to create a cube map texture view with arrayLayerCount == 6 - // it is an error to create a cube map texture view with arrayLayerCount != 6 - { dimension: 'cube', arrayLayerCount: 3, _success: false }, - { dimension: 'cube', arrayLayerCount: 7, _success: false }, - { dimension: 'cube', arrayLayerCount: 12, _success: false }, - { dimension: 'cube', _success: false }, - { dimension: 'cube-array', arrayLayerCount: 12, _success: true }, // it is OK to create a cube map array texture view with arrayLayerCount % 6 == 0 - // it is an error to create a cube map array texture view with arrayLayerCount % 6 != 0 - { dimension: 'cube-array', arrayLayerCount: 11, _success: false }, - { dimension: 'cube-array', arrayLayerCount: 13, _success: false }, -]); - -g.test('creating cube map texture view with a non square texture', async t => { - const { dimension, arrayLayerCount } = t.params; - - const nonSquareTexture = t.createTexture({ - arrayLayerCount: 18, - width: 32, - height: 16, - mipLevelCount: 5, - }); +g.test('creating_cube_map_texture_view') + .params([ + { dimension: 'cube', arrayLayerCount: 6, _success: true }, // it is OK to create a cube map texture view with arrayLayerCount == 6 + // it is an error to create a cube map texture view with arrayLayerCount != 6 + { dimension: 'cube', arrayLayerCount: 3, _success: false }, + { dimension: 'cube', arrayLayerCount: 7, _success: false }, + { dimension: 'cube', arrayLayerCount: 12, _success: false }, + { dimension: 'cube', _success: false }, + { dimension: 'cube-array', arrayLayerCount: 12, _success: true }, // it is OK to create a cube map array texture view with arrayLayerCount % 6 == 0 + // it is an error to create a cube map array texture view with arrayLayerCount % 6 != 0 + { dimension: 'cube-array', arrayLayerCount: 11, _success: false }, + { dimension: 'cube-array', arrayLayerCount: 13, _success: false }, + ] as const) + .fn(async t => { + const { dimension = '2d-array', arrayLayerCount, _success } = t.params; + + const texture = t.createTexture({ arrayLayerCount: 16 }); + + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount, + }); - const descriptor = t.getDescriptor({ - dimension, - arrayLayerCount, + t.expectValidationError(() => { + texture.createView(descriptor); + }, !_success); }); - t.expectValidationError(() => { - nonSquareTexture.createView(descriptor); +g.test('creating_cube_map_texture_view_with_a_non_square_texture') + .params([ + { dimension: 'cube', arrayLayerCount: 6 }, // it is an error to create a cube map texture view with width != height. + { dimension: 'cube-array', arrayLayerCount: 12 }, // it is an error to create a cube map array texture view with width != height. + ] as const) + .fn(async t => { + const { dimension, arrayLayerCount } = t.params; + + const nonSquareTexture = t.createTexture({ + arrayLayerCount: 18, + width: 32, + height: 16, + mipLevelCount: 5, + }); + + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount, + }); + + t.expectValidationError(() => { + nonSquareTexture.createView(descriptor); + }); }); -}).params([ - { dimension: 'cube', arrayLayerCount: 6 }, // it is an error to create a cube map texture view with width != height. - { dimension: 'cube-array', arrayLayerCount: 12 }, // it is an error to create a cube map array texture view with width != height. -]); // TODO: add more tests when rules are fully implemented. -g.test('test the format compatibility rules when creating a texture view', async t => { +g.test('test_the_format_compatibility_rules_when_creating_a_texture_view').fn(async t => { const texture = t.createTexture({ arrayLayerCount: 1 }); const descriptor = t.getDescriptor({ @@ -249,7 +258,7 @@ g.test('test the format compatibility rules when creating a texture view', async }); }); -g.test('it is invalid to use a texture view created from a destroyed texture', async t => { +g.test('it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture').fn(async t => { const texture = t.createTexture({ arrayLayerCount: 1 }); const commandEncoder = t.device.createCommandEncoder(); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/error_scope.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/error_scope.spec.ts index 1a5b8984080..eb2a2166ac0 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/error_scope.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/error_scope.spec.ts @@ -4,7 +4,7 @@ error scope validation tests. import { Fixture } from '../../../common/framework/fixture.js'; import { getGPU } from '../../../common/framework/gpu/implementation.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { assert, raceWithRejectOnTimeout } from '../../../common/framework/util/util.js'; class F extends Fixture { @@ -58,9 +58,9 @@ class F extends Fixture { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('simple case where the error scope catches an error', async t => { +g.test('simple_case_where_the_error_scope_catches_an_error').fn(async t => { t.device.pushErrorScope('validation'); t.createErrorBuffer(); @@ -69,7 +69,7 @@ g.test('simple case where the error scope catches an error', async t => { t.expect(error instanceof GPUValidationError); }); -g.test('errors bubble to the parent scope if not handled by the current scope', async t => { +g.test('errors_bubble_to_the_parent_scope_if_not_handled_by_the_current_scope').fn(async t => { t.device.pushErrorScope('validation'); t.device.pushErrorScope('out-of-memory'); @@ -85,7 +85,7 @@ g.test('errors bubble to the parent scope if not handled by the current scope', } }); -g.test('if an error scope matches an error it does not bubble to the parent scope', async t => { +g.test('if_an_error_scope_matches_an_error_it_does_not_bubble_to_the_parent_scope').fn(async t => { t.device.pushErrorScope('validation'); t.device.pushErrorScope('validation'); @@ -101,7 +101,7 @@ g.test('if an error scope matches an error it does not bubble to the parent scop } }); -g.test('if no error scope handles an error it fires an uncapturederror event', async t => { +g.test('if_no_error_scope_handles_an_error_it_fires_an_uncapturederror_event').fn(async t => { t.device.pushErrorScope('out-of-memory'); const uncapturedErrorEvent = await t.expectUncapturedError(() => { @@ -113,7 +113,7 @@ g.test('if no error scope handles an error it fires an uncapturederror event', a t.expect(error === null); }); -g.test('push/popping sibling error scopes must be balanced', async t => { +g.test('push,popping_sibling_error_scopes_must_be_balanced').fn(async t => { { const promise = t.device.popErrorScope(); t.shouldReject('OperationError', promise); @@ -133,7 +133,7 @@ g.test('push/popping sibling error scopes must be balanced', async t => { } }); -g.test('push/popping nested error scopes must be balanced', async t => { +g.test('push,popping_nested_error_scopes_must_be_balanced').fn(async t => { { const promise = t.device.popErrorScope(); t.shouldReject('OperationError', promise); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/fences.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/fences.spec.ts index a89fcff13ee..32d133304ef 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/fences.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/fences.spec.ts @@ -2,14 +2,14 @@ export const description = ` fences validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; -export const g = new TestGroup(ValidationTest); +export const g = makeTestGroup(ValidationTest); // TODO: Remove if https://github.com/gpuweb/gpuweb/issues/377 is decided -g.test('wait on a fence without signaling the value is invalid', async t => { +g.test('wait_on_a_fence_without_signaling_the_value_is_invalid').fn(async t => { const fence = t.queue.createFence(); t.expectValidationError(() => { @@ -19,7 +19,7 @@ g.test('wait on a fence without signaling the value is invalid', async t => { }); // TODO: Remove if https://github.com/gpuweb/gpuweb/issues/377 is decided -g.test('wait on a fence with a value greater than signaled value is invalid', async t => { +g.test('wait_on_a_fence_with_a_value_greater_than_signaled_value_is_invalid').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); @@ -29,7 +29,7 @@ g.test('wait on a fence with a value greater than signaled value is invalid', as }); }); -g.test('signal a value lower than signaled value is invalid', async t => { +g.test('signal_a_value_lower_than_signaled_value_is_invalid').fn(async t => { const fence = t.queue.createFence({ initialValue: 1 }); t.expectValidationError(() => { @@ -37,7 +37,7 @@ g.test('signal a value lower than signaled value is invalid', async t => { }); }); -g.test('signal a value equal to signaled value is invalid', async t => { +g.test('signal_a_value_equal_to_signaled_value_is_invalid').fn(async t => { const fence = t.queue.createFence({ initialValue: 1 }); t.expectValidationError(() => { @@ -45,7 +45,7 @@ g.test('signal a value equal to signaled value is invalid', async t => { }); }); -g.test('increasing fence value by more than 1 succeeds', async t => { +g.test('increasing_fence_value_by_more_than_1_succeeds').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); @@ -55,29 +55,33 @@ g.test('increasing fence value by more than 1 succeeds', async t => { await fence.onCompletion(6); }); -g.test('signal a fence on a different device than it was created on is invalid', async t => { - const fence = t.queue.createFence(); - +g.test('signal_a_fence_on_a_different_device_than_it_was_created_on_is_invalid').fn(async t => { const anotherDevice = await t.device.adapter.requestDevice(); - const anotherQueue = anotherDevice.defaultQueue; + const fence = anotherDevice.defaultQueue.createFence(); t.expectValidationError(() => { - anotherQueue.signal(fence, 2); + t.queue.signal(fence, 2); }); }); -g.test('signal a fence on a different device does not update fence signaled value', async t => { - const fence = t.queue.createFence({ initialValue: 1 }); - +g.test('signal_a_fence_on_a_different_device_does_not_update_fence_signaled_value').fn(async t => { const anotherDevice = await t.device.adapter.requestDevice(); - const anotherQueue = anotherDevice.defaultQueue; + const fence = anotherDevice.defaultQueue.createFence({ initialValue: 1 }); t.expectValidationError(() => { - anotherQueue.signal(fence, 2); + t.queue.signal(fence, 2); }); t.expect(fence.getCompletedValue() === 1); - t.queue.signal(fence, 2); + anotherDevice.pushErrorScope('validation'); + + anotherDevice.defaultQueue.signal(fence, 2); await fence.onCompletion(2); + t.expect(fence.getCompletedValue() === 2); + + const gpuValidationError = await anotherDevice.popErrorScope(); + if (gpuValidationError instanceof GPUValidationError) { + t.fail(`Captured validation error - ${gpuValidationError.message}`); + } }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/queue_submit.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/queue_submit.spec.ts index b8d93a920a0..fd11ec0c8b0 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/queue_submit.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/queue_submit.spec.ts @@ -2,13 +2,13 @@ export const description = ` queue submit validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; -export const g = new TestGroup(ValidationTest); +export const g = makeTestGroup(ValidationTest); -g.test('submitting with a mapped buffer is disallowed', async t => { +g.test('submitting_with_a_mapped_buffer_is_disallowed').fn(async t => { const buffer = t.device.createBuffer({ size: 4, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC, diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass.spec.ts index 88801f49b9e..f0e36b3b350 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass.spec.ts @@ -2,14 +2,14 @@ export const description = ` render pass validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; class F extends ValidationTest { getUniformBuffer(): GPUBuffer { return this.device.createBuffer({ - size: 4 * Float32Array.BYTES_PER_ELEMENT, + size: 8 * Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM, }); } @@ -67,80 +67,82 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('it is invalid to draw in a render pass with missing bind groups', async t => { - const { setBindGroup1, setBindGroup2, _success } = t.params; +g.test('it_is_invalid_to_draw_in_a_render_pass_with_missing_bind_groups') + .params([ + { setBindGroup1: true, setBindGroup2: true, _success: true }, + { setBindGroup1: true, setBindGroup2: false, _success: false }, + { setBindGroup1: false, setBindGroup2: true, _success: false }, + { setBindGroup1: false, setBindGroup2: false, _success: false }, + ]) + .fn(async t => { + const { setBindGroup1, setBindGroup2, _success } = t.params; - const uniformBuffer = t.getUniformBuffer(); + const uniformBuffer = t.getUniformBuffer(); - const bindGroupLayout1 = t.device.createBindGroupLayout({ - entries: [ - { - binding: 0, - visibility: GPUShaderStage.VERTEX, - type: 'uniform-buffer', - }, - ], - }); - - const bindGroup1 = t.device.createBindGroup({ - entries: [ - { - binding: 0, - resource: { - buffer: uniformBuffer, + const bindGroupLayout1 = t.device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: GPUShaderStage.VERTEX, + type: 'uniform-buffer', }, - }, - ], - layout: bindGroupLayout1, - }); + ], + }); - const bindGroupLayout2 = t.device.createBindGroupLayout({ - entries: [ - { - binding: 0, - visibility: GPUShaderStage.FRAGMENT, - type: 'uniform-buffer', - }, - ], - }); + const bindGroup1 = t.device.createBindGroup({ + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + }, + }, + ], + layout: bindGroupLayout1, + }); - const bindGroup2 = t.device.createBindGroup({ - entries: [ - { - binding: 0, - resource: { - buffer: uniformBuffer, + const bindGroupLayout2 = t.device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type: 'uniform-buffer', }, - }, - ], - layout: bindGroupLayout2, - }); + ], + }); - const pipelineLayout = t.device.createPipelineLayout({ - bindGroupLayouts: [bindGroupLayout1, bindGroupLayout2], - }); + const bindGroup2 = t.device.createBindGroup({ + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + }, + }, + ], + layout: bindGroupLayout2, + }); - const pipeline = t.createRenderPipeline(pipelineLayout); + const pipelineLayout = t.device.createPipelineLayout({ + bindGroupLayouts: [bindGroupLayout1, bindGroupLayout2], + }); - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline); - if (setBindGroup1) { - renderPass.setBindGroup(0, bindGroup1); - } - if (setBindGroup2) { - renderPass.setBindGroup(1, bindGroup2); - } - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - t.expectValidationError(() => { - commandEncoder.finish(); - }, !_success); -}).params([ - { setBindGroup1: true, setBindGroup2: true, _success: true }, - { setBindGroup1: true, setBindGroup2: false, _success: false }, - { setBindGroup1: false, setBindGroup2: true, _success: false }, - { setBindGroup1: false, setBindGroup2: false, _success: false }, -]); + const pipeline = t.createRenderPipeline(pipelineLayout); + + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline); + if (setBindGroup1) { + renderPass.setBindGroup(0, bindGroup1); + } + if (setBindGroup2) { + renderPass.setBindGroup(1, bindGroup2); + } + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + t.expectValidationError(() => { + commandEncoder.finish(); + }, !_success); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass_descriptor.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass_descriptor.spec.ts index 192de3adfdd..a40a0f13e92 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass_descriptor.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/render_pass_descriptor.spec.ts @@ -2,7 +2,7 @@ export const description = ` render pass descriptor validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -75,9 +75,9 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('a render pass with only one color is ok', t => { +g.test('a_render_pass_with_only_one_color_is_ok').fn(t => { const colorTexture = t.createTexture({ format: 'rgba8unorm' }); const descriptor = { colorAttachments: [t.getColorAttachment(colorTexture)], @@ -86,7 +86,7 @@ g.test('a render pass with only one color is ok', t => { t.tryRenderPass(true, descriptor); }); -g.test('a render pass with only one depth attachment is ok', t => { +g.test('a_render_pass_with_only_one_depth_attachment_is_ok').fn(t => { const depthStencilTexture = t.createTexture({ format: 'depth24plus-stencil8' }); const descriptor = { colorAttachments: [], @@ -96,22 +96,24 @@ g.test('a render pass with only one depth attachment is ok', t => { t.tryRenderPass(true, descriptor); }); -g.test('OOB color attachment indices are handled', async t => { - const { colorAttachmentsCount, _success } = t.params; - - const colorAttachments = []; - for (let i = 0; i < colorAttachmentsCount; i++) { - const colorTexture = t.createTexture(); - colorAttachments.push(t.getColorAttachment(colorTexture)); - } - - await t.tryRenderPass(_success, { colorAttachments }); -}).params([ - { colorAttachmentsCount: 4, _success: true }, // Control case - { colorAttachmentsCount: 5, _success: false }, // Out of bounds -]); +g.test('OOB_color_attachment_indices_are_handled') + .params([ + { colorAttachmentsCount: 4, _success: true }, // Control case + { colorAttachmentsCount: 5, _success: false }, // Out of bounds + ]) + .fn(async t => { + const { colorAttachmentsCount, _success } = t.params; + + const colorAttachments = []; + for (let i = 0; i < colorAttachmentsCount; i++) { + const colorTexture = t.createTexture(); + colorAttachments.push(t.getColorAttachment(colorTexture)); + } + + await t.tryRenderPass(_success, { colorAttachments }); + }); -g.test('attachments must have the same size', async t => { +g.test('attachments_must_have_the_same_size').fn(async t => { const colorTexture1x1A = t.createTexture({ width: 1, height: 1, format: 'rgba8unorm' }); const colorTexture1x1B = t.createTexture({ width: 1, height: 1, format: 'rgba8unorm' }); const colorTexture2x2 = t.createTexture({ width: 2, height: 2, format: 'rgba8unorm' }); @@ -163,7 +165,7 @@ g.test('attachments must have the same size', async t => { } }); -g.test('attachments must match whether they are used for color or depth stencil', async t => { +g.test('attachments_must_match_whether_they_are_used_for_color_or_depth_stencil').fn(async t => { const colorTexture = t.createTexture({ format: 'rgba8unorm' }); const depthStencilTexture = t.createTexture({ format: 'depth24plus-stencil8' }); @@ -186,158 +188,164 @@ g.test('attachments must match whether they are used for color or depth stencil' } }); -g.test('check layer count for color or depth stencil', async t => { - const { arrayLayerCount, baseArrayLayer, _success } = t.params; - - const ARRAY_LAYER_COUNT = 10; - const MIP_LEVEL_COUNT = 1; - const COLOR_FORMAT = 'rgba8unorm'; - const DEPTH_STENCIL_FORMAT = 'depth24plus-stencil8'; - - const colorTexture = t.createTexture({ - format: COLOR_FORMAT, - width: 32, - height: 32, - mipLevelCount: MIP_LEVEL_COUNT, - arrayLayerCount: ARRAY_LAYER_COUNT, - }); - const depthStencilTexture = t.createTexture({ - format: DEPTH_STENCIL_FORMAT, - width: 32, - height: 32, - mipLevelCount: MIP_LEVEL_COUNT, - arrayLayerCount: ARRAY_LAYER_COUNT, - }); - - const baseTextureViewDescriptor: GPUTextureViewDescriptor = { - dimension: '2d-array', - baseArrayLayer, - arrayLayerCount, - baseMipLevel: 0, - mipLevelCount: MIP_LEVEL_COUNT, - }; - - { - // Check 2D array texture view for color - const textureViewDescriptor: GPUTextureViewDescriptor = { - ...baseTextureViewDescriptor, +g.test('check_layer_count_for_color_or_depth_stencil') + .params([ + { arrayLayerCount: 5, baseArrayLayer: 0, _success: false }, // using 2D array texture view with arrayLayerCount > 1 is not allowed + { arrayLayerCount: 1, baseArrayLayer: 0, _success: true }, // using 2D array texture view that covers the first layer of the texture is OK + { arrayLayerCount: 1, baseArrayLayer: 9, _success: true }, // using 2D array texture view that covers the last layer is OK for depth stencil + ]) + .fn(async t => { + const { arrayLayerCount, baseArrayLayer, _success } = t.params; + + const ARRAY_LAYER_COUNT = 10; + const MIP_LEVEL_COUNT = 1; + const COLOR_FORMAT = 'rgba8unorm'; + const DEPTH_STENCIL_FORMAT = 'depth24plus-stencil8'; + + const colorTexture = t.createTexture({ format: COLOR_FORMAT, - }; - - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [t.getColorAttachment(colorTexture, textureViewDescriptor)], - }; - - await t.tryRenderPass(_success, descriptor); - } - { - // Check 2D array texture view for depth stencil - const textureViewDescriptor: GPUTextureViewDescriptor = { - ...baseTextureViewDescriptor, + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT, + }); + const depthStencilTexture = t.createTexture({ format: DEPTH_STENCIL_FORMAT, - }; + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT, + }); - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [], - depthStencilAttachment: t.getDepthStencilAttachment( - depthStencilTexture, - textureViewDescriptor - ), + const baseTextureViewDescriptor: GPUTextureViewDescriptor = { + dimension: '2d-array', + baseArrayLayer, + arrayLayerCount, + baseMipLevel: 0, + mipLevelCount: MIP_LEVEL_COUNT, }; - await t.tryRenderPass(_success, descriptor); - } -}).params([ - { arrayLayerCount: 5, baseArrayLayer: 0, _success: false }, // using 2D array texture view with arrayLayerCount > 1 is not allowed - { arrayLayerCount: 1, baseArrayLayer: 0, _success: true }, // using 2D array texture view that covers the first layer of the texture is OK - { arrayLayerCount: 1, baseArrayLayer: 9, _success: true }, // using 2D array texture view that covers the last layer is OK for depth stencil -]); - -g.test('check mip level count for color or depth stencil', async t => { - const { mipLevelCount, baseMipLevel, _success } = t.params; - - const ARRAY_LAYER_COUNT = 1; - const MIP_LEVEL_COUNT = 4; - const COLOR_FORMAT = 'rgba8unorm'; - const DEPTH_STENCIL_FORMAT = 'depth24plus-stencil8'; - - const colorTexture = t.createTexture({ - format: COLOR_FORMAT, - width: 32, - height: 32, - mipLevelCount: MIP_LEVEL_COUNT, - arrayLayerCount: ARRAY_LAYER_COUNT, - }); - const depthStencilTexture = t.createTexture({ - format: DEPTH_STENCIL_FORMAT, - width: 32, - height: 32, - mipLevelCount: MIP_LEVEL_COUNT, - arrayLayerCount: ARRAY_LAYER_COUNT, + { + // Check 2D array texture view for color + const textureViewDescriptor: GPUTextureViewDescriptor = { + ...baseTextureViewDescriptor, + format: COLOR_FORMAT, + }; + + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [t.getColorAttachment(colorTexture, textureViewDescriptor)], + }; + + await t.tryRenderPass(_success, descriptor); + } + { + // Check 2D array texture view for depth stencil + const textureViewDescriptor: GPUTextureViewDescriptor = { + ...baseTextureViewDescriptor, + format: DEPTH_STENCIL_FORMAT, + }; + + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment( + depthStencilTexture, + textureViewDescriptor + ), + }; + + await t.tryRenderPass(_success, descriptor); + } }); - const baseTextureViewDescriptor: GPUTextureViewDescriptor = { - dimension: '2d', - baseArrayLayer: 0, - arrayLayerCount: ARRAY_LAYER_COUNT, - baseMipLevel, - mipLevelCount, - }; - - { - // Check 2D texture view for color - const textureViewDescriptor: GPUTextureViewDescriptor = { - ...baseTextureViewDescriptor, +g.test('check_mip_level_count_for_color_or_depth_stencil') + .params([ + { mipLevelCount: 2, baseMipLevel: 0, _success: false }, // using 2D texture view with mipLevelCount > 1 is not allowed + { mipLevelCount: 1, baseMipLevel: 0, _success: true }, // using 2D texture view that covers the first level of the texture is OK + { mipLevelCount: 1, baseMipLevel: 3, _success: true }, // using 2D texture view that covers the last level of the texture is OK + ]) + .fn(async t => { + const { mipLevelCount, baseMipLevel, _success } = t.params; + + const ARRAY_LAYER_COUNT = 1; + const MIP_LEVEL_COUNT = 4; + const COLOR_FORMAT = 'rgba8unorm'; + const DEPTH_STENCIL_FORMAT = 'depth24plus-stencil8'; + + const colorTexture = t.createTexture({ format: COLOR_FORMAT, - }; + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT, + }); + const depthStencilTexture = t.createTexture({ + format: DEPTH_STENCIL_FORMAT, + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT, + }); - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [t.getColorAttachment(colorTexture, textureViewDescriptor)], + const baseTextureViewDescriptor: GPUTextureViewDescriptor = { + dimension: '2d', + baseArrayLayer: 0, + arrayLayerCount: ARRAY_LAYER_COUNT, + baseMipLevel, + mipLevelCount, }; - await t.tryRenderPass(_success, descriptor); - } - { - // Check 2D texture view for depth stencil - const textureViewDescriptor: GPUTextureViewDescriptor = { - ...baseTextureViewDescriptor, - format: DEPTH_STENCIL_FORMAT, - }; + { + // Check 2D texture view for color + const textureViewDescriptor: GPUTextureViewDescriptor = { + ...baseTextureViewDescriptor, + format: COLOR_FORMAT, + }; + + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [t.getColorAttachment(colorTexture, textureViewDescriptor)], + }; + + await t.tryRenderPass(_success, descriptor); + } + { + // Check 2D texture view for depth stencil + const textureViewDescriptor: GPUTextureViewDescriptor = { + ...baseTextureViewDescriptor, + format: DEPTH_STENCIL_FORMAT, + }; + + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment( + depthStencilTexture, + textureViewDescriptor + ), + }; + + await t.tryRenderPass(_success, descriptor); + } + }); + +g.test('it_is_invalid_to_set_resolve_target_if_color_attachment_is_non_multisampled').fn( + async t => { + const colorTexture = t.createTexture({ sampleCount: 1 }); + const resolveTargetTexture = t.createTexture({ sampleCount: 1 }); const descriptor: GPURenderPassDescriptor = { - colorAttachments: [], - depthStencilAttachment: t.getDepthStencilAttachment( - depthStencilTexture, - textureViewDescriptor - ), + colorAttachments: [ + { + attachment: colorTexture.createView(), + resolveTarget: resolveTargetTexture.createView(), + loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, + }, + ], }; - await t.tryRenderPass(_success, descriptor); + await t.tryRenderPass(false, descriptor); } -}).params([ - { mipLevelCount: 2, baseMipLevel: 0, _success: false }, // using 2D texture view with mipLevelCount > 1 is not allowed - { mipLevelCount: 1, baseMipLevel: 0, _success: true }, // using 2D texture view that covers the first level of the texture is OK - { mipLevelCount: 1, baseMipLevel: 3, _success: true }, // using 2D texture view that covers the last level of the texture is OK -]); - -g.test('it is invalid to set resolve target if color attachment is non multisampled', async t => { - const colorTexture = t.createTexture({ sampleCount: 1 }); - const resolveTargetTexture = t.createTexture({ sampleCount: 1 }); - - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [ - { - attachment: colorTexture.createView(), - resolveTarget: resolveTargetTexture.createView(), - loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, - }, - ], - }; - - await t.tryRenderPass(false, descriptor); -}); +); -g.test('check the use of multisampled textures as color attachments', async t => { +g.test('check_the_use_of_multisampled_textures_as_color_attachments').fn(async t => { const colorTexture = t.createTexture({ sampleCount: 1 }); const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); @@ -361,7 +369,7 @@ g.test('check the use of multisampled textures as color attachments', async t => } }); -g.test('it is invalid to use a multisampled resolve target', async t => { +g.test('it_is_invalid_to_use_a_multisampled_resolve_target').fn(async t => { const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); const multisampledResolveTargetTexture = t.createTexture({ sampleCount: 4 }); @@ -375,35 +383,39 @@ g.test('it is invalid to use a multisampled resolve target', async t => { await t.tryRenderPass(false, descriptor); }); -g.test('it is invalid to use a resolve target with array layer count greater than 1', async t => { - const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); - const resolveTargetTexture = t.createTexture({ arrayLayerCount: 2 }); +g.test('it_is_invalid_to_use_a_resolve_target_with_array_layer_count_greater_than_1').fn( + async t => { + const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); + const resolveTargetTexture = t.createTexture({ arrayLayerCount: 2 }); - const colorAttachment = t.getColorAttachment(multisampledColorTexture); - colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [colorAttachment], - }; + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [colorAttachment], + }; - await t.tryRenderPass(false, descriptor); -}); + await t.tryRenderPass(false, descriptor); + } +); -g.test('it is invalid to use a resolve target with mipmap level count greater than 1', async t => { - const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); - const resolveTargetTexture = t.createTexture({ mipLevelCount: 2 }); +g.test('it_is_invalid_to_use_a_resolve_target_with_mipmap_level_count_greater_than_1').fn( + async t => { + const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); + const resolveTargetTexture = t.createTexture({ mipLevelCount: 2 }); - const colorAttachment = t.getColorAttachment(multisampledColorTexture); - colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [colorAttachment], - }; + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [colorAttachment], + }; - await t.tryRenderPass(false, descriptor); -}); + await t.tryRenderPass(false, descriptor); + } +); -g.test('it is invalid to use a resolve target whose usage is not output attachment', async t => { +g.test('it_is_invalid_to_use_a_resolve_target_whose_usage_is_not_output_attachment').fn(async t => { const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); const resolveTargetTexture = t.createTexture({ usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST, @@ -419,7 +431,7 @@ g.test('it is invalid to use a resolve target whose usage is not output attachme await t.tryRenderPass(false, descriptor); }); -g.test('it is invalid to use a resolve target in error state', async t => { +g.test('it_is_invalid_to_use_a_resolve_target_in_error_state').fn(async t => { const ARRAY_LAYER_COUNT = 1; const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); @@ -441,35 +453,39 @@ g.test('it is invalid to use a resolve target in error state', async t => { await t.tryRenderPass(false, descriptor); }); -g.test('use of multisampled attachment and non multisampled resolve target is allowed', async t => { - const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); - const resolveTargetTexture = t.createTexture({ sampleCount: 1 }); +g.test('use_of_multisampled_attachment_and_non_multisampled_resolve_target_is_allowed').fn( + async t => { + const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); + const resolveTargetTexture = t.createTexture({ sampleCount: 1 }); - const colorAttachment = t.getColorAttachment(multisampledColorTexture); - colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [colorAttachment], - }; + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [colorAttachment], + }; - t.tryRenderPass(true, descriptor); -}); + t.tryRenderPass(true, descriptor); + } +); -g.test('use a resolve target in a format different than the attachment is not allowed', async t => { - const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); - const resolveTargetTexture = t.createTexture({ format: 'bgra8unorm' }); +g.test('use_a_resolve_target_in_a_format_different_than_the_attachment_is_not_allowed').fn( + async t => { + const multisampledColorTexture = t.createTexture({ sampleCount: 4 }); + const resolveTargetTexture = t.createTexture({ format: 'bgra8unorm' }); - const colorAttachment = t.getColorAttachment(multisampledColorTexture); - colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); - const descriptor: GPURenderPassDescriptor = { - colorAttachments: [colorAttachment], - }; + const descriptor: GPURenderPassDescriptor = { + colorAttachments: [colorAttachment], + }; - await t.tryRenderPass(false, descriptor); -}); + await t.tryRenderPass(false, descriptor); + } +); -g.test('size of the resolve target must be the same as the color attachment', async t => { +g.test('size_of_the_resolve_target_must_be_the_same_as_the_color_attachment').fn(async t => { const size = 16; const multisampledColorTexture = t.createTexture({ width: size, height: size, sampleCount: 4 }); const resolveTargetTexture = t.createTexture({ @@ -507,7 +523,7 @@ g.test('size of the resolve target must be the same as the color attachment', as } }); -g.test('check depth stencil attachment sample counts mismatch', async t => { +g.test('check_depth_stencil_attachment_sample_counts_mismatch').fn(async t => { const multisampledDepthStencilTexture = t.createTexture({ sampleCount: 4, format: 'depth24plus-stencil8', diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBindGroup.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBindGroup.spec.ts index 2965fc39281..c7bbd9e873d 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBindGroup.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBindGroup.spec.ts @@ -2,8 +2,8 @@ export const description = ` setBindGroup validation tests. `; -import { pcombine, poptions } from '../../../common/framework/params.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { poptions, params } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -48,133 +48,139 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); - -g.test('dynamic offsets passed but not expected/compute pass', async t => { - const bindGroupLayout = t.device.createBindGroupLayout({ entries: [] }); - const bindGroup = t.device.createBindGroup({ layout: bindGroupLayout, entries: [] }); - - const { type } = t.params; - const dynamicOffsets = [0]; - - t.expectValidationError(() => { - if (type === 'compute') { - const encoder = t.device.createCommandEncoder(); - const computePass = encoder.beginComputePass(); - computePass.setBindGroup(0, bindGroup, dynamicOffsets); - computePass.endPass(); - encoder.finish(); - } else if (type === 'renderpass') { - const encoder = t.device.createCommandEncoder(); - const renderPass = encoder.beginRenderPass({ - colorAttachments: [ - { - attachment: t.makeAttachmentTexture().createView(), - loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, - }, - ], - }); - renderPass.setBindGroup(0, bindGroup, dynamicOffsets); - renderPass.endPass(); - encoder.finish(); - } else if (type === 'renderbundle') { - const encoder = t.device.createRenderBundleEncoder({ - colorFormats: ['rgba8unorm'], - }); - encoder.setBindGroup(0, bindGroup, dynamicOffsets); - encoder.finish(); - } else { - t.fail(); - } - }); -}).params(poptions('type', ['compute', 'renderpass', 'renderbundle'])); - -g.test('dynamic offsets match expectations in pass encoder', async t => { - // Dynamic buffer offsets require offset to be divisible by 256 - const MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT = 256; - const BINDING_SIZE = 9; - - const bindGroupLayout = t.device.createBindGroupLayout({ - entries: [ - { - binding: 0, - visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, - type: 'uniform-buffer', - hasDynamicOffset: true, - }, - { - binding: 1, - visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, - type: 'storage-buffer', - hasDynamicOffset: true, - }, - ], +export const g = makeTestGroup(F); + +g.test('dynamic_offsets_passed_but_not_expected,compute_pass') + .params(poptions('type', ['compute', 'renderpass', 'renderbundle'])) + .fn(async t => { + const bindGroupLayout = t.device.createBindGroupLayout({ entries: [] }); + const bindGroup = t.device.createBindGroup({ layout: bindGroupLayout, entries: [] }); + + const { type } = t.params; + const dynamicOffsets = [0]; + + t.expectValidationError(() => { + if (type === 'compute') { + const encoder = t.device.createCommandEncoder(); + const computePass = encoder.beginComputePass(); + computePass.setBindGroup(0, bindGroup, dynamicOffsets); + computePass.endPass(); + encoder.finish(); + } else if (type === 'renderpass') { + const encoder = t.device.createCommandEncoder(); + const renderPass = encoder.beginRenderPass({ + colorAttachments: [ + { + attachment: t.makeAttachmentTexture().createView(), + loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, + }, + ], + }); + renderPass.setBindGroup(0, bindGroup, dynamicOffsets); + renderPass.endPass(); + encoder.finish(); + } else if (type === 'renderbundle') { + const encoder = t.device.createRenderBundleEncoder({ + colorFormats: ['rgba8unorm'], + }); + encoder.setBindGroup(0, bindGroup, dynamicOffsets); + encoder.finish(); + } else { + t.fail(); + } + }); }); - const uniformBuffer = t.device.createBuffer({ - size: 2 * MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT + 8, - usage: GPUBufferUsage.UNIFORM, - }); +g.test('dynamic_offsets_match_expectations_in_pass_encoder') + .params( + params() + .combine(poptions('type', ['compute', 'renderpass', 'renderbundle'])) + .combine([ + { dynamicOffsets: [256, 0], _success: true }, // Dynamic offsets aligned + { dynamicOffsets: [1, 2], _success: false }, // Dynamic offsets not aligned + + // Wrong number of dynamic offsets + { dynamicOffsets: [256, 0, 0], _success: false }, + { dynamicOffsets: [256], _success: false }, + { dynamicOffsets: [], _success: false }, + + // Dynamic uniform buffer out of bounds because of binding size + { dynamicOffsets: [512, 0], _success: false }, + { dynamicOffsets: [1024, 0], _success: false }, + { dynamicOffsets: [0xffffffff, 0], _success: false }, + + // Dynamic storage buffer out of bounds because of binding size + { dynamicOffsets: [0, 512], _success: false }, + { dynamicOffsets: [0, 1024], _success: false }, + { dynamicOffsets: [0, 0xffffffff], _success: false }, + ]) + ) + .fn(async t => { + // Dynamic buffer offsets require offset to be divisible by 256 + const MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT = 256; + const BINDING_SIZE = 9; + + const bindGroupLayout = t.device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + type: 'uniform-buffer', + hasDynamicOffset: true, + }, + { + binding: 1, + visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + type: 'storage-buffer', + hasDynamicOffset: true, + }, + ], + }); - const storageBuffer = t.device.createBuffer({ - size: 2 * MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT + 8, - usage: GPUBufferUsage.STORAGE, - }); + const uniformBuffer = t.device.createBuffer({ + size: 2 * MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT + 8, + usage: GPUBufferUsage.UNIFORM, + }); - const bindGroup = t.device.createBindGroup({ - layout: bindGroupLayout, - entries: [ - { - binding: 0, - resource: { - buffer: uniformBuffer, - size: BINDING_SIZE, + const storageBuffer = t.device.createBuffer({ + size: 2 * MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT + 8, + usage: GPUBufferUsage.STORAGE, + }); + + const bindGroup = t.device.createBindGroup({ + layout: bindGroupLayout, + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + size: BINDING_SIZE, + }, }, - }, - { - binding: 1, - resource: { - buffer: storageBuffer, - size: BINDING_SIZE, + { + binding: 1, + resource: { + buffer: storageBuffer, + size: BINDING_SIZE, + }, }, - }, - ], - }); - - const { type, dynamicOffsets, _success } = t.params; + ], + }); - t.expectValidationError(() => { - if (type === 'compute') { + const { type, dynamicOffsets, _success } = t.params; + + t.expectValidationError(() => { + if (type === 'compute') { + t.testComputePass(bindGroup, dynamicOffsets); + } else if (type === 'renderpass') { + t.testRenderPass(bindGroup, dynamicOffsets); + } else if (type === 'renderbundle') { + t.testRenderBundle(bindGroup, dynamicOffsets); + } else { + t.fail(); + } t.testComputePass(bindGroup, dynamicOffsets); - } else if (type === 'renderpass') { - t.testRenderPass(bindGroup, dynamicOffsets); - } else if (type === 'renderbundle') { - t.testRenderBundle(bindGroup, dynamicOffsets); - } else { - t.fail(); - } - t.testComputePass(bindGroup, dynamicOffsets); - }, !_success); -}).params( - pcombine(poptions('type', ['compute', 'renderpass', 'renderbundle']), [ - { dynamicOffsets: [256, 0], _success: true }, // Dynamic offsets aligned - { dynamicOffsets: [1, 2], _success: false }, // Dynamic offsets not aligned - - // Wrong number of dynamic offsets - { dynamicOffsets: [256, 0, 0], _success: false }, - { dynamicOffsets: [256], _success: false }, - { dynamicOffsets: [], _success: false }, - - // Dynamic uniform buffer out of bounds because of binding size - { dynamicOffsets: [512, 0], _success: false }, - { dynamicOffsets: [1024, 0], _success: false }, - { dynamicOffsets: [Number.MAX_SAFE_INTEGER, 0], _success: false }, - - // Dynamic storage buffer out of bounds because of binding size - { dynamicOffsets: [0, 512], _success: false }, - { dynamicOffsets: [0, 1024], _success: false }, - { dynamicOffsets: [0, Number.MAX_SAFE_INTEGER], _success: false }, - ]) -); + }, !_success); + }); // TODO: test error bind group diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBlendColor.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBlendColor.spec.ts index 3dca9c7d8aa..ec0172d8668 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBlendColor.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setBlendColor.spec.ts @@ -2,7 +2,7 @@ export const description = ` setBlendColor validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -26,9 +26,9 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('basic use of setBlendColor', t => { +g.test('basic_use_of_setBlendColor').fn(t => { const commandEncoder = t.device.createCommandEncoder(); const renderPass = t.beginRenderPass(commandEncoder); renderPass.setBlendColor({ r: 0, g: 0, b: 0, a: 0 }); @@ -36,7 +36,7 @@ g.test('basic use of setBlendColor', t => { commandEncoder.finish(); }); -g.test('setBlendColor allows any number value', t => { +g.test('setBlendColor_allows_any_number_value').fn(t => { const values = [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]; for (const value of values) { const commandEncoder = t.device.createCommandEncoder(); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setScissorRect.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setScissorRect.spec.ts index 358f11dc839..73895f6fef8 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setScissorRect.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setScissorRect.spec.ts @@ -2,7 +2,7 @@ export const description = ` setScissorRect validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -29,23 +29,25 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); - -g.test('use of setScissorRect', async t => { - const { x, y, width, height, _success } = t.params; - - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setScissorRect(x, y, width, height); - renderPass.endPass(); - - t.expectValidationError(() => { - commandEncoder.finish(); - }, !_success); -}).params([ - { x: 0, y: 0, width: 1, height: 1, _success: true }, // Basic use - { x: 0, y: 0, width: 0, height: 1, _success: false }, // Width of zero is not allowed - { x: 0, y: 0, width: 1, height: 0, _success: false }, // Height of zero is not allowed - { x: 0, y: 0, width: 0, height: 0, _success: false }, // Both width and height of zero are not allowed - { x: 0, y: 0, width: TEXTURE_WIDTH + 1, height: TEXTURE_HEIGHT + 1, _success: true }, // Scissor larger than the framebuffer is allowed -]); +export const g = makeTestGroup(F); + +g.test('use_of_setScissorRect') + .params([ + { x: 0, y: 0, width: 1, height: 1, _success: true }, // Basic use + { x: 0, y: 0, width: 0, height: 1, _success: false }, // Width of zero is not allowed + { x: 0, y: 0, width: 1, height: 0, _success: false }, // Height of zero is not allowed + { x: 0, y: 0, width: 0, height: 0, _success: false }, // Both width and height of zero are not allowed + { x: 0, y: 0, width: TEXTURE_WIDTH + 1, height: TEXTURE_HEIGHT + 1, _success: true }, // Scissor larger than the framebuffer is allowed + ]) + .fn(async t => { + const { x, y, width, height, _success } = t.params; + + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setScissorRect(x, y, width, height); + renderPass.endPass(); + + t.expectValidationError(() => { + commandEncoder.finish(); + }, !_success); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setStencilReference.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setStencilReference.spec.ts index 53ad5215666..bccc5113854 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setStencilReference.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setStencilReference.spec.ts @@ -2,8 +2,8 @@ export const description = ` setStencilReference validation tests. `; -import { poptions } from '../../../common/framework/params.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { poptions } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -27,14 +27,16 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('use of setStencilReference', t => { - const { reference } = t.params; +g.test('use_of_setStencilReference') + .params(poptions('reference', [0, 0xffffffff])) + .fn(t => { + const { reference } = t.params; - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setStencilReference(reference); - renderPass.endPass(); - commandEncoder.finish(); -}).params(poptions('reference', [0, 0xffffffff])); + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setStencilReference(reference); + renderPass.endPass(); + commandEncoder.finish(); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setVertexBuffer.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setVertexBuffer.spec.ts index 14582bd1007..efd38fe6d34 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setVertexBuffer.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setVertexBuffer.spec.ts @@ -2,7 +2,7 @@ export const description = ` setVertexBuffer validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { range } from '../../../common/framework/util/util.js'; import { ValidationTest } from './validation_test.js'; @@ -88,9 +88,9 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('vertex buffers inherit from previous pipeline', async t => { +g.test('vertex_buffers_inherit_from_previous_pipeline').fn(async t => { const pipeline1 = t.createRenderPipeline(1); const pipeline2 = t.createRenderPipeline(2); @@ -125,7 +125,7 @@ g.test('vertex buffers inherit from previous pipeline', async t => { } }); -g.test('vertex buffers do not inherit between render passes', async t => { +g.test('vertex_buffers_do_not_inherit_between_render_passes').fn(async t => { const pipeline1 = t.createRenderPipeline(1); const pipeline2 = t.createRenderPipeline(2); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setViewport.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setViewport.spec.ts index 0f0bfa75259..29b22b14ab9 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setViewport.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/setViewport.spec.ts @@ -2,7 +2,7 @@ export const description = ` setViewport validation tests. `; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -29,41 +29,43 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('use of setViewport', async t => { - const { x, y, width, height, minDepth, maxDepth, _success } = t.params; +g.test('use_of_setViewport') + .params([ + { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Basic use + { x: 0, y: 0, width: 0, height: 1, minDepth: 0, maxDepth: 1, _success: false }, // Width of zero is not allowed + { x: 0, y: 0, width: 1, height: 0, minDepth: 0, maxDepth: 1, _success: false }, // Height of zero is not allowed + { x: 0, y: 0, width: 0, height: 0, minDepth: 0, maxDepth: 1, _success: false }, // Both width and height of zero are not allowed + { x: -1, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Negative x is allowed + { x: 0, y: -1, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Negative y is allowed + { x: 0, y: 0, width: -1, height: 1, minDepth: 0, maxDepth: 1, _success: false }, // Negative width is not allowed + { x: 0, y: 0, width: 1, height: -1, minDepth: 0, maxDepth: 1, _success: false }, // Negative height is not allowed + { x: 0, y: 0, width: 1, height: 1, minDepth: -1, maxDepth: 1, _success: false }, // Negative minDepth is not allowed + { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: -1, _success: false }, // Negative maxDepth is not allowed + { x: 0, y: 0, width: 1, height: 1, minDepth: 10, maxDepth: 1, _success: false }, // minDepth greater than 1 is not allowed + { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 10, _success: false }, // maxDepth greater than 1 is not allowed + { x: 0, y: 0, width: 1, height: 1, minDepth: 0.5, maxDepth: 0.5, _success: true }, // minDepth equal to maxDepth is allowed + { x: 0, y: 0, width: 1, height: 1, minDepth: 0.8, maxDepth: 0.5, _success: true }, // minDepth greater than maxDepth is allowed + { + x: 0, + y: 0, + width: TEXTURE_WIDTH + 1, + height: TEXTURE_HEIGHT + 1, + minDepth: 0, + maxDepth: 1, + _success: true, + }, // Viewport larger than the framebuffer is allowed + ]) + .fn(async t => { + const { x, y, width, height, minDepth, maxDepth, _success } = t.params; - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setViewport(x, y, width, height, minDepth, maxDepth); - renderPass.endPass(); + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setViewport(x, y, width, height, minDepth, maxDepth); + renderPass.endPass(); - t.expectValidationError(() => { - commandEncoder.finish(); - }, !_success); -}).params([ - { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Basic use - { x: 0, y: 0, width: 0, height: 1, minDepth: 0, maxDepth: 1, _success: false }, // Width of zero is not allowed - { x: 0, y: 0, width: 1, height: 0, minDepth: 0, maxDepth: 1, _success: false }, // Height of zero is not allowed - { x: 0, y: 0, width: 0, height: 0, minDepth: 0, maxDepth: 1, _success: false }, // Both width and height of zero are not allowed - { x: -1, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Negative x is allowed - { x: 0, y: -1, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Negative y is allowed - { x: 0, y: 0, width: -1, height: 1, minDepth: 0, maxDepth: 1, _success: false }, // Negative width is not allowed - { x: 0, y: 0, width: 1, height: -1, minDepth: 0, maxDepth: 1, _success: false }, // Negative height is not allowed - { x: 0, y: 0, width: 1, height: 1, minDepth: -1, maxDepth: 1, _success: false }, // Negative minDepth is not allowed - { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: -1, _success: false }, // Negative maxDepth is not allowed - { x: 0, y: 0, width: 1, height: 1, minDepth: 10, maxDepth: 1, _success: false }, // minDepth greater than 1 is not allowed - { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 10, _success: false }, // maxDepth greater than 1 is not allowed - { x: 0, y: 0, width: 1, height: 1, minDepth: 0.5, maxDepth: 0.5, _success: true }, // minDepth equal to maxDepth is allowed - { x: 0, y: 0, width: 1, height: 1, minDepth: 0.8, maxDepth: 0.5, _success: true }, // minDepth greater than maxDepth is allowed - { - x: 0, - y: 0, - width: TEXTURE_WIDTH + 1, - height: TEXTURE_HEIGHT + 1, - minDepth: 0, - maxDepth: 1, - _success: true, - }, // Viewport larger than the framebuffer is allowed -]); + t.expectValidationError(() => { + commandEncoder.finish(); + }, !_success); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/validation_test.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/validation_test.ts index 9e1ccd50b31..0a09c58eaa2 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/validation_test.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/validation_test.ts @@ -1,36 +1,7 @@ import { unreachable } from '../../../common/framework/util/util.js'; +import { BindableResource } from '../../capability_info.js'; import { GPUTest } from '../../gpu_test.js'; -export enum BindingResourceType { - 'error-buffer' = 'error-buffer', - 'error-sampler' = 'error-sampler', - 'error-textureview' = 'error-textureview', - 'uniform-buffer' = 'uniform-buffer', - 'storage-buffer' = 'storage-buffer', - 'sampler' = 'sampler', - 'sampled-textureview' = 'sampled-textureview', - 'storage-textureview' = 'storage-textureview', -} - -export function resourceBindingMatches(b: GPUBindingType, r: BindingResourceType): boolean { - switch (b) { - case 'storage-buffer': - case 'readonly-storage-buffer': - return r === 'storage-buffer'; - case 'sampled-texture': - return r === 'sampled-textureview'; - case 'sampler': - return r === 'sampler'; - case 'readonly-storage-texture': - case 'writeonly-storage-texture': - return r === 'storage-textureview'; - case 'uniform-buffer': - return r === 'uniform-buffer'; - default: - unreachable('unknown GPUBindingType'); - } -} - export class ValidationTest extends GPUTest { getStorageBuffer(): GPUBuffer { return this.device.createBuffer({ size: 1024, usage: GPUBufferUsage.STORAGE }); @@ -54,6 +25,10 @@ export class ValidationTest extends GPUTest { return this.device.createSampler(); } + getComparisonSampler(): GPUSampler { + return this.device.createSampler({ compare: 'never' }); + } + getErrorSampler(): GPUSampler { this.device.pushErrorScope('validation'); const sampler = this.device.createSampler({ lodMinClamp: -1 }); @@ -90,23 +65,25 @@ export class ValidationTest extends GPUTest { return view; } - getBindingResource(bindingType: BindingResourceType): GPUBindingResource { + getBindingResource(bindingType: BindableResource): GPUBindingResource { switch (bindingType) { - case 'error-buffer': + case 'errorBuf': return { buffer: this.getErrorBuffer() }; - case 'error-sampler': + case 'errorSamp': return this.getErrorSampler(); - case 'error-textureview': + case 'errorTex': return this.getErrorTextureView(); - case 'uniform-buffer': + case 'uniformBuf': return { buffer: this.getUniformBuffer() }; - case 'storage-buffer': + case 'storageBuf': return { buffer: this.getStorageBuffer() }; - case 'sampler': + case 'plainSamp': return this.getSampler(); - case 'sampled-textureview': + case 'compareSamp': + return this.getComparisonSampler(); + case 'sampledTex': return this.getSampledTexture().createView(); - case 'storage-textureview': + case 'storageTex': return this.getStorageTexture().createView(); default: unreachable('unknown binding resource type'); @@ -128,7 +105,7 @@ export class ValidationTest extends GPUTest { const gpuValidationError = await promise; if (!gpuValidationError) { niceStack.message = 'Validation error was expected.'; - this.rec.fail(niceStack); + this.rec.validationFailed(niceStack); } else if (gpuValidationError instanceof GPUValidationError) { niceStack.message = `Captured validation error - ${gpuValidationError.message}`; this.rec.debug(niceStack); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/vertex_state.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/vertex_state.spec.ts index 24382306521..455dbccb8e4 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/vertex_state.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/api/validation/vertex_state.spec.ts @@ -2,8 +2,7 @@ export const description = ` vertexState validation tests. `; -import * as C from '../../../common/constants.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; @@ -56,15 +55,15 @@ class F extends ValidationTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('an empty vertex input is valid', t => { +g.test('an_empty_vertex_input_is_valid').fn(t => { const vertexState: GPUVertexStateDescriptor = {}; const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); t.device.createRenderPipeline(descriptor); }); -g.test('a null buffer is valid', t => { +g.test('a_null_buffer_is_valid').fn(t => { { // One null buffer is OK const vertexState: GPUVertexStateDescriptor = { @@ -136,7 +135,7 @@ g.test('a null buffer is valid', t => { } }); -g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => { +g.test('pipeline_vertex_buffers_are_backed_by_attributes_in_vertex_input').fn(async t => { const vertexState: GPUVertexStateDescriptor = { vertexBuffers: [ { @@ -198,14 +197,14 @@ g.test('pipeline vertex buffers are backed by attributes in vertex input', async } }); -g.test('an arrayStride of 0 is valid', t => { +g.test('an_arrayStride_of_0_is_valid').fn(t => { const vertexState = { vertexBuffers: [ { arrayStride: 0, attributes: [ { - format: C.VertexFormat.Float, + format: 'float' as const, offset: 0, shaderLocation: 0, }, @@ -226,73 +225,76 @@ g.test('an arrayStride of 0 is valid', t => { } }); -g.test('offset should be within vertex buffer arrayStride if arrayStride is not zero', async t => { - const vertexState = { - vertexBuffers: [ - { - arrayStride: 2 * SIZEOF_FLOAT, - attributes: [ - { - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0, - }, - { - format: C.VertexFormat.Float, - offset: SIZEOF_FLOAT, - shaderLocation: 1, - }, - ], - }, - ], - }; - { - // Control case, setting correct arrayStride and offset - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute offset exceed vertex buffer arrayStride range - const badVertexState = clone(vertexState); - badVertexState.vertexBuffers[0].attributes[1].format = C.VertexFormat.Float2; - const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - - t.expectValidationError(() => { +g.test('offset_should_be_within_vertex_buffer_arrayStride_if_arrayStride_is_not_zero').fn( + async t => { + const vertexState = { + vertexBuffers: [ + { + arrayStride: 2 * SIZEOF_FLOAT, + attributes: [ + { + format: 'float' as GPUVertexFormat, + offset: 0, + shaderLocation: 0, + }, + { + format: 'float' as GPUVertexFormat, + offset: SIZEOF_FLOAT, + shaderLocation: 1, + }, + ], + }, + ], + }; + { + // Control case, setting correct arrayStride and offset + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); t.device.createRenderPipeline(descriptor); - }); - } - { - // Test vertex attribute offset exceed vertex buffer arrayStride range - const badVertexState = clone(vertexState); - badVertexState.vertexBuffers[0].arrayStride = SIZEOF_FLOAT; - const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + } + { + // Test vertex attribute offset exceed vertex buffer arrayStride range + const badVertexState = clone(vertexState); + badVertexState.vertexBuffers[0].attributes[1].format = 'float2'; + const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // Test vertex attribute offset exceed vertex buffer arrayStride range + const badVertexState = clone(vertexState); + badVertexState.vertexBuffers[0].arrayStride = SIZEOF_FLOAT; + const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // It's OK if arrayStride is zero + const goodVertexState = clone(vertexState); + goodVertexState.vertexBuffers[0].arrayStride = 0; + const descriptor = t.getDescriptor(goodVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); t.device.createRenderPipeline(descriptor); - }); - } - { - // It's OK if arrayStride is zero - const goodVertexState = clone(vertexState); - goodVertexState.vertexBuffers[0].arrayStride = 0; - const descriptor = t.getDescriptor(goodVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); + } } -}); +); -g.test('check two attributes overlapping', async t => { +// TODO: This should be made into an operation test. +g.test('check_two_attributes_overlapping').fn(async t => { const vertexState = { vertexBuffers: [ { arrayStride: 2 * SIZEOF_FLOAT, attributes: [ { - format: C.VertexFormat.Float, + format: 'float' as GPUVertexFormat, offset: 0, shaderLocation: 0, }, { - format: C.VertexFormat.Float, + format: 'float' as GPUVertexFormat, offset: SIZEOF_FLOAT, shaderLocation: 1, }, @@ -307,17 +309,14 @@ g.test('check two attributes overlapping', async t => { } { // Test two attributes overlapping - const badVertexState = clone(vertexState); - badVertexState.vertexBuffers[0].attributes[0].format = C.VertexFormat.Int2; - const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); + const overlappingVertexState = clone(vertexState); + overlappingVertexState.vertexBuffers[0].attributes[0].format = 'int2'; + const descriptor = t.getDescriptor(overlappingVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); } }); -g.test('check out of bounds condition on total number of vertex buffers', async t => { +g.test('check_out_of_bounds_condition_on_total_number_of_vertex_buffers').fn(async t => { const vertexBuffers: GPUVertexBufferLayoutDescriptor[] = []; for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) { @@ -363,60 +362,62 @@ g.test('check out of bounds condition on total number of vertex buffers', async } }); -g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => { - const vertexAttributes: GPUVertexAttributeDescriptor[] = []; +g.test('check_out_of_bounds_on_number_of_vertex_attributes_on_a_single_vertex_buffer').fn( + async t => { + const vertexAttributes: GPUVertexAttributeDescriptor[] = []; - for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { - vertexAttributes.push({ - format: 'float', - offset: 0, - shaderLocation: i, - }); - } - { - // Control case, setting max vertex buffer number - const vertexState: GPUVertexStateDescriptor = { - vertexBuffers: [ - { - arrayStride: 0, - attributes: vertexAttributes, - }, - ], - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute number exceed the limit - const vertexState: GPUVertexStateDescriptor = { - vertexBuffers: [ - { - arrayStride: 0, - attributes: [ - ...vertexAttributes, - { - format: 'float', - offset: 0, - shaderLocation: MAX_VERTEX_ATTRIBUTES, - }, - ], - }, - ], - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - - t.expectValidationError(() => { + for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { + vertexAttributes.push({ + format: 'float', + offset: 0, + shaderLocation: i, + }); + } + { + // Control case, setting max vertex buffer number + const vertexState: GPUVertexStateDescriptor = { + vertexBuffers: [ + { + arrayStride: 0, + attributes: vertexAttributes, + }, + ], + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); t.device.createRenderPipeline(descriptor); - }); + } + { + // Test vertex attribute number exceed the limit + const vertexState: GPUVertexStateDescriptor = { + vertexBuffers: [ + { + arrayStride: 0, + attributes: [ + ...vertexAttributes, + { + format: 'float', + offset: 0, + shaderLocation: MAX_VERTEX_ATTRIBUTES, + }, + ], + }, + ], + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } } -}); +); -g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => { +g.test('check_out_of_bounds_on_number_of_vertex_attributes_across_vertex_buffers').fn(async t => { const vertexBuffers = []; for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { vertexBuffers.push({ arrayStride: 0, - attributes: [{ format: C.VertexFormat.Float, offset: 0, shaderLocation: i }], + attributes: [{ format: 'float' as const, offset: 0, shaderLocation: i }], }); } @@ -429,7 +430,7 @@ g.test('check out of bounds on number of vertex attributes across vertex buffers { // Test vertex attribute number exceed the limit vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributes.push({ - format: C.VertexFormat.Float, + format: 'float' as const, offset: 0, shaderLocation: MAX_VERTEX_ATTRIBUTES, }); @@ -442,7 +443,7 @@ g.test('check out of bounds on number of vertex attributes across vertex buffers } }); -g.test('check out of bounds condition on input strides', async t => { +g.test('check_out_of_bounds_condition_on_input_strides').fn(async t => { const vertexState = { vertexBuffers: [{ arrayStride: MAX_VERTEX_BUFFER_ARRAY_STRIDE, attributes: [] }], }; @@ -462,12 +463,12 @@ g.test('check out of bounds condition on input strides', async t => { } }); -g.test('check multiple of 4 bytes constraint on input arrayStride', async t => { +g.test('check_multiple_of_4_bytes_constraint_on_input_arrayStride').fn(async t => { const vertexState = { vertexBuffers: [ { arrayStride: 4, - attributes: [{ format: C.VertexFormat.Uchar2, offset: 0, shaderLocation: 0 }], + attributes: [{ format: 'uchar2' as const, offset: 0, shaderLocation: 0 }], }, ], }; @@ -487,12 +488,12 @@ g.test('check multiple of 4 bytes constraint on input arrayStride', async t => { } }); -g.test('identical duplicate attributes are invalid', async t => { +g.test('identical_duplicate_attributes_are_invalid').fn(async t => { const vertexState = { vertexBuffers: [ { arrayStride: 0, - attributes: [{ format: C.VertexFormat.Float, offset: 0, shaderLocation: 0 }], + attributes: [{ format: 'float' as const, offset: 0, shaderLocation: 0 }], }, ], }; @@ -504,7 +505,7 @@ g.test('identical duplicate attributes are invalid', async t => { { // Oh no, attribute 0 is set twice vertexState.vertexBuffers[0].attributes.push({ - format: C.VertexFormat.Float, + format: 'float' as const, offset: 0, shaderLocation: 0, }); @@ -516,15 +517,15 @@ g.test('identical duplicate attributes are invalid', async t => { } }); -g.test('we cannot set same shader location', async t => { +g.test('we_cannot_set_same_shader_location').fn(async t => { { const vertexState = { vertexBuffers: [ { arrayStride: 0, attributes: [ - { format: C.VertexFormat.Float, offset: 0, shaderLocation: 0 }, - { format: C.VertexFormat.Float, offset: SIZEOF_FLOAT, shaderLocation: 1 }, + { format: 'float' as const, offset: 0, shaderLocation: 0 }, + { format: 'float' as const, offset: SIZEOF_FLOAT, shaderLocation: 1 }, ], }, ], @@ -578,13 +579,13 @@ g.test('we cannot set same shader location', async t => { } }); -g.test('check out of bounds condition on attribute shader location', async t => { +g.test('check_out_of_bounds_condition_on_attribute_shader_location').fn(async t => { const vertexState = { vertexBuffers: [ { arrayStride: 0, attributes: [ - { format: C.VertexFormat.Float, offset: 0, shaderLocation: MAX_VERTEX_ATTRIBUTES - 1 }, + { format: 'float' as const, offset: 0, shaderLocation: MAX_VERTEX_ATTRIBUTES - 1 }, ], }, ], @@ -605,14 +606,14 @@ g.test('check out of bounds condition on attribute shader location', async t => } }); -g.test('check attribute offset out of bounds', async t => { +g.test('check_attribute_offset_out_of_bounds').fn(async t => { const vertexState = { vertexBuffers: [ { arrayStride: 0, attributes: [ { - format: C.VertexFormat.Float2, + format: 'float2' as const, offset: MAX_VERTEX_BUFFER_END - 2 * SIZEOF_FLOAT, shaderLocation: 0, }, @@ -642,12 +643,14 @@ g.test('check attribute offset out of bounds', async t => { } }); -g.test('check multiple of 4 bytes constraint on offset', async t => { +g.test('check_multiple_of_4_bytes_constraint_on_offset').fn(async t => { const vertexState = { vertexBuffers: [ { arrayStride: 0, - attributes: [{ format: C.VertexFormat.Float, offset: SIZEOF_FLOAT, shaderLocation: 0 }], + attributes: [ + { format: 'float' as GPUVertexFormat, offset: SIZEOF_FLOAT, shaderLocation: 0 }, + ], }, ], }; @@ -659,7 +662,7 @@ g.test('check multiple of 4 bytes constraint on offset', async t => { { // Test offset of 2 bytes with uchar2 format vertexState.vertexBuffers[0].attributes[0].offset = 2; - vertexState.vertexBuffers[0].attributes[0].format = C.VertexFormat.Uchar2; + vertexState.vertexBuffers[0].attributes[0].format = 'uchar2'; const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); t.expectValidationError(() => { t.device.createRenderPipeline(descriptor); @@ -668,7 +671,7 @@ g.test('check multiple of 4 bytes constraint on offset', async t => { { // Test offset of 2 bytes with float format vertexState.vertexBuffers[0].attributes[0].offset = 2; - vertexState.vertexBuffers[0].attributes[0].format = C.VertexFormat.Float; + vertexState.vertexBuffers[0].attributes[0].format = 'float'; const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); t.expectValidationError(() => { @@ -677,7 +680,7 @@ g.test('check multiple of 4 bytes constraint on offset', async t => { } }); -g.test('check attribute offset overflow', async t => { +g.test('check_attribute_offset_overflow').fn(async t => { const vertexState: GPUVertexStateDescriptor = { vertexBuffers: [ { diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/capability_info.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/capability_info.ts index 47a1ad806f2..2f17bff08f0 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/capability_info.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/capability_info.ts @@ -1,11 +1,26 @@ import * as C from '../common/constants.js'; +function keysOf<T extends string>(obj: { [k in T]: unknown }): readonly T[] { + return (Object.keys(obj) as unknown[]) as T[]; +} + +function numericKeysOf<T>(obj: object): readonly T[] { + return (Object.keys(obj).map(n => Number(n)) as unknown[]) as T[]; +} + // Textures export const kTextureFormatInfo: { - [k in GPUTextureFormat]: { - renderable: boolean; - color: boolean; + readonly [k in GPUTextureFormat]: { + readonly renderable: boolean; + readonly color: boolean; + readonly depth: boolean; + readonly stencil: boolean; + readonly storage: boolean; + readonly copyable: boolean; + readonly bytesPerBlock?: number; + readonly blockWidth?: number; + readonly blockHeight?: number; // Add fields as needed }; } = /* prettier-ignore */ { @@ -13,99 +28,230 @@ export const kTextureFormatInfo: { // (Note: this list should always match the one in the spec.) // 8-bit formats - 'r8unorm': { renderable: true, color: true }, - 'r8snorm': { renderable: false, color: true }, - 'r8uint': { renderable: true, color: true }, - 'r8sint': { renderable: true, color: true }, + 'r8unorm': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 1, blockWidth: 1, blockHeight: 1 }, + 'r8snorm': { renderable: false, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 1, blockWidth: 1, blockHeight: 1 }, + 'r8uint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 1, blockWidth: 1, blockHeight: 1 }, + 'r8sint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 1, blockWidth: 1, blockHeight: 1 }, // 16-bit formats - 'r16uint': { renderable: true, color: true }, - 'r16sint': { renderable: true, color: true }, - 'r16float': { renderable: true, color: true }, - 'rg8unorm': { renderable: true, color: true }, - 'rg8snorm': { renderable: false, color: true }, - 'rg8uint': { renderable: true, color: true }, - 'rg8sint': { renderable: true, color: true }, + 'r16uint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, + 'r16sint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, + 'r16float': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, + 'rg8unorm': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, + 'rg8snorm': { renderable: false, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, + 'rg8uint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, + 'rg8sint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 2, blockWidth: 1, blockHeight: 1 }, // 32-bit formats - 'r32uint': { renderable: true, color: true }, - 'r32sint': { renderable: true, color: true }, - 'r32float': { renderable: true, color: true }, - 'rg16uint': { renderable: true, color: true }, - 'rg16sint': { renderable: true, color: true }, - 'rg16float': { renderable: true, color: true }, - 'rgba8unorm': { renderable: true, color: true }, - 'rgba8unorm-srgb': { renderable: true, color: true }, - 'rgba8snorm': { renderable: false, color: true }, - 'rgba8uint': { renderable: true, color: true }, - 'rgba8sint': { renderable: true, color: true }, - 'bgra8unorm': { renderable: true, color: true }, - 'bgra8unorm-srgb': { renderable: true, color: true }, + 'r32uint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'r32sint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'r32float': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rg16uint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rg16sint': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rg16float': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rgba8unorm': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rgba8unorm-srgb': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rgba8snorm': { renderable: false, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rgba8uint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rgba8sint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'bgra8unorm': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'bgra8unorm-srgb': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, // Packed 32-bit formats - 'rgb10a2unorm': { renderable: true, color: true }, - 'rg11b10float': { renderable: false, color: true }, + 'rgb10a2unorm': { renderable: true, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'rg11b10float': { renderable: false, color: true, depth: false, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, // 64-bit formats - 'rg32uint': { renderable: true, color: true }, - 'rg32sint': { renderable: true, color: true }, - 'rg32float': { renderable: true, color: true }, - 'rgba16uint': { renderable: true, color: true }, - 'rgba16sint': { renderable: true, color: true }, - 'rgba16float': { renderable: true, color: true }, + 'rg32uint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 8, blockWidth: 1, blockHeight: 1 }, + 'rg32sint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 8, blockWidth: 1, blockHeight: 1 }, + 'rg32float': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 8, blockWidth: 1, blockHeight: 1 }, + 'rgba16uint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 8, blockWidth: 1, blockHeight: 1 }, + 'rgba16sint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 8, blockWidth: 1, blockHeight: 1 }, + 'rgba16float': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 8, blockWidth: 1, blockHeight: 1 }, // 128-bit formats - 'rgba32uint': { renderable: true, color: true }, - 'rgba32sint': { renderable: true, color: true }, - 'rgba32float': { renderable: true, color: true }, + 'rgba32uint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 16, blockWidth: 1, blockHeight: 1 }, + 'rgba32sint': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 16, blockWidth: 1, blockHeight: 1 }, + 'rgba32float': { renderable: true, color: true, depth: false, stencil: false, storage: true, copyable: true, bytesPerBlock: 16, blockWidth: 1, blockHeight: 1 }, // Depth/stencil formats - 'depth32float': { renderable: true, color: false }, - 'depth24plus': { renderable: true, color: false }, - 'depth24plus-stencil8': { renderable: true, color: false }, + 'depth32float': { renderable: true, color: false, depth: true, stencil: false, storage: false, copyable: true, bytesPerBlock: 4, blockWidth: 1, blockHeight: 1 }, + 'depth24plus': { renderable: true, color: false, depth: true, stencil: false, storage: false, copyable: false, }, + 'depth24plus-stencil8': { renderable: true, color: false, depth: true, stencil: true, storage: false, copyable: false, }, }; -export const kTextureFormats = Object.keys(kTextureFormatInfo) as GPUTextureFormat[]; +export const kTextureFormats = keysOf(kTextureFormatInfo); -// Bindings +export const kTextureDimensionInfo: { + readonly [k in GPUTextureDimension]: { + // Add fields as needed + }; +} = /* prettier-ignore */ { + '1d': {}, + '2d': {}, + '3d': {}, +}; +export const kTextureDimensions = keysOf(kTextureDimensionInfo); -export const kMaxBindingsPerBindGroup = 16; +export const kTextureAspectInfo: { + readonly [k in GPUTextureAspect]: { + // Add fields as needed + }; +} = /* prettier-ignore */ { + 'all': {}, + 'depth-only': {}, + 'stencil-only': {}, +}; +export const kTextureAspects = keysOf(kTextureAspectInfo); + +export const kTextureUsageInfo: { + readonly [k in C.TextureUsage]: {}; +} = { + [C.TextureUsage.CopySrc]: {}, + [C.TextureUsage.CopyDst]: {}, + [C.TextureUsage.Sampled]: {}, + [C.TextureUsage.Storage]: {}, + [C.TextureUsage.OutputAttachment]: {}, +}; +export const kTextureUsages = numericKeysOf<C.TextureUsage>(kTextureUsageInfo); + +// Typedefs for bindings -export type PerStageBindingLimitType = - | 'uniform-buffer' - | 'storage-buffer' +export type PerStageBindingLimitClass = + | 'uniformBuf' + | 'storageBuf' | 'sampler' + | 'sampledTex' + | 'storageTex'; +export type PerPipelineBindingLimitClass = PerStageBindingLimitClass; + +type ValidBindableResource = + | 'uniformBuf' + | 'storageBuf' + | 'plainSamp' + | 'compareSamp' + | 'sampledTex' + | 'storageTex'; +type ErrorBindableResource = 'errorBuf' | 'errorSamp' | 'errorTex'; +export type BindableResource = ValidBindableResource | ErrorBindableResource; + +type BufferBindingType = 'uniform-buffer' | 'storage-buffer' | 'readonly-storage-buffer'; +type SamplerBindingType = 'sampler' | 'comparison-sampler'; +type TextureBindingType = | 'sampled-texture' - | 'storage-texture'; + | 'writeonly-storage-texture' + | 'readonly-storage-texture'; + +// Bindings + +export const kMaxBindingsPerBindGroup = 16; + export const kPerStageBindingLimits: { - [k in PerStageBindingLimitType]: number; + readonly [k in PerStageBindingLimitClass]: { + readonly class: k; + readonly max: number; + // Add fields as needed + }; } = /* prettier-ignore */ { - 'uniform-buffer': 12, - 'storage-buffer': 4, - 'sampler': 16, - 'sampled-texture': 16, - 'storage-texture': 4, + 'uniformBuf': { class: 'uniformBuf', max: 12, }, + 'storageBuf': { class: 'storageBuf', max: 4, }, + 'sampler': { class: 'sampler', max: 16, }, + 'sampledTex': { class: 'sampledTex', max: 16, }, + 'storageTex': { class: 'storageTex', max: 4, }, }; -const kStagesAll = C.ShaderStage.Vertex | C.ShaderStage.Fragment | C.ShaderStage.Compute; -const kStagesCompute = C.ShaderStage.Compute; -export const kBindingTypeInfo: { - [k in GPUBindingType]: { - type: 'buffer' | 'texture' | 'sampler'; - validStages: GPUShaderStageFlags; - perStageLimitType: PerStageBindingLimitType; - maxDynamicCount: number; +export const kPerPipelineBindingLimits: { + readonly [k in PerPipelineBindingLimitClass]: { + readonly class: k; + readonly maxDynamic: number; // Add fields as needed }; - // TODO: maxDynamicCount should be kPerPipelineLayoutBindingLimits instead } = /* prettier-ignore */ { - 'uniform-buffer': { type: 'buffer', validStages: kStagesAll, perStageLimitType: 'uniform-buffer', maxDynamicCount: 8 }, - 'storage-buffer': { type: 'buffer', validStages: kStagesCompute, perStageLimitType: 'storage-buffer', maxDynamicCount: 4 }, - 'readonly-storage-buffer': { type: 'buffer', validStages: kStagesAll, perStageLimitType: 'storage-buffer', maxDynamicCount: 4 }, - 'sampler': { type: 'sampler', validStages: kStagesAll, perStageLimitType: 'sampler', maxDynamicCount: 0 }, - 'comparison-sampler': { type: 'sampler', validStages: kStagesAll, perStageLimitType: 'sampler', maxDynamicCount: 0 }, - 'sampled-texture': { type: 'texture', validStages: kStagesAll, perStageLimitType: 'sampled-texture', maxDynamicCount: 0 }, - 'writeonly-storage-texture': { type: 'texture', validStages: kStagesCompute, perStageLimitType: 'storage-texture', maxDynamicCount: 0 }, - 'readonly-storage-texture': { type: 'texture', validStages: kStagesAll, perStageLimitType: 'storage-texture', maxDynamicCount: 0 }, + 'uniformBuf': { class: 'uniformBuf', maxDynamic: 8, }, + 'storageBuf': { class: 'storageBuf', maxDynamic: 4, }, + 'sampler': { class: 'sampler', maxDynamic: 0, }, + 'sampledTex': { class: 'sampledTex', maxDynamic: 0, }, + 'storageTex': { class: 'storageTex', maxDynamic: 0, }, +}; + +const kBindableResource: { + readonly [k in BindableResource]: {}; +} = /* prettier-ignore */ { + uniformBuf: {}, storageBuf: {}, plainSamp: {}, compareSamp: {}, sampledTex: {}, storageTex: {}, + errorBuf: {}, errorSamp: {}, errorTex: {}, +}; +export const kBindableResources = keysOf(kBindableResource); + +interface BindingKindInfo { + readonly resource: ValidBindableResource; + readonly perStageLimitClass: typeof kPerStageBindingLimits[PerStageBindingLimitClass]; + readonly perPipelineLimitClass: typeof kPerPipelineBindingLimits[PerPipelineBindingLimitClass]; + // Add fields as needed +} + +const kBindingKind: { + readonly [k in ValidBindableResource]: BindingKindInfo; +} = /* prettier-ignore */ { + uniformBuf: { resource: 'uniformBuf', perStageLimitClass: kPerStageBindingLimits.uniformBuf, perPipelineLimitClass: kPerPipelineBindingLimits.uniformBuf, }, + storageBuf: { resource: 'storageBuf', perStageLimitClass: kPerStageBindingLimits.storageBuf, perPipelineLimitClass: kPerPipelineBindingLimits.storageBuf, }, + plainSamp: { resource: 'plainSamp', perStageLimitClass: kPerStageBindingLimits.sampler, perPipelineLimitClass: kPerPipelineBindingLimits.sampler, }, + compareSamp: { resource: 'compareSamp', perStageLimitClass: kPerStageBindingLimits.sampler, perPipelineLimitClass: kPerPipelineBindingLimits.sampler, }, + sampledTex: { resource: 'sampledTex', perStageLimitClass: kPerStageBindingLimits.sampledTex, perPipelineLimitClass: kPerPipelineBindingLimits.sampledTex, }, + storageTex: { resource: 'storageTex', perStageLimitClass: kPerStageBindingLimits.storageTex, perPipelineLimitClass: kPerPipelineBindingLimits.storageTex, }, +}; + +// Binding type info + +interface BindingTypeInfo extends BindingKindInfo { + readonly validStages: GPUShaderStageFlags; + // Add fields as needed +} +const kValidStagesAll = { + validStages: C.ShaderStage.Vertex | C.ShaderStage.Fragment | C.ShaderStage.Compute, +}; +const kValidStagesStorageWrite = { validStages: C.ShaderStage.Fragment | C.ShaderStage.Compute }; + +export const kBufferBindingTypeInfo: { + readonly [k in BufferBindingType]: { + readonly usage: C.BufferUsage; + // Add fields as needed + } & BindingTypeInfo; +} = /* prettier-ignore */ { + 'uniform-buffer': { usage: C.BufferUsage.Uniform, ...kBindingKind.uniformBuf, ...kValidStagesAll, }, + 'storage-buffer': { usage: C.BufferUsage.Storage, ...kBindingKind.storageBuf, ...kValidStagesStorageWrite, }, + 'readonly-storage-buffer': { usage: C.BufferUsage.Storage, ...kBindingKind.storageBuf, ...kValidStagesAll, }, +}; +export const kBufferBindingTypes = keysOf(kBufferBindingTypeInfo); + +export const kSamplerBindingTypeInfo: { + readonly [k in SamplerBindingType]: { + // Add fields as needed + } & BindingTypeInfo; +} = /* prettier-ignore */ { + 'sampler': { ...kBindingKind.plainSamp, ...kValidStagesAll, }, + 'comparison-sampler': { ...kBindingKind.compareSamp, ...kValidStagesAll, }, +}; +export const kSamplerBindingTypes = keysOf(kSamplerBindingTypeInfo); + +export const kTextureBindingTypeInfo: { + readonly [k in TextureBindingType]: { + readonly usage: C.TextureUsage; + // Add fields as needed + } & BindingTypeInfo; +} = /* prettier-ignore */ { + 'sampled-texture': { usage: C.TextureUsage.Sampled, ...kBindingKind.sampledTex, ...kValidStagesAll, }, + 'writeonly-storage-texture': { usage: C.TextureUsage.Storage, ...kBindingKind.storageTex, ...kValidStagesStorageWrite, }, + 'readonly-storage-texture': { usage: C.TextureUsage.Storage, ...kBindingKind.storageTex, ...kValidStagesAll, }, +}; +export const kTextureBindingTypes = keysOf(kTextureBindingTypeInfo); + +// All binding types (merged from above) + +export const kBindingTypeInfo: { + readonly [k in GPUBindingType]: BindingTypeInfo; +} = { + ...kBufferBindingTypeInfo, + ...kSamplerBindingTypeInfo, + ...kTextureBindingTypeInfo, }; -export const kBindingTypes = Object.keys(kBindingTypeInfo) as GPUBindingType[]; +export const kBindingTypes = keysOf(kBindingTypeInfo); -export const kShaderStages: GPUShaderStageFlags[] = [ +export const kShaderStages: readonly GPUShaderStageFlags[] = [ C.ShaderStage.Vertex, C.ShaderStage.Fragment, C.ShaderStage.Compute, ]; -export const kShaderStageCombinations: GPUShaderStageFlags[] = [0, 1, 2, 3, 4, 5, 6, 7]; +export const kShaderStageCombinations: readonly GPUShaderStageFlags[] = [0, 1, 2, 3, 4, 5, 6, 7]; diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/examples.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/examples.spec.ts index 7cbe5b76943..024817fde8e 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/examples.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/examples.spec.ts @@ -4,7 +4,7 @@ Examples of writing CTS tests with various features. Start here when looking for examples of basic framework usage. `; -import { TestGroup } from '../common/framework/test_group.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; import { GPUTest } from './gpu_test.js'; @@ -18,12 +18,13 @@ import { GPUTest } from './gpu_test.js'; // - ?q=webgpu:examples:basic/ // - ?q=webgpu:examples: -export const g = new TestGroup(GPUTest); +export const g = makeTestGroup(GPUTest); // Note: spaces in test names are replaced with underscores: webgpu:examples:test_name= -g.test('test name', t => {}); +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +g.test('test_name').fn(t => {}); -g.test('basic', t => { +g.test('basic').fn(t => { t.expect(true); t.expect(true, 'true should be true'); @@ -39,7 +40,7 @@ g.test('basic', t => { ); }); -g.test('basic/async', async t => { +g.test('basic,async').fn(async t => { // shouldReject must be awaited to ensure it can wait for the promise before the test ends. t.shouldReject( // The expected '.name' of the thrown error. @@ -68,22 +69,24 @@ g.test('basic/async', async t => { // // - webgpu:examples:basic/params={"x":2,"y":4} runs with t.params = {x: 2, y: 5, _result: 6}. // - webgpu:examples:basic/params={"x":-10,"y":18} runs with t.params = {x: -10, y: 18, _result: 8}. -g.test('basic/params', t => { - t.expect(t.params.x + t.params.y === t.params._result); -}).params([ - { x: 2, y: 4, _result: 6 }, // - { x: -10, y: 18, _result: 8 }, -]); +g.test('basic,params') + .params([ + { x: 2, y: 4, _result: 6 }, // + { x: -10, y: 18, _result: 8 }, + ]) + .fn(t => { + t.expect(t.params.x + t.params.y === t.params._result); + }); // (note the blank comment above to enforce newlines on autoformat) -g.test('gpu/async', async t => { +g.test('gpu,async').fn(async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); await fence.onCompletion(1); t.expect(fence.getCompletedValue() === 2); }); -g.test('gpu/buffers', async t => { +g.test('gpu,buffers').fn(async t => { const data = new Uint32Array([0, 1234, 0]); const [src, map] = t.device.createBufferMapped({ size: 12, diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/gpu_test.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/gpu_test.ts index daa00c234f9..4b4ec7ab35c 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/gpu_test.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/gpu_test.ts @@ -1,45 +1,37 @@ import { Fixture } from '../common/framework/fixture.js'; import { compileGLSL, initGLSL } from '../common/framework/glsl.js'; -import { getGPU } from '../common/framework/gpu/implementation.js'; -import { assert, unreachable } from '../common/framework/util/util.js'; +import { DevicePool, TestOOMedShouldAttemptGC } from '../common/framework/gpu/device_pool.js'; +import { attemptGarbageCollection } from '../common/framework/util/collect_garbage.js'; +import { assert } from '../common/framework/util/util.js'; -type ShaderStage = import('@webgpu/glslang/dist/web-devel/glslang').ShaderStage; - -class DevicePool { - device: GPUDevice | undefined = undefined; - state: 'free' | 'acquired' | 'uninitialized' | 'failed' = 'uninitialized'; - - private async initialize(): Promise<void> { - try { - const gpu = getGPU(); - const adapter = await gpu.requestAdapter(); - this.device = await adapter.requestDevice(); - } catch (ex) { - this.state = 'failed'; - throw ex; - } - } - - async acquire(): Promise<GPUDevice> { - assert(this.state !== 'acquired', 'Device was in use'); - assert(this.state !== 'failed', 'Failed to initialize WebGPU device'); - - const state = this.state; - this.state = 'acquired'; - if (state === 'uninitialized') { - await this.initialize(); - } +import { + fillTextureDataWithTexelValue, + getTextureCopyLayout, + LayoutOptions as TextureLayoutOptions, +} from './util/texture/layout.js'; +import { PerTexelComponent, getTexelDataRepresentation } from './util/texture/texelData.js'; - assert(!!this.device); - return this.device; - } +type ShaderStage = import('@webgpu/glslang/dist/web-devel/glslang').ShaderStage; - release(device: GPUDevice): void { - assert(this.state === 'acquired'); - assert(device === this.device, 'Released device was the wrong device'); - this.state = 'free'; - } -} +type TypedArrayBufferView = + | Uint8Array + | Uint16Array + | Uint32Array + | Int8Array + | Int16Array + | Int32Array + | Float32Array + | Float64Array; + +type TypedArrayBufferViewConstructor = + | Uint8ArrayConstructor + | Uint16ArrayConstructor + | Uint32ArrayConstructor + | Int8ArrayConstructor + | Int16ArrayConstructor + | Int32ArrayConstructor + | Float32ArrayConstructor + | Float64ArrayConstructor; const devicePool = new DevicePool(); @@ -64,39 +56,33 @@ export class GPUTest extends Fixture { const device = await devicePool.acquire(); const queue = device.defaultQueue; this.objects = { device, queue }; - - try { - await device.popErrorScope(); - unreachable('There was an error scope on the stack at the beginning of the test'); - } catch (ex) {} - - device.pushErrorScope('out-of-memory'); - device.pushErrorScope('validation'); - - this.initialized = true; } + // Note: finalize is called even if init was unsuccessful. async finalize(): Promise<void> { - // Note: finalize is called even if init was unsuccessful. await super.finalize(); - if (this.initialized) { - const gpuValidationError = await this.device.popErrorScope(); - if (gpuValidationError !== null) { - assert(gpuValidationError instanceof GPUValidationError); - this.fail(`Unexpected validation error occurred: ${gpuValidationError.message}`); + if (this.objects) { + let threw: undefined | Error; + { + const objects = this.objects; + this.objects = undefined; + try { + await devicePool.release(objects.device); + } catch (ex) { + threw = ex; + } } + // The GPUDevice and GPUQueue should now have no outstanding references. - const gpuOutOfMemoryError = await this.device.popErrorScope(); - if (gpuOutOfMemoryError !== null) { - assert(gpuOutOfMemoryError instanceof GPUOutOfMemoryError); - this.fail('Unexpected out-of-memory error occurred'); + if (threw) { + if (threw instanceof TestOOMedShouldAttemptGC) { + // Try to clean up, in case there are stray GPU resources in need of collection. + await attemptGarbageCollection(); + } + throw threw; } } - - if (this.objects) { - devicePool.release(this.objects.device); - } } makeShaderModule(stage: ShaderStage, code: { glsl: string } | { wgsl: string }): GPUShaderModule { @@ -109,14 +95,14 @@ export class GPUTest extends Fixture { } } - createCopyForMapRead(src: GPUBuffer, size: number): GPUBuffer { + createCopyForMapRead(src: GPUBuffer, start: number, size: number): GPUBuffer { const dst = this.device.createBuffer({ size, usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, }); const c = this.device.createCommandEncoder(); - c.copyBufferToBuffer(src, 0, dst, 0, size); + c.copyBufferToBuffer(src, start, dst, 0, size); this.queue.submit([c.finish()]); @@ -125,16 +111,20 @@ export class GPUTest extends Fixture { // TODO: add an expectContents for textures, which logs data: uris on failure - expectContents(src: GPUBuffer, expected: ArrayBufferView): void { - const exp = new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength); - const dst = this.createCopyForMapRead(src, expected.buffer.byteLength); + expectContents(src: GPUBuffer, expected: TypedArrayBufferView): void { + this.expectSubContents(src, 0, expected); + } + + expectSubContents(src: GPUBuffer, start: number, expected: TypedArrayBufferView): void { + const dst = this.createCopyForMapRead(src, start, expected.buffer.byteLength); this.eventualAsyncExpectation(async niceStack => { - const actual = new Uint8Array(await dst.mapReadAsync()); - const check = this.checkBuffer(actual, exp); + const constructor = expected.constructor as TypedArrayBufferViewConstructor; + const actual = new constructor(await dst.mapReadAsync()); + const check = this.checkBuffer(actual, expected); if (check !== undefined) { niceStack.message = check; - this.rec.fail(niceStack); + this.rec.expectationFailed(niceStack); } dst.destroy(); }); @@ -143,27 +133,42 @@ export class GPUTest extends Fixture { expectBuffer(actual: Uint8Array, exp: Uint8Array): void { const check = this.checkBuffer(actual, exp); if (check !== undefined) { - this.rec.fail(new Error(check)); + this.rec.expectationFailed(new Error(check)); } } - checkBuffer(actual: Uint8Array, exp: Uint8Array): string | undefined { + checkBuffer( + actual: TypedArrayBufferView, + exp: TypedArrayBufferView, + tolerance: number | ((i: number) => number) = 0 + ): string | undefined { + assert(actual.constructor === exp.constructor); + const size = exp.byteLength; if (actual.byteLength !== size) { return 'size mismatch'; } - const lines = []; - let failedPixels = 0; + const failedByteIndices: string[] = []; + const failedByteExpectedValues: string[] = []; + const failedByteActualValues: string[] = []; for (let i = 0; i < size; ++i) { - if (actual[i] !== exp[i]) { - if (failedPixels > 4) { - lines.push('... and more'); + const tol = typeof tolerance === 'function' ? tolerance(i) : tolerance; + if (Math.abs(actual[i] - exp[i]) > tol) { + if (failedByteIndices.length >= 4) { + failedByteIndices.push('...'); + failedByteExpectedValues.push('...'); + failedByteActualValues.push('...'); break; } - failedPixels++; - lines.push(`at [${i}], expected ${exp[i]}, got ${actual[i]}`); + failedByteIndices.push(i.toString()); + failedByteExpectedValues.push(exp[i].toString()); + failedByteActualValues.push(actual[i].toString()); } } + const summary = `at [${failedByteIndices.join(', ')}], \ +expected [${failedByteExpectedValues.join(', ')}], \ +got [${failedByteActualValues.join(', ')}]`; + const lines = [summary]; // TODO: Could make a more convenient message, which could look like e.g.: // @@ -180,19 +185,99 @@ export class GPUTest extends Fixture { // Or, maybe these diffs aren't actually very useful (given we have the prints just above here), // and we should remove them. More important will be logging of texture data in a visual format. - if (size <= 256 && failedPixels > 0) { - const expHex = Array.from(exp) + if (size <= 256 && failedByteIndices.length > 0) { + const expHex = Array.from(new Uint8Array(exp.buffer, exp.byteOffset, exp.byteLength)) .map(x => x.toString(16).padStart(2, '0')) .join(''); - const actHex = Array.from(actual) + const actHex = Array.from(new Uint8Array(actual.buffer, actual.byteOffset, actual.byteLength)) .map(x => x.toString(16).padStart(2, '0')) .join(''); - lines.push('EXPECT: ' + expHex); - lines.push('ACTUAL: ' + actHex); + lines.push('EXPECT:\t ' + exp.join(' ')); + lines.push('\t0x' + expHex); + lines.push('ACTUAL:\t ' + actual.join(' ')); + lines.push('\t0x' + actHex); } - if (failedPixels) { + if (failedByteIndices.length) { return lines.join('\n'); } return undefined; } + + expectSingleColor( + src: GPUTexture, + format: GPUTextureFormat, + { + size, + exp, + dimension = '2d', + slice = 0, + layout, + }: { + size: [number, number, number]; + exp: PerTexelComponent<number>; + dimension?: GPUTextureDimension; + slice?: number; + layout?: TextureLayoutOptions; + } + ): void { + const { byteLength, bytesPerRow, rowsPerImage, mipSize } = getTextureCopyLayout( + format, + dimension, + size, + layout + ); + const expectedTexelData = getTexelDataRepresentation(format).getBytes(exp); + + const buffer = this.device.createBuffer({ + size: byteLength, + usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, + }); + + const commandEncoder = this.device.createCommandEncoder(); + commandEncoder.copyTextureToBuffer( + { texture: src, mipLevel: layout?.mipLevel, arrayLayer: slice }, + { buffer, bytesPerRow, rowsPerImage }, + mipSize + ); + this.queue.submit([commandEncoder.finish()]); + const arrayBuffer = new ArrayBuffer(byteLength); + fillTextureDataWithTexelValue(expectedTexelData, format, dimension, arrayBuffer, size, layout); + this.expectContents(buffer, new Uint8Array(arrayBuffer)); + } + + expectGPUError<R>(filter: GPUErrorFilter, fn: () => R): R { + this.device.pushErrorScope(filter); + const returnValue = fn(); + const promise = this.device.popErrorScope(); + + this.eventualAsyncExpectation(async niceStack => { + const error = await promise; + + let failed = false; + switch (filter) { + case 'none': + failed = error !== null; + break; + case 'out-of-memory': + failed = !(error instanceof GPUOutOfMemoryError); + break; + case 'validation': + failed = !(error instanceof GPUValidationError); + break; + } + + if (failed) { + niceStack.message = `Expected ${filter} error`; + this.rec.expectationFailed(niceStack); + } else { + niceStack.message = `Captured ${filter} error`; + if (error instanceof GPUValidationError) { + niceStack.message += ` - ${error.message}`; + } + this.rec.debug(niceStack); + } + }); + + return returnValue; + } } diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/idl/constants/flags.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/idl/constants/flags.spec.ts new file mode 100644 index 00000000000..80cc8125a6e --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/idl/constants/flags.spec.ts @@ -0,0 +1,55 @@ +export const description = ` +Test the values of flags interfaces (e.g. GPUTextureUsage). +`; + +import { BufferUsage, TextureUsage, ColorWrite, ShaderStage } from '../../../common/constants.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; +import { IDLTest } from '../idl_test.js'; + +export const g = makeTestGroup(IDLTest); + +g.test('BufferUsage').fn(t => { + const expected = { + MAP_READ: BufferUsage.MapRead, + MAP_WRITE: BufferUsage.MapWrite, + COPY_SRC: BufferUsage.CopySrc, + COPY_DST: BufferUsage.CopyDst, + INDEX: BufferUsage.Index, + VERTEX: BufferUsage.Vertex, + UNIFORM: BufferUsage.Uniform, + STORAGE: BufferUsage.Storage, + INDIRECT: BufferUsage.Indirect, + }; + t.assertMembers(GPUBufferUsage, expected); +}); + +g.test('TextureUsage').fn(t => { + const expected = { + COPY_SRC: TextureUsage.CopySrc, + COPY_DST: TextureUsage.CopyDst, + SAMPLED: TextureUsage.Sampled, + STORAGE: TextureUsage.Storage, + OUTPUT_ATTACHMENT: TextureUsage.OutputAttachment, + }; + t.assertMembers(GPUTextureUsage, expected); +}); + +g.test('ColorWrite').fn(t => { + const expected = { + RED: ColorWrite.Red, + GREEN: ColorWrite.Green, + BLUE: ColorWrite.Blue, + ALPHA: ColorWrite.Alpha, + ALL: ColorWrite.All, + }; + t.assertMembers(GPUColorWrite, expected); +}); + +g.test('ShaderStage').fn(t => { + const expected = { + VERTEX: ShaderStage.Vertex, + FRAGMENT: ShaderStage.Fragment, + COMPUTE: ShaderStage.Compute, + }; + t.assertMembers(GPUShaderStage, expected); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/idl/idl_test.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/idl/idl_test.ts new file mode 100644 index 00000000000..5eb9a61172d --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/idl/idl_test.ts @@ -0,0 +1,27 @@ +import { Fixture } from '../../common/framework/fixture.js'; +import { assert } from '../../common/framework/util/util.js'; + +interface UnknownObject { + [k: string]: unknown; +} + +export class IDLTest extends Fixture { + /** + * Asserts that an IDL interface has the expected members. + */ + // TODO: exp should allow sentinel markers for unnameable values, such as methods and attributes + // TODO: handle extensions + // TODO: check prototype chains (maybe as separate method) + assertMembers(act: UnknownObject, exp: UnknownObject) { + const expKeys = Object.keys(exp); + for (const k of expKeys) { + assert(k in act, () => `Expected key ${k} missing`); + assert(act[k] === exp[k], () => `Value of [${k}] was ${act[k]}, expected ${exp[k]}`); + } + const actKeys = Object.keys(act); + assert( + actKeys.length === expKeys.length, + () => `Had ${actKeys.length} keys, expected ${expKeys.length}` + ); + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/listing.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/listing.ts index ba26ed77bd4..2d6f4cf8ecf 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/listing.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/listing.ts @@ -1,4 +1,4 @@ -import { TestSuiteListing } from '../common/framework/listing.js'; +import { TestSuiteListing } from '../common/framework/test_suite_listing.js'; import { makeListing } from '../common/tools/crawl.js'; export const listing: Promise<TestSuiteListing> = makeListing(__filename); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/shader/execution/robust_access.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/shader/execution/robust_access.spec.ts new file mode 100644 index 00000000000..9b31dcfb16a --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/shader/execution/robust_access.spec.ts @@ -0,0 +1,368 @@ +export const description = ` +Tests to check array clamping in shaders is correctly implemented including vector / matrix indexing +`; + +import { params, poptions } from '../../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; +import { assert } from '../../../common/framework/util/util.js'; +import { GPUTest } from '../../gpu_test.js'; + +export const g = makeTestGroup(GPUTest); + +// Utilities that should probably live in some shared place. +function copyArrayBuffer(src: ArrayBuffer): ArrayBuffer { + const dst = new ArrayBuffer(src.byteLength); + new Uint8Array(dst).set(new Uint8Array(src)); + return dst; +} + +const kUintMax = 4294967295; +const kIntMax = 2147483647; + +// A small utility to test shaders: +// - it wraps the source into a small harness that checks the runTest() function returns 0. +// - it runs the shader with the testBindings set as bindgroup 0. +// +// The shader also has access to a uniform value that's equal to 1u to avoid constant propagation +// in the shader compiler. +function runShaderTest( + t: GPUTest, + stage: GPUShaderStageFlags, + testSource: string, + testBindings: GPUBindGroupEntry[] +): void { + assert(stage === GPUShaderStage.COMPUTE, 'Only know how to deal with compute for now'); + + const [constantsBuffer, constantsInit] = t.device.createBufferMapped({ + size: 4, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM, + }); + + const constantsData = new Uint32Array(constantsInit); + constantsData[0] = 1; + constantsBuffer.unmap(); + + const resultBuffer = t.device.createBuffer({ + size: 4, + usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE, + }); + + const source = `#version 450 + layout(std140, set = 1, binding = 0) uniform Constants { + uint one; + }; + layout(std430, set = 1, binding = 1) buffer Result { + uint result; + }; + + ${testSource} + + void main() { + result = runTest(); + }`; + + const pipeline = t.device.createComputePipeline({ + computeStage: { + entryPoint: 'main', + module: t.makeShaderModule('compute', { glsl: source }), + }, + }); + + const group = t.device.createBindGroup({ + layout: pipeline.getBindGroupLayout(1), + entries: [ + { binding: 0, resource: { buffer: constantsBuffer } }, + { binding: 1, resource: { buffer: resultBuffer } }, + ], + }); + + const testGroup = t.device.createBindGroup({ + layout: pipeline.getBindGroupLayout(0), + entries: testBindings, + }); + + const encoder = t.device.createCommandEncoder(); + const pass = encoder.beginComputePass(); + pass.setPipeline(pipeline); + pass.setBindGroup(0, testGroup); + pass.setBindGroup(1, group); + pass.dispatch(1); + pass.endPass(); + + t.queue.submit([encoder.finish()]); + + t.expectContents(resultBuffer, new Uint32Array([0])); +} + +// The definition of base types for aggregate types, for example float, uint, etc. +interface BaseType { + // The name which is also the GLSL type. + name: string; + // The size in byte in a buffer. + byteSize: number; + // The prefix when used in aggregate names, the "u" in "uvec2" + glslPrefix: string; + glslZero: string; + // Fill the buffer with 42s, except the regions of `size` elements starting at `zeroStart` + // offset from the start of the buffer, which is filled with zeroes instead. + fillBuffer: (data: ArrayBuffer, zeroStart: number, size: number) => void; +} + +interface BaseTypeDictionary { + [key: string]: BaseType; +} + +const baseTypes: BaseTypeDictionary = { + // TODO bools + uint: { + name: 'uint', + byteSize: 4, + glslPrefix: 'u', + glslZero: '0u', + fillBuffer(data: ArrayBuffer, zeroStart: number, size: number): void { + const typedData = new Uint32Array(data); + typedData.fill(42); + for (let i = 0; i < size / 4; i++) { + typedData[zeroStart / 4 + i] = 0; + } + }, + }, + int: { + name: 'int', + byteSize: 4, + glslPrefix: 'i', + glslZero: '0', + fillBuffer(data: ArrayBuffer, zeroStart: number, size: number): void { + const typedData = new Int32Array(data); + typedData.fill(42); + for (let i = 0; i < size / 4; i++) { + typedData[zeroStart / 4 + i] = 0; + } + }, + }, + float: { + name: 'float', + byteSize: 4, + glslPrefix: '', + glslZero: '0.0f', + fillBuffer(data: ArrayBuffer, zeroStart: number, size: number): void { + const typedData = new Float32Array(data); + typedData.fill(42); + for (let i = 0; i < size / 4; i++) { + typedData[zeroStart / 4 + i] = 0; + } + }, + }, + bool: { + name: 'bool', + byteSize: 4, + glslPrefix: 'b', + glslZero: 'false', + fillBuffer(data: ArrayBuffer, zeroStart: number, size: number): void { + const typedData = new Uint32Array(data); + typedData.fill(42); + for (let i = 0; i < size / 4; i++) { + typedData[zeroStart / 4 + i] = 0; + } + }, + }, +}; + +// The definition of aggregate types. +interface Type { + // String to declare a variable named "data" of that type. + declaration: string; + // The array length, which also defines the bounds for this type. + length: number; + // The footprints in the buffer of this type, in baseTypes + std140Length: number; + std430Length: number; + // String to produce this type filled with zeroes. + zero: string; + baseType: BaseType; + isUnsizedArray?: true; +} + +interface TypeDictionary { + [key: string]: Type; +} + +const typeParams: TypeDictionary = (() => { + const types: TypeDictionary = {}; + for (const baseTypeName of Object.keys(baseTypes)) { + const baseType = baseTypes[baseTypeName]; + + // Arrays + types[`${baseTypeName}_sizedArray`] = { + declaration: `${baseTypeName} data[3]`, + length: 3, + std140Length: 2 * 4 + 1, + std430Length: 3, + zero: baseType.glslZero, + baseType, + }; + types[`${baseTypeName}_unsizedArray`] = { + declaration: `${baseTypeName} data[]`, + length: 3, + std140Length: 0, // Unused + std430Length: 3, + zero: baseType.glslZero, + baseType, + isUnsizedArray: true, + }; + + // Vectors + for (let dimension = 2; dimension <= 4; dimension++) { + types[`${baseTypeName}_vector${dimension}`] = { + declaration: `${baseType.glslPrefix}vec${dimension} data`, + length: dimension, + std140Length: dimension, + std430Length: dimension, + zero: baseType.glslZero, + baseType, + }; + } + } + + // Matrices, there are only float matrics in GLSL. + for (const transposed of [false, true]) { + for (let numColumns = 2; numColumns <= 4; numColumns++) { + for (let numRows = 2; numRows <= 4; numRows++) { + const majorDim = transposed ? numRows : numColumns; + const minorDim = transposed ? numColumns : numRows; + + const std140SizePerMinorDim = 4; + const std430SizePerMinorDim = minorDim === 3 ? 4 : minorDim; + + let typeName = `mat${numColumns}`; + if (numColumns !== numRows) { + typeName += `x${numRows}`; + } + + types[(transposed ? 'transposed_' : '') + typeName] = { + declaration: (transposed ? 'layout(row_major) ' : '') + `${typeName} data`, + length: numColumns, + std140Length: std140SizePerMinorDim * (majorDim - 1) + minorDim, + std430Length: std430SizePerMinorDim * (majorDim - 1) + minorDim, + zero: `vec${numRows}(0.0f)`, + baseType: baseTypes['float'], + }; + } + } + } + + return types; +})(); + +g.test('bufferMemory') + .params( + params() + .combine(poptions('type', Object.keys(typeParams))) + .combine([ + { memory: 'storage', access: 'read' }, + { memory: 'storage', access: 'write' }, + { memory: 'storage', access: 'atomic' }, + { memory: 'uniform', access: 'read' }, + ]) + // Unsized arrays are only supported with SSBOs + .unless(p => typeParams[p.type].isUnsizedArray === true && p.memory !== 'storage') + // Atomics are only supported with integers + .unless(p => p.access === 'atomic' && !(typeParams[p.type].baseType.name in ['uint', 'int'])) + ) + .fn(async t => { + const type = typeParams[t.params.type]; + const baseType = type.baseType; + + const indicesToTest = [ + // Write to the inside of the type so we can check the size computations were correct. + '0', + `${type.length} - 1`, + + // Check exact bounds + '-1', + `${type.length}`, + + // Check large offset + '-1000000', + '1000000', + + // Check with max uint + `${kUintMax}`, + `-1 * ${kUintMax}`, + + // Check with max int + `${kIntMax}`, + `-1 * ${kIntMax}`, + ]; + + let testSource = ''; + let byteSize = 0; + + // Declare the data that will be accessed to check robust access. + if (t.params.memory === 'uniform') { + testSource += ` + layout(std140, set = 0, binding = 0) uniform TestData { + ${type.declaration}; + };`; + byteSize = baseType.byteSize * type.std140Length; + } else { + testSource += ` + layout(std430, set = 0, binding = 0) buffer TestData { + ${type.declaration}; + };`; + byteSize = baseType.byteSize * type.std430Length; + } + + // Build the test function that will do the tests. + testSource += ` + uint runTest() { + `; + + for (const indexToTest of indicesToTest) { + // TODO check with constants too. + const index = `(${indexToTest}) * one`; + + if (t.params.access === 'read') { + testSource += ` + if(data[${index}] != ${type.zero}) { + return __LINE__; + }`; + } else if (t.params.access === 'write') { + testSource += `data[${index}] = ${type.zero};`; + } else { + testSource += `atomicAdd(data[${index}], 1);`; + } + } + + testSource += ` + return 0; + }`; + + // Create a buffer that contains zeroes in the allowed access area, and 42s everywhere else. + const [testBuffer, testInit] = t.device.createBufferMapped({ + size: 512, + usage: + GPUBufferUsage.COPY_SRC | + GPUBufferUsage.UNIFORM | + GPUBufferUsage.STORAGE | + GPUBufferUsage.COPY_DST, + }); + baseType.fillBuffer(testInit, 256, byteSize); + const testInitCopy = copyArrayBuffer(testInit); + testBuffer.unmap(); + + // Run the shader, accessing the buffer. + runShaderTest(t, GPUShaderStage.COMPUTE, testSource, [ + { binding: 0, resource: { buffer: testBuffer, offset: 256, size: byteSize } }, + ]); + + // Check that content of the buffer outside of the allowed area didn't change. + t.expectSubContents(testBuffer, 0, new Uint8Array(testInitCopy.slice(0, 256))); + const dataEnd = 256 + byteSize; + t.expectSubContents(testBuffer, dataEnd, new Uint8Array(testInitCopy.slice(dataEnd, 512))); + }); + +// TODO: also check other shader stages. +// TODO: also check global, function local, and shared variables. +// TODO: also check interface variables. +// TODO: also check storage texture access. diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/util/conversion.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/util/conversion.ts new file mode 100644 index 00000000000..3d62cdae3f5 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/util/conversion.ts @@ -0,0 +1,71 @@ +import { assert } from '../../common/framework/util/util.js'; + +export function floatAsNormalizedInteger(float: number, bits: number, signed: boolean): number { + if (signed) { + assert(float >= -1 && float <= 1); + const max = Math.pow(2, bits - 1) - 1; + return Math.round(float * max); + } else { + assert(float >= 0 && float <= 1); + const max = Math.pow(2, bits) - 1; + return Math.round(float * max); + } +} + +// Does not handle clamping, underflow, overflow, denormalized numbers +export function float32ToFloatBits( + n: number, + signBits: 0 | 1, + exponentBits: number, + fractionBits: number, + bias: number +): number { + assert(exponentBits <= 8); + assert(fractionBits <= 23); + assert(Number.isFinite(n)); + + if (n === 0) { + return 0; + } + + if (signBits === 0) { + assert(n >= 0); + } + + const buf = new DataView(new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT)); + buf.setFloat32(0, n, true); + const bits = buf.getUint32(0, true); + // bits (32): seeeeeeeefffffffffffffffffffffff + + const fractionBitsToDiscard = 23 - fractionBits; + + // 0 or 1 + const sign = (bits >> 31) & signBits; + + // >> to remove fraction, & to remove sign, - 127 to remove bias. + const exp = ((bits >> 23) & 0xff) - 127; + + // Convert to the new biased exponent. + const newBiasedExp = bias + exp; + assert(newBiasedExp >= 0 && newBiasedExp < 1 << exponentBits); + + // Mask only the fraction, and discard the lower bits. + const newFraction = (bits & 0x7fffff) >> fractionBitsToDiscard; + return (sign << (exponentBits + fractionBits)) | (newBiasedExp << fractionBits) | newFraction; +} + +export function assertInIntegerRange(n: number, bits: number, signed: boolean): void { + if (signed) { + const min = -Math.pow(2, bits - 1); + const max = Math.pow(2, bits - 1) - 1; + assert(n >= min && n <= max); + } else { + const max = Math.pow(2, bits) - 1; + assert(n >= 0 && n <= max); + } +} + +export function gammaCompress(n: number): number { + n = n <= 0.0031308 ? 12.92 * n : 1.055 * Math.pow(n, 1 / 2.4) - 0.055; + return n < 0 ? 0 : n > 1 ? 1 : n; +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/util/math.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/util/math.ts new file mode 100644 index 00000000000..61f898d6295 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/util/math.ts @@ -0,0 +1,7 @@ +export function align(n: number, alignment: number): number { + return Math.ceil(n / alignment) * alignment; +} + +export function isAligned(n: number, alignment: number): boolean { + return n === align(n, alignment); +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/layout.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/layout.ts new file mode 100644 index 00000000000..ccc0bd2f4fb --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/layout.ts @@ -0,0 +1,157 @@ +import { assert, unreachable } from '../../../common/framework/util/util.js'; +import { kTextureFormatInfo } from '../../capability_info.js'; +import { align, isAligned } from '../math.js'; + +export const kBytesPerRowAlignment = 256; +export const kBufferCopyAlignment = 4; + +export interface LayoutOptions { + mipLevel: number; + bytesPerRow?: number; + rowsPerImage?: number; +} + +const kDefaultLayoutOptions = { mipLevel: 0, bytesPerRow: undefined, rowsPerImage: undefined }; + +export function getMipSizePassthroughLayers( + dimension: GPUTextureDimension, + size: [number, number, number], + mipLevel: number +): [number, number, number] { + const shiftMinOne = (n: number) => Math.max(1, n >> mipLevel); + switch (dimension) { + case '1d': + assert(size[2] === 1); + return [shiftMinOne(size[0]), size[1], size[2]]; + case '2d': + return [shiftMinOne(size[0]), shiftMinOne(size[1]), size[2]]; + case '3d': + return [shiftMinOne(size[0]), shiftMinOne(size[1]), shiftMinOne(size[2])]; + default: + unreachable(); + } +} + +export function getTextureCopyLayout( + format: GPUTextureFormat, + dimension: GPUTextureDimension, + size: [number, number, number], + options: LayoutOptions = kDefaultLayoutOptions +): { + bytesPerBlock: number; + byteLength: number; + minBytesPerRow: number; + bytesPerRow: number; + rowsPerImage: number; + mipSize: [number, number, number]; +} { + const { mipLevel } = options; + let { bytesPerRow, rowsPerImage } = options; + + const mipSize = getMipSizePassthroughLayers(dimension, size, mipLevel); + + const { blockWidth, blockHeight, bytesPerBlock } = kTextureFormatInfo[format]; + assert(!!bytesPerBlock && !!blockWidth && !!blockHeight); + + assert(isAligned(mipSize[0], blockWidth)); + const minBytesPerRow = (mipSize[0] / blockWidth) * bytesPerBlock; + const alignedMinBytesPerRow = align(minBytesPerRow, kBytesPerRowAlignment); + if (bytesPerRow !== undefined) { + assert(bytesPerRow >= alignedMinBytesPerRow); + assert(isAligned(bytesPerRow, kBytesPerRowAlignment)); + } else { + bytesPerRow = alignedMinBytesPerRow; + } + + if (rowsPerImage !== undefined) { + assert(rowsPerImage >= mipSize[1]); + } else { + rowsPerImage = mipSize[1]; + } + + assert(isAligned(rowsPerImage, blockHeight)); + const bytesPerSlice = bytesPerRow * (rowsPerImage / blockHeight); + const sliceSize = + bytesPerRow * (mipSize[1] / blockHeight - 1) + bytesPerBlock * (mipSize[0] / blockWidth); + const byteLength = bytesPerSlice * (mipSize[2] - 1) + sliceSize; + + return { + bytesPerBlock, + byteLength: align(byteLength, kBufferCopyAlignment), + minBytesPerRow, + bytesPerRow, + rowsPerImage, + mipSize, + }; +} + +export function fillTextureDataWithTexelValue( + texelValue: ArrayBuffer, + format: GPUTextureFormat, + dimension: GPUTextureDimension, + outputBuffer: ArrayBuffer, + size: [number, number, number], + options: LayoutOptions = kDefaultLayoutOptions +): void { + const { blockWidth, blockHeight, bytesPerBlock } = kTextureFormatInfo[format]; + assert(!!bytesPerBlock && !!blockWidth && !!blockHeight); + assert(bytesPerBlock === texelValue.byteLength); + + const { byteLength, rowsPerImage, bytesPerRow } = getTextureCopyLayout( + format, + dimension, + size, + options + ); + + assert(byteLength <= outputBuffer.byteLength); + + const mipSize = getMipSizePassthroughLayers(dimension, size, options.mipLevel); + + const texelValueBytes = new Uint8Array(texelValue); + const outputTexelValueBytes = new Uint8Array(outputBuffer); + for (let slice = 0; slice < mipSize[2]; ++slice) { + for (let row = 0; row < mipSize[1]; row += blockHeight) { + for (let col = 0; col < mipSize[0]; col += blockWidth) { + const byteOffset = + slice * rowsPerImage * bytesPerRow + row * bytesPerRow + col * texelValue.byteLength; + outputTexelValueBytes.set(texelValueBytes, byteOffset); + } + } + } +} + +export function createTextureUploadBuffer( + texelValue: ArrayBuffer, + device: GPUDevice, + format: GPUTextureFormat, + dimension: GPUTextureDimension, + size: [number, number, number], + options: LayoutOptions = kDefaultLayoutOptions +): { + buffer: GPUBuffer; + bytesPerRow: number; + rowsPerImage: number; +} { + const { byteLength, bytesPerRow, rowsPerImage, bytesPerBlock } = getTextureCopyLayout( + format, + dimension, + size, + options + ); + + const [buffer, mapping] = device.createBufferMapped({ + size: byteLength, + usage: GPUBufferUsage.COPY_SRC, + }); + + assert(texelValue.byteLength === bytesPerBlock); + fillTextureDataWithTexelValue(texelValue, format, dimension, mapping, size, options); + buffer.unmap(); + + return { + buffer, + bytesPerRow, + rowsPerImage, + }; +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/subresource.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/subresource.ts new file mode 100644 index 00000000000..8201002a5f1 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/subresource.ts @@ -0,0 +1,55 @@ +export interface BeginCountRange { + begin: number; + count: number; +} + +export interface BeginEndRange { + begin: number; + end: number; +} + +function endOfRange(r: BeginEndRange | BeginCountRange): number { + return 'count' in r ? r.begin + r.count : r.end; +} + +function* rangeAsIterator(r: BeginEndRange | BeginCountRange): Generator<number> { + for (let i = r.begin; i < endOfRange(r); ++i) { + yield i; + } +} + +export class SubresourceRange { + readonly mipRange: BeginEndRange; + readonly sliceRange: BeginEndRange; + + constructor(subresources: { + mipRange: BeginEndRange | BeginCountRange; + sliceRange: BeginEndRange | BeginCountRange; + }) { + this.mipRange = { + begin: subresources.mipRange.begin, + end: endOfRange(subresources.mipRange), + }; + this.sliceRange = { + begin: subresources.sliceRange.begin, + end: endOfRange(subresources.sliceRange), + }; + } + + *each(): Generator<{ level: number; slice: number }> { + for (let level = this.mipRange.begin; level < this.mipRange.end; ++level) { + for (let slice = this.sliceRange.begin; slice < this.sliceRange.end; ++slice) { + yield { level, slice }; + } + } + } + + *mipLevels(): Generator<{ level: number; slices: Generator<number> }> { + for (let level = this.mipRange.begin; level < this.mipRange.end; ++level) { + yield { + level, + slices: rangeAsIterator(this.sliceRange), + }; + } + } +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/texelData.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/texelData.ts new file mode 100644 index 00000000000..2229a76c16b --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/util/texture/texelData.ts @@ -0,0 +1,341 @@ +import { assert, unreachable } from '../../../common/framework/util/util.js'; +import { kTextureFormatInfo } from '../../capability_info.js'; +import { + assertInIntegerRange, + float32ToFloatBits, + floatAsNormalizedInteger, + gammaCompress, +} from '../conversion.js'; + +export const enum TexelComponent { + R = 'R', + G = 'G', + B = 'B', + A = 'A', + Depth = 'Depth', + Stencil = 'Stencil', +} + +export type PerTexelComponent<T> = { [c in TexelComponent]?: T }; + +const enum TexelWriteType { + Sint, + Uint, + Float, +} + +// Function to convert a value into a texel value. It returns the converted value +// and the type of the converted value. For example, conversion may convert: +// - floats to unsigned normalized integers +// - floats to half floats, interpreted as uint16 bits +type TexelWriteFn = (value: number) => { value: number; type: TexelWriteType }; + +interface SingleComponentInfo { + write: TexelWriteFn; + bitLength: number; +} + +type TexelComponentInfo = PerTexelComponent<null | SingleComponentInfo>; + +const kR = [TexelComponent.R]; +const kRG = [TexelComponent.R, TexelComponent.G]; +const kRGB = [TexelComponent.R, TexelComponent.G, TexelComponent.B]; +const kRGBA = [TexelComponent.R, TexelComponent.G, TexelComponent.B, TexelComponent.A]; +const kBGRA = [TexelComponent.B, TexelComponent.G, TexelComponent.R, TexelComponent.A]; + +const unorm = (bitLength: number) => (n: number) => ({ + value: floatAsNormalizedInteger(n, bitLength, false), + type: TexelWriteType.Uint, +}); + +const snorm = (bitLength: number) => (n: number) => ({ + value: floatAsNormalizedInteger(n, bitLength, true), + type: TexelWriteType.Sint, +}); + +const uint = (bitLength: number) => (n: number) => ({ + value: (assertInIntegerRange(n, bitLength, false), n), + type: TexelWriteType.Uint, +}); + +const sint = (bitLength: number) => (n: number) => ({ + value: (assertInIntegerRange(n, bitLength, true), n), + type: TexelWriteType.Sint, +}); + +const unorm2 = { write: unorm(2), bitLength: 2 }; +const unorm8 = { write: unorm(8), bitLength: 8 }; +const unorm10 = { write: unorm(10), bitLength: 10 }; + +const snorm8 = { write: snorm(8), bitLength: 8 }; + +const uint8 = { write: uint(8), bitLength: 8 }; +const uint16 = { write: uint(16), bitLength: 16 }; +const uint32 = { write: uint(32), bitLength: 32 }; + +const sint8 = { write: sint(8), bitLength: 8 }; +const sint16 = { write: sint(16), bitLength: 16 }; +const sint32 = { write: sint(32), bitLength: 32 }; + +const float10 = { + write: (n: number) => ({ + value: float32ToFloatBits(n, 0, 5, 5, 15), + type: TexelWriteType.Uint, + }), + bitLength: 10, +}; + +const float11 = { + write: (n: number) => ({ + value: float32ToFloatBits(n, 0, 5, 6, 15), + type: TexelWriteType.Uint, + }), + bitLength: 11, +}; + +const float16 = { + write: (n: number) => ({ + value: float32ToFloatBits(n, 1, 5, 10, 15), + type: TexelWriteType.Uint, + }), + bitLength: 16, +}; + +const float32 = { + write: (n: number) => ({ + value: Math.fround(n), + type: TexelWriteType.Float, + }), + bitLength: 32, +}; + +const repeatComponents = ( + componentOrder: TexelComponent[], + perComponentInfo: SingleComponentInfo +) => { + const componentInfo = componentOrder.reduce((acc, curr) => { + return Object.assign(acc, { + [curr]: perComponentInfo, + }); + }, {}); + + return { + componentOrder, + componentInfo, + }; +}; + +const kRepresentationInfo: { + [k in GPUTextureFormat]: { + componentOrder: TexelComponent[]; + componentInfo: TexelComponentInfo; + sRGB: boolean; + // Add fields as needed + }; +} = /* prettier-ignore */ { + 'r8unorm': { ...repeatComponents( kR, unorm8), sRGB: false }, + 'r8snorm': { ...repeatComponents( kR, snorm8), sRGB: false }, + 'r8uint': { ...repeatComponents( kR, uint8), sRGB: false }, + 'r8sint': { ...repeatComponents( kR, sint8), sRGB: false }, + 'r16uint': { ...repeatComponents( kR, uint16), sRGB: false }, + 'r16sint': { ...repeatComponents( kR, sint16), sRGB: false }, + 'r16float': { ...repeatComponents( kR, float16), sRGB: false }, + 'rg8unorm': { ...repeatComponents( kRG, unorm8), sRGB: false }, + 'rg8snorm': { ...repeatComponents( kRG, snorm8), sRGB: false }, + 'rg8uint': { ...repeatComponents( kRG, uint8), sRGB: false }, + 'rg8sint': { ...repeatComponents( kRG, sint8), sRGB: false }, + 'r32uint': { ...repeatComponents( kR, uint32), sRGB: false }, + 'r32sint': { ...repeatComponents( kR, sint32), sRGB: false }, + 'r32float': { ...repeatComponents( kR, float32), sRGB: false }, + 'rg16uint': { ...repeatComponents( kRG, uint16), sRGB: false }, + 'rg16sint': { ...repeatComponents( kRG, sint16), sRGB: false }, + 'rg16float': { ...repeatComponents( kRG, float16), sRGB: false }, + + 'rgba8unorm': { ...repeatComponents(kRGBA, unorm8), sRGB: false }, + 'rgba8unorm-srgb': { ...repeatComponents(kRGBA, unorm8), sRGB: true }, + 'rgba8snorm': { ...repeatComponents(kRGBA, snorm8), sRGB: false }, + 'rgba8uint': { ...repeatComponents(kRGBA, uint8), sRGB: false }, + 'rgba8sint': { ...repeatComponents(kRGBA, sint8), sRGB: false }, + 'bgra8unorm': { ...repeatComponents(kBGRA, unorm8), sRGB: false }, + 'bgra8unorm-srgb': { ...repeatComponents(kBGRA, unorm8), sRGB: true }, + 'rg32uint': { ...repeatComponents( kRG, uint32), sRGB: false }, + 'rg32sint': { ...repeatComponents( kRG, sint32), sRGB: false }, + 'rg32float': { ...repeatComponents( kRG, float32), sRGB: false }, + 'rgba16uint': { ...repeatComponents(kRGBA, uint16), sRGB: false }, + 'rgba16sint': { ...repeatComponents(kRGBA, sint16), sRGB: false }, + 'rgba16float': { ...repeatComponents(kRGBA, float16), sRGB: false }, + 'rgba32uint': { ...repeatComponents(kRGBA, uint32), sRGB: false }, + 'rgba32sint': { ...repeatComponents(kRGBA, sint32), sRGB: false }, + 'rgba32float': { ...repeatComponents(kRGBA, float32), sRGB: false }, + + 'rgb10a2unorm': { componentOrder: kRGBA, componentInfo: { R: unorm10, G: unorm10, B: unorm10, A: unorm2 }, sRGB: false }, + 'rg11b10float': { componentOrder: kRGB, componentInfo: { R: float11, G: float11, B: float10 }, sRGB: false }, + + 'depth32float': { componentOrder: [TexelComponent.Depth], componentInfo: { Depth: float32 }, sRGB: false }, + 'depth24plus': { componentOrder: [TexelComponent.Depth], componentInfo: { Depth: null }, sRGB: false }, + 'depth24plus-stencil8': { componentOrder: [TexelComponent.Depth, TexelComponent.Stencil], componentInfo: { Depth: null, Stencil: null }, sRGB: false }, +}; + +export interface TexelDataRepresentation { + readonly componentOrder: TexelComponent[]; + readonly componentInfo: TexelComponentInfo; + getBytes(components: { [c in TexelComponent]?: number }): ArrayBuffer; +} + +class TexelDataRepresentationImpl implements TexelDataRepresentation { + // TODO: Determine endianness of the GPU data? + private isGPULittleEndian = true; + + constructor( + private readonly format: GPUTextureFormat, + readonly componentOrder: TexelComponent[], + readonly componentInfo: TexelComponentInfo, + private readonly sRGB: boolean + ) {} + + private totalBitLength(): number { + return this.componentOrder.reduce((acc, curr) => { + return acc + this.componentInfo[curr]!.bitLength; + }, 0); + } + + private setComponent(data: ArrayBuffer, component: TexelComponent, n: number): void { + const componentIndex = this.componentOrder.indexOf(component); + assert(componentIndex !== -1); + const bitOffset = this.componentOrder.slice(0, componentIndex).reduce((acc, curr) => { + const componentInfo = this.componentInfo[curr]; + assert(!!componentInfo); + return acc + componentInfo.bitLength; + }, 0); + + const componentInfo = this.componentInfo[component]; + assert(!!componentInfo); + const { write, bitLength } = componentInfo; + + const { value, type } = write(n); + switch (type) { + case TexelWriteType.Float: { + const byteOffset = Math.floor(bitOffset / 8); + const byteLength = Math.ceil(bitLength / 8); + assert(byteOffset === bitOffset / 8 && byteLength === bitLength / 8); + switch (byteLength) { + case 4: + new DataView(data, byteOffset, byteLength).setFloat32(0, value, this.isGPULittleEndian); + break; + default: + unreachable(); + } + break; + } + case TexelWriteType.Sint: { + const byteOffset = Math.floor(bitOffset / 8); + const byteLength = Math.ceil(bitLength / 8); + assert(byteOffset === bitOffset / 8 && byteLength === bitLength / 8); + switch (byteLength) { + case 1: + new DataView(data, byteOffset, byteLength).setInt8(0, value); + break; + case 2: + new DataView(data, byteOffset, byteLength).setInt16(0, value, this.isGPULittleEndian); + break; + case 4: + new DataView(data, byteOffset, byteLength).setInt32(0, value, this.isGPULittleEndian); + break; + default: + unreachable(); + } + break; + } + case TexelWriteType.Uint: { + const byteOffset = Math.floor(bitOffset / 8); + const byteLength = Math.ceil(bitLength / 8); + if (byteOffset === bitOffset / 8 && byteLength === bitLength / 8) { + switch (byteLength) { + case 1: + new DataView(data, byteOffset, byteLength).setUint8(0, value); + break; + case 2: + new DataView(data, byteOffset, byteLength).setUint16( + 0, + value, + this.isGPULittleEndian + ); + break; + case 4: + new DataView(data, byteOffset, byteLength).setUint32( + 0, + value, + this.isGPULittleEndian + ); + break; + default: + unreachable(); + } + } else { + // Packed representations are all 32-bit and use Uint as the data type. + // ex.) rg10b11float, rgb10a2unorm + switch (this.totalBitLength()) { + case 32: { + const view = new DataView(data); + const currentValue = view.getUint32(0, this.isGPULittleEndian); + + let mask = 0xffffffff; + const bitsToClearRight = bitOffset; + const bitsToClearLeft = 32 - (bitLength + bitOffset); + + mask = (mask >>> bitsToClearRight) << bitsToClearRight; + mask = (mask << bitsToClearLeft) >>> bitsToClearLeft; + + const newValue = (currentValue & ~mask) | (value << bitOffset); + + view.setUint32(0, newValue, this.isGPULittleEndian); + break; + } + default: + unreachable(); + } + } + break; + } + default: + unreachable(); + } + } + + getBytes(components: PerTexelComponent<number>): ArrayBuffer { + if (this.sRGB) { + components = Object.assign({}, components); + assert(components.R !== undefined); + assert(components.G !== undefined); + assert(components.B !== undefined); + [components.R, components.G, components.B] = [ + gammaCompress(components.R), + gammaCompress(components.G), + gammaCompress(components.B), + ]; + } + + const bytesPerBlock = kTextureFormatInfo[this.format].bytesPerBlock; + assert(!!bytesPerBlock); + + const data = new ArrayBuffer(bytesPerBlock); + for (const c of this.componentOrder) { + const componentValue = components[c]; + assert(componentValue !== undefined); + this.setComponent(data, c, componentValue); + } + return data; + } +} + +const kRepresentationCache: Map<GPUTextureFormat, TexelDataRepresentationImpl> = new Map(); +export function getTexelDataRepresentation(format: GPUTextureFormat): TexelDataRepresentation { + if (!kRepresentationCache.has(format)) { + const { componentOrder, componentInfo, sRGB } = kRepresentationInfo[format]; + kRepresentationCache.set( + format, + new TexelDataRepresentationImpl(format, componentOrder, componentInfo, sRGB) + ); + } + return kRepresentationCache.get(format)!; +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/canvas/context_creation.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/canvas/context_creation.spec.ts index a3de901e919..e2c79db9fe2 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/canvas/context_creation.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/canvas/context_creation.spec.ts @@ -1,11 +1,11 @@ -export const description = ``; +export const description = ''; import { Fixture } from '../../../common/framework/fixture.js'; -import { TestGroup } from '../../../common/framework/test_group.js'; +import { makeTestGroup } from '../../../common/framework/test_group.js'; -export const g = new TestGroup(Fixture); +export const g = makeTestGroup(Fixture); -g.test('canvas element getContext returns GPUCanvasContext', async t => { +g.test('canvas_element_getContext_returns_GPUCanvasContext').fn(async t => { if (typeof document === 'undefined') { // Skip if there is no document (Workers, Node) t.skip('DOM is not available to create canvas element'); @@ -16,8 +16,8 @@ g.test('canvas element getContext returns GPUCanvasContext', async t => { canvas.height = 10; // TODO: fix types so these aren't necessary - // tslint:disable-next-line: no-any + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const ctx: any = canvas.getContext('gpupresent'); - // tslint:disable-next-line: no-any + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ t.expect(ctx instanceof (window as any).GPUCanvasContext); }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/copyImageBitmapToTexture.spec.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/copyImageBitmapToTexture.spec.ts index ce411f2eab6..34cd83982e8 100644 --- a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/copyImageBitmapToTexture.spec.ts +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/copyImageBitmapToTexture.spec.ts @@ -2,8 +2,8 @@ export const description = ` copy imageBitmap To texture tests. `; -import { pcombine, poptions } from '../../common/framework/params.js'; -import { TestGroup } from '../../common/framework/test_group.js'; +import { poptions, params } from '../../common/framework/params_builder.js'; +import { makeTestGroup } from '../../common/framework/test_group.js'; import { GPUTest } from '../gpu_test.js'; function calculateRowPitch(width: number, bytesPerPixel: number): number { @@ -22,7 +22,7 @@ class F extends GPUTest { ): void { const exp = new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength); const rowPitch = calculateRowPitch(width, bytesPerPixel); - const dst = this.createCopyForMapRead(src, rowPitch * height); + const dst = this.createCopyForMapRead(src, 0, rowPitch * height); this.eventualAsyncExpectation(async niceStack => { const actual = new Uint8Array(await dst.mapReadAsync()); @@ -36,7 +36,7 @@ class F extends GPUTest { ); if (check !== undefined) { niceStack.message = check; - this.rec.fail(niceStack); + this.rec.expectationFailed(niceStack); } dst.destroy(); }); @@ -50,27 +50,33 @@ class F extends GPUTest { rowPitch: number, bytesPerPixel: number ): string | undefined { - const lines = []; - let failedPixels = 0; - for (let i = 0; i < height; ++i) { + const failedByteIndices: string[] = []; + const failedByteExpectedValues: string[] = []; + const failedByteActualValues: string[] = []; + iLoop: for (let i = 0; i < height; ++i) { const bytesPerRow = width * bytesPerPixel; for (let j = 0; j < bytesPerRow; ++j) { const indexExp = j + i * bytesPerRow; const indexActual = j + rowPitch * i; if (actual[indexActual] !== exp[indexExp]) { - if (failedPixels > 4) { - break; + if (failedByteIndices.length >= 4) { + failedByteIndices.push('...'); + failedByteExpectedValues.push('...'); + failedByteActualValues.push('...'); + break iLoop; } - failedPixels++; - lines.push(`at [${indexExp}], expected ${exp[indexExp]}, got ${actual[indexActual]}`); + failedByteIndices.push(`(${i},${j})`); + failedByteExpectedValues.push(exp[indexExp].toString()); + failedByteActualValues.push(actual[indexActual].toString()); } } - if (failedPixels > 4) { - lines.push('... and more'); - break; - } } - return failedPixels > 0 ? lines.join('\n') : undefined; + if (failedByteIndices.length > 0) { + return `at [${failedByteIndices.join(', ')}], \ +expected [${failedByteExpectedValues.join(', ')}], \ +got [${failedByteActualValues.join(', ')}]`; + } + return undefined; } doTestAndCheckResult( @@ -114,108 +120,156 @@ class F extends GPUTest { } } -export const g = new TestGroup(F); +export const g = makeTestGroup(F); -g.test('from ImageData', async t => { - const { width, height } = t.params; +g.test('from_ImageData') + .params( + params() + .combine(poptions('width', [1, 2, 4, 15, 255, 256])) + .combine(poptions('height', [1, 2, 4, 15, 255, 256])) + .combine(poptions('alpha', ['none', 'premultiply'])) + .combine(poptions('orientation', ['none', 'flipY'])) + ) + .fn(async t => { + const { width, height, alpha, orientation } = t.params; - // The texture format is rgba8unorm, so the bytes per pixel is 4. - const bytesPerPixel = 4; + // The texture format is rgba8unorm, so the bytes per pixel is 4. + const bytesPerPixel = 4; - const imagePixels = new Uint8ClampedArray(bytesPerPixel * width * height); - for (let i = 0; i < width * height * bytesPerPixel; ++i) { - imagePixels[i] = i % 4 === 3 ? 255 : i % 256; - } + const imagePixels = new Uint8ClampedArray(bytesPerPixel * width * height); + if (alpha === 'premultiply') { + // Make expected value simple to construct: + // Input is (255, 255, 255, a), which will be stored into the ImageBitmap + // as (a, a, a, a). + for (let i = 0; i < width * height * bytesPerPixel; ++i) { + imagePixels[i] = i % 4 !== 3 ? 255 : i % 256; + } + } else { + for (let i = 0; i < width * height * bytesPerPixel; ++i) { + imagePixels[i] = i % 4 === 3 ? 255 : i % 256; + } + } + + const imageData = new ImageData(imagePixels, width, height); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const imageBitmap = await (createImageBitmap as any)(imageData, { + premultiplyAlpha: alpha, + imageOrientation: orientation, + }); + + const dst = t.device.createTexture({ + size: { + width: imageBitmap.width, + height: imageBitmap.height, + depth: 1, + }, + format: 'rgba8unorm', + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, + }); + + // Construct expected value + const expectedPixels = new Uint8ClampedArray(bytesPerPixel * width * height); + for (let i = 0; i < width * height * bytesPerPixel; ++i) { + expectedPixels[i] = imagePixels[i]; + } + + if (orientation === 'flipY') { + for (let i = 0; i < height; ++i) { + for (let j = 0; j < width * bytesPerPixel; ++j) { + const pos_image_pixel = (height - i - 1) * width * bytesPerPixel + j; + const pos_expected_value = i * width * bytesPerPixel + j; + expectedPixels[pos_expected_value] = imagePixels[pos_image_pixel]; + } + } + } + + if (alpha === 'premultiply') { + for (let i = 0; i < width * height * bytesPerPixel; ++i) { + const alpha_value_position = 3 - (i % 4) + i; + if (i % 4 !== 3) { + // Expected value is (a, a, a, a) + expectedPixels[i] = expectedPixels[alpha_value_position]; + } + } + } - const imageData = new ImageData(imagePixels, width, height); - const imageBitmap = await createImageBitmap(imageData); - - const dst = t.device.createTexture({ - size: { - width: imageBitmap.width, - height: imageBitmap.height, - depth: 1, - }, - format: 'rgba8unorm', - usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, + t.doTestAndCheckResult( + { imageBitmap, origin: { x: 0, y: 0 } }, + { texture: dst }, + { width: imageBitmap.width, height: imageBitmap.height, depth: 1 }, + bytesPerPixel, + expectedPixels + ); }); - t.doTestAndCheckResult( - { imageBitmap, origin: { x: 0, y: 0 } }, - { texture: dst }, - { width: imageBitmap.width, height: imageBitmap.height, depth: 1 }, - bytesPerPixel, - imagePixels - ); -}).params( - pcombine( - poptions('width', [1, 2, 4, 15, 255, 256]), // - poptions('height', [1, 2, 4, 15, 255, 256]) +g.test('from_canvas') + .params( + params() + .combine(poptions('width', [1, 2, 4, 15, 255, 256])) + .combine(poptions('height', [1, 2, 4, 15, 255, 256])) ) -); - -g.test('from canvas', async t => { - const { width, height } = t.params; - - // CTS sometimes runs on worker threads, where document is not available. - // In this case, OffscreenCanvas can be used instead of <canvas>. - // But some browsers don't support OffscreenCanvas, and some don't - // support '2d' contexts on OffscreenCanvas. - // In this situation, the case will be skipped. - let imageCanvas; - if (typeof document !== 'undefined') { - imageCanvas = document.createElement('canvas'); - imageCanvas.width = width; - imageCanvas.height = height; - } else if (typeof OffscreenCanvas === 'undefined') { - t.skip('OffscreenCanvas is not supported'); - return; - } else { - imageCanvas = new OffscreenCanvas(width, height); - } - const imageCanvasContext = imageCanvas.getContext('2d'); - if (imageCanvasContext === null) { - t.skip('OffscreenCanvas "2d" context not available'); - return; - } + .fn(async t => { + const { width, height } = t.params; - // The texture format is rgba8unorm, so the bytes per pixel is 4. - const bytesPerPixel = 4; + // CTS sometimes runs on worker threads, where document is not available. + // In this case, OffscreenCanvas can be used instead of <canvas>. + // But some browsers don't support OffscreenCanvas, and some don't + // support '2d' contexts on OffscreenCanvas. + // In this situation, the case will be skipped. + let imageCanvas; + if (typeof document !== 'undefined') { + imageCanvas = document.createElement('canvas'); + imageCanvas.width = width; + imageCanvas.height = height; + } else if (typeof OffscreenCanvas === 'undefined') { + t.skip('OffscreenCanvas is not supported'); + return; + } else { + imageCanvas = new OffscreenCanvas(width, height); + } + const imageCanvasContext = imageCanvas.getContext('2d'); + if (imageCanvasContext === null) { + t.skip('OffscreenCanvas "2d" context not available'); + return; + } - // Generate original data. - const imagePixels = new Uint8ClampedArray(bytesPerPixel * width * height); - for (let i = 0; i < width * height * bytesPerPixel; ++i) { - imagePixels[i] = i % 256; - } + // The texture format is rgba8unorm, so the bytes per pixel is 4. + const bytesPerPixel = 4; - const imageData = new ImageData(imagePixels, width, height); - imageCanvasContext.putImageData(imageData, 0, 0); + // Generate original data. + const imagePixels = new Uint8ClampedArray(bytesPerPixel * width * height); + for (let i = 0; i < width * height * bytesPerPixel; ++i) { + imagePixels[i] = i % 4 === 3 ? 255 : i % 256; + } - const imageBitmap = await createImageBitmap(imageCanvas); + const imageData = new ImageData(imagePixels, width, height); + imageCanvasContext.putImageData(imageData, 0, 0); - const dst = t.device.createTexture({ - size: { - width: imageBitmap.width, - height: imageBitmap.height, - depth: 1, - }, - format: 'rgba8unorm', - usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, - }); + const imageBitmap = await createImageBitmap(imageCanvas); - const expectedData = imageCanvasContext.getImageData(0, 0, imageBitmap.width, imageBitmap.height) - .data; - - t.doTestAndCheckResult( - { imageBitmap, origin: { x: 0, y: 0 } }, - { texture: dst }, - { width: imageBitmap.width, height: imageBitmap.height, depth: 1 }, - bytesPerPixel, - expectedData - ); -}).params( - pcombine( - poptions('width', [1, 2, 4, 15, 255, 256]), // - poptions('height', [1, 2, 4, 15, 255, 256]) - ) -); + const dst = t.device.createTexture({ + size: { + width: imageBitmap.width, + height: imageBitmap.height, + depth: 1, + }, + format: 'rgba8unorm', + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, + }); + + // This will get origin data and even it has premultiplied-alpha + const expectedData = imageCanvasContext.getImageData( + 0, + 0, + imageBitmap.width, + imageBitmap.height + ).data; + + t.doTestAndCheckResult( + { imageBitmap, origin: { x: 0, y: 0 } }, + { texture: dst }, + { width: imageBitmap.width, height: imageBitmap.height, depth: 1 }, + bytesPerPixel, + expectedData + ); + }); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_clear.html b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_clear.html new file mode 100644 index 00000000000..86a3da939db --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_clear.html @@ -0,0 +1,10 @@ +<html class="reftest-wait"> + <title>WebGPU canvas_clear</title> + <meta charset="utf-8" /> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <meta name="assert" content="WebGPU cleared canvas should be presented correctly" /> + <link rel="match" href="./ref/canvas_clear-ref.html" /> + <canvas id="gpucanvas" width="10" height="10"></canvas> + <script src="/common/reftest-wait.js"></script> + <script type="module" src="canvas_clear.js"></script> +</html> diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_clear.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_clear.ts new file mode 100644 index 00000000000..799e3ad9292 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_clear.ts @@ -0,0 +1,27 @@ +import { runRefTest } from './gpu_ref_test.js'; + +runRefTest(async t => { + const canvas = document.getElementById('gpucanvas') as HTMLCanvasElement; + + const ctx = (canvas.getContext('gpupresent') as unknown) as GPUCanvasContext; + const swapChain = ctx.configureSwapChain({ + device: t.device, + format: 'bgra8unorm', + }); + + const colorAttachment = swapChain.getCurrentTexture(); + const colorAttachmentView = colorAttachment.createView(); + + const encoder = t.device.createCommandEncoder(); + const pass = encoder.beginRenderPass({ + colorAttachments: [ + { + attachment: colorAttachmentView, + loadValue: { r: 0.0, g: 1.0, b: 0.0, a: 1.0 }, + storeOp: 'store', + }, + ], + }); + pass.endPass(); + t.device.defaultQueue.submit([encoder.finish()]); +}); diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_complex.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_complex.ts new file mode 100644 index 00000000000..4c8854b732f --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_complex.ts @@ -0,0 +1,76 @@ +import { unreachable } from '../../../common/framework/util/util.js'; + +import { runRefTest } from './gpu_ref_test.js'; + +// <canvas> element from html page +declare const cvs: HTMLCanvasElement; + +export function run(format: GPUTextureFormat) { + runRefTest(async t => { + const ctx = (cvs.getContext('gpupresent') as unknown) as GPUCanvasContext; + + switch (format) { + case 'bgra8unorm': + case 'rgba16float': + break; + default: + unreachable(); + } + + const swapChain = ctx.configureSwapChain({ + device: t.device, + format, + usage: GPUTextureUsage.COPY_DST, + }); + + const rows = 2; + const bytesPerRow = 256; + const [buffer, mapping] = t.device.createBufferMapped({ + size: rows * bytesPerRow, + usage: GPUBufferUsage.COPY_SRC, + }); + switch (format) { + case 'bgra8unorm': + { + const data = new Uint8Array(mapping); + data.set(new Uint8Array([0x00, 0x00, 0x7f, 0xff]), 0); // red + data.set(new Uint8Array([0x00, 0x7f, 0x00, 0xff]), 4); // green + data.set(new Uint8Array([0x7f, 0x00, 0x00, 0xff]), 256 + 0); // blue + data.set(new Uint8Array([0x00, 0x7f, 0x7f, 0xff]), 256 + 4); // yellow + } + break; + case 'rgba16float': + { + // Untested! + const zero = 0x0000; + const half = 0x3800; + const one = 0x3c00; + const data = new DataView(mapping); + data.setUint16(0x000, half, false); // red + data.setUint16(0x002, zero, false); + data.setUint16(0x004, zero, false); + data.setUint16(0x008, one, false); + data.setUint16(0x010, zero, false); // green + data.setUint16(0x020, half, false); + data.setUint16(0x040, zero, false); + data.setUint16(0x080, one, false); + data.setUint16(0x100, zero, false); // blue + data.setUint16(0x102, zero, false); + data.setUint16(0x104, half, false); + data.setUint16(0x108, one, false); + data.setUint16(0x110, half, false); // yellow + data.setUint16(0x120, half, false); + data.setUint16(0x140, zero, false); + data.setUint16(0x180, one, false); + } + break; + } + buffer.unmap(); + + const texture = swapChain.getCurrentTexture(); + + const encoder = t.device.createCommandEncoder(); + encoder.copyBufferToTexture({ buffer, bytesPerRow }, { texture }, [2, 2, 1]); + t.device.defaultQueue.submit([encoder.finish()]); + }); +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html new file mode 100644 index 00000000000..1310543648e --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html @@ -0,0 +1,18 @@ +<html class="reftest-wait"> + <title>WebGPU canvas_complex_bgra8unorm</title> + <meta charset="utf-8" /> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <meta + name="assert" + content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" + /> + <link rel="match" href="./ref/canvas_complex-ref.html" /> + + <canvas id="cvs" width="2" height="2" style="width: 20px; height: 20px;"></canvas> + <script src="/common/reftest-wait.js"></script> + <script type="module"> + import { run } from './canvas_complex.js'; + run('bgra8unorm'); + // TODO: make a copy of this test for rgba16float + </script> +</html> diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/gpu_ref_test.ts b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/gpu_ref_test.ts new file mode 100644 index 00000000000..929f143b0ba --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/gpu_ref_test.ts @@ -0,0 +1,23 @@ +import { assert } from '../../../common/framework/util/util.js'; + +declare function takeScreenshotDelayed(ms: number): void; + +interface GPURefTest { + readonly device: GPUDevice; + readonly queue: GPUQueue; +} + +export async function runRefTest(fn: (t: GPURefTest) => Promise<void>): Promise<void> { + assert( + typeof navigator !== 'undefined' && navigator.gpu !== undefined, + 'No WebGPU implementation found' + ); + + const adapter = await navigator.gpu.requestAdapter(); + const device = await adapter.requestDevice(); + const queue = device.defaultQueue; + + await fn({ device, queue }); + + takeScreenshotDelayed(50); +} diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/ref/canvas_clear-ref.html b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/ref/canvas_clear-ref.html new file mode 100644 index 00000000000..2e078118627 --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/ref/canvas_clear-ref.html @@ -0,0 +1,12 @@ +<html> + <title>WebGPU canvas_clear (ref)</title> + <meta charset="utf-8" /> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <canvas id="myCanvas" width="10" height="10"></canvas> + <script> + var c = document.getElementById('myCanvas'); + var ctx = c.getContext('2d'); + ctx.fillStyle = '#00FF00'; + ctx.fillRect(0, 0, c.width, c.height); + </script> +</html> diff --git a/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/ref/canvas_complex-ref.html b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/ref/canvas_complex-ref.html new file mode 100644 index 00000000000..3d5b3b3376d --- /dev/null +++ b/chromium/third_party/webgpu-cts/src/src/webgpu/web-platform/reftests/ref/canvas_complex-ref.html @@ -0,0 +1,17 @@ +<html> + <title>WebGPU canvas_complex (ref)</title> + <meta charset="utf-8" /> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <canvas id="cvs" width="2" height="2" style="width: 20px; height: 20px;"></canvas> + <script> + const ctx = cvs.getContext('2d'); + ctx.fillStyle = '#7F0000'; + ctx.fillRect(0, 0, 1, 1); + ctx.fillStyle = '#007F00'; + ctx.fillRect(1, 0, 1, 1); + ctx.fillStyle = '#00007F'; + ctx.fillRect(0, 1, 1, 1); + ctx.fillStyle = '#7F7F00'; + ctx.fillRect(1, 1, 1, 1); + </script> +</html> diff --git a/chromium/third_party/webgpu-cts/src/standalone/index.html b/chromium/third_party/webgpu-cts/src/standalone/index.html index 7f59163f409..67e579b2809 100644 --- a/chromium/third_party/webgpu-cts/src/standalone/index.html +++ b/chromium/third_party/webgpu-cts/src/standalone/index.html @@ -1,6 +1,6 @@ <html> <head> - <title></title> + <title>WebGPU CTS</title> <link id="favicon" rel="shortcut icon" @@ -39,10 +39,15 @@ .nodeheader { display: flex; width: 100%; - padding: 1px 2px 1px 1px; + padding: 0px 2px 0px 1px; } - .noderun, + .nodeheader:hover { + background: rgba(0, 0, 0, 0.1); + } + .subtreerun, + .leafrun, .nodelink, + .collapsebtn, .testcaselogbtn { display: inline-block; flex-shrink: 0; @@ -54,18 +59,22 @@ border: 1px solid #888; } @media (pointer: fine) { - .noderun, + .subtreerun, + .leafrun, .nodelink, + .collapsebtn, .testcaselogbtn { flex-basis: 24px; border-radius: 4px; width: 24px; - height: 24px; + height: 18px; } } @media (pointer: coarse) { - .noderun, + .subtreerun, + .leafrun, .nodelink, + .collapsebtn, .testcaselogbtn { flex-basis: 36px; border-radius: 6px; @@ -73,7 +82,10 @@ height: 36px; } } - .noderun { + .subtreerun { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAQMAAADaX5RTAAAABlBMVEUAAAAAAAClZ7nPAAAAAXRSTlMAQObYZgAAAB5JREFUCNdjOMDAsIGBoYeBoZmBoaEBRPaARQ4wAABTfwX/l/WQvgAAAABJRU5ErkJggg==); + } + .leafrun { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAANklEQVQoU2NkYGD4zwABjFAagwJJwBTBJDEUY1OEoRifIrhiYhSBHYvuJnSHM5LtJry+wxlOAGPTCQmAB/WwAAAAAElFTkSuQmCC); } .nodelink { @@ -83,12 +95,21 @@ flex: 10 0 4em; } .nodename { - user-select: all; - word-break: break-word; - } - @media only screen and (max-width: 600px) { - /* TODO: make the uninteresting part of the name be really small or something, such that it gets - * auto selected but doesn't take space. */ + margin: 0 0.5em; + padding: 2px; + } + .leafname { + background: black; + color: white; + } + .nodequery { + background: transparent; + border: none; + padding: 2px; + margin: 0 0.5em; + color: #999; + width: 50%; + max-width: 50%; } .nodedescription { margin: 0; @@ -101,7 +122,20 @@ margin: 0px; border-width: 1px 0 0 1px; border-style: solid; - border-color: gray; + border-color: #ddd; + } + .subtree:hover { + border-left-color: #000; + } + .subtree.multifile > .subtreechildren > .subtree.multitest, + .subtree.multifile > .subtreechildren > .subtree.multicase { + border-width: 2px 0 0 1px; + border-color: #55f; + } + .subtree.multitest > .subtreechildren > .subtree.multicase, + .subtree.multitest > .subtreechildren > .testcase { + border-width: 2px 0 0 1px; + border-color: #bbf; } .subtreechildren { margin-left: 6px; @@ -116,7 +150,7 @@ background: white; } .testcase[data-status='fail'] { - background: #fcc; + background: #fdd; } .testcase[data-status='warn'] { background: #ffb; @@ -125,7 +159,7 @@ background: #cfc; } .testcase[data-status='skip'] { - background: #ccc; + background: #eee; } .testcasetime { white-space: nowrap; @@ -174,18 +208,14 @@ } } </style> - <script> - if (!window.location.search) { - window.location += '?runnow=0&worker=0&debug=0&q=webgpu:'; - } - </script> </head> <body> <h1>WebGPU Conformance Test Suite</h1> + <input type="checkbox" id="expandall" /><label for="expandall">Expand All</label> <div id="info"></div> <div id="resultsVis"></div> - <textarea id="resultsJSON"></textarea> + <textarea id="resultsJSON" spellcheck="false"></textarea> <script type="module" src="../out/common/runtime/standalone.js"></script> </body> diff --git a/chromium/third_party/webgpu-cts/src/tools/gen_version b/chromium/third_party/webgpu-cts/src/tools/gen_version index a8194e0f9af..fad05631769 100755 --- a/chromium/third_party/webgpu-cts/src/tools/gen_version +++ b/chromium/third_party/webgpu-cts/src/tools/gen_version @@ -3,7 +3,7 @@ // Get the current git hash, and save (overwrite) it into out/framework/version.js // so it can be read when running inside the browser. -// tslint:disable: no-console +/* eslint-disable no-console */ require('../src/common/tools/setup-ts-in-node.js'); const fs = require('fs'); diff --git a/chromium/third_party/webgpu-cts/src/tsconfig.json b/chromium/third_party/webgpu-cts/src/tsconfig.json index 4b4005c2e2b..7c7ea043d51 100644 --- a/chromium/third_party/webgpu-cts/src/tsconfig.json +++ b/chromium/third_party/webgpu-cts/src/tsconfig.json @@ -3,22 +3,17 @@ "compilerOptions": { "lib": ["dom", "es2016"], "module": "esnext", - /* Output options */ "noEmit": true, - /* Strict type-checking options */ "allowJs": false, "strict": true, "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, "noUnusedLocals": true, - /* Module Options */ "moduleResolution": "node", - "esModuleInterop": false, + "esModuleInterop": false }, - "include": [ - "src/**/*.ts", - ], + "include": ["src/**/*.ts"] } diff --git a/chromium/third_party/webgpu-cts/src/tslint.json b/chromium/third_party/webgpu-cts/src/tslint.json deleted file mode 100644 index 9c3e591cba9..00000000000 --- a/chromium/third_party/webgpu-cts/src/tslint.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "extends": "gts/tslint.json", - "rules": { - "ban": [ - true, - { - "name": "setTimeout", - "message": "WPT (Web Platform Tests) doesn't allow setTimeout." - } - ], - "linebreak-style": [ - true, - "LF" - ], - "no-console": [ - true - ], - "ordered-imports": [ - true, - { - "grouped-imports": true, - "named-imports-order": "lowercase-last" - } - ], - "typedef": [ - true, - "call-signature", - "parameter", - "property-declaration" - ], - "no-inferrable-types": false - }, - "linterOptions": { - "exclude": [ - "**/*.json" - ] - } -} diff --git a/chromium/third_party/webgpu-cts/src/yarn.lock b/chromium/third_party/webgpu-cts/src/yarn.lock deleted file mode 100644 index dd28454d3c8..00000000000 --- a/chromium/third_party/webgpu-cts/src/yarn.lock +++ /dev/null @@ -1,3557 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/cli@^7.7.7": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.8.4.tgz#505fb053721a98777b2b175323ea4f090b7d3c1c" - integrity sha512-XXLgAm6LBbaNxaGhMAznXXaxtCWfuv6PIDJ9Alsy9JYTOh+j2jJz+L/162kkfU1j/pTSxK1xGmlwI4pdIMkoag== - dependencies: - commander "^4.0.1" - convert-source-map "^1.1.0" - fs-readdir-recursive "^1.1.0" - glob "^7.0.0" - lodash "^4.17.13" - make-dir "^2.1.0" - slash "^2.0.0" - source-map "^0.5.0" - optionalDependencies: - chokidar "^2.1.8" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/core@^7.7.7": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce" - integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA== - dependencies: - "@babel/types" "^7.9.0" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-create-class-features-plugin@^7.8.3": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz#243a5b46e2f8f0f674dc1387631eb6b28b851de0" - integrity sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-split-export-declaration" "^7.8.3" - -"@babel/helper-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" - integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== - -"@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== - dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-validator-identifier@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" - integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== - -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" - integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== - -"@babel/plugin-proposal-class-properties@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e" - integrity sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-dynamic-import@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-import-meta@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.8.3.tgz#230afff79d3ccc215b5944b438e4e266daf3d84d" - integrity sha512-vYiGd4wQ9gx0Lngb7+bPCwQXGK/PR6FeTIJ+TIOlq+OfOKG/kCAOO2+IBac3oMM9qV7/fU76hfcqxUaLKZf1hQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-typescript@^7.3.3", "@babel/plugin-syntax-typescript@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz#c1f659dda97711a569cef75275f7e15dcaa6cabc" - integrity sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-typescript@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.9.4.tgz#4bb4dde4f10bbf2d787fce9707fb09b483e33359" - integrity sha512-yeWeUkKx2auDbSxRe8MusAG+n4m9BFY/v+lPjmQDgOFX5qnySkUY5oXzkp6FwPdsYqnKay6lorXYdC0n3bZO7w== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-typescript" "^7.8.3" - -"@babel/preset-typescript@^7.7.7": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz#87705a72b1f0d59df21c179f7c3d2ef4b16ce192" - integrity sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-typescript" "^7.9.0" - -"@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" - integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" - integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== - dependencies: - "@nodelib/fs.stat" "2.0.3" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== - dependencies: - "@nodelib/fs.scandir" "2.1.3" - fastq "^1.6.0" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -"@types/jquery@^3.3.30": - version "3.3.34" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.34.tgz#0d3b94057063d3854adaeb579652048fec07ba6c" - integrity sha512-lW9vsVL53Xu/Nj4gi2hNmHGc4u3KKghjqTkAlO0kF5GIOPxbqqnQpgqJBzmn3yXLrPqHb6cmNJ6URnS23Vtvbg== - dependencies: - "@types/sizzle" "*" - -"@types/node@^13.1.2": - version "13.11.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b" - integrity sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ== - -"@types/offscreencanvas@^2019.6.1": - version "2019.6.2" - resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.6.2.tgz#9bd6f5a9a70459ec0ce7ecedf45d63e38d744c86" - integrity sha512-ndVeLKDF10p4hZswi0KKSUWAmNoTcgz8LUPiIIPeT3qD8bTaYe0pXyuyQ21+DmGRMkT8orxiISm4O+YpMLCDBw== - dependencies: - "@types/webgl2" "*" - -"@types/sizzle@*": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" - integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== - -"@types/webgl2@*": - version "0.0.5" - resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.5.tgz#dd925e20ab8ace80eb4b1e46fda5b109c508fb0d" - integrity sha512-oGaKsBbxQOY5+aJFV3KECDhGaXt+yZJt2y/OZsnQGLRkH6Fvr7rv4pCt3SRH1somIHfej/c4u7NSpCyd9x+1Ow== - -"@webgpu/glslang@^0.0.15": - version "0.0.15" - resolved "https://registry.yarnpkg.com/@webgpu/glslang/-/glslang-0.0.15.tgz#f5ccaf6015241e6175f4b90906b053f88483d1f2" - integrity sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q== - -"@webgpu/types@0.0.22": - version "0.0.22" - resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.0.22.tgz#320ccd7a8560061b5a6a2db7d5965b861bded004" - integrity sha512-qT2NUglkiWcnqmgyrqDU79F7FdQXQX4h1TEALWIY7od2gI+1FcbKnAPvb6qW9XfGEqGaxOFVliotY5U/ewdQAA== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -ansi-align@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" - integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== - dependencies: - string-width "^3.0.0" - -ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== - dependencies: - type-fest "^0.11.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -async@^1.5.2, async@~1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - -async@^2.6.1, async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -babel-plugin-add-header-comment@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-add-header-comment/-/babel-plugin-add-header-comment-1.0.3.tgz#511c4901062640d5a480b4ac3edd6944195850ec" - integrity sha1-URxJAQYmQNWkgLSsPt1pRBlYUOw= - -babel-plugin-const-enum@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/babel-plugin-const-enum/-/babel-plugin-const-enum-0.0.5.tgz#1e807d52572bb193a0df60130ed06b07a59b04b3" - integrity sha512-EAOnmHcsn+hbMS1yYZoc0jBemNbRR+NATO9RrLJF/1iXJbDTEaOwH0Y7XPb7vvWc5C/nHp7v8WhAsHW7UjxYQA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.3.3" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -boxen@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-3.2.0.tgz#fbdff0de93636ab4450886b6ff45b92d098f45eb" - integrity sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A== - dependencies: - ansi-align "^3.0.0" - camelcase "^5.3.1" - chalk "^2.4.2" - cli-boxes "^2.2.0" - string-width "^3.0.0" - term-size "^1.2.0" - type-fest "^0.3.0" - widest-line "^2.0.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2, chalk@~2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -chokidar@^2.0.4, chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -clang-format@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.4.0.tgz#1ee2f10637eb5bb0bd7d0b82c949af68e848367e" - integrity sha512-NrdyUnHJOGvMa60vbWk7GJTvOdhibj3uK5C0FlwdNG4301OUvqEJTFce9I9x8qw2odBbIVrJ+9xbsFS3a4FbDA== - dependencies: - async "^1.5.2" - glob "^7.0.0" - resolve "^1.1.6" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -cli-boxes@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d" - integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -coffeescript@~1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.10.0.tgz#e7aa8301917ef621b35d8a39f348dcdd1db7e33e" - integrity sha1-56qDAZF+9iGzXYo580jc3R234z4= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - -colors@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= - -commander@^2.12.1, commander@^2.19.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - -commandpost@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/commandpost/-/commandpost-1.4.0.tgz#89218012089dfc9b67a337ba162f15c88e0f1048" - integrity sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ== - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -configstore@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" - integrity sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ== - dependencies: - dot-prop "^4.1.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - unique-string "^1.0.0" - write-file-atomic "^2.0.0" - xdg-basedir "^3.0.0" - -convert-source-map@^1.1.0, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -corser@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= - -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-random-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= - -csproj2ts@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/csproj2ts/-/csproj2ts-1.1.0.tgz#e6a8c20464b0031a16a219431ce5e4017fc780d5" - integrity sha512-sk0RTT51t4lUNQ7UfZrqjQx7q4g0m3iwNA6mvyh7gLsgQYvwKzfdyoAgicC9GqJvkoIkU0UmndV9c7VZ8pJ45Q== - dependencies: - es6-promise "^4.1.1" - lodash "^4.17.4" - semver "^5.4.1" - xml2js "^0.4.19" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - -dateformat@~1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" - integrity sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk= - dependencies: - get-stdin "^4.0.1" - meow "^3.3.0" - -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.0.0, debug@^3.1.1: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -decamelize-keys@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= - dependencies: - repeating "^2.0.0" - -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -divhide@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/divhide/-/divhide-2.0.1.tgz#8c7b026f7ff0e975803cbb965aeca114de82d9bb" - integrity sha1-jHsCb3/w6XWAPLuWWuyhFN6C2bs= - dependencies: - lodash "=3.9.3" - -dot-prop@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" - integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== - dependencies: - is-obj "^1.0.0" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -ecstatic@^3.0.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48" - integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog== - dependencies: - he "^1.1.1" - mime "^1.6.0" - minimist "^1.1.0" - url-join "^2.0.5" - -editorconfig@^0.15.0: - version "0.15.3" - resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" - integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g== - dependencies: - commander "^2.19.0" - lru-cache "^4.1.5" - semver "^5.6.0" - sigmund "^1.0.1" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es6-promise@^4.1.1: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promise@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-0.1.2.tgz#f112c29fea5a0998539fcb6a2fd21443d28f05f7" - integrity sha1-8RLCn+paCZhTn8tqL9IUQ9KPBfc= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -eventemitter2@~0.4.13: - version "0.4.14" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" - integrity sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas= - -eventemitter3@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" - integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== - -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -exit@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -fast-glob@^3.1.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" - integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fastq@^1.6.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.7.0.tgz#fcd79a08c5bd7ec5b55cd3f5c4720db551929801" - integrity sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ== - dependencies: - reusify "^1.0.4" - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-sync-cmp@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz#a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b" - integrity sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs= - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -findup-sync@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" - integrity sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY= - dependencies: - glob "~5.0.0" - -follow-redirects@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" - integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA== - dependencies: - debug "^3.0.0" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.12" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.12.tgz#db7e0d8ec3b0b45724fd4d83d43554a8f1f0de5c" - integrity sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" - integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== - dependencies: - pump "^3.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getobject@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/getobject/-/getobject-0.1.0.tgz#047a449789fa160d018f5486ed91320b6ec7885c" - integrity sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw= - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== - dependencies: - is-glob "^4.0.1" - -glob@^7.0.0, glob@^7.1.1, glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~5.0.0: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~7.0.0: - version "7.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" - integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= - dependencies: - ini "^1.3.4" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -grunt-babel@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/grunt-babel/-/grunt-babel-8.0.0.tgz#92ef63aafadf938c488dc2f926ac9846e0c93d1b" - integrity sha512-WuiZFvGzcyzlEoPIcY1snI234ydDWeWWV5bpnB7PZsOLHcDsxWKnrR1rMWEUsbdVPPjvIirwFNsuo4CbJmsdFQ== - -grunt-cli@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/grunt-cli/-/grunt-cli-1.2.0.tgz#562b119ebb069ddb464ace2845501be97b35b6a8" - integrity sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg= - dependencies: - findup-sync "~0.3.0" - grunt-known-options "~1.1.0" - nopt "~3.0.6" - resolve "~1.1.0" - -grunt-contrib-clean@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/grunt-contrib-clean/-/grunt-contrib-clean-2.0.0.tgz#3be7ca480da4b740aa5e9d863e2f7e8b24f8a68b" - integrity sha512-g5ZD3ORk6gMa5ugZosLDQl3dZO7cI3R14U75hTM+dVLVxdMNJCPVmwf9OUt4v4eWgpKKWWoVK9DZc1amJp4nQw== - dependencies: - async "^2.6.1" - rimraf "^2.6.2" - -grunt-contrib-copy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz#7060c6581e904b8ab0d00f076e0a8f6e3e7c3573" - integrity sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM= - dependencies: - chalk "^1.1.1" - file-sync-cmp "^0.1.0" - -grunt-http-server@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/grunt-http-server/-/grunt-http-server-2.1.0.tgz#d43d9f8d2ac3c16f3cc9e9199751295d09413b69" - integrity sha512-kv1qgucbRG0XthXu/uyoi15mYeF8W2QDODPurKE9zuRaJPhpuglOkHThGmqKdmJU38CEqc/Q49+Z51VhGFsN8g== - dependencies: - divhide "2.0.1" - http-server "0.11.1" - lodash "4.17.5" - opener "1.4.3" - showdown "1.8.6" - -grunt-known-options@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/grunt-known-options/-/grunt-known-options-1.1.1.tgz#6cc088107bd0219dc5d3e57d91923f469059804d" - integrity sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ== - -grunt-legacy-log-utils@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz#d2f442c7c0150065d9004b08fd7410d37519194e" - integrity sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA== - dependencies: - chalk "~2.4.1" - lodash "~4.17.10" - -grunt-legacy-log@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz#c8cd2c6c81a4465b9bbf2d874d963fef7a59ffb9" - integrity sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw== - dependencies: - colors "~1.1.2" - grunt-legacy-log-utils "~2.0.0" - hooker "~0.2.3" - lodash "~4.17.5" - -grunt-legacy-util@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz#e10624e7c86034e5b870c8a8616743f0a0845e42" - integrity sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A== - dependencies: - async "~1.5.2" - exit "~0.1.1" - getobject "~0.1.0" - hooker "~0.2.3" - lodash "~4.17.10" - underscore.string "~3.3.4" - which "~1.3.0" - -grunt-mkdir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/grunt-mkdir/-/grunt-mkdir-1.0.0.tgz#73e1a26ac24a08596363f4dd954b0d32485e58e9" - integrity sha1-c+GiasJKCFljY/TdlUsNMkheWOk= - -grunt-run@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/grunt-run/-/grunt-run-0.8.1.tgz#502f988947a59f9ad567e2dcb5eeedec712980ec" - integrity sha512-+wvoOJevugcjMLldbVCyspRHHntwVIJiTGjx0HFq+UwXhVPe7AaAiUdY4135CS68pAoRLhd7pAILpL2ITe1tmA== - dependencies: - strip-ansi "^3.0.0" - -grunt-ts@^6.0.0-beta.22: - version "6.0.0-beta.22" - resolved "https://registry.yarnpkg.com/grunt-ts/-/grunt-ts-6.0.0-beta.22.tgz#a628f6fb943b0a6e00afecaa721291611994f553" - integrity sha512-g9e+ZImQ7W38dfpwhp0+GUltXWidy3YGPfIA/IyGL5HMv6wmVmMMoSgscI5swhs2HSPf8yAvXAAJbwrouijoRg== - dependencies: - chokidar "^2.0.4" - csproj2ts "^1.1.0" - detect-indent "^4.0.0" - detect-newline "^2.1.0" - es6-promise "~0.1.1" - jsmin2 "^1.2.1" - lodash "~4.17.10" - ncp "0.5.1" - rimraf "2.2.6" - semver "^5.3.0" - strip-bom "^2.0.0" - -grunt@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/grunt/-/grunt-1.1.0.tgz#97dc6e6add901459774a988e4f454a12e24c9d3d" - integrity sha512-+NGod0grmviZ7Nzdi9am7vuRS/h76PcWDsV635mEXF0PEQMUV6Kb+OjTdsVxbi0PZmfQOjCMKb3w8CVZcqsn1g== - dependencies: - coffeescript "~1.10.0" - dateformat "~1.0.12" - eventemitter2 "~0.4.13" - exit "~0.1.1" - findup-sync "~0.3.0" - glob "~7.0.0" - grunt-cli "~1.2.0" - grunt-known-options "~1.1.0" - grunt-legacy-log "~2.0.0" - grunt-legacy-util "~1.1.1" - iconv-lite "~0.4.13" - js-yaml "~3.13.1" - minimatch "~3.0.2" - mkdirp "~1.0.3" - nopt "~3.0.6" - path-is-absolute "~1.0.0" - rimraf "~2.6.2" - -gts@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/gts/-/gts-1.1.2.tgz#970003f6633c9c384705dab60251b58f6d659c78" - integrity sha512-WWuagkjlFpSfQfShnlpbiJoKRuFXq9Yoj75Re1KVzd109vWo2RmcxaSe1lDtzNFtQFixcBy5TfV1QirTDfjZRA== - dependencies: - chalk "^3.0.0" - diff "^4.0.1" - inquirer "^7.0.0" - meow "^5.0.0" - ncp "^2.0.0" - prettier "^1.19.1" - rimraf "^3.0.0" - tslint "^5.12.0" - tslint-config-prettier "^1.18.0" - update-notifier "^3.0.0" - write-file-atomic "^3.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has-yarn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" - integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== - -he@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hooker@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/hooker/-/hooker-0.2.3.tgz#b834f723cc4a242aa65963459df6d984c5d3d959" - integrity sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk= - -hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - -http-proxy@^1.8.1: - version "1.18.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" - integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-server@0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" - integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w== - dependencies: - colors "1.0.3" - corser "~2.0.0" - ecstatic "^3.0.0" - http-proxy "^1.8.1" - opener "~1.4.0" - optimist "0.6.x" - portfinder "^1.0.13" - union "~0.4.3" - -iconv-lite@^0.4.24, iconv-lite@~0.4.13: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@^1.3.4, ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inquirer@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" - integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== - dependencies: - ansi-escapes "^4.2.1" - chalk "^3.0.0" - cli-cursor "^3.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.5.3" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-installed-globally@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" - integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= - dependencies: - global-dirs "^0.1.0" - is-path-inside "^1.0.0" - -is-npm@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-3.0.0.tgz#ec9147bfb629c43f494cf67936a961edec7e8053" - integrity sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA== - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-yarn-global@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" - integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1, js-yaml@~3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsmin2@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jsmin2/-/jsmin2-1.2.1.tgz#88fbe2fbf75f0a91f66020fd981cd693f4bfe57e" - integrity sha1-iPvi+/dfCpH2YCD9mBzWk/S/5X4= - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json5@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" - integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== - dependencies: - minimist "^1.2.5" - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -latest-version@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" - integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== - dependencies: - package-json "^6.3.0" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash@4.17.5: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== - -lodash@=3.9.3: - version "3.9.3" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.9.3.tgz#0159e86832feffc6d61d852b12a953b99496bd32" - integrity sha1-AVnoaDL+/8bWHYUrEqlTuZSWvTI= - -lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@~4.17.10, lodash@~4.17.5: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^4.0.1, lru-cache@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - -make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - -meow@^3.3.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - -meow@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" - -merge2@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" - integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== - -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -mime@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.1, mkdirp@^0.5.3: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mkdirp@~1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -ncp@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.5.1.tgz#743985316e3db459281b587169e845735a05439f" - integrity sha1-dDmFMW49tFkoG1hxaehFc1oFQ58= - -ncp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" - integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= - -nopt@~3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - dependencies: - abbrev "1" - -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== - dependencies: - mimic-fn "^2.1.0" - -opener@1.4.3, opener@~1.4.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= - -optimist@0.6.x: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -package-json@^6.3.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" - integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== - dependencies: - got "^9.6.0" - registry-auth-token "^4.0.0" - registry-url "^5.0.0" - semver "^6.2.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0, path-is-absolute@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -portfinder@^1.0.13: - version "1.0.25" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" - integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== - dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.1" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -prettier@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -qs@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" - integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ= - -quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - -quiet-grunt@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/quiet-grunt/-/quiet-grunt-0.2.3.tgz#f0908979a97d242ac2d8d6eebcfe558f59c06184" - integrity sha1-8JCJeal9JCrC2NbuvP5Vj1nAYYQ= - -rc@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -readable-stream@^2.0.2: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - -redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -registry-auth-token@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.1.1.tgz#40a33be1e82539460f94328b0f7f0f84c16d9479" - integrity sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA== - dependencies: - rc "^1.2.8" - -registry-url@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" - integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== - dependencies: - rc "^1.2.8" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - dependencies: - path-parse "^1.0.6" - -resolve@~1.1.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.6.tgz#c59597569b14d956ad29cacc42bdddf5f0ea4f4c" - integrity sha1-xZWXVpsU2VatKcrMQr3d9fDqT0w= - -rimraf@^2.6.2: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8" - integrity sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg== - dependencies: - is-promise "^2.1.0" - -run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== - -rxjs@^6.5.3: - version "6.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" - integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -semver-diff@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" - integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= - dependencies: - semver "^5.0.3" - -"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.4.1, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -showdown@1.8.6: - version "1.8.6" - resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.8.6.tgz#91ea4ee3b7a5448aaca6820a4e27e690c6ad771c" - integrity sha1-kepO47elRIqspoIKTifmkMatdxw= - dependencies: - yargs "^10.0.3" - -sigmund@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.6: - version "0.5.16" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" - integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" - integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -term-size@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" - integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= - dependencies: - execa "^0.7.0" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - -trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - -ts-node@^8.5.4: - version "8.8.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.8.1.tgz#7c4d3e9ed33aa703b64b28d7f9d194768be5064d" - integrity sha512-10DE9ONho06QORKAaCBpPiFCdW+tZJuY/84tyypGtl6r+/C7Asq0dhqbRZURuUlLQtZxxDvT8eoj8cGW0ha6Bg== - dependencies: - arg "^4.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.6" - yn "3.1.1" - -tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - -tslint-config-prettier@^1.18.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" - integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== - -tslint@^5.12.0: - version "5.20.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" - integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== - dependencies: - "@babel/code-frame" "^7.0.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^4.0.1" - glob "^7.1.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - mkdirp "^0.5.1" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.8.0" - tsutils "^2.29.0" - -tslint@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.1.tgz#ac03fbd17f85bfefaae348b353b25a88efe10cde" - integrity sha512-kd6AQ/IgPRpLn6g5TozqzPdGNZ0q0jtXW4//hRcj10qLYBaa3mTUU2y2MCG+RXZm8Zx+KZi0eA+YCrMyNlF4UA== - dependencies: - "@babel/code-frame" "^7.0.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^4.0.1" - glob "^7.1.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - mkdirp "^0.5.3" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.10.0" - tsutils "^2.29.0" - -tsutils@^2.29.0: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - dependencies: - tslib "^1.8.1" - -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== - -type-fest@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typescript-formatter@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/typescript-formatter/-/typescript-formatter-7.2.2.tgz#a147181839b7bb09c2377b072f20f6336547c00a" - integrity sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ== - dependencies: - commandpost "^1.0.0" - editorconfig "^0.15.0" - -typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== - -underscore.string@~3.3.4: - version "3.3.5" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" - integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg== - dependencies: - sprintf-js "^1.0.3" - util-deprecate "^1.0.2" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -union@~0.4.3: - version "0.4.6" - resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" - integrity sha1-GY+9rrolTniLDvy2MLwR8kopWeA= - dependencies: - qs "~2.3.3" - -unique-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" - integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= - dependencies: - crypto-random-string "^1.0.0" - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - -update-notifier@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-3.0.1.tgz#78ecb68b915e2fd1be9f767f6e298ce87b736250" - integrity sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ== - dependencies: - boxen "^3.0.0" - chalk "^2.0.1" - configstore "^4.0.0" - has-yarn "^2.1.0" - import-lazy "^2.1.0" - is-ci "^2.0.0" - is-installed-globally "^0.1.0" - is-npm "^3.0.0" - is-yarn-global "^0.3.0" - latest-version "^5.0.0" - semver-diff "^2.0.0" - xdg-basedir "^3.0.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-join@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9, which@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -widest-line@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" - integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== - dependencies: - string-width "^2.1.1" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^2.0.0: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -xdg-basedir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" - integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= - -xml2js@^0.4.19: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yargs-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - -yargs-parser@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== - dependencies: - camelcase "^4.1.0" - -yargs@^10.0.3: - version "10.1.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" - integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^8.1.0" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== |