diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index e420640..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,143 +0,0 @@ -version: 2 -jobs: - -# python_test: -# docker: -# - image: cimg/python:3.11.2 -# steps: -# - checkout -# - restore_cache: -# keys: -# - venv-{{ checksum "python/ci_requirements.txt"}} -# - tox-{{ checksum "python/tox.ini" }} -# -# - run: -# name: install dependencies -# command: | -# cd python/ -# python3 -m venv venv || true -# python3 -m pip install -U pip -# python3 -m pip install -r ci_requirements.txt -# -# - save_cache: -# paths: -# - python/venv -# key: venv-{{ checksum "python/ci_requirements.txt"}} -# -# - save_cache: -# paths: -# - python/.tox -# key: tox-{{ checksum "python/tox.ini" }} -# -# - run: -# name: run python tests -# command: | -# cd python/ -# venv/bin/tox -e py3112 -e black-check -e cov -e codecov -# -# python_deploy: -# docker: -# - image: cimg/python:3.11.2 -# steps: -# - checkout -# - restore_cache: -# keys: -# - venv-{{ checksum "python/ci_requirements.txt"}} -# -# - run: -# name: install dependencies -# command: | -# cd python/ -# python3 -m venv venv || true -# python3 -m pip install -U pip -# python3 -m pip install -r ci_requirements.txt -# -# - save_cache: -# paths: -# - python/venv -# key: venv-{{ checksum "python/ci_requirements.txt"}} -# -# - run: -# name: build and push -# command: | -# cd python/ -# source venv/bin/activate -# python ./setup.py sdist bdist_wheel -# venv/bin/twine upload dist/* --non-interactive --skip-existing - - node_test: - docker: - - image: circleci/node:stretch - steps: - - checkout - - restore_cache: - keys: - - node_modules-{{ checksum "typescript/package.json" }} - - - run: - name: install dependencies - command: | - cd typescript/ - npm install - - - save_cache: - paths: - - typescript/node_modules - key: node_modules-{{ checksum "typescript/package.json" }} - - - run: - name: run node tests - command: | - cd typescript/ - npm test -- --coverage - npm run codecov - - node_deploy: - docker: - - image: circleci/node:stretch - steps: - - checkout - - restore_cache: - keys: - - node_modules-{{ checksum "typescript/package.json" }} - - - run: - name: install dependencies - command: | - cd typescript/ - npm install - - - save_cache: - paths: - - typescript/node_modules - key: node_modules-{{ checksum "typescript/package.json" }} - - - run: - name: Authenticate with registry - command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > typescript/.npmrc - - - run: - name: build and push - command: | - cd typescript/ - npm run build - npm publish || true - -workflows: - version: 2 - test_deploy: - jobs: - - python_test - - node_test - - python_deploy: - filters: - branches: - only: master - requires: - - python_test - - node_deploy: - filters: - branches: - only: master - requires: - - node_test \ No newline at end of file diff --git a/.github/workflows/python.yaml b/.github/workflows/python.yaml new file mode 100644 index 0000000..67b27bc --- /dev/null +++ b/.github/workflows/python.yaml @@ -0,0 +1,61 @@ +name: python +on: + push: + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.7", "3.11"] + defaults: + run: + working-directory: python + + steps: + - uses: actions/checkout@v3 + - name: setup + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: install + run: | + python -m pip install --upgrade pip + python -m pip install -r ci_requirements.txt + - name: test + run: | + pytest --cov=covertable --cov-report=xml + - name: codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./python/coverage.xml + verbose: true + + release: + needs: tests + runs-on: ubuntu-latest + defaults: + run: + working-directory: python + if: github.ref == 'refs/heads/master' + name: pypi upload + steps: + - uses: actions/checkout@v3 + - name: setup + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: install + run: | + python -m pip install --upgrade pip + python -m pip install -r ci_requirements.txt + - name: build + run: | + python -m build --sdist --wheel --outdir dist/ . + - name: upload + run: | + twine upload dist/* --non-interactive --skip-existing + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/typescript.yaml b/.github/workflows/typescript.yaml new file mode 100644 index 0000000..536e942 --- /dev/null +++ b/.github/workflows/typescript.yaml @@ -0,0 +1,65 @@ +name: typescript +on: + push: + +jobs: + tests: + runs-on: ubuntu-latest + defaults: + run: + working-directory: typescript + + steps: + - uses: actions/checkout@v3 + - name: setup + uses: actions/setup-node@v3 + with: + node-version: "16" + - name: cache + uses: actions/cache@v3 + with: + path: | + node_modules + key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + - name: install + run: | + npm install + - name: test + run: | + npm test -- --coverage + # npm run codecov + - name: codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./typescript/coverage/lcov.info + verbose: true + + release: + needs: tests + runs-on: ubuntu-latest + defaults: + run: + working-directory: typescript + + if: github.ref == 'refs/heads/master' + name: npm upload + steps: + - uses: actions/checkout@v3 + - name: setup + uses: actions/setup-node@v3 + with: + node-version: "16" + - name: cache + uses: actions/cache@v3 + with: + path: | + node_modules + key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + - name: upload + run: | + npm install + npm run build + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc + npm publish || true + diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d6fdfc --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# CoverTable + +![covertable logo](./covertable.png) + +Time is limited. + +Creating a test case that satisfies all possible factors is often unrealistic and, more importantly, tedious. + +Save time with CoverTable, a flexible pairwise tool that generates combinations covering two (or more) factors. + +## Implementations + +CoverTable is available in two implementations, with TypeScript as the primary focus and Python offered as a secondary option. + +### TypeScript + +[![NPM Version](https://badge.fury.io/js/covertable.svg)](https://badge.fury.io/js/covertable) [![Build Status](https://github.com/walkframe/covertable/actions/workflows/typescript.yaml/badge.svg)](https://github.com/walkframe/covertable/actions/workflows/typescript.yaml) + +- [README](https://github.com/walkframe/covertable/blob/master/typescript/README.md) +- [History](https://github.com/walkframe/covertable/blob/master/typescript/history.md) + +### Python (Legacy Support) + +[![PyPI Version](https://badge.fury.io/py/covertable.svg)](https://badge.fury.io/py/covertable) [![Build Status](https://github.com/walkframe/covertable/actions/workflows/python.yaml/badge.svg)](https://github.com/walkframe/covertable/actions/workflows/python.yaml) + +- [README](https://github.com/walkframe/covertable/blob/master/python/README.rst) +- [History](https://github.com/walkframe/covertable/blob/master/python/history.md) + + +For more details, please refer to the links above. + +## Performance + +> **Note:** +> The following data was measured in Python 3.7.7 on a `3.1 GHz 6-Core Intel Core i5`. +> The coverage number is `2`. + +| Combination | Default | Minimum case | Fastest case | +|-------------------|-------------------------------------|---------------------------------------|------------------------------------| +| **3^4** | num: `9`
time: `0.0006s` | num: `9`
time: `0.0006s` | num: `14`
time: `0.0005s` | +| **3^13** | num: `19`
time: `0.03s` | num: `17`
time: `0.03s` | num: `21`
time: `0.003s` | +| **4^15 + 3^17 + 2^29** | num: `36`
time: `7.41s` | num: `34`
time: `7.47s` | num: `42`
time: `0.40s` | +| **4^1 + 3^39 + 2^35** | num: `27`
time: `15.19s` | num: `26`
time: `14.70s` | num: `30`
time: `0.51s` | +| **2^100** | num: `14`
time: `23.97s` | num: `12`
time: `0.63s` | num: `13`
time: `0.48s` | +| **10^20** | num: `198`
time: `14.28s` | num: `195`
time: `14.48s` | num: `284`
time: `0.53s` | + +In general, as the number of elements or coverage increases, the number of combinations tends to increase significantly. + +## Tolerance + +If you use the `greedy` criterion and specify a positive integer for the `tolerance` option, you can increase speed at the expense of the number of combinations. + +The greater the `tolerance`, the faster the speed and the larger the number of combinations. + +### Example: 10^20 Test Cases + +| Tolerance | num | time | +|-----------|------|--------| +| 0 (default) | `195` | `14.48s` | +| 1 | `199` | `12.45s` | +| 2 | `201` | `9.48s` | +| 3 | `201` | `7.17s` | +| 4 | `207` | `5.70s` | +| 5 | `212` | `4.58s` | +| 6 | `212` | `3.65s` | +| 7 | `216` | `3.07s` | +| 8 | `223` | `2.57s` | +| 9 | `226` | `2.14s` | +| 10 | `233` | `1.84s` | +| 11 | `237` | `1.61s` | +| 12 | `243` | `1.43s` | +| 13 | `249` | `1.28s` | +| 14 | `254` | `1.19s` | + + diff --git a/README.rst b/README.rst deleted file mode 100644 index 4b554e8..0000000 --- a/README.rst +++ /dev/null @@ -1,206 +0,0 @@ -.. image:: ./covertable.png - :alt: covertable logo - - -.. image:: https://circleci.com/gh/walkframe/covertable.svg?style=shield - :target: https://circleci.com/gh/walkframe/covertable - -Time is limited. - -It is not realistic to create a test case that satisfies all the multiple factors, -and above all, it is tedious. - -Save time with covertable. It is a flexible pairwise tool to create a two (or more) factor covered combination. - - -Now it has 2 implementations. - -:Python: - - - .. image:: https://badge.fury.io/py/covertable.svg - :target: https://badge.fury.io/py/covertable - - `README `__ - - `Code `__ - -:TypeScript: - - - .. image:: https://badge.fury.io/js/covertable.svg - :target: https://badge.fury.io/js/covertable - - `README `__ - - `Code `__ - - -Go see the detail from these links. - -Performance -=================== - -.. note:: - - - The following data was measured in Python 3.7.7 and ``3.1 GHz 6 Cores Intel Core i5``. - - coverage number is `2`. - -.. list-table:: Number and time of combinations. - :widths: 1 3 3 3 - :header-rows: 1 - :stub-columns: 1 - - * - Combination - - Default - - Minimum case - - Fastest case - * - 3^4 - - - num: ``9`` - - cond: *default* - - time: ``0.0006s`` - - - num: ``9`` - - cond: *default* - - time: ``0.0006s`` - - - num: ``14`` - - cond: ``sorter: random, criterion: simple`` - - time: ``0.0005s`` - * - 3^13 - - - num: ``19`` - - cond: *default* - - time: ``0.03s`` - - - num: ``17`` - - cond: ``seed: 1084`` - - time: ``0.03s`` - - - num: ``21`` - - cond: ``sorter: random, criterion: simple`` - - time: ``0.003s`` - * - 4^15 + 3^17 + 2^29 - - - num: ``36`` - - cond: *default* - - time: ``7.41s`` - - - num: ``34`` - - cond: ``seed: 19`` - - time: ``7.47s`` - - - num: ``42`` - - cond: ``sorter: random, criterion: simple`` - - time: ``0.40s`` - * - 4^1 + 3^39 + 2^35 - - - num: ``27`` - - cond: *default* - - time: ``15.19s`` - - - num: ``26`` - - cond: ``seed: 14`` - - time: ``14.70s`` - - - num: ``30`` - - cond: ``sorter: random, criterion: simple`` - - time: ``0.51s`` - * - 2^100 - - - num: ``14`` - - cond: *default* - - time: ``23.97s`` - - - num: ``12`` - - cond: ``seed: 6, criterion: simple`` - - time: ``0.63s`` - - - num: ``13`` - - cond: ``sorter: random, criterion: simple`` - - time: ``0.48s`` - * - 10^20 - - - num: ``198`` - - cond: *default* - - time: ``14.28s`` - - - num: ``195`` - - cond: ``seed: 1139`` - - time: ``14.48s`` - - - num: ``284`` - - cond: ``sorter: random, criterion: simple`` - - time: ``0.53s`` - -In general, as the number of elements or coverage increases, -the number of combinations have a tendency to increase significantly. - -Tolerance ----------------- - -If you use `greedy` criterion and specify a positive integer to `tolerance` option, -it can increase the speed at the expense of the number of combinations. - -The greater the `tolerance`, the shorter the speed and bigger the number of combinations. - -.. list-table:: Table for the case when combinations are created from ``10^20`` test cases. - :widths: 1 3 3 - :header-rows: 1 - :stub-columns: 1 - - * - tolerance - - num - - time - * - 0 (default) - - ``195`` - - ``14.48s`` - * - 1 - - ``199`` - - ``12.45s`` - * - 2 - - ``201`` - - ``9.48s`` - * - 3 - - ``201`` - - ``7.17s`` - * - 4 - - ``207`` - - ``5.70s`` - * - 5 - - ``212`` - - ``4.58s`` - * - 6 - - ``212`` - - ``3.65s`` - * - 7 - - ``216`` - - ``3.07s`` - * - 8 - - ``223`` - - ``2.57s`` - * - 9 - - ``226`` - - ``2.14s`` - * - 10 - - ``233`` - - ``1.84s`` - * - 11 - - ``237`` - - ``1.61s`` - * - 12 - - ``243`` - - ``1.43s`` - * - 13 - - ``249`` - - ``1.28s`` - * - 14 - - ``254`` - - ``1.19s`` - - -History -======= -:2.0.x: - - - sorter option was splitted into sorter and criterion. - - - e.g. greedy -> hash sorter + greedy criterion. - - - `greedy` method is much faster than before. - - `greedy` method got an option `tolerance` to balance speed and results. - - - sequenctial sorter was dropped. - - - Because The number of combinations would be huge in TypeScript. - -:1.1.x: - - - Greedy sorter improved in both implementations. - - - It got increased in speed. - -:1.0.x: - - - First release 🎉 - -.. note:: - - It moved from `twopairs`. diff --git a/python/.gitignore b/python/.gitignore index 5f5970b..ba7e8c5 100644 --- a/python/.gitignore +++ b/python/.gitignore @@ -3,9 +3,10 @@ __pycache__/ .tox/ venv/ .coverage +coverage.xml .junit.xml htmlcov/ pip-wheel-metadata *.egg-info build/ -dist/ \ No newline at end of file +dist/ diff --git a/python/README.rst b/python/README.rst index c06c2d3..07e5389 100644 --- a/python/README.rst +++ b/python/README.rst @@ -1,8 +1,8 @@ .. image:: https://badge.fury.io/py/covertable.svg :target: https://badge.fury.io/py/covertable -.. image:: https://circleci.com/gh/walkframe/covertable.svg?style=shield - :target: https://circleci.com/gh/walkframe/covertable +.. image:: https://github.com/walkframe/covertable/actions/workflows/python.yaml/badge.svg + :target: https://github.com/walkframe/covertable/actions/workflows/python.yaml .. image:: https://codecov.io/gh/walkframe/covertable/branch/master/graph/badge.svg :target: https://codecov.io/gh/walkframe/covertable @@ -17,7 +17,7 @@ Requirements ============ - Python: 3.3 or later. - - Tested with 3.7 + - Tested with 3.7, 3.11 Installation @@ -158,7 +158,7 @@ Development (venv) $ pip install -r dev_requirements.txt # testing - (venv) $ tox # -e py37 -e cov -e black + (venv) $ pytest Publish diff --git a/python/ci_requirements.txt b/python/ci_requirements.txt index 8091e2b..2e4f605 100644 --- a/python/ci_requirements.txt +++ b/python/ci_requirements.txt @@ -1,4 +1,5 @@ -tox -setuptools -wheel +pytest +pytest-cov +codecov +build twine diff --git a/python/covertable/criteria/greedy.py b/python/covertable/criteria/greedy.py index 389a2d6..27953be 100644 --- a/python/covertable/criteria/greedy.py +++ b/python/covertable/criteria/greedy.py @@ -3,19 +3,19 @@ from itertools import combinations -def get_num_removable_pairs(indexes, incompleted, length): +def get_num_removable_pairs(indexes, incomplete, length): removing_keys = combinations(indexes, length) - return len(incompleted.intersection(removing_keys)) + return len(incomplete.intersection(removing_keys)) def extract( - sorted_incompleted, row, parents, length, incompleted, tolerance=0, **kwargs + sorted_incomplete, row, parents, length, incomplete, tolerance=0, **kwargs ): while True: max_num_pairs = None efficient_pair = None - for pair in sorted_incompleted: + for pair in sorted_incomplete: if not row: yield pair continue @@ -31,7 +31,7 @@ def extract( continue num_pairs = get_num_removable_pairs( - sorted({*row.values(), *pair}), incompleted, length + sorted({*row.values(), *pair}), incomplete, length ) if num_pairs + tolerance > len(row) * storable: efficient_pair = pair diff --git a/python/covertable/criteria/simple.py b/python/covertable/criteria/simple.py index b14f5ea..66517a8 100644 --- a/python/covertable/criteria/simple.py +++ b/python/covertable/criteria/simple.py @@ -1,5 +1,5 @@ -def extract(sorted_incompleted, row, parents, **kwargs): - for pair in sorted_incompleted: +def extract(sorted_incomplete, row, parents, **kwargs): + for pair in sorted_incomplete: storable = row.storable([(parents[p], p) for p in pair]) if storable is None: continue diff --git a/python/covertable/main.py b/python/covertable/main.py index 1e5c490..7d86b9b 100644 --- a/python/covertable/main.py +++ b/python/covertable/main.py @@ -29,12 +29,12 @@ def convert_factors_to_serials(factors): return serials, parents -def make_incompleted(serials, length): - incompleted = set() +def make_incomplete(serials, length): + incomplete = set() for keys in combinations([k for k, _ in get_items(serials)], length): for pair in product(*[serials[keys[i]] for i in range(length)]): - incompleted.add(pair) - return incompleted + incomplete.add(pair) + return incomplete class Row(dict): @@ -65,7 +65,7 @@ def storable(self, candidate=[]): if self.pre_filter is None: return num nxt = self.new({**self, **dict(candidate)}) - if not self.pre_filter(nxt.restore()): + if not self.pre_filter(nxt.resolve()): return None return num @@ -79,14 +79,21 @@ def complement(self): raise InvalidCondition(InvalidCondition.message) return self - def restore(self): + def resolve(self): return self.new( [key, self.factors[key][serial - self.serials[key][0]]] for key, serial in self.items() ) + def restore(self): + resolved = self.resolve() + if issubclass(self.type, list): + return [r for _, r in sorted(resolved.items())] + if issubclass(self.type, dict): + return dict(resolved) + -def make( +def make_async( factors, length=2, progress=False, @@ -97,20 +104,21 @@ def make( **params, ): serials, parents = convert_factors_to_serials(factors) - incompleted = make_incompleted(serials, length) - len_incompleted = float(len(incompleted)) + incomplete = make_incomplete(serials, length) + len_incomplete = float(len(incomplete)) md5_cache = {} - rows, row = [], Row(None, factors, serials, pre_filter) + row = Row(None, factors, serials, pre_filter) # When pre_filter is specified, - # it will be applied to incompleted through `row.storable` beforehand. - for pair in list(filter(lambda _: pre_filter, incompleted)): + # it will be applied to incomplete through `row.storable` beforehand. + for pair in list(filter(lambda _: pre_filter, incomplete)): if not row.storable([(parents[p], p) for p in pair]): - incompleted.discard(pair) + incomplete.discard(pair) - while incompleted: + while incomplete: if row.filled(): - rows.append(row) + if post_filter is None or post_filter(row.resolve()): + yield row.restore() row = row.new() common_kwargs = { @@ -118,34 +126,48 @@ def make( "row": row, "parents": parents, "length": length, - "incompleted": incompleted, + "incomplete": incomplete, "md5_cache": md5_cache, } - sorted_incompleted = sorter.sort(**common_kwargs) - for pair in criterion.extract(sorted_incompleted, **common_kwargs): + sorted_incomplete = sorter.sort(**common_kwargs) + for pair in criterion.extract(sorted_incomplete, **common_kwargs): if row.filled(): break row.update((parents[p], p) for p in pair) for vs in combinations(sorted(row.values()), length): - incompleted.discard(vs) + incomplete.discard(vs) else: if not row.filled(): row.complement() if progress: - rate = (len_incompleted - len(incompleted)) / len_incompleted + rate = (len_incomplete - len(incomplete)) / len_incomplete print("{0:.2%}\r".format(rate), end="") if row: - rows.append(row.complement()) - - result = [] - for row in rows: - restored = row.restore() - if post_filter and not post_filter(restored): - continue - if issubclass(row.type, list): - result.append([r for _, r in sorted(restored.items())]) - elif issubclass(row.type, dict): - result.append(dict(restored)) - return result + row.complement() + if post_filter is None or post_filter(row.resolve()): + yield row.restore() + + +def make( + factors, + length=2, + progress=False, + sorter=sorters.hash, + criterion=criteria.greedy, + pre_filter=None, + post_filter=None, + **params, +): + gen = make_async( + factors, + length=length, + progress=progress, + sorter=sorter, + criterion=criterion, + pre_filter=pre_filter, + post_filter=post_filter, + **params, + ) + return list(gen) diff --git a/python/covertable/sorters/hash.py b/python/covertable/sorters/hash.py index ec2238d..4e433d8 100644 --- a/python/covertable/sorters/hash.py +++ b/python/covertable/sorters/hash.py @@ -4,7 +4,7 @@ import hashlib -def sort(incompleted, md5_cache, seed="", use_cache=True, *args, **kwargs): +def sort(incomplete, md5_cache, seed="", use_cache=True, *args, **kwargs): def comparer(v): if use_cache and v in md5_cache: return md5_cache[v] @@ -15,4 +15,4 @@ def comparer(v): md5_cache[v] = value return value - return sorted(incompleted, key=comparer) + return sorted(incomplete, key=comparer) diff --git a/python/covertable/sorters/random.py b/python/covertable/sorters/random.py index 67cbfcf..8851b1f 100644 --- a/python/covertable/sorters/random.py +++ b/python/covertable/sorters/random.py @@ -8,5 +8,5 @@ def random_comparer(_): return random.random() -def sort(incompleted, *args, **kwargs): - return sorted(incompleted, key=random_comparer) +def sort(incomplete, *args, **kwargs): + return sorted(incomplete, key=random_comparer) diff --git a/python/history.md b/python/history.md new file mode 100644 index 0000000..004b330 --- /dev/null +++ b/python/history.md @@ -0,0 +1,22 @@ +# History + +## 2.1.x +- Add `make_async` function to generate combinations sequentially. + +## 2.0.x + +- The `sorter` option was split into `sorter` and `criterion`. + - e.g., greedy -> hash sorter + greedy criterion. +- The `greedy` method is much faster than before. +- The `greedy` method now includes a `tolerance` option to balance speed and results. +- The sequential sorter was dropped. + - Due to the potential for huge numbers of combinations in TypeScript. + +## 1.1.x + +- The greedy sorter was improved in both implementations. + - Speed has been increased. + +## 1.0.x + +- First release 🎉 diff --git a/python/pytest.ini b/python/pytest.ini new file mode 100644 index 0000000..b42ddf9 --- /dev/null +++ b/python/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +python_files = tests.py + diff --git a/python/setup.cfg b/python/setup.cfg index ceb5e32..65df6ed 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = covertable -version = 2.0.1 +version = 2.1.0 author = righ author_email = righ.m9@gmail.com url = https://github.com/walkframe/covertable/ @@ -36,5 +36,5 @@ keywords = covering-arrays pict -description = It makes combinations covering pairs for pairwise testing. +description = A flexible pairwise tool written in Python. long_description = file: README.rst diff --git a/python/tox.ini b/python/tox.ini deleted file mode 100644 index 460300e..0000000 --- a/python/tox.ini +++ /dev/null @@ -1,44 +0,0 @@ -[tox] -envlist = py37, blacken -skipsdist = True - -[pytest] -addopts = --durations=10 -python_paths = . -python_files = tests.py - -[testenv] -deps = - pytest - pytest-pythonpath -commands = py.test {posargs} - -[testenv:cov] -deps = - pytest - pytest-pythonpath - pytest-cov - coverage -commands = py.test {posargs} \ - --junitxml={toxinidir}/.junit.xml \ - --cov="covertable" --cov="sorters/" --cov="criteria" --cov="exceptions" - -[testenv:blacken] -basepython = python3.7 -deps = black -commands = - black . - -[testenv:black-check] -basepython = python3.7 -deps = black -commands = - black . --check - -[testenv:codecov] -passenv = - TOXENV - CI - CODECOV_* -deps = codecov -commands = codecov diff --git a/typescript/README.md b/typescript/README.md index 7259b70..134dd77 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -1,184 +1,40 @@ [![npm version](https://badge.fury.io/js/covertable.svg)](https://badge.fury.io/js/covertable) -[![CircleCI](https://circleci.com/gh/walkframe/covertable.svg?style=shield)](https://circleci.com/gh/walkframe/covertable) +[![Workflow](https://github.com/walkframe/covertable/actions/workflows/typescript.yaml/badge.svg)](https://github.com/walkframe/covertable/actions/workflows/typescript.yaml) [![codecov](https://codecov.io/gh/walkframe/covertable/branch/master/graph/badge.svg)](https://codecov.io/gh/walkframe/covertable) +[![github](https://img.shields.io/github/stars/walkframe/covertable)](https://github.com/walkframe/covertable) -# Installation +# What is covertable? +covertable is a powerful tool for generating pairwise combinations of input factors, designed for both Node.js and browser environments. It's easy to use, flexible, and supports advanced filtering options, making it perfect for testing scenarios and generating comprehensive datasets. -```sh -$ npm install covertable --save -``` - -# Usage - -## Simple demo in Node.js: +# Simple usage ```javascript -var covertable = require('covertable'); -var make = covertable.default; - -var machine = ['iphone', 'pixel']; -var os = ['ios', 'android']; -var browser = ['FireFox', 'Chrome', 'Safari']; - +import { make } from "covertable"; +const machine = ["iPhone", "Pixel", "XPERIA", "ZenFone", "Galaxy"]; +const os = ["iOS", "Android"]; +const browser = ["FireFox", "Chrome", "Safari"]; make([machine, os, browser]); ``` -Output: ```javascript [ - [ 'pixel', 'android', 'Chrome' ], - [ 'pixel', 'ios', 'Safari' ], - [ 'pixel', 'android', 'FireFox' ], - [ 'iphone', 'android', 'Safari' ], - [ 'iphone', 'ios', 'Chrome' ], - [ 'iphone', 'ios', 'FireFox' ] -] -``` - -Of course, it also works in the browser well. - -## Advanced demo in TypeScript: - -```typescript -import { default as make, makeAsync, sorters, criteria } from "covertable"; - -const machine = ['iphone', 'pixel']; -const os = ['ios', 'android']; -const browser = ['FireFox', 'Chrome', 'Safari']; - -make([machine, os, browser], { // optional - length: 2, // default: 2 - criterion: criteria.simple, // default: criteria.greedy - sorter: sorters.random, // default: sorters.hash - preFilter: (row: any) => !(row[1] === 'android' && row[0] !== 'pixel'), // default: null - postFilter: (row: any) => !(row[1] === 'ios' && row[2] !== 'Safari'), // default: null -}); -``` - -Output: - -```typescript -[ // filtered - [ 'iphone', 'ios', 'Safari' ], - [ 'pixel', 'android', 'Chrome' ], - [ 'pixel', 'ios', 'Safari' ] -] -``` - -You can use also `makeAsync` function (generator). -- It receives the same arguments with `make` function. -- It returns the row at the time it's made. - -## Object input and output - -You can specify `factors` as object type: - -```typescript -import { default as make, sorters, criteria } from "covertable"; - -const machine = ['iphone', 'pixel']; -const os = ['ios', 'android']; -const browser = ['FireFox', 'Chrome', 'Safari']; - -make({machine, os, browser}, { // optional - length: 2, - preFilter: (row: any) => !(row.os === 'android' && row.machine !== 'pixel'), // default: null - postFilter: (row: any) => !(row.os === 'ios' && row.browser !== 'Safari'), // default: null -}); -``` - -Then the output will change as follows: - -```typescript -[ // filtered - { machine: 'iphone', browser: 'Safari', os: 'ios' }, - { machine: 'pixel', browser: 'Chrome', os: 'android' }, - { machine: 'pixel', browser: 'Safari', os: 'ios' }, + [ 'Pixel', 'iOS', 'Chrome' ], + [ 'ZenFone', 'iOS', 'FireFox' ], + [ 'Pixel', 'Android', 'Safari' ], + [ 'Galaxy', 'Android', 'Chrome' ], + [ 'XPERIA', 'Android', 'FireFox' ], + [ 'Pixel', 'iOS', 'FireFox' ], + [ 'iPhone', 'iOS', 'Safari' ], + [ 'Galaxy', 'iOS', 'Safari' ], + [ 'XPERIA', 'iOS', 'Chrome' ], + [ 'ZenFone', 'Android', 'Chrome' ], + [ 'Galaxy', 'iOS', 'FireFox' ], + [ 'iPhone', 'Android', 'Chrome' ], + [ 'iPhone', 'iOS', 'FireFox' ], + [ 'ZenFone', 'iOS', 'Safari' ], + [ 'XPERIA', 'iOS', 'Safari' ] ] ``` -## Options -`covertable.make` function has options as `object` at 2nd argument. - -All options are omittable. - -### length -Number of factors to be covered. (default: 2) - -Obviously the more it increases, the more number of combinations increases. - -### sorter -Combinations depend on the order of spreading all over the rows. - -You can choice a sorter from the following: - -- sorters.random: It makes different combinations everytime. (fastest) -- sorters.hash: It makes combinations depending on hash of the pair and seed. (default) - - - It receives `seed`. - - `seed` option decides the order of storing from unstored pairs. - - When the combination of factors and seed are the same, covertable reproduces the same collective. - -### criterion -You can choice a criterion from the following: - -- `criteria.simple`: it extracts any pairs that can be stored into the processing row. -- `criteria.greedy`: it attempts to make most efficient combinations. (default) - - It receives [tolerance](https://github.com/walkframe/covertable#tolerance) option. - -While `criteria.simple` processes quickly, `criteria.greedy` makes fewer combinations. -Although the latter is superior to former in terms of fewer combinations generally, it is time-intensive process. - -Not relevant options will be ignored. - -### preFilter -This is a function to filter beforehand. - -It receives an argument `row` as `object` type. - -When the function returns `false`, the row combination will not be registered. -- If factors type is `Array`, you should specify an index at the subscript like `row => row[1] < 6`. -- If factors type is `Object`, you should specify a key at the subscript like `row => row.month < 6` or `row => row['month'] < 6` - -### postFilter -This means a function to filter later. - -The usage is the same as `preFilter`, only the difference is the timing of the call. -It will delete rows not matched this function at the last. - -For this reason, the final test cases may not satisfy the factors coverage. - -# Requirement - -ES2015 or later - -- [Generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) -- [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) -- [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- [Object.keys](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) -- [Object.entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) - -# Development - -```sh -$ npm install -``` - -## Testing -```sh -$ npm test -- --coverage -``` - -## Publish - -```sh -$ # npm adduser -$ npm run build -$ npm version patch -$ npm publish -``` - -# More info - -- [walkframe/covertable - GitHub](https://github.com/walkframe/covertable) +# Advanced usage +Advanced usage is [here](https://docs.walkframe.com/covertable/advanced) \ No newline at end of file diff --git a/typescript/history.md b/typescript/history.md new file mode 100644 index 0000000..810b3a8 --- /dev/null +++ b/typescript/history.md @@ -0,0 +1,38 @@ +# History + +## 2.4.x +- Fixed an issue where preFilter was evaluating and excluding incomplete elements. This is a minor upgrade due to the large scope of the impact. +- Type names are now unified with the Type suffix. + +## 2.3.x +- PictConstraintsLexer was added. ([#37](https://github.com/walkframe/covertable/pull/37)) + - It is a lexer designed to parse PICT constraints. + - It parses constraints written in the PICT format, enabling the evaluation of complex conditions. + - The parsed constraints are then used in the make function to dynamically filter the generated combinations based on the specified rules. + +## 2.2.x +- Speed is increased by expressing combinations of elements as a product of prime numbers. +- Added `SuggestRowType` to infer the row type. + +## 2.1.x +- Speed up processing speed by pre-sorting target pairs. +- Added `makeAsync` function to generate combinations sequentially. + + +## 2.0.x + +- The `sorter` option was split into `sorter` and `criterion`. + - e.g., greedy -> hash sorter + greedy criterion. +- The `greedy` method is much faster than before. +- The `greedy` method now includes a `tolerance` option to balance speed and results. +- The sequential sorter was dropped. + - Due to the potential for huge numbers of combinations in TypeScript. + +## 1.1.x + +- The greedy sorter was improved in both implementations. + - Speed has been increased. + +## 1.0.x + +- First release 🎉 diff --git a/typescript/package-lock.json b/typescript/package-lock.json index 10c3bf3..6cab470 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -1,13 +1,13 @@ { "name": "covertable", - "version": "2.2.6", + "version": "2.5.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "covertable", - "version": "2.2.6", - "license": "ISC", + "version": "2.5.1", + "license": "Apache-2.0", "dependencies": { "js-md5": "^0.7.3" }, @@ -19,7 +19,11 @@ "jest": "^26.0.1", "nyc": "^15.1.0", "ts-jest": "^26.1.0", - "typescript": "^3.9.3" + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "typescript": "^4.9.3", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4" } }, "node_modules/@babel/code-frame": { @@ -570,6 +574,27 @@ "node": ">=0.1.95" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1186,6 +1211,84 @@ "node": ">= 8.3" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@sinonjs/commons": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", @@ -1216,6 +1319,30 @@ "node": ">= 6" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.1.12", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", @@ -1261,6 +1388,32 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/eslint": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1317,6 +1470,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/node": { "version": "14.14.31", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", @@ -1362,6 +1521,208 @@ "dev": true, "license": "MIT" }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "node_modules/abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -1430,6 +1791,31 @@ "node": ">=8" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/ansi-escapes": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", @@ -1518,6 +1904,12 @@ "dev": true, "license": "MIT" }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1859,9 +2251,9 @@ "license": "BSD-2-Clause" }, "node_modules/browserslist": { - "version": "4.20.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", - "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -1871,14 +2263,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001317", - "electron-to-chromium": "^1.4.84", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -1975,9 +2370,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001331", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001331.tgz", - "integrity": "sha512-Y1xk6paHpUXKP/P6YjQv1xqyTbgAP05ycHBcRdQjTcyXlWol868sJJPlmk5ylOekw2BrucWes5jk+LvVd7WZ5Q==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true, "funding": [ { @@ -1987,6 +2382,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -2027,6 +2426,15 @@ "node": ">=10" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -2092,6 +2500,20 @@ "wrap-ansi": "^6.2.0" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -2164,6 +2586,12 @@ "dev": true, "license": "MIT" }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2176,6 +2604,12 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -2217,6 +2651,12 @@ "node": ">=0.10.0" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -2433,6 +2873,15 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "25.2.6", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", @@ -2467,9 +2916,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.107", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz", - "integrity": "sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", "dev": true }, "node_modules/emittery": { @@ -2502,6 +2951,31 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2512,6 +2986,12 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -2520,11 +3000,10 @@ "license": "MIT" }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -2561,6 +3040,28 @@ "source-map": "~0.6.1" } }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -2575,6 +3076,18 @@ "node": ">=4" } }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", @@ -2593,6 +3106,15 @@ "node": ">=0.10.0" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/exec-sh": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", @@ -2876,6 +3398,12 @@ "node": ">=0.10.0" } }, + "node_modules/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 + }, "node_modules/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", @@ -2889,6 +3417,15 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", @@ -2944,9 +3481,18 @@ "node": ">=8" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true, "license": "MIT", @@ -3182,6 +3728,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3193,11 +3745,10 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true, - "license": "ISC" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/growly": { "version": "1.3.0", @@ -3478,6 +4029,15 @@ "dev": true, "license": "ISC" }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -5916,6 +6476,12 @@ "dev": true, "license": "MIT" }, + "node_modules/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 + }, "node_modules/json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -5982,6 +6548,15 @@ "dev": true, "license": "MIT" }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -6226,6 +6801,12 @@ "dev": true, "license": "MIT" }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -6367,9 +6948,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", - "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "node_modules/normalize-package-data": { @@ -6740,9 +7321,9 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -6873,6 +7454,15 @@ "node": ">=6" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -6924,6 +7514,18 @@ "node": ">=8" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -7290,6 +7892,24 @@ "node": ">=10" } }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -7300,6 +7920,15 @@ "semver": "bin/semver.js" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -7336,6 +7965,18 @@ "node": ">=0.10.0" } }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -7584,11 +8225,10 @@ } }, "node_modules/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==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, - "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7864,6 +8504,15 @@ "dev": true, "license": "MIT" }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/teeny-request": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.1.tgz", @@ -7895,6 +8544,109 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/terser": { + "version": "5.31.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.5.tgz", + "integrity": "sha512-YPmas0L0rE1UyLL/llTWA0SiDOqIcAQYLeUj7cJYzXHlRTAnMSg9pPe4VJ5PlKvTrPQsdVFuiRiwyeNlYgwh2Q==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -8069,6 +8821,130 @@ "node": ">=10" } }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -8112,11 +8988,10 @@ } }, "node_modules/typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8202,6 +9077,45 @@ "node": ">=0.10.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -8237,6 +9151,12 @@ "uuid": "bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", @@ -8306,6 +9226,19 @@ "makeerror": "1.0.x" } }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -8316,6 +9249,210 @@ "node": ">=10.4" } }, + "node_modules/webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-cli/node_modules/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, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webpack-cli/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli/node_modules/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, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", @@ -8367,6 +9504,12 @@ "dev": true, "license": "ISC" }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -8496,6 +9639,15 @@ "engines": { "node": ">=6" } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } } }, "dependencies": { @@ -8932,6 +10084,21 @@ "minimist": "^1.2.0" } }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -9414,6 +10581,79 @@ "chalk": "^3.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@sinonjs/commons": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", @@ -9438,6 +10678,30 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "@types/babel__core": { "version": "7.1.12", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", @@ -9479,6 +10743,32 @@ "@babel/types": "^7.3.0" } }, + "@types/eslint": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -9529,6 +10819,12 @@ "integrity": "sha512-FUPoQkpQTzA5wz9ebrdVRjsjQsFehr+cW1CVhLcI2UwD/SO/4NHPO1esrXPPbx7ux762U0POmWFSrUjQq2ophw==", "dev": true }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "@types/node": { "version": "14.14.31", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", @@ -9568,6 +10864,185 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, + "@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "requires": {} + }, + "@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -9615,6 +11090,25 @@ "indent-string": "^4.0.0" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, "ansi-escapes": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", @@ -9672,6 +11166,12 @@ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, + "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", @@ -9921,16 +11421,15 @@ "dev": true }, "browserslist": { - "version": "4.20.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", - "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001317", - "electron-to-chromium": "^1.4.84", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" } }, "bs-logger": { @@ -9999,9 +11498,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001331", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001331.tgz", - "integrity": "sha512-Y1xk6paHpUXKP/P6YjQv1xqyTbgAP05ycHBcRdQjTcyXlWol868sJJPlmk5ylOekw2BrucWes5jk+LvVd7WZ5Q==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true }, "capture-exit": { @@ -10029,6 +11528,12 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -10081,6 +11586,17 @@ "wrap-ansi": "^6.2.0" } }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -10131,6 +11647,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -10140,6 +11662,12 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -10173,6 +11701,12 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -10329,6 +11863,12 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "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 + }, "diff-sequences": { "version": "25.2.6", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", @@ -10353,9 +11893,9 @@ } }, "electron-to-chromium": { - "version": "1.4.107", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz", - "integrity": "sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", "dev": true }, "emittery": { @@ -10379,6 +11919,22 @@ "once": "^1.4.0" } }, + "enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -10388,6 +11944,12 @@ "is-arrayish": "^0.2.1" } }, + "es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -10395,9 +11957,9 @@ "dev": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true }, "escape-string-regexp": { @@ -10419,12 +11981,39 @@ "source-map": "~0.6.1" } }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, "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 }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, "estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", @@ -10437,6 +12026,12 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, "exec-sh": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", @@ -10654,6 +12249,12 @@ } } }, + "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-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -10666,6 +12267,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, "fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", @@ -10705,6 +12312,12 @@ "path-exists": "^4.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -10856,6 +12469,12 @@ "path-is-absolute": "^1.0.0" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -10863,9 +12482,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "growly": { @@ -11072,6 +12691,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true + }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -12875,6 +14500,12 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "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 + }, "json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -12918,6 +14549,12 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "dev": true }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -13097,6 +14734,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -13202,9 +14845,9 @@ } }, "node-releases": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", - "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "normalize-package-data": { @@ -13470,9 +15113,9 @@ "dev": true }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "picomatch": { @@ -13564,6 +15207,15 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -13601,6 +15253,15 @@ "type-fest": "^0.8.1" } }, + "rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "requires": { + "resolve": "^1.20.0" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -13873,12 +15534,32 @@ "xmlchars": "^2.2.0" } }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -13908,6 +15589,15 @@ } } }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -14096,9 +15786,9 @@ } }, "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==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -14309,6 +15999,12 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, "teeny-request": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.1.tgz", @@ -14332,6 +16028,71 @@ "supports-hyperlinks": "^2.0.0" } }, + "terser": { + "version": "5.31.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.5.tgz", + "integrity": "sha512-YPmas0L0rE1UyLL/llTWA0SiDOqIcAQYLeUj7cJYzXHlRTAnMSg9pPe4VJ5PlKvTrPQsdVFuiRiwyeNlYgwh2Q==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -14457,6 +16218,81 @@ } } }, + "ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + } + } + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true + }, + "acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "requires": { + "acorn": "^8.11.0" + } + } + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -14488,9 +16324,9 @@ } }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "union-value": { @@ -14551,6 +16387,25 @@ } } }, + "update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -14575,6 +16430,12 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "v8-to-istanbul": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", @@ -14631,12 +16492,156 @@ "makeerror": "1.0.x" } }, + "watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true }, + "webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true + }, + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "requires": {} + } + } + }, + "webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "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" + } + }, + "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" + } + } + } + }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, "whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", @@ -14678,6 +16683,12 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -14772,6 +16783,12 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "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/typescript/package.json b/typescript/package.json index ebce18c..190d03a 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -1,8 +1,8 @@ { "name": "covertable", - "version": "2.2.6", + "version": "2.5.2", "description": "A flexible pairwise tool written in TypeScript", - "homepage": "https://github.com/walkframe/covertable", + "homepage": "https://docs.walkframe.com/covertable", "repository": { "type": "git", "url": "git+https://github.com/walkframe/covertable.git" @@ -36,8 +36,8 @@ "main": "dist/index.js", "scripts": { "test": "jest", - "build": "$(npm bin)/tsc", - "watch": "$(npm bin)/tsc -w", + "build": "rm -rf dist/ && $(npm bin)/webpack", + "watch": "$(npm bin)/webpack --watch", "codecov": "$(npm bin)/codecov" }, "jest": { @@ -66,7 +66,11 @@ "jest": "^26.0.1", "nyc": "^15.1.0", "ts-jest": "^26.1.0", - "typescript": "^3.9.3" + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "typescript": "^4.9.3", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4" }, "dependencies": { "js-md5": "^0.7.3" diff --git a/typescript/src/__tests__/filter.test.ts b/typescript/src/__tests__/filter.test.ts new file mode 100644 index 0000000..d6ccad1 --- /dev/null +++ b/typescript/src/__tests__/filter.test.ts @@ -0,0 +1,61 @@ +import { make, DictType, SuggestRowType } from "../"; + +const machine = ["iPhone", "Pixel", "XPERIA", "ZenFone", "Galaxy"]; +const os = ["iOS", "Android"]; +const browser = ["FireFox", "Chrome", "Safari"]; + +test('exclude impossible combinations', () => { + const factors = {machine, os, browser}; + const preFilter = (row: DictType) => { + return !( + (row.machine === 'iPhone' && row.os !== 'iOS') || + (row.machine !== 'iPhone' && row.os === 'iOS') + ); + }; + const rows = make(factors, { preFilter }); + expect(rows.filter(row => row.machine === 'iPhone' && row.os === 'iOS').length).toBe(browser.length); + expect(rows.filter(row => row.machine === 'iPhone' && row.os !== 'iOS').length).toBe(0); + expect(rows.filter(row => row.machine !== 'iPhone' && row.os === 'iOS').length).toBe(0); + + expect(rows.filter(row => row.machine === 'Pixel' && row.os === 'Android').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'XPERIA' && row.os === 'Android').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'ZenFone' && row.os === 'Android').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'Galaxy' && row.os === 'Android').length).toBeGreaterThanOrEqual(1); + + expect(rows.filter(row => row.machine === 'iPhone' && row.browser === 'FireFox').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'iPhone' && row.browser === 'Chrome').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'iPhone' && row.browser === 'Safari').length).toBeGreaterThanOrEqual(1); + + expect(rows.filter(row => row.machine === 'Pixel' && row.browser === 'FireFox').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'Pixel' && row.browser === 'Chrome').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.machine === 'Pixel' && row.browser === 'Safari').length).toBeGreaterThanOrEqual(1); + + expect(rows.filter(row => row.os === 'iOS' && row.browser === 'FireFox').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.os === 'iOS' && row.browser === 'Chrome').length).toBeGreaterThanOrEqual(1); + expect(rows.filter(row => row.os === 'iOS' && row.browser === 'Safari').length).toBeGreaterThanOrEqual(1); +}); + +test('Limited to iphone and iOS combinations only.', () => { + const factors = {machine, os, browser}; + const preFilter = (row: SuggestRowType) => row.machine === 'iPhone' && row.os === 'iOS'; + const rows = make(factors, { preFilter }); + expect(rows.length).toBe(browser.length); + expect(rows.filter(row => row.machine === 'iPhone' && row.os === 'iOS').length).toBe(browser.length); + expect(rows.filter(row => row.machine === 'Pixel').length).toBe(0); + expect(rows.filter(row => row.os == 'Android').length).toBe(0); +}); + + +test('Use a constant-false function for preFilter', () => { + const factors = {machine, os, browser}; + const preFilter = (row: DictType) => false; + const rows = make(factors, { preFilter }); + expect(rows).toEqual([]); +}); + +test('Use the wrong conditional function for preFilter', () => { + const factors = {machine, os, browser}; + const preFilter = (row: DictType) => row.machine === 'WindowsPhone'; + const rows = make(factors, { preFilter }); + expect(rows).toEqual([]); +}); diff --git a/typescript/src/__tests__/index.test.ts b/typescript/src/__tests__/index.test.ts index 6de8151..db68b71 100644 --- a/typescript/src/__tests__/index.test.ts +++ b/typescript/src/__tests__/index.test.ts @@ -1,6 +1,6 @@ import { default as make, sorters, criteria } from '../index'; -import { product, combinations, range, len, all, getItems } from '../utils'; -import { FactorsType, Scalar, Dict, PairType } from '../types'; +import { product, combinations, range, len, all, getItems } from '../lib'; +import { FactorsType, ScalarType, DictType, PairType } from '../types'; const getPairs = function* (factors: FactorsType, length = 2) { const allKeys = getItems(factors).map(([k, _]) => k); @@ -69,7 +69,7 @@ test('prefilter excludes specified pairs before', () => { ["d", "e"], ["f"], ]; - const preFilter = (row: Dict) => { + const preFilter = (row: DictType) => { if (row[0] === "a" && row[1] === "d") { return false; } @@ -89,23 +89,6 @@ test('prefilter excludes specified pairs before', () => { } }); -test('never matching prefilter throws an exception', () => { - const factors = [ - ["a", "b", "c"], - ["d", "e"], - ["f"], - ]; - const preFilter = (row: Dict) => { - if (row[2] === "f") { - return false; - } - return true; - } - expect(() => { - make(factors, { preFilter }) - }).toThrow(); -}); - test("greedy sorter should make rows less than seed's one with 2", () => { const factors = [ ["a", "b", "c"], @@ -168,7 +151,7 @@ test('dict type factors make dict row', () => { 'key5': ["m", "n", "o"], }; const rows = make(factors); - const sorter = (a: Scalar, b: Scalar) => a > b ? 1 : -1; + const sorter = (a: ScalarType, b: ScalarType) => a > b ? 1 : -1; for (let row of rows) { const keys1 = Object.keys(row).sort(sorter); const keys2 = Object.keys(factors).sort(sorter); diff --git a/typescript/src/__tests__/pict.test.ts b/typescript/src/__tests__/pict.test.ts new file mode 100644 index 0000000..ad75558 --- /dev/null +++ b/typescript/src/__tests__/pict.test.ts @@ -0,0 +1,391 @@ +import { PictConstraintsLexer } from "../utils/pict"; + +describe('PictConstraintsLexer with single constraints', () => { + it('Blank', () => { + const lexer = new PictConstraintsLexer(``, true); + expect(lexer.filters.length).toBe(0); + expect(lexer.errors.length).toBe(0); + + const row1 = { PRICE: 150, DISCOUNT: 'YES' }; + expect(lexer.filter(row1)).toBe(true); + }); + + it('should filter correctly with LIKE and IN conditions', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] LIKE "Alic?" THEN [STATUS] IN {"Active", "Pending"} ELSE [AGE] > 20 OR [COUNTRY] = "USA"; + `, false); + const row1 = { NAME: 'Alice', STATUS: 'Active' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { NAME: 'Alice', STATUS: 'Inactive' }; + expect(lexer.filter(row2)).toBe(false); + }); + + it('should filter correctly with numeric conditions', () => { + const lexer = new PictConstraintsLexer(` + IF [PRICE] > 100 THEN [DISCOUNT] = "YES" ELSE [DISCOUNT] = "NO"; + `, false); + const row1 = { PRICE: 150, DISCOUNT: 'YES' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { PRICE: 90, DISCOUNT: 'NO' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { PRICE: 90, DISCOUNT: 'YES' }; + expect(lexer.filter(row3)).toBe(false); + }); + + it('should handle NOT conditions correctly', () => { + const lexer = new PictConstraintsLexer(` + IF NOT [PRODUCT] = "Book" THEN [AVAILABLE] <> "No" ELSE [AVAILABLE] = "No"; + `, false); + const row1 = { PRODUCT: 'Pen', AVAILABLE: 'Yes' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { PRODUCT: 'Book', AVAILABLE: 'No' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { PRODUCT: 'Pen', AVAILABLE: 'No' }; + expect(lexer.filter(row3)).toBe(false); + }); + + it('should filter with AND conditions', () => { + const lexer = new PictConstraintsLexer(` + IF [CATEGORY] = "Electronics" AND [BRAND] = "Sony" THEN [WARRANTY] = "Included" ELSE [WARRANTY] = "Not Included"; + `, false); + const row1 = { CATEGORY: 'Electronics', BRAND: 'Sony', WARRANTY: 'Included' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { CATEGORY: 'Electronics', BRAND: 'General Electric Company', WARRANTY: 'Not Included' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { CATEGORY: 'Electronics', BRAND: 'Sony', WARRANTY: 'Not Included' }; + expect(lexer.filter(row3)).toBe(false); + }); + + it('should handle nested conditions with parentheses', () => { + const lexer = new PictConstraintsLexer(` + IF ([CATEGORY] = "Electronics" AND [BRAND] = "Sony") OR [BRAND] = "Apple" THEN [WARRANTY] = "Included" ELSE [WARRANTY] = "Not Included"; + `, false); + const row1 = { CATEGORY: 'Electronics', BRAND: 'Sony', WARRANTY: 'Included' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { CATEGORY: 'Electronics', BRAND: 'Apple', WARRANTY: 'Included' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { CATEGORY: 'Furniture', BRAND: 'IKEA', WARRANTY: 'Not Included' }; + expect(lexer.filter(row3)).toBe(true); + + const row4 = { CATEGORY: 'Electronics', BRAND: 'Samsung', WARRANTY: 'Included' }; + expect(lexer.filter(row4)).toBe(false); + }); + + it('should handle fields containing spaces', () => { + const lexer = new PictConstraintsLexer(` + IF [PRODUCT NAME] = "Laptop" THEN [PRICE] > 500 ELSE [PRICE] <= 500; + `, false); + const row1 = { 'PRODUCT NAME': 'Laptop', PRICE: 600 }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { 'PRODUCT NAME': 'Laptop', PRICE: 400 }; + expect(lexer.filter(row2)).toBe(false); + + const row3 = { 'PRODUCT NAME': 'Desktop', PRICE: 600 }; + expect(lexer.filter(row3)).toBe(false); + }); + + it('should handle IN conditions', () => { + const lexer = new PictConstraintsLexer(` + IF [COLOR] IN {"Red", "Blue", "Green"} THEN [CATEGORY] = "Primary" ELSE [CATEGORY] = "Secondary"; + `, false); + const row1 = { COLOR: 'Red', CATEGORY: 'Primary' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { COLOR: 'Yellow', CATEGORY: 'Secondary' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { COLOR: 'Red', CATEGORY: 'Secondary' }; + expect(lexer.filter(row3)).toBe(false); + }); + + it('should handle complex conditions with nested parentheses', () => { + const lexer = new PictConstraintsLexer(` + IF ([AGE] > 20 AND ([COUNTRY] = "USA" OR [COUNTRY] = "Canada")) THEN [STATUS] = "Allowed" ELSE [STATUS] = "Denied"; + `, false); + const row1 = { AGE: 25, COUNTRY: 'USA', STATUS: 'Allowed' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { AGE: 18, COUNTRY: 'USA', STATUS: 'Denied' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { AGE: 25, COUNTRY: 'UK', STATUS: 'Denied' }; + expect(lexer.filter(row3)).toBe(true); + + const row4 = { AGE: 25, COUNTRY: 'Canada', STATUS: 'Allowed' }; + expect(lexer.filter(row4)).toBe(true); + + const row5 = { AGE: 25, COUNTRY: 'Canada', STATUS: 'Denied' }; + expect(lexer.filter(row5)).toBe(false); + }); + it('should handle false in ELSE condition', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] = "Bob" THEN [STATUS] = "Inactive" ELSE FALSE; + `, false); + const row1 = { NAME: 'Bob', STATUS: 'Inactive' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { NAME: 'Alice', STATUS: 'Active' }; + expect(lexer.filter(row2)).toBe(false); + }); + + it('should handle true in ELSE condition', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] = "Bob" THEN [STATUS] = "Inactive" ELSE true; + `, false); + const row1 = { NAME: 'Bob', STATUS: 'Inactive' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { NAME: 'Alice', STATUS: 'Active' }; + expect(lexer.filter(row2)).toBe(true); + }); + it('Compare with other fields', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] = [ALIAS] THEN [AGE] <= 26; + `, false); + const row1 = { NAME: 'Bob', ALIAS: 'Bob', AGE: 18 }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { NAME: 'Alice', ALIAS: 'Lissie', AGE: 25 }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { NAME: 'Shohei', ALIAS: 'Shohei', AGE: 30 }; + expect(lexer.filter(row3)).toBe(false); + }); +}); + +describe('PictConstraintsLexer with multiple constraints', () => { + it('should handle multiple constraints correctly (Test Case 1)', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] = "Alice" THEN [AGE] > 20 ELSE [AGE] < 20; + IF [COUNTRY] = "USA" THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive"; + `, false); + + const row1 = { NAME: 'Alice', AGE: 25, COUNTRY: 'USA', STATUS: 'Active' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { NAME: 'Alice', AGE: 25, COUNTRY: 'Canada', STATUS: 'Inactive' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { NAME: 'Alice', AGE: 18, COUNTRY: 'USA', STATUS: 'Active' }; + expect(lexer.filter(row3)).toBe(false); + + const row4 = { NAME: 'Bob', AGE: 15, COUNTRY: 'USA', STATUS: 'Inactive' }; + expect(lexer.filter(row4)).toBe(false); + }); + + it('should handle multiple constraints correctly (Test Case 2)', () => { + const lexer = new PictConstraintsLexer(` + IF [SCORE] >= 90 THEN [GRADE] = "A" ELSE [GRADE] = "B"; + IF [MEMBER] = "YES" THEN [DISCOUNT] = "20%" ELSE [DISCOUNT] = "10%"; + `, false); + + const row1 = { SCORE: 95, GRADE: 'A', MEMBER: 'YES', DISCOUNT: '20%' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { SCORE: 85, GRADE: 'B', MEMBER: 'NO', DISCOUNT: '10%' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { SCORE: 85, GRADE: 'B', MEMBER: 'YES', DISCOUNT: '20%' }; + expect(lexer.filter(row3)).toBe(true); + + const row4 = { SCORE: 85, GRADE: 'A', MEMBER: 'YES', DISCOUNT: '10%' }; + expect(lexer.filter(row4)).toBe(false); + }); + + it('should handle multiple constraints correctly (Test Case 3)', () => { + const lexer = new PictConstraintsLexer(` + IF [TEMP] > 30 THEN [STATE] = "HOT" ELSE [STATE] = "COLD"; + IF [HUMIDITY] < 50 THEN [COMFORT] = "DRY" ELSE [COMFORT] = "HUMID"; + `, false); + + const row1 = { TEMP: 35, STATE: 'HOT', HUMIDITY: 45, COMFORT: 'DRY' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { TEMP: 25, STATE: 'COLD', HUMIDITY: 55, COMFORT: 'HUMID' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { TEMP: 25, STATE: 'HOT', HUMIDITY: 55, COMFORT: 'DRY' }; + expect(lexer.filter(row3)).toBe(false); + + const row4 = { TEMP: 35, STATE: 'HOT', HUMIDITY: 55, COMFORT: 'HUMID' }; + expect(lexer.filter(row4)).toBe(true); + }); + + it('should handle multiple constraints correctly (Test Case 4)', () => { + const lexer = new PictConstraintsLexer(` + IF [CATEGORY] = "Electronics" THEN [WARRANTY] = "Included" ELSE [WARRANTY] = "Not Included"; + IF [PRICE] > 100 THEN [DISCOUNT] = "YES" ELSE [DISCOUNT] = "NO"; + `, false); + + const row1 = { CATEGORY: 'Electronics', WARRANTY: 'Included', PRICE: 150, DISCOUNT: 'YES' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { CATEGORY: 'Furniture', WARRANTY: 'Not Included', PRICE: 90, DISCOUNT: 'NO' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { CATEGORY: 'Electronics', WARRANTY: 'Not Included', PRICE: 150, DISCOUNT: 'NO' }; + expect(lexer.filter(row3)).toBe(false); + + const row4 = { CATEGORY: 'Furniture', WARRANTY: 'Not Included', PRICE: 150, DISCOUNT: 'YES' }; + expect(lexer.filter(row4)).toBe(true); + }); + + it('should handle multiple constraints correctly (Test Case 5)', () => { + const lexer = new PictConstraintsLexer(` + IF [COLOR] = "Red" THEN [CATEGORY] = "Primary" ELSE [CATEGORY] = "Secondary"; + IF [QUANTITY] < 10 THEN [STOCK] = "Low" ELSE [STOCK] = "High"; + `, false); + + const row1 = { COLOR: 'Red', CATEGORY: 'Primary', QUANTITY: 5, STOCK: 'Low' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { COLOR: 'Blue', CATEGORY: 'Secondary', QUANTITY: 20, STOCK: 'High' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { COLOR: 'Red', CATEGORY: 'Secondary', QUANTITY: 5, STOCK: 'High' }; + expect(lexer.filter(row3)).toBe(false); + + const row4 = { COLOR: 'Red', CATEGORY: 'Primary', QUANTITY: 20, STOCK: 'High' }; + expect(lexer.filter(row4)).toBe(true); + }); + + it('should handle multiple constraints correctly (Test Case 6)', () => { + const lexer = new PictConstraintsLexer(` + IF [SIZE] = "Large" THEN [AVAILABILITY] = "In Stock" ELSE [AVAILABILITY] = "Out of Stock"; + IF ([DISCOUNT] = "YES" AND [MEMBER] = "YES") THEN [PRICE] < 100 ELSE [PRICE] >= 100; + `, false); + + const row1 = { SIZE: 'Large', AVAILABILITY: 'In Stock', DISCOUNT: 'YES', MEMBER: 'YES', PRICE: 90 }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { SIZE: 'Medium', AVAILABILITY: 'Out of Stock', DISCOUNT: 'NO', MEMBER: 'NO', PRICE: 120 }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { SIZE: 'Large', AVAILABILITY: 'In Stock', DISCOUNT: 'YES', MEMBER: 'NO', PRICE: 110 }; + expect(lexer.filter(row3)).toBe(true); + }); + + it('should handle multiple constraints correctly (Test Case 7)', () => { + const lexer = new PictConstraintsLexer(` + IF [SEASON] = "Winter" THEN [CLOTHING] = "Coat" ELSE [CLOTHING] = "Shirt"; + IF ([TEMP] < 0 AND [WEATHER] = "Snowy") THEN [ACTIVITY] = "Skiing" ELSE [ACTIVITY] = "Running"; + `, false); + + const row1 = { SEASON: 'Winter', CLOTHING: 'Coat', TEMP: -5, WEATHER: 'Snowy', ACTIVITY: 'Skiing' }; + expect(lexer.filter(row1)).toBe(true); + + const row2 = { SEASON: 'Summer', CLOTHING: 'Shirt', TEMP: 25, WEATHER: 'Sunny', ACTIVITY: 'Running' }; + expect(lexer.filter(row2)).toBe(true); + + const row3 = { SEASON: 'Winter', CLOTHING: 'Coat', TEMP: 5, WEATHER: 'Sunny', ACTIVITY: 'Running' }; + expect(lexer.filter(row3)).toBe(true); + }); +}); + +describe('PictConstraintsLexer with invalid constraints', () => { + it('Unknown comparer', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] @ "Alice" THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive"; + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Unknown comparison operator: @'); + }); + + it('Comparison operator missing, got a value', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] "Alice" THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive"; + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Expected comparison operator but found value: "Alice"'); + }); + + it('Comparison operator missing, got an operator', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] AND TRUE THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive"; + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Expected comparison operator but found operator: AND'); + }); + + it('Comparison operator and value missing, got then', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive" + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('A comparison operator and value are required after the field.'); + }); + it('Nothing after IF', () => { + const lexer = new PictConstraintsLexer(` + IF THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive" + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Expected field or value after "IF", "THEN", "ELSE"'); + }); + + it('Nothing after THEN', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] = "Summer" THEN ELSE [STATUS] = "Active" + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Expected field or value after "IF", "THEN", "ELSE"'); + }); + + it('Nothing after ELSE', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] = "Summer" THEN [STATUS] = "Active" ELSE + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Expected field or value after "IF", "THEN", "ELSE"'); + }); + + + it('IF is missing, typo', () => { + const lexer = new PictConstraintsLexer(` + F [NAME] = "Summer" THEN [STATUS] = "Active" + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('Unknown token: F'); + }); + + it('IF is nothing', () => { + const lexer = new PictConstraintsLexer(` + [NAME] = "Summer" THEN [STATUS] = "Active" + `, false); + expect(lexer.errors.length).toBe(1); + expect(lexer.errors[0]).toBe('The leading "IF" is missing, found [NAME]'); + }); + + it('Multiple invalid expressions', () => { + const lexer = new PictConstraintsLexer(` + IF [NAME] THEN [STATUS] = "Active"; + IF [NAME] = "Summer" THEN [STATUS] = "Active"; + IF [NAME] = "Summer" THEN [STATUS] = "Active" ELSE; + IF [NAME] = "Summer" THEN [STATUS] = "Active"; + IF [NAME] @ "Summer" THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive"; + `, false); + + expect(lexer.errors.length).toBe(5); + + expect(lexer.errors[0]).toBe('A comparison operator and value are required after the field.' ); + expect(lexer.errors[1]).toBe(null); + expect(lexer.errors[2]).toBe('Expected field or value after "IF", "THEN", "ELSE"' ); + expect(lexer.errors[3]).toBe(null); + expect(lexer.errors[4]).toBe('Unknown comparison operator: @'); + + expect(lexer.filters[0]).toBeNull(); + expect(lexer.filters[1]).not.toBeNull(); + expect(lexer.filters[2]).toBeNull(); + expect(lexer.filters[3]).not.toBeNull(); + expect(lexer.filters[4]).toBeNull(); + }); +}); \ No newline at end of file diff --git a/typescript/src/controller.ts b/typescript/src/controller.ts new file mode 100644 index 0000000..80544c1 --- /dev/null +++ b/typescript/src/controller.ts @@ -0,0 +1,321 @@ +import greedy from "./criteria/greedy"; +import hash from "./sorters/hash"; +import { + range, + product, + combinations, + len, + getItems, + getCandidate, + ascOrder, + primeGenerator, + unique, + proxyHandler, +} from "./lib"; + +import { + IndicesType, + FactorsType, + SerialsType, + ScalarType, + DictType, + PairByKeyType, + ParentsType, + CandidateType, + RowType, + OptionsType, + PairType, + SuggestRowType, +} from "./types"; +import { NeverMatch, NotReady } from "./exceptions"; + +export class Row extends Map implements RowType { + // index: number + public consumed: PairByKeyType = new Map(); + + constructor(row: CandidateType) { + super(); + for (const [k, v] of row) { + this.set(k, v); + } + } + getPairKey(...newPair: number[]) { + const pair = [...this.values(), ...newPair]; + return unique(pair); + } + copy(row: Row) { + for (let [k, v] of row.entries()) { + this.set(k, v); + } + } +} + +export class Controller { + public factorLength: number; + public factorIsArray: Boolean; + + private serials: SerialsType = new Map(); + private parents: ParentsType = new Map(); + private indices: IndicesType = new Map(); + public incomplete: PairByKeyType = new Map(); + private numAllChunks: number = 0; + + private rejected: Set = new Set(); + public row: Row; + + constructor(public factors: FactorsType, public options: OptionsType = {}) { + this.serialize(factors); + this.setIncomplete(); + this.numAllChunks = this.incomplete.size; + this.row = new Row([]); + this.factorLength = len(factors); + this.factorIsArray = factors instanceof Array; + + // Delete initial pairs that do not satisfy preFilter + for (const [pairKey, pair] of this.incomplete.entries()) { + const cand = this.getCandidate(pair); + const storable = this.storable(cand); + if (storable == null) { + this.incomplete.delete(pairKey); + } + } + } + + private serialize(factors: FactorsType) { + let origin = 0; + const primer = primeGenerator(); + getItems(factors).map(([subscript, elements]) => { + const lenElements = len(elements); + const serialList: number[] = []; + range(origin, origin + lenElements).map((index) => { + const serial = primer.next().value; + serialList.push(serial); + this.parents.set(serial, subscript); + this.indices.set(serial, index); + }); + this.serials.set(subscript, serialList); + origin += lenElements; + }); + }; + + private setIncomplete() { + const { sorter = hash, seed = "" } = this.options; + const pairs: PairType[] = []; + const allKeys = getItems(this.serials).map(([k, _]) => k); + for (const keys of combinations(allKeys, this.pairwiseCount)) { + const comb = range(0, this.pairwiseCount).map((i) => this.serials.get(keys[i]) as PairType); + for (let pair of product(...comb)) { + pair = pair.sort(ascOrder); + pairs.push(pair); + } + } + for (let pair of sorter(pairs, { seed, indices: this.indices })) { + this.incomplete.set(unique(pair), pair); + } + } + + private setPair(pair: PairType) { + for (let [key, value] of this.getCandidate(pair)) { + this.row.set(key, value); + } + //this.consume(pair); + for (let p of combinations([...this.row.values()], this.pairwiseCount)) { + this.consume(p); + } + } + + public consume(pair: PairType) { + const pairKey = unique(pair); + const deleted = this.incomplete.delete(pairKey); + if (deleted) { + this.row.consumed.set(pairKey, pair); + } + } + public consumeRow(row: Row) { + for (let pair of combinations([...row.values()], this.pairwiseCount)) { + this.consume(pair); + } + } + + public getCandidate(pair: PairType) { + return getCandidate(pair, this.parents); + } + + // Returns a negative value if it is unknown if it can be stored. + public storable(candidate: CandidateType) { + let num = 0; + for (let [key, el] of candidate) { + let existing: number | undefined = this.row.get(key); + if (typeof existing === "undefined") { + num++; + } else if (existing != el) { + return null; + } + } + if (!this.options.preFilter) { + return num; + } + const candidates: CandidateType = [...this.row.entries()].concat(candidate); + const nxt = new Row(candidates); + const proxy = this.toProxy(nxt); + try { + const ok = this.options.preFilter(proxy); + if (!ok) { + this.consumeRow(nxt); + return null; + } + } catch (e) { + if (e instanceof NotReady) { + return -num; + } + throw e + } + return num; + } + + public isFilled(row: Row): boolean { + return row.size === this.factorLength; + } + + private toMap(row: Row): Map { + const result: Map = new Map(); + for (let [key, serial] of row.entries()) { + const index = this.indices.get(serial) as number; + const first = this.indices.get((this.serials.get(key) as PairType)[0]); + // @ts-ignore TS7015 + result.set(key, this.factors[key][index - first]); + } + return result; + } + + private toProxy(row: Row) { + const obj: DictType = {}; + for (let [key, value] of this.toMap(row).entries()) { + obj[key] = value; + } + return new Proxy(obj, proxyHandler) as SuggestRowType; + } + + private toObject(row: Row) { + const obj: DictType = {}; + for (let [key, value] of this.toMap(row).entries()) { + obj[key] = value; + } + return obj as SuggestRowType; + } + + private reset() { + this.row.consumed.forEach((pair, pairKey) => { + this.incomplete.set(pairKey, pair); + }); + this.row = new Row([]); + } + + private discard() { + const pairKey = this.row.getPairKey(); + this.rejected.add(pairKey); + this.row = new Row([]); + } + + private restore() { + const row = this.row; + this.row = new Row([]); + if (this.factorIsArray) { + const map = this.toMap(row); + return getItems(map) + .sort((a, b) => (a[0] > b[0] ? 1 : -1)) + .map(([_, v]) => v); + } + return this.toObject(row); + } + + private close() { + const trier = new Row([...this.row.entries()]); + const kvs = getItems(this.serials); + for (let [k, vs] of kvs) { + for (let v of vs) { + const pairKey = trier.getPairKey(v); + if (this.rejected.has(pairKey)) { + continue; + } + const cand: CandidateType = [[k, v]]; + const storable = this.storable(cand); + if (storable == null) { + this.rejected.add(pairKey); + continue; + } + trier.set(k, v); + break; + } + } + this.row.copy(trier); + if (this.isComplete) { + return true; + } + if (trier.size === 0) { + return false; + } + const pairKey = trier.getPairKey(); + if (this.rejected.has(pairKey)) { + throw new NeverMatch(); + } + this.rejected.add(pairKey); + this.reset(); + return false; + } + + get pairwiseCount() { + return this.options.length || 2; + } + + get isComplete() { + const filled = this.isFilled(this.row); + if (!filled) { + return false; + } + const proxy = this.toProxy(this.row); + try { + return this.options.preFilter?.(proxy) ?? true; + } catch (e) { + if (e instanceof NotReady) { + return false; + } + throw e; + } + } + + get progress() { + if (this.numAllChunks === 0) { + return 0; + } + return 1 - this.incomplete.size / this.numAllChunks; + } + + public *makeAsync() { + const {criterion = greedy, postFilter} = this.options; + do { + for (let pair of criterion(this)) { + if (this.isFilled(this.row)) { + break; + } + this.setPair(pair); + } + try { + const complete = this.close(); + if (complete) { + if (!postFilter || postFilter(this.toObject(this.row))) { + yield this.restore() as SuggestRowType; + } else { + this.discard(); + } + } + } catch (e) { + if (e instanceof NeverMatch) { + break; + } + throw e; + } + } while (this.incomplete.size); + this.incomplete.clear(); + } +} diff --git a/typescript/src/criteria/greedy.ts b/typescript/src/criteria/greedy.ts index 46c92ae..512b6de 100644 --- a/typescript/src/criteria/greedy.ts +++ b/typescript/src/criteria/greedy.ts @@ -1,53 +1,53 @@ -import {CriterionArgsType, IncompletedType, PairType} from '../types'; -import {getCandidate, combinations, ascOrder, unique} from '../utils'; +import type {FactorsType, PairByKeyType, PairType} from '../types'; +import { combinations, unique } from '../lib'; +import { Controller } from '../controller'; -const getNumRemovablePairs = (indexes: Set, incompleted: IncompletedType, length: number) => { +const getNumRemovablePairs = (indexes: Set, incomplete: PairByKeyType, length: number) => { let num = 0; const removingKeys = combinations([... indexes], length); for (let pair of removingKeys) { const key = unique(pair); - if (incompleted.has(key)) { + if (incomplete.has(key)) { num++; } } return num; }; -export default function* ( - incompleted: IncompletedType, - criterionArgs: CriterionArgsType, -): Generator { - let {row, parents, length, tolerance} = criterionArgs; - +export default function* (ctrl: Controller): Generator { while (true) { let maxNumPairs: number | null = null; let efficientPair: PairType | null = null; - for (let [pairKey, pair] of incompleted.entries()) { - const rowSize = row.size; + for (const [pairKey, pair] of ctrl.incomplete.entries()) { + const rowSize = ctrl.row.size; if (rowSize === 0) { yield pair; continue; } - if (row.filled()) { + if (ctrl.isFilled(ctrl.row)) { break; } - const storable = row.storable(getCandidate(pair, parents)); + const storable = ctrl.storable(ctrl.getCandidate(pair)); if (storable === null) { continue; } if (storable === 0) { - incompleted.delete(pairKey); + ctrl.consume(pair); continue; } + const storableAbs = Math.abs(storable); + const { tolerance = 0 } = ctrl.options!; const numPairs = getNumRemovablePairs( - new Set([... row.values(), ...pair]), incompleted, length + new Set([...ctrl.row.values(), ...pair]), + ctrl.incomplete, + ctrl.pairwiseCount, ); - if (numPairs + tolerance > rowSize * storable) { + if (numPairs + tolerance > rowSize * storableAbs) { efficientPair = pair; break; } diff --git a/typescript/src/criteria/index.ts b/typescript/src/criteria/index.ts deleted file mode 100644 index 76a88d0..0000000 --- a/typescript/src/criteria/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {default as simple} from './simple'; -export {default as greedy} from './greedy'; diff --git a/typescript/src/criteria/simple.ts b/typescript/src/criteria/simple.ts index 8ec9515..e3000d6 100644 --- a/typescript/src/criteria/simple.ts +++ b/typescript/src/criteria/simple.ts @@ -1,13 +1,11 @@ -import {CriterionArgsType, IncompletedType, PairType} from '../types'; -import {getCandidate} from '../utils'; +import type {FactorsType, PairType} from '../types'; +import { Controller } from '../controller'; -export default function* ( - incompleted: IncompletedType, - criterionArgs: CriterionArgsType, -): Generator { - const {row, parents} = criterionArgs; - for (let pair of incompleted.values()) { - const storable = row.storable(getCandidate(pair, parents)); +export default function* (ctrl: Controller): Generator { + const incomplete = ctrl.incomplete; + for (let pair of incomplete.values()) { + const cand = ctrl.getCandidate(pair); + const storable = ctrl.storable(cand); if (storable === null || storable === 0) { continue; } diff --git a/typescript/src/exceptions.ts b/typescript/src/exceptions.ts index ca6e51e..677f9fe 100644 --- a/typescript/src/exceptions.ts +++ b/typescript/src/exceptions.ts @@ -1,5 +1,10 @@ +import { ScalarType } from "./types"; -export class InvalidCondition { - public name = 'InvalidCondition'; - public message = 'It will never meet the condition'; +export class NotReady extends Error { + constructor(public key: ScalarType) { + super(`Not yet '${key}' in the object`); + } +} + +export class NeverMatch extends Error { }; diff --git a/typescript/src/index.ts b/typescript/src/index.ts index 2f9949f..2b86560 100644 --- a/typescript/src/index.ts +++ b/typescript/src/index.ts @@ -1,238 +1,43 @@ -import * as sorters from "./sorters/index"; -import * as criteria from "./criteria/index"; -import * as exceptions from "./exceptions"; -import { - range, - product, - combinations, - len, - getItems, - getCandidate, - ascOrder, - primeGenerator, - unique, -} from "./utils"; -import { - IndicesType, - FactorsType, - SerialsType, - MappingTypes, - Scalar, - Dict, - IncompletedType, - ParentsType, - CandidateType, - RowType, - OptionsType, - FilterType, - PairType, - SorterType, - SuggestRowType, -} from "./types"; - -const serialize = (factors: FactorsType): MappingTypes => { - let origin = 0; - const serials: SerialsType = new Map(); - const indices: IndicesType = new Map(); - const parents: ParentsType = new Map(); - - const primer = primeGenerator(); - getItems(factors).map(([subscript, factorList]) => { - const length = len(factorList); - const serialList: number[] = []; - range(origin, origin + length).map((index) => { - const serial = primer.next().value; - serialList.push(serial); - parents.set(serial, subscript); - indices.set(serial, index); - }); - serials.set(subscript, serialList); - origin += length; - }); - return { serials, parents, indices }; -}; - -const makeIncompleted = ( - mappings: MappingTypes, - length: number, - sorter: SorterType, - seed: Scalar -): IncompletedType => { - const { serials, indices } = mappings; - const pairs: PairType[] = []; - const allKeys = getItems(serials).map(([k, _]) => k); - for (const keys of combinations(allKeys, length)) { - const comb = range(0, length).map((i) => serials.get(keys[i]) as PairType); - for (let pair of product(...comb)) { - pair = pair.sort(ascOrder); - pairs.push(pair); - } - } - const incompleted: IncompletedType = new Map(); - for (let pair of sorter(pairs, { seed, indices })) { - incompleted.set(unique(pair), pair); - } - return incompleted; -}; - -class Row extends Map implements RowType { - // index: number - private length: number; - public isArray: Boolean; - constructor( - row: CandidateType, - private mappings: MappingTypes, - private factors: FactorsType, - public preFilter?: FilterType - ) { - super(); - for (const [k, v] of row) { - this.set(k, v); - } - this.length = len(factors); - this.isArray = factors instanceof Array; - } - - filled(): boolean { - return this.size === this.length; - } - New(row?: CandidateType) { - return new Row(row || [], this.mappings, this.factors, this.preFilter); - } +import hash from "./sorters/hash"; +import random from "./sorters/random"; - storable(candidate: CandidateType) { - let num = 0; - for (let [key, el] of candidate) { - let existing: number | undefined = this.get(key); - if (typeof existing === "undefined") { - num++; - } else if (existing != el) { - return null; - } - } - if (!this.preFilter) { - return num; - } - const candidates: CandidateType = [...this.entries()].concat(candidate); - const nxt: Row = this.New(candidates); - if (!this.preFilter(nxt.toObject())) { - return null; - } - return num; - } +import greedy from "./criteria/greedy"; +import simple from "./criteria/simple"; - toMap(): Map { - const result: Map = new Map(); - const { indices, serials } = this.mappings; - for (let [key, serial] of this.entries()) { - const index = indices.get(serial) as number; - const first = indices.get((serials.get(key) as PairType)[0]); - // @ts-ignore TS7015 - result.set(key, this.factors[key][index - first]); - } - return result; - } - - toObject() { - const obj: Dict = {}; - for (let [key, value] of this.toMap().entries()) { - obj[key] = value; - } - return obj; - } - - restore() { - if (this.isArray) { - const map = this.toMap(); - return getItems(map) - .sort((a, b) => (a[0] > b[0] ? 1 : -1)) - .map(([_, v]) => v); - } - return this.toObject(); - } - - complement(): Row { - getItems(this.mappings.serials).map(([k, vs]) => { - for (let v of vs) { - if (this.storable([[k, v]])) { - this.set(k, v); - break; - } - } - }); - if (!this.filled()) { - throw new exceptions.InvalidCondition(); - } - return this; - } -} +import {PictConstraintsLexer} from "./utils/pict"; +import { FactorsType, OptionsType, SuggestRowType, DictType, ListType } from "./types"; +import { Controller } from "./controller"; const makeAsync = function* ( factors: T, - options: OptionsType = {} -) { - let { - length = 2, - sorter = sorters.hash, - criterion = criteria.greedy, - seed = "", - tolerance = 0, - } = options; - - const { preFilter, postFilter } = options; - const mappings = serialize(factors); - const { parents } = mappings; - const incompleted = makeIncompleted(mappings, length, sorter, seed); // {"1,2": [1,2], "3,4": [3,4]} - - let row: Row = new Row([], mappings, factors, preFilter); + options: OptionsType = {} +): Generator, void, unknown> { + const ctrl = new Controller(factors, options); + yield* ctrl.makeAsync(); +}; - for (let [pairKey, pair] of incompleted.entries()) { - if (!row.storable(getCandidate(pair, parents))) { - incompleted.delete(pairKey); - } - } - while (incompleted.size) { - if (row.filled()) { - if (!postFilter || postFilter(row.toObject())) { - yield row.restore() as SuggestRowType; - } - row = row.New([]); - } - let finished = true; - for (let pair of criterion(incompleted, { - row, - parents, - length, - tolerance, - })) { - if (row.filled()) { - finished = false; - break; - } +const make = (factors: T, options: OptionsType = {}) => { + return [...makeAsync(factors, options)]; +}; - for (let [key, value] of getCandidate(pair, parents)) { - row.set(key, value); - } +const sorters = { hash, random }; +const criteria = { greedy, simple }; - for (let p of combinations([...row.values()], length)) { - incompleted.delete(unique(p)); - } - } - if (finished && !row.filled()) { - row.complement(); - } - } - if (row.size) { - row = row.complement(); - if (!postFilter || postFilter(row.toObject())) { - yield row.restore() as SuggestRowType; - } - } +export { + make, + makeAsync, + sorters, + criteria, + PictConstraintsLexer, + Controller, }; -const make = (factors: T, options: OptionsType = {}) => { - return [...makeAsync(factors, options)]; -}; +export type { + OptionsType, + SuggestRowType, + DictType, + ListType, +} -export { make as default, make, makeAsync, sorters, criteria }; +export default make; diff --git a/typescript/src/utils.ts b/typescript/src/lib.ts similarity index 83% rename from typescript/src/utils.ts rename to typescript/src/lib.ts index 24a904b..90e454b 100644 --- a/typescript/src/utils.ts +++ b/typescript/src/lib.ts @@ -1,6 +1,10 @@ // @ts-ignore 2307 export { hex as md5 } from 'js-md5'; -import { FactorsType, Scalar, ParentsType, CandidateType, PairType } from './types'; +import { NotReady } from './exceptions'; +import type { + FactorsType, ScalarType, ParentsType, CandidateType, PairType, + DictType, +} from './types'; // https://gist.github.com/righ/71e32be8e33f74bde516c06f80c941e8 @@ -75,7 +79,7 @@ export const len = (obj: any[] | object): number => { return Object.keys(obj).length; } -export const getItems = (container: FactorsType | Map): [Scalar, any[]][] => { +export const getItems = (container: FactorsType | Map): [ScalarType, any[]][] => { if (Array.isArray(container)) { return container.map((v, i) => [i, v]); } @@ -86,13 +90,13 @@ export const getItems = (container: FactorsType | Map): [Scalar, } export const getCandidate = (pair: number[], parents: ParentsType): CandidateType => { - const keys: Scalar[] = pair.map(p => parents.get(p) || 0); + const keys: ScalarType[] = pair.map(p => parents.get(p) || 0); return zip(keys, pair); } export const ascOrder = (a: number, b: number) => a > b ? 1 : -1; -export const unique = (pair: PairType): Scalar => { +export const unique = (pair: PairType): ScalarType => { const total = pair.reduce((a, b) => a * b); if (Number.isSafeInteger(total)) { return total; @@ -123,3 +127,15 @@ export function* primeGenerator(): Generator { } } } + + + +export const proxyHandler = { + get(obj: DictType, key: string, receiver: any) { + if (key in obj) { + return obj[key]; + } + throw new NotReady(key); + }, +}; + diff --git a/typescript/src/sorters/hash.ts b/typescript/src/sorters/hash.ts index 39228e1..be75f52 100644 --- a/typescript/src/sorters/hash.ts +++ b/typescript/src/sorters/hash.ts @@ -1,5 +1,5 @@ -import {md5} from '../utils'; -import { +import {md5} from '../lib'; +import type { PairType, SortArgsType, } from '../types'; diff --git a/typescript/src/sorters/index.ts b/typescript/src/sorters/index.ts deleted file mode 100644 index 31e8ed9..0000000 --- a/typescript/src/sorters/index.ts +++ /dev/null @@ -1,3 +0,0 @@ - -export {default as random} from './random'; -export {default as hash} from './hash'; diff --git a/typescript/src/sorters/random.ts b/typescript/src/sorters/random.ts index 82c17e6..b43c453 100644 --- a/typescript/src/sorters/random.ts +++ b/typescript/src/sorters/random.ts @@ -1,4 +1,4 @@ -import {PairType, SortArgsType} from '../types'; +import type {PairType, SortArgsType} from '../types'; const comparer = (a: any, b: any) => { return Math.random() > 0.5 ? 1 : -1; diff --git a/typescript/src/types.ts b/typescript/src/types.ts index 787f31f..e48be1d 100644 --- a/typescript/src/types.ts +++ b/typescript/src/types.ts @@ -1,35 +1,38 @@ -export type Scalar = number | string; -export type Dict = { [s: string]: any }; -export type List = { [index: number]: any[] }; +import type { Controller } from "./controller"; -export type SerialsType = Map; -export type ParentsType = Map; -export type IndicesType = Map; +export type ScalarType = number | string; +export type DictType = { [s: string]: any }; +export type ListType = { [index: number]: any[] }; -export type MappingTypes = { - serials: SerialsType; - parents: ParentsType; - indices: IndicesType; -}; +export type SerialsType = Map; +export type ParentsType = Map; +export type IndicesType = Map; -export type FilterType = (row: { +export type FilterRowType = { [key: string]: any; [index: number]: any; -}) => boolean; +} -export type PairType = number[]; +export type ArrayTupleType = any[][]; +export type ArrayObjectType = { [s: string]: any[] }; +export type FactorsType = ArrayTupleType | ArrayObjectType; -export type IncompletedType = Map; +export type SuggestRowType = T extends ArrayTupleType + ? T[number][number][] + : T extends ArrayObjectType ? { [K in keyof T]: T[K][number] } + : unknown; +export type FilterType = (row: FilterRowType) => boolean; +export type SuggestFilterType = (row: SuggestRowType) => boolean; -export type CandidateType = [Scalar, number][]; +export type PairType = number[]; + +export type PairByKeyType = Map; + +export type CandidateType = [ScalarType, number][]; export interface RowType { - size: number; - isArray: Boolean; - filled: () => Boolean; - values: () => IterableIterator; - storable: (candidate: CandidateType) => number | null; + consumed: PairByKeyType; }; export type SorterType = ( @@ -38,7 +41,7 @@ export type SorterType = ( ) => PairType[]; export interface SortArgsType { - seed: Scalar; + seed: ScalarType; indices: IndicesType; }; @@ -49,21 +52,12 @@ export interface CriterionArgsType { tolerance: number; }; -export interface OptionsType { +export interface OptionsType { length?: number; sorter?: SorterType; - criterion?: (incompleted: IncompletedType, options: CriterionArgsType) => IterableIterator; - seed?: Scalar; + criterion?: (ctrl: Controller) => IterableIterator; + seed?: ScalarType; tolerance?: number; - preFilter?: FilterType; - postFilter?: FilterType; + preFilter?: FilterType | SuggestFilterType; + postFilter?: FilterType | SuggestFilterType; }; - -export type ArrayTuple = any[][]; -export type ArrayObject = { [s: string]: any[] }; -export type FactorsType = ArrayTuple | ArrayObject; - -export type SuggestRowType = T extends ArrayTuple - ? T[number][number][] - : T extends ArrayObject ? { [K in keyof T]: T[K][number] } - : unknown; diff --git a/typescript/src/utils/pict.ts b/typescript/src/utils/pict.ts new file mode 100644 index 0000000..5ebef26 --- /dev/null +++ b/typescript/src/utils/pict.ts @@ -0,0 +1,465 @@ +import type { FilterRowType, FilterType } from '../types'; + +type Token = { + type: TokenType; + value: string; +} + +type CacheType = { + [key: string]: any; +}; + +enum TokenType { + REF = 'REF', + STRING = 'STRING', + NUMBER = 'NUMBER', + BOOLEAN = 'BOOLEAN', + NULL = 'NULL', + IF = 'IF', + ELSE = 'ELSE', + THEN = 'THEN', + COMPARER = 'COMPARER', + OPERATOR = 'OPERATOR', + LPAREN = 'LPAREN', + RPAREN = 'RPAREN', + LBRACE = 'LBRACE', + RBRACE = 'RBRACE', + COMMA = 'COMMA', + COLON = 'COLON', + SEMICOLON = 'SEMICOLON', + WHITESPACE = 'WHITESPACE', + UNKNOWN = 'UNKNOWN', +} + +function classifyToken(token: string): Token { + if (token.startsWith('[') && token.endsWith(']')) { + return { type: TokenType.REF, value: token }; + } + if (token.startsWith('"') && token.endsWith('"')) { + return { type: TokenType.STRING, value: token }; + } + if (!isNaN(parseFloat(token))) { + return { type: TokenType.NUMBER, value: token }; + } + if (['TRUE', 'FALSE'].includes(token.toUpperCase())) { + return { type: TokenType.BOOLEAN, value: token.toUpperCase() }; + } + if (token.toUpperCase() === TokenType.NULL) { + return { type: TokenType.NULL, value: token.toUpperCase() }; + } + if ([TokenType.IF, TokenType.ELSE, TokenType.THEN].includes(token.toUpperCase() as TokenType)) { + return { type: token.toUpperCase() as TokenType, value: token.toUpperCase() }; + } + if (['=', '<>', '>', '<', '>=', '<=', 'IN', 'LIKE'].includes(token.toUpperCase())) { + return { type: TokenType.COMPARER, value: token.toUpperCase() }; + } + if (['AND', 'OR', 'NOT'].includes(token.toUpperCase())) { + return { type: TokenType.OPERATOR, value: token.toUpperCase() }; + } + switch (token) { + case '(': return { type: TokenType.LPAREN, value: token }; + case ')': return { type: TokenType.RPAREN, value: token }; + case '{': return { type: TokenType.LBRACE, value: token }; + case '}': return { type: TokenType.RBRACE, value: token }; + case ',': return { type: TokenType.COMMA, value: token }; + case ':': return { type: TokenType.COLON, value: token }; + case ';': return { type: TokenType.SEMICOLON, value: token }; + default: return { type: TokenType.UNKNOWN, value: token }; + } +} + +const isWhiteSpace = (char: string) => { + return char === ' ' || char === '\n' || char === '\t'; +}; + +export class PictConstraintsLexer { + private tokens: Token[] = []; + private cache: CacheType = {}; + public filters: (FilterType | null)[] = []; + public errors: (string | null)[] = []; + + constructor(private input: string, private debug=false) { + this.tokenize(); + this.analyze(); + } + private tokenize(): Token[] { + const constraints = this.input; + const tokens: Token[] = []; + let buffer = ''; + let insideQuotes = false; + let insideBraces = false; + let insideBrackets = false; + + const addToken = (type: TokenType, value: string) => { + tokens.push({ type, value }); + }; + + for (let i = 0; i < constraints.length; i++) { + const char = constraints[i]; + + if (char === '"') { + insideQuotes = !insideQuotes; + buffer += char; + if (!insideQuotes) { + addToken(TokenType.STRING, buffer); + buffer = ''; + } + } else if (insideQuotes) { + buffer += char; + } else if (char === '[') { + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + buffer = ''; + } + insideBrackets = true; + buffer += char; + } else if (char === ']' && insideBrackets) { + buffer += char; + tokens.push(classifyToken(buffer)); + insideBrackets = false; + buffer = ''; + } else if (char === '{') { + insideBraces = true; + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + buffer = ''; + } + addToken(TokenType.LBRACE, char); + } else if (char === '}') { + insideBraces = false; + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + buffer = ''; + } + addToken(TokenType.RBRACE, char); + } else if (char === ',' && insideBraces) { + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + buffer = ''; + } + addToken(TokenType.COMMA, char); + } else if ('[]=<>!();:'.includes(char) && !insideBraces && !insideBrackets) { + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + buffer = ''; + } + if (char === '<' || char === '>' || char === '!' || char === '=') { + const nextChar = constraints[i + 1]; + if (nextChar === '=') { + tokens.push(classifyToken(char + '=')); + i++; + } else if (char === '<' && nextChar === '>') { + tokens.push(classifyToken('<>')); + i++; + } else { + tokens.push(classifyToken(char)); + } + } else { + tokens.push(classifyToken(char)); + } + } else if (isWhiteSpace(char) && !insideBraces && !insideBrackets) { + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + buffer = ''; + } + let whitespaceBuffer = char; + while (i + 1 < constraints.length && isWhiteSpace(constraints[i + 1])) { + whitespaceBuffer += constraints[++i]; + } + addToken(TokenType.WHITESPACE, whitespaceBuffer); + } else if (isWhiteSpace(char) && (insideBraces || insideBrackets)) { + buffer += char; + } else { + buffer += char; + } + } + + if (buffer.length > 0) { + tokens.push(classifyToken(buffer)); + } + this.tokens = tokens; + return tokens; + } + + private analyze() { + let tokenIndex = 0; + let setIndex = 0; + let regexIndex = 0; + const tokens = this.tokens; + + const nextToken = () => { + while (tokenIndex < tokens.length && tokens[tokenIndex].type === 'WHITESPACE') { + tokenIndex++; + } + return tokenIndex < tokens.length ? tokens[tokenIndex++] : null; + } + + const parseExpression: () => string = () => { + let expr = parseTerm(); + let token = nextToken(); + if (token?.type === TokenType.UNKNOWN) { + throw new Error(`Unexpected token: ${token.value}`); + } + while (token && token.type === 'OPERATOR' && token.value === 'OR') { + const right = parseTerm(); + expr = `(${expr} || ${right})`; + token = nextToken(); + } + tokenIndex--; // Go back one token + return expr || 'true'; + } + + const parseTerm: () => string = () => { + let term = parseFactor(); + + let token = nextToken(); + if (token?.type === TokenType.UNKNOWN) { + throw new Error(`Unexpected token: ${token.value}`); + } + while (token && token.type === 'OPERATOR' && token.value === 'AND') { + const right = parseFactor(); + term = `(${term} && ${right})`; + token = nextToken(); + } + tokenIndex--; // Go back one token + return term; + } + + const parseFactor: () => string = () => { + let token = nextToken(); + if (token != null) { + if (token.type === 'OPERATOR' && token.value === 'NOT') { + const factor = parseFactor(); + return `!(${factor})`; + } + if (token.type === TokenType.LPAREN) { + const expr = parseExpression(); + token = nextToken(); + if (!token || token.type !== TokenType.RPAREN) { + throw new Error('Expected closing parenthesis'); + } + return `(${expr})`; + } + if (token.type === TokenType.BOOLEAN) { + return token.value.toUpperCase() === 'TRUE' ? 'true' : 'false'; + } + if (token.type === TokenType.UNKNOWN) { + throw new Error(`Unexpected token: ${token.value}`); + } + } + tokenIndex--; // Go back one token + return parseCondition(); + } + + const parseCondition: () => string = () => { + const left = parseOperand(); + if (left == null) { + throw new Error('Expected field or value after "IF", "THEN", "ELSE"'); + + } + const comparerToken = nextToken(); + if ([TokenType.NUMBER, TokenType.STRING, TokenType.BOOLEAN, TokenType.NULL].includes(comparerToken?.type!)) { + throw new Error(`Expected comparison operator but found value: ${comparerToken?.value}`); + } + if (comparerToken?.type === TokenType.THEN) { + throw new Error('A comparison operator and value are required after the field.'); + } + if (comparerToken?.type === 'OPERATOR') { + throw new Error(`Expected comparison operator but found operator: ${comparerToken.value}`); + } + + const comparer = comparerToken?.value; + + if (comparer === 'IN') { + const right = parseSet(); + return `${right}.has(${left})`; + } + const right = parseOperand(); + if (right == null) { + throw new Error('Expected field or value'); + } + switch (comparer) { + case '=': + return `${left} === ${right}`; + case '<>': + return `${left} !== ${right}`; + case '>': + return `${left} > ${right}`; + case '<': + return `${left} < ${right}`; + case '>=': + return `${left} >= ${right}`; + case '<=': + return `${left} <= ${right}`; + case 'LIKE': + const regexPattern = right.slice(1, -1).replace(/\*/g, '.*').replace(/\?/g, '.'); // remove quotes and replace wildcards + const regexKey = `re_${regexIndex++}`; + if (!this.cache[regexKey]) { + this.cache[regexKey] = new RegExp('^' + regexPattern + '$'); + } + return `this.cache['${regexKey}'].test(${left})`; + default: + throw new Error(`Unknown comparison operator: ${comparer}`); + } + } + + const parseSet: () => string = () => { + const elements: string[] = []; + let token = nextToken(); + if (token && token.type === TokenType.LBRACE) { + token = nextToken(); + while (token && token.type !== TokenType.RBRACE) { + if (token.type === TokenType.STRING) { + elements.push(token.value.slice(1, -1)); // remove quotes + } else if (token.type !== TokenType.COMMA && token.type !== TokenType.WHITESPACE) { + throw new Error(`Unexpected token in array: ${token.value}`); + } + token = nextToken(); + } + } else { + throw new Error(`Expected '{' but found ${token ? token.value : TokenType.NULL}`); + } + const setKey = `set_${setIndex++}`; + if (!this.cache[setKey]) { + this.cache[setKey] = new Set(elements); + } + return `this.cache['${setKey}']`; + } + + const parseOperand: () => string | null = () => { + const token = nextToken(); + if (token == null) { + return null; + } + if (token.type === TokenType.REF) { + const key = token.value.slice(1, -1); // remove [ and ] + return `row["${key}"]`; + } else if (token.type === TokenType.STRING) { + const value = token.value; // keep quotes for string literals + return `${value}`; + } else if (token.type === TokenType.NUMBER) { + return token.value; + } else if (token.type === TokenType.BOOLEAN) { + return token.value === 'TRUE' ? 'true' : 'false'; + } else if (token.type === TokenType.NULL) { + return TokenType.NULL; + } else { + return null; + } + } + + const abandon = () => { + while (tokenIndex < tokens.length && tokens[tokenIndex].type !== TokenType.SEMICOLON) { + tokenIndex++; + } + } + + const close = (code: string | null, error: string | null) => { + // Invariably, one of the two will be null. + if (code == null) { + if (this.debug) { + console.error(`Error[${this.errors.length}]:`, error); + } + this.filters.push(null); + this.errors.push(error); + } else { + if (this.debug) { + console.debug(`Code[${this.filters.length}]:`, code); + } + try { + const f = this.makeClosure(code); + this.filters.push(f); + this.errors.push(null); + } catch (e) { + console.error(e); + this.filters.push(null); + // @ts-ignore + this.errors.push(`RuntimeError[${this.errors.length}]:`, e.message); + } + + } + } + + const read = () => { + try { + const expr = parseExpression(); + return expr; + } catch (e) { + // @ts-ignore + close(null, e.message); + } + // If the conditional expression ends with “ELSE”, + // the current index reaches a semicolon, and the next expression is skipped by the abandon function. + // Therefore, the index is reset to the previous one. + tokenIndex--; + abandon(); + return null; + }; + + while (tokens[tokenIndex] != null) { + const token = nextToken(); + if (token == null) { + break; + } + if (token.type === TokenType.IF) { + const action = read(); + if (action == null) { + continue; + } + const thenToken = nextToken(); + if (!thenToken || thenToken.type !== TokenType.THEN) { + abandon() + continue; + } + const thenAction = read(); + if (thenAction == null) { + continue; + } + + const elseToken = nextToken(); + let elseAction: string | null = 'true'; + if (elseToken && elseToken.type === TokenType.ELSE) { + elseAction = read(); + if (elseAction == null) { + continue; + } + } else { + tokenIndex--; // Go back one token if ELSE is not found + } + const code = `return (${action} ? (${thenAction}) : (${elseAction}));`; + close(code, null); + } else if (token.type === TokenType.SEMICOLON) { + // do nothing + } else { + if (token.type === TokenType.UNKNOWN) { + close(null, `Unknown token: ${token.value}`); + } else { + close(null, `The leading "IF" is missing, found ${token.value}`); + } + abandon(); + } + } + } + + private makeClosure (code: string) { + return new Function('row', code).bind(this) as FilterType; + } + + filter = (row: FilterRowType, ...additionalFilters: FilterType[]) => { + for (const f of this.filters) { + if (f == null) { + continue; + } + if (!f(row)) { + return false; + } + } + for (const f of additionalFilters) { + if (!f(row)) { + return false; + } + } + return true; + } +} + diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 8bf419f..0707532 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -46,7 +46,7 @@ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ @@ -59,5 +59,9 @@ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + "baseUrl": ".", + "paths": { + "covertable/utils/pict": ["./dist/utils/pict"] + } } } diff --git a/typescript/webpack.config.js b/typescript/webpack.config.js new file mode 100644 index 0000000..2d4cf5f --- /dev/null +++ b/typescript/webpack.config.js @@ -0,0 +1,23 @@ +const path = require('path'); + +module.exports = { + entry: './src/index.ts', + module: { + rules: [ + { + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: ['.ts', '.js'], + }, + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + libraryTarget: 'umd', + }, + target: 'node', +};