aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:55 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:55 +0800
commitfc8c5fdce62fb229202659408798a7b6c98f6e8b (patch)
tree7554f80e50de4af6fd255afa7c21bcdd58a7af34
parentdd84b9d64fb98746a230cd24233ff50a562c39c9 (diff)
downloadHydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.tar.gz
HydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.zip
-rw-r--r--cli/.gitignore21
-rw-r--r--cli/.golangci.yml30
-rw-r--r--cli/LICENSE373
-rw-r--r--cli/Makefile332
-rw-r--r--cli/README.md3
-rw-r--r--cli/cmd/turbo/main.go28
-rw-r--r--cli/cmd/turbo/version.go3
-rw-r--r--cli/combined-release.yml78
-rw-r--r--cli/combined-shim.yml78
-rw-r--r--cli/cross-release.yml61
-rw-r--r--cli/darwin-release.yml35
-rw-r--r--cli/fixtures/01-git-hash-object/.gitignore2
-rw-r--r--cli/fixtures/01-git-hash-object/child/child.json0
-rw-r--r--cli/fixtures/01-git-hash-object/child/grandchild/grandchild.json0
-rw-r--r--cli/fixtures/01-git-hash-object/root.json0
-rw-r--r--cli/go.mod91
-rw-r--r--cli/go.sum952
-rw-r--r--cli/internal/analytics/analytics.go175
-rw-r--r--cli/internal/analytics/analytics_test.go192
-rw-r--r--cli/internal/cache/async_cache.go82
-rw-r--r--cli/internal/cache/cache.go317
-rw-r--r--cli/internal/cache/cache_fs.go174
-rw-r--r--cli/internal/cache/cache_fs_test.go253
-rw-r--r--cli/internal/cache/cache_http.go375
-rw-r--r--cli/internal/cache/cache_http_test.go245
-rw-r--r--cli/internal/cache/cache_noop.go23
-rw-r--r--cli/internal/cache/cache_signature_authentication.go88
-rw-r--r--cli/internal/cache/cache_signature_authentication_test.go195
-rw-r--r--cli/internal/cache/cache_test.go318
-rw-r--r--cli/internal/cacheitem/cacheitem.go76
-rw-r--r--cli/internal/cacheitem/create.go119
-rw-r--r--cli/internal/cacheitem/create_test.go205
-rw-r--r--cli/internal/cacheitem/create_unix_test.go20
-rw-r--r--cli/internal/cacheitem/create_windows_test.go14
-rw-r--r--cli/internal/cacheitem/filepath.go162
-rw-r--r--cli/internal/cacheitem/filepath_unix.go14
-rw-r--r--cli/internal/cacheitem/filepath_windows.go50
-rw-r--r--cli/internal/cacheitem/restore.go200
-rw-r--r--cli/internal/cacheitem/restore_directory.go144
-rw-r--r--cli/internal/cacheitem/restore_directory_test.go103
-rw-r--r--cli/internal/cacheitem/restore_regular.go46
-rw-r--r--cli/internal/cacheitem/restore_symlink.go180
-rw-r--r--cli/internal/cacheitem/restore_test.go1493
-rw-r--r--cli/internal/chrometracing/chrometracing.go227
-rw-r--r--cli/internal/chrometracing/chrometracing_close.go26
-rw-r--r--cli/internal/ci/ci.go58
-rw-r--r--cli/internal/ci/ci_test.go105
-rw-r--r--cli/internal/ci/vendors.go253
-rw-r--r--cli/internal/client/analytics.go21
-rw-r--r--cli/internal/client/cache.go167
-rw-r--r--cli/internal/client/client.go309
-rw-r--r--cli/internal/client/client_test.go159
-rw-r--r--cli/internal/cmd/root.go157
-rw-r--r--cli/internal/cmdutil/cmdutil.go245
-rw-r--r--cli/internal/cmdutil/cmdutil_test.go109
-rw-r--r--cli/internal/colorcache/colorcache.go56
-rw-r--r--cli/internal/config/config_file.go192
-rw-r--r--cli/internal/config/config_file_test.go157
-rw-r--r--cli/internal/context/context.go480
-rw-r--r--cli/internal/context/context_test.go162
-rw-r--r--cli/internal/context/testdata/dupe-workspace-names/apps/a/package.json6
-rw-r--r--cli/internal/context/testdata/dupe-workspace-names/apps/b/package.json6
-rw-r--r--cli/internal/context/testdata/dupe-workspace-names/package.json7
-rw-r--r--cli/internal/context/testdata/dupe-workspace-names/packages/ui/package.json3
-rw-r--r--cli/internal/context/testdata/dupe-workspace-names/pnpm-lock.yaml21
-rw-r--r--cli/internal/context/testdata/dupe-workspace-names/pnpm-workspace.yaml3
-rw-r--r--cli/internal/core/engine.go591
-rw-r--r--cli/internal/core/engine_test.go88
-rw-r--r--cli/internal/daemon/connector/connector.go391
-rw-r--r--cli/internal/daemon/connector/connector_test.go256
-rw-r--r--cli/internal/daemon/connector/fork.go15
-rw-r--r--cli/internal/daemon/connector/fork_windows.go15
-rw-r--r--cli/internal/daemon/daemon.go307
-rw-r--r--cli/internal/daemon/daemon_test.go262
-rw-r--r--cli/internal/daemonclient/daemonclient.go70
-rw-r--r--cli/internal/doublestar/doublestar.go11
-rw-r--r--cli/internal/doublestar/doublestar_test.go557
-rw-r--r--cli/internal/doublestar/glob.go393
-rw-r--r--cli/internal/doublestar/globwalk.go277
-rw-r--r--cli/internal/doublestar/match.go377
-rw-r--r--cli/internal/doublestar/utils.go71
-rw-r--r--cli/internal/doublestar/validate.go83
-rw-r--r--cli/internal/encoding/gitoutput/gitoutput.go345
-rw-r--r--cli/internal/encoding/gitoutput/gitoutput_test.go377
-rw-r--r--cli/internal/encoding/gitoutput/validators.go148
-rw-r--r--cli/internal/encoding/gitoutput/validators_test.go514
-rw-r--r--cli/internal/ffi/bindings.h21
-rw-r--r--cli/internal/ffi/ffi.go224
-rw-r--r--cli/internal/ffi/proto/messages.pb.go1380
-rw-r--r--cli/internal/filewatcher/backend.go209
-rw-r--r--cli/internal/filewatcher/backend_darwin.go220
-rw-r--r--cli/internal/filewatcher/cookie.go160
-rw-r--r--cli/internal/filewatcher/cookie_test.go130
-rw-r--r--cli/internal/filewatcher/filewatcher.go167
-rw-r--r--cli/internal/filewatcher/filewatcher_test.go152
-rw-r--r--cli/internal/fs/copy_file.go81
-rw-r--r--cli/internal/fs/copy_file_test.go198
-rw-r--r--cli/internal/fs/fs.go191
-rw-r--r--cli/internal/fs/fs_test.go60
-rw-r--r--cli/internal/fs/fs_windows_test.go18
-rw-r--r--cli/internal/fs/get_turbo_data_dir_go.go16
-rw-r--r--cli/internal/fs/get_turbo_data_dir_rust.go16
-rw-r--r--cli/internal/fs/hash.go61
-rw-r--r--cli/internal/fs/hash_test.go53
-rw-r--r--cli/internal/fs/lstat.go74
-rw-r--r--cli/internal/fs/package_json.go142
-rw-r--r--cli/internal/fs/package_json_test.go174
-rw-r--r--cli/internal/fs/path.go113
-rw-r--r--cli/internal/fs/testdata/both/package.json7
-rw-r--r--cli/internal/fs/testdata/both/turbo.json18
-rw-r--r--cli/internal/fs/testdata/correct/turbo.json49
-rw-r--r--cli/internal/fs/testdata/invalid-env-1/turbo.json8
-rw-r--r--cli/internal/fs/testdata/invalid-env-2/turbo.json8
-rw-r--r--cli/internal/fs/testdata/invalid-global-env/turbo.json11
-rw-r--r--cli/internal/fs/testdata/legacy-env/turbo.json34
-rw-r--r--cli/internal/fs/testdata/legacy-only/package.json7
-rw-r--r--cli/internal/fs/turbo_json.go741
-rw-r--r--cli/internal/fs/turbo_json_test.go277
-rw-r--r--cli/internal/globby/globby.go187
-rw-r--r--cli/internal/globby/globby_test.go832
-rw-r--r--cli/internal/globwatcher/globwatcher.go210
-rw-r--r--cli/internal/globwatcher/globwatcher_test.go232
-rw-r--r--cli/internal/graph/graph.go274
-rw-r--r--cli/internal/graph/graph_test.go50
-rw-r--r--cli/internal/graphvisualizer/graphvisualizer.go205
-rw-r--r--cli/internal/hashing/package_deps_hash.go461
-rw-r--r--cli/internal/hashing/package_deps_hash_test.go386
-rw-r--r--cli/internal/inference/inference.go167
-rw-r--r--cli/internal/inference/inference_test.go97
-rw-r--r--cli/internal/lockfile/berry_lockfile.go709
-rw-r--r--cli/internal/lockfile/berry_lockfile_test.go273
-rw-r--r--cli/internal/lockfile/lockfile.go135
-rw-r--r--cli/internal/lockfile/lockfile_test.go25
-rw-r--r--cli/internal/lockfile/npm_lockfile.go107
-rw-r--r--cli/internal/lockfile/pnpm_lockfile.go579
-rw-r--r--cli/internal/lockfile/pnpm_lockfile_test.go405
-rw-r--r--cli/internal/lockfile/testdata/berry.lock3283
-rw-r--r--cli/internal/lockfile/testdata/minimal-berry.lock45
-rw-r--r--cli/internal/lockfile/testdata/npm-lock-workspace-variation.json186
-rw-r--r--cli/internal/lockfile/testdata/npm-lock.json6472
-rw-r--r--cli/internal/lockfile/testdata/pnpm-absolute-v6.yaml18
-rw-r--r--cli/internal/lockfile/testdata/pnpm-absolute.yaml38
-rw-r--r--cli/internal/lockfile/testdata/pnpm-patch-v6.yaml40
-rw-r--r--cli/internal/lockfile/testdata/pnpm-patch.yaml63
-rw-r--r--cli/internal/lockfile/testdata/pnpm-peer-v6.yaml67
-rw-r--r--cli/internal/lockfile/testdata/pnpm-top-level-dupe.yaml36
-rw-r--r--cli/internal/lockfile/testdata/pnpm6-workspace.yaml1704
-rw-r--r--cli/internal/lockfile/testdata/pnpm7-workspace.yaml3445
-rw-r--r--cli/internal/lockfile/testdata/pnpm8.yaml107
-rw-r--r--cli/internal/lockfile/testdata/pnpm_override.yaml24
-rw-r--r--cli/internal/lockfile/testdata/yarn.lock2304
-rw-r--r--cli/internal/lockfile/yarn_lockfile.go124
-rw-r--r--cli/internal/lockfile/yarn_lockfile_test.go51
-rw-r--r--cli/internal/logstreamer/logstreamer.go159
-rw-r--r--cli/internal/logstreamer/logstreamer_test.go114
-rw-r--r--cli/internal/nodes/packagetask.go45
-rw-r--r--cli/internal/packagemanager/berry.go156
-rw-r--r--cli/internal/packagemanager/fixtures/package.json7
-rw-r--r--cli/internal/packagemanager/fixtures/pnpm-patches.json11
-rw-r--r--cli/internal/packagemanager/fixtures/pnpm-workspace.yaml3
-rw-r--r--cli/internal/packagemanager/infer_root.go146
-rw-r--r--cli/internal/packagemanager/infer_root_test.go347
-rw-r--r--cli/internal/packagemanager/npm.go59
-rw-r--r--cli/internal/packagemanager/packagemanager.go197
-rw-r--r--cli/internal/packagemanager/packagemanager_test.go411
-rw-r--r--cli/internal/packagemanager/pnpm.go168
-rw-r--r--cli/internal/packagemanager/pnpm6.go63
-rw-r--r--cli/internal/packagemanager/pnpm_test.go57
-rw-r--r--cli/internal/packagemanager/yarn.go116
-rw-r--r--cli/internal/process/child.go406
-rw-r--r--cli/internal/process/child_nix_test.go190
-rw-r--r--cli/internal/process/child_test.go193
-rw-r--r--cli/internal/process/manager.go120
-rw-r--r--cli/internal/process/manager_test.go94
-rw-r--r--cli/internal/process/sys_nix.go23
-rw-r--r--cli/internal/process/sys_windows.go17
-rw-r--r--cli/internal/prune/prune.go314
-rw-r--r--cli/internal/run/dry_run.go122
-rw-r--r--cli/internal/run/global_hash.go164
-rw-r--r--cli/internal/run/graph_run.go46
-rw-r--r--cli/internal/run/log_tag_go.go11
-rw-r--r--cli/internal/run/log_tag_rust.go11
-rw-r--r--cli/internal/run/real_run.go420
-rw-r--r--cli/internal/run/run.go487
-rw-r--r--cli/internal/run/run_spec.go90
-rw-r--r--cli/internal/run/run_spec_test.go107
-rw-r--r--cli/internal/runcache/output_watcher.go32
-rw-r--r--cli/internal/runcache/runcache.go354
-rw-r--r--cli/internal/runsummary/execution_summary.go282
-rw-r--r--cli/internal/runsummary/format_execution_summary.go70
-rw-r--r--cli/internal/runsummary/format_json.go66
-rw-r--r--cli/internal/runsummary/format_text.go100
-rw-r--r--cli/internal/runsummary/globalhash_summary.go38
-rw-r--r--cli/internal/runsummary/run_summary.go320
-rw-r--r--cli/internal/runsummary/spaces.go96
-rw-r--r--cli/internal/runsummary/task_summary.go117
-rw-r--r--cli/internal/scm/git_go.go111
-rw-r--r--cli/internal/scm/git_rust.go34
-rw-r--r--cli/internal/scm/scm.go53
-rw-r--r--cli/internal/scm/stub.go14
-rw-r--r--cli/internal/scope/filter/filter.go421
-rw-r--r--cli/internal/scope/filter/filter_test.go614
-rw-r--r--cli/internal/scope/filter/matcher.go32
-rw-r--r--cli/internal/scope/filter/matcher_test.go65
-rw-r--r--cli/internal/scope/filter/parse_target_selector.go165
-rw-r--r--cli/internal/scope/filter/parse_target_selector_test.go311
-rw-r--r--cli/internal/scope/scope.go380
-rw-r--r--cli/internal/scope/scope_test.go550
-rw-r--r--cli/internal/server/server.go192
-rw-r--r--cli/internal/server/server_test.go73
-rw-r--r--cli/internal/signals/signals.go60
-rw-r--r--cli/internal/spinner/spinner.go89
-rw-r--r--cli/internal/tarpatch/tar.go92
-rw-r--r--cli/internal/tarpatch/tar_unix.go42
-rw-r--r--cli/internal/tarpatch/tar_windows.go27
-rw-r--r--cli/internal/taskhash/taskhash.go497
-rw-r--r--cli/internal/taskhash/taskhash_test.go138
-rw-r--r--cli/internal/turbodprotocol/turbod.proto53
-rw-r--r--cli/internal/turbopath/absolute_system_path.go258
-rw-r--r--cli/internal/turbopath/absolute_system_path_darwin.go23
-rw-r--r--cli/internal/turbopath/absolute_system_path_notdarwin.go13
-rw-r--r--cli/internal/turbopath/absolute_system_path_test.go174
-rw-r--r--cli/internal/turbopath/anchored_system_path.go75
-rw-r--r--cli/internal/turbopath/anchored_unix_path.go31
-rw-r--r--cli/internal/turbopath/find_up.go50
-rw-r--r--cli/internal/turbopath/relative_system_path.go44
-rw-r--r--cli/internal/turbopath/relative_unix_path.go31
-rw-r--r--cli/internal/turbopath/turbopath.go112
-rw-r--r--cli/internal/turbostate/turbostate.go141
-rw-r--r--cli/internal/ui/charset.go3
-rw-r--r--cli/internal/ui/colors.go54
-rw-r--r--cli/internal/ui/spinner.go80
-rw-r--r--cli/internal/ui/term/cursor.go73
-rw-r--r--cli/internal/ui/term/cursor_test.go43
-rw-r--r--cli/internal/ui/ui.go121
-rw-r--r--cli/internal/util/backends.go30
-rw-r--r--cli/internal/util/browser/open.go37
-rw-r--r--cli/internal/util/closer.go15
-rw-r--r--cli/internal/util/cmd.go24
-rw-r--r--cli/internal/util/filter/filter.go133
-rw-r--r--cli/internal/util/filter/filter_test.go116
-rw-r--r--cli/internal/util/graph.go35
-rw-r--r--cli/internal/util/modulo.go13
-rw-r--r--cli/internal/util/parse_concurrency.go39
-rw-r--r--cli/internal/util/parse_concurrency_test.go79
-rw-r--r--cli/internal/util/printf.go63
-rw-r--r--cli/internal/util/run_opts.go53
-rw-r--r--cli/internal/util/semaphore.go43
-rw-r--r--cli/internal/util/set.go147
-rw-r--r--cli/internal/util/set_test.go149
-rw-r--r--cli/internal/util/status.go47
-rw-r--r--cli/internal/util/task_id.go66
-rw-r--r--cli/internal/util/task_output_mode.go100
-rw-r--r--cli/internal/workspace/workspace.go10
-rw-r--r--cli/internal/xxhash/xxhash.go202
-rw-r--r--cli/internal/yaml/apic.go747
-rw-r--r--cli/internal/yaml/decode.go1000
-rw-r--r--cli/internal/yaml/emitterc.go2019
-rw-r--r--cli/internal/yaml/encode.go577
-rw-r--r--cli/internal/yaml/parserc.go1274
-rw-r--r--cli/internal/yaml/readerc.go434
-rw-r--r--cli/internal/yaml/resolve.go326
-rw-r--r--cli/internal/yaml/scannerc.go3040
-rw-r--r--cli/internal/yaml/sorter.go134
-rw-r--r--cli/internal/yaml/writerc.go48
-rw-r--r--cli/internal/yaml/yaml.go693
-rw-r--r--cli/internal/yaml/yamlh.go809
-rw-r--r--cli/internal/yaml/yamlprivateh.go198
-rw-r--r--cli/package.json18
-rw-r--r--cli/scripts/generate.mjs297
-rw-r--r--cli/scripts/nginx/.dockerignore1
-rw-r--r--cli/scripts/nginx/Dockerfile.cacher11
-rw-r--r--cli/scripts/nginx/docker-compose.yml9
-rw-r--r--cli/scripts/nginx/nginx.conf39
-rw-r--r--cli/scripts/npm-native-packages/.gitignore1
-rw-r--r--cli/scripts/npm-native-packages/npm-native-packages.js57
-rw-r--r--cli/scripts/npm-native-packages/template/README.md3
-rw-r--r--cli/scripts/npm-native-packages/template/bin/turbo15
-rw-r--r--cli/scripts/npm-native-packages/template/template.package.json12
-rw-r--r--cli/scripts/templates/jest.config.js10
-rw-r--r--cli/scripts/templates/src/__tests__/index.test.ts7
-rw-r--r--cli/scripts/templates/src/__tests__/tsconfig.json4
-rw-r--r--cli/scripts/templates/src/index.ts3
-rw-r--r--cli/scripts/templates/tsconfig.json9
-rw-r--r--cli/turbo.json17
285 files changed, 0 insertions, 68689 deletions
diff --git a/cli/.gitignore b/cli/.gitignore
deleted file mode 100644
index 10e16a2..0000000
--- a/cli/.gitignore
+++ /dev/null
@@ -1,21 +0,0 @@
-/internal/turbodprotocol/*.go
-
-/demo/
-/dist/
-/dist-*
-
-# Built binaries.
-/turbo
-/turbo-new
-/turbo-new.exe
-/turbo.exe
-/go-turbo
-/go-turbo.exe
-
-testbed
-
-# Windows lib files
-turbo.h
-turbo.lib
-libturbo.a
-libturbo.h
diff --git a/cli/.golangci.yml b/cli/.golangci.yml
deleted file mode 100644
index 2008477..0000000
--- a/cli/.golangci.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-# Refer to golangci-lint's example config file for more options and information:
-# https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml
-
-run:
- timeout: 5m
- modules-download-mode: readonly
- go: 1.17
- skip-dirs:
- - internal/yaml # vendored upstream library
- skip-files:
- - internal/chrometracing/chrometracing.go # vendored upstream library
-
-linters:
- enable:
- - errcheck
- - goimports
- - govet
- - staticcheck
- - revive
- - nakedret
-
-linters-settings:
- nakedret:
- # Aggressively disallow naked returns
- max-func-lines: 3
-
-issues:
- exclude-use-default: false
- max-issues-per-linter: 0
- max-same-issues: 0
diff --git a/cli/LICENSE b/cli/LICENSE
deleted file mode 100644
index fa0086a..0000000
--- a/cli/LICENSE
+++ /dev/null
@@ -1,373 +0,0 @@
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
- means each individual or legal entity that creates, contributes to
- the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
- means the combination of the Contributions of others (if any) used
- by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
- means Source Code Form to which the initial Contributor has attached
- the notice in Exhibit A, the Executable Form of such Source Code
- Form, and Modifications of such Source Code Form, in each case
- including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- (a) that the initial Contributor has attached the notice described
- in Exhibit B to the Covered Software; or
-
- (b) that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the
- terms of a Secondary License.
-
-1.6. "Executable Form"
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
- means a work that combines Covered Software with other material, in
- a separate file or files, that is not Covered Software.
-
-1.8. "License"
- means this document.
-
-1.9. "Licensable"
- means having the right to grant, to the maximum extent possible,
- whether at the time of the initial grant or subsequently, any and
- all of the rights conveyed by this License.
-
-1.10. "Modifications"
- means any of the following:
-
- (a) any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered
- Software; or
-
- (b) any new file in Source Code Form that contains any Covered
- Software.
-
-1.11. "Patent Claims" of a Contributor
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the
- License, by the making, using, selling, offering for sale, having
- made, import, or transfer of either its Contributions or its
- Contributor Version.
-
-1.12. "Secondary License"
- means either the GNU General Public License, Version 2.0, the GNU
- Lesser General Public License, Version 2.1, the GNU Affero General
- Public License, Version 3.0, or any later versions of those
- licenses.
-
-1.13. "Source Code Form"
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that
- controls, is controlled by, or is under common control with You. For
- purposes of this definition, "control" means (a) the power, direct
- or indirect, to cause the direction or management of such entity,
- whether by contract or otherwise, or (b) ownership of more than
- fifty percent (50%) of the outstanding shares or beneficial
- ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
- for sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
- or
-
-(b) for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
- Form, as described in Section 3.1, and You must inform recipients of
- the Executable Form how they can obtain a copy of such Source Code
- Form by reasonable means in a timely manner, at a charge no more
- than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter
- the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-* *
-* 6. Disclaimer of Warranty *
-* ------------------------- *
-* *
-* Covered Software is provided under this License on an "as is" *
-* basis, without warranty of any kind, either expressed, implied, or *
-* statutory, including, without limitation, warranties that the *
-* Covered Software is free of defects, merchantable, fit for a *
-* particular purpose or non-infringing. The entire risk as to the *
-* quality and performance of the Covered Software is with You. *
-* Should any Covered Software prove defective in any respect, You *
-* (not any Contributor) assume the cost of any necessary servicing, *
-* repair, or correction. This disclaimer of warranty constitutes an *
-* essential part of this License. No use of any Covered Software is *
-* authorized under this License except under this disclaimer. *
-* *
-************************************************************************
-
-************************************************************************
-* *
-* 7. Limitation of Liability *
-* -------------------------- *
-* *
-* Under no circumstances and under no legal theory, whether tort *
-* (including negligence), contract, or otherwise, shall any *
-* Contributor, or anyone who distributes Covered Software as *
-* permitted above, be liable to You for any direct, indirect, *
-* special, incidental, or consequential damages of any character *
-* including, without limitation, damages for lost profits, loss of *
-* goodwill, work stoppage, computer failure or malfunction, or any *
-* and all other commercial damages or losses, even if such party *
-* shall have been informed of the possibility of such damages. This *
-* limitation of liability shall not apply to liability for death or *
-* personal injury resulting from such party's negligence to the *
-* extent applicable law prohibits such limitation. Some *
-* jurisdictions do not allow the exclusion or limitation of *
-* incidental or consequential damages, so this exclusion and *
-* limitation may not apply to You. *
-* *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
- This Source Code Form is "Incompatible With Secondary Licenses", as
- defined by the Mozilla Public License, v. 2.0. \ No newline at end of file
diff --git a/cli/Makefile b/cli/Makefile
deleted file mode 100644
index 90db191..0000000
--- a/cli/Makefile
+++ /dev/null
@@ -1,332 +0,0 @@
-TURBO_VERSION = $(shell cat ../version.txt | sed -n '1 p')
-TURBO_TAG = $(shell cat ../version.txt | sed -n '2 p')
-
-EXT :=
-ifeq ($(OS),Windows_NT)
- UNAME := Windows
- EXT = .exe
-else
- UNAME := $(shell uname -s)
-endif
-
-GOARCH:=$(shell go env GOARCH | xargs)
-GOOS:=$(shell go env GOOS | xargs)
-
-# Strip debug info
-GO_FLAGS += "-ldflags=-s -w"
-
-# Avoid embedding the build path in the executable for more reproducible builds
-GO_FLAGS += -trimpath
-
-CLI_DIR = $(shell pwd)
-
-# allow opting in to the rust codepaths
-GO_TAG ?= rust
-
-GO_FILES = $(shell find . -name "*.go")
-SRC_FILES = $(shell find . -name "*.go" | grep -v "_test.go")
-GENERATED_FILES = internal/turbodprotocol/turbod.pb.go internal/turbodprotocol/turbod_grpc.pb.go
-
-# We do not set go-turbo as a dependency because the Rust build.rs
-# script will call it for us and copy over the binary
-turbo:
- cargo build -p turbo
-
-turbo-prod:
- cargo build --release --manifest-path ../crates/turborepo/Cargo.toml
-
-go-turbo$(EXT): $(GENERATED_FILES) $(SRC_FILES) go.mod turborepo-ffi-install
- CGO_ENABLED=1 go build -tags $(GO_TAG) -o go-turbo$(EXT) ./cmd/turbo
-
-
-.PHONY: turborepo-ffi-install
-turborepo-ffi-install: turborepo-ffi turborepo-ffi-copy-bindings
- cp ../crates/turborepo-ffi/target/debug/libturborepo_ffi.a ./internal/ffi/libturborepo_ffi_$(GOOS)_$(GOARCH).a
-
-.PHONY: turborepo-ffi
-turborepo-ffi:
- cd ../crates/turborepo-ffi && cargo build --target-dir ./target
-
-.PHONY: turborepo-ffi-copy-bindings
-turborepo-ffi-copy-bindings:
- cp ../crates/turborepo-ffi/bindings.h ./internal/ffi/bindings.h
-
-#
-# ffi cross compiling
-#
-# these targets are used to build the ffi library for each platform
-# when doing a release. they _may_ work on your local machine, but
-# they're not intended to be used for development.
-#
-
-.PHONY: turborepo-ffi-install-windows-amd64
-turborepo-ffi-install-windows-amd64: turborepo-ffi-windows-amd64 turborepo-ffi-copy-bindings
- cp ../crates/turborepo-ffi/target/x86_64-pc-windows-gnu/release/libturborepo_ffi.a ./internal/ffi/libturborepo_ffi_windows_amd64.a
-
-.PHONY: turborepo-ffi-install-darwin-arm64
-turborepo-ffi-install-darwin-arm64: turborepo-ffi-darwin-arm64 turborepo-ffi-copy-bindings
- cp ../crates/turborepo-ffi/target/aarch64-apple-darwin/release/libturborepo_ffi.a ./internal/ffi/libturborepo_ffi_darwin_arm64.a
-
-.PHONY: turborepo-ffi-install-darwin-amd64
-turborepo-ffi-install-darwin-amd64: turborepo-ffi-darwin-amd64 turborepo-ffi-copy-bindings
- cp ../crates/turborepo-ffi/target/x86_64-apple-darwin/release/libturborepo_ffi.a ./internal/ffi/libturborepo_ffi_darwin_amd64.a
-
-.PHONY: turborepo-ffi-install-linux-arm64
-turborepo-ffi-install-linux-arm64: turborepo-ffi-linux-arm64 turborepo-ffi-copy-bindings
- cp ../crates/turborepo-ffi/target/aarch64-unknown-linux-musl/release/libturborepo_ffi.a ./internal/ffi/libturborepo_ffi_linux_arm64.a
-
-.PHONY: turborepo-ffi-install-linux-amd64
-turborepo-ffi-install-linux-amd64: turborepo-ffi-linux-amd64 turborepo-ffi-copy-bindings
- cp ../crates/turborepo-ffi/target/x86_64-unknown-linux-musl/release/libturborepo_ffi.a ./internal/ffi/libturborepo_ffi_linux_amd64.a
-
-.PHONY: turborepo-ffi-windows-amd64
-turborepo-ffi-windows-amd64:
- cd ../crates/turborepo-ffi && cargo build --release --target-dir ./target --target x86_64-pc-windows-gnu
-
-.PHONY: turborepo-ffi-darwin-arm64
-turborepo-ffi-darwin-arm64:
- cd ../crates/turborepo-ffi && cargo build --release --target-dir ./target --target aarch64-apple-darwin
-
-.PHONY: turborepo-ffi-darwin-amd64
-turborepo-ffi-darwin-amd64:
- cd ../crates/turborepo-ffi && cargo build --release --target-dir ./target --target x86_64-apple-darwin
-
-.PHONY: turborepo-ffi-linux-arm64
-turborepo-ffi-linux-arm64:
- cd ../crates/turborepo-ffi && CC="zig cc -target aarch64-linux-musl" cargo build --release --target-dir ./target --target aarch64-unknown-linux-musl
-
-.PHONY: turborepo-ffi-linux-amd64
-turborepo-ffi-linux-amd64:
- cd ../crates/turborepo-ffi && CC="zig cc -target x86_64-linux-musl" cargo build --release --target-dir ./target --target x86_64-unknown-linux-musl
-
-#
-# end
-#
-
-.PHONY: turborepo-ffi-proto
-turborepo-ffi-proto:
- protoc -I../crates/ ../crates/turborepo-ffi/messages.proto --go_out=./internal/
-
-protoc: internal/turbodprotocol/turbod.proto
- protoc --go_out=. --go_opt=paths=source_relative \
- --go-grpc_out=. --go-grpc_opt=paths=source_relative \
- internal/turbodprotocol/turbod.proto
-
-$(GENERATED_FILES): internal/turbodprotocol/turbod.proto
- make protoc
-
-compile-protos: $(GENERATED_FILES)
-
-ewatch: scripts/...
- nodemon --exec "make e2e" -e .ts,.go
-
-check-go-version:
- @go version | grep ' go1\.18\.0 ' || (echo 'Please install Go version 1.18.0' && false)
-
-# This "TURBO_RACE" variable exists at the request of a user on GitHub who
-# wants to run "make test-go" on an unsupported version of macOS (version 10.9).
-# Go's race detector does not run correctly on that version. With this flag
-# you can run "TURBO_RACE= make test-go" to disable the race detector.
-TURBO_RACE ?= -race
-
-ifeq ($(UNAME), Windows)
- TURBO_RACE=
-endif
-
-clean-go:
- go clean -testcache -r
-
-test-go: $(GENERATED_FILES) $(GO_FILES) go.mod go.sum turborepo-ffi-install
- go test $(TURBO_RACE) -tags $(GO_TAG) ./...
-
-# protos need to be compiled before linting, since linting needs to pick up
-# some types from the generated code
-lint-go: $(GENERATED_FILES) $(GO_FILES) go.mod go.sum
- golangci-lint run --new-from-rev=main
-
-fmt-go: $(GO_FILES) go.mod go.sum
- go fmt ./...
-
-install: | ./package.json
- pnpm install --filter=cli
-
-corepack:
- which corepack || npm install -g corepack@latest
- corepack enable
-
-e2e: corepack install turbo
- node -r esbuild-register scripts/e2e/e2e.ts
-
-# Expects turbo to be built and up to date
-# Only should be used by CI
-e2e-prebuilt: corepack install
- node -r esbuild-register scripts/e2e/e2e.ts
-
-cmd/turbo/version.go: ../version.txt
- # Update this atomically to avoid issues with this being overwritten during use
- node -e 'console.log(`package main\n\nconst turboVersion = "$(TURBO_VERSION)"`)' > cmd/turbo/version.go.txt
- mv cmd/turbo/version.go.txt cmd/turbo/version.go
-
-build: install
- cd $(CLI_DIR)/../ && pnpm install --filter=create-turbo && pnpm turbo build --filter=create-turbo...
- cd $(CLI_DIR)/../ && pnpm install --filter=@turbo/codemod && pnpm turbo build --filter=@turbo/codemod...
- cd $(CLI_DIR)/../ && pnpm install --filter=turbo-ignore && pnpm turbo build --filter=turbo-ignore...
- cd $(CLI_DIR)/../ && pnpm install --filter=@turbo/workspaces && pnpm turbo build --filter=@turbo/workspaces...
- cd $(CLI_DIR)/../ && pnpm install --filter=eslint-plugin-turbo && pnpm turbo build --filter=eslint-plugin-turbo...
- cd $(CLI_DIR)/../ && pnpm install --filter=eslint-config-turbo && pnpm turbo build --filter=eslint-config-turbo...
-
-.PHONY: prepublish
-prepublish: compile-protos cmd/turbo/version.go
- make -j3 bench/turbo test-go
-
-.PHONY: publish-turbo-cross
-publish-turbo-cross: prepublish
- goreleaser release --rm-dist -f cross-release.yml
-
-.PHONY: publish-turbo-darwin
-publish-turbo-darwin: prepublish
- goreleaser release --rm-dist -f darwin-release.yml
-
-.PHONY: snapshot-turbo-cross
-snapshot-turbo-cross:
- goreleaser release --snapshot --rm-dist -f cross-release.yml
-
-.PHONY: snapshot-turbo-darwin
-snapshot-turbo-darwin:
- goreleaser release --snapshot --rm-dist -f darwin-release.yml
-
-.PHONY: snapshot-lib-turbo-darwin
-snapshot-lib-turbo-darwin:
- goreleaser release --snapshot --rm-dist -f darwin-lib.yml
-
-.PHONY: snapshot-lib-turbo-cross
-snapshot-lib-turbo-cross:
- goreleaser release --snapshot --rm-dist -f cross-lib.yml
-
-.PHONY: build-lib-turbo-darwin
-build-lib-turbo-darwin:
- goreleaser release --rm-dist -f darwin-lib.yml
-
-.PHONY: build-go-turbo-darwin
-build-go-turbo-darwin:
- goreleaser release --rm-dist -f darwin-release.yml
-
-.PHONY: build-go-turbo-cross
-build-go-turbo-cross:
- goreleaser release --rm-dist -f cross-release.yml
-
-.PHONY: build-lib-turbo-cross
-build-lib-turbo-cross:
- goreleaser release --rm-dist -f cross-lib.yml
-
-.PHONY: stage-release
-stage-release: cmd/turbo/version.go
- echo "Version: $(TURBO_VERSION)"
- echo "Tag: $(TURBO_TAG)"
- cat $(CLI_DIR)/../version.txt
- git diff -- $(CLI_DIR)/../version.txt
- git status
- @test main = "`git rev-parse --abbrev-ref HEAD`" || (echo "Refusing to publish from non-main branch `git rev-parse --abbrev-ref HEAD`" && false)
- @test "" = "`git cherry`" || (echo "Refusing to publish with unpushed commits" && false)
-
- # Stop if versions are not updated.
- @test "" != "`git diff -- $(CLI_DIR)/../version.txt`" || (echo "Refusing to publish with unupdated version.txt" && false)
- @test "" != "`git diff -- $(CLI_DIR)/cmd/turbo/version.go`" || (echo "Refusing to publish with unupdated version.go" && false)
-
- # Prepare the packages.
- cd $(CLI_DIR)/../packages/turbo && pnpm version "$(TURBO_VERSION)" --allow-same-version
- cd $(CLI_DIR)/../packages/create-turbo && pnpm version "$(TURBO_VERSION)" --allow-same-version
- cd $(CLI_DIR)/../packages/turbo-codemod && pnpm version "$(TURBO_VERSION)" --allow-same-version
- cd $(CLI_DIR)/../packages/turbo-ignore && pnpm version "$(TURBO_VERSION)" --allow-same-version
- cd $(CLI_DIR)/../packages/turbo-workspaces && pnpm version "$(TURBO_VERSION)" --allow-same-version
- cd $(CLI_DIR)/../packages/eslint-plugin-turbo && pnpm version "$(TURBO_VERSION)" --allow-same-version
- cd $(CLI_DIR)/../packages/eslint-config-turbo && pnpm version "$(TURBO_VERSION)" --allow-same-version
-
- git checkout -b staging-$(TURBO_VERSION)
- git commit -anm "publish $(TURBO_VERSION) to registry"
- git tag "v$(TURBO_VERSION)"
- git push origin staging-$(TURBO_VERSION) --tags --force
-
-.PHONY: publish-turbo
-publish-turbo: clean build
- echo "Version: $(TURBO_VERSION)"
- echo "Tag: $(TURBO_TAG)"
-
- # Include the patch in the log.
- git format-patch HEAD~1 --stdout | cat
-
- npm config set --location=project "//registry.npmjs.org/:_authToken" $(NPM_TOKEN)
-
- # Publishes the native npm modules.
- goreleaser release --rm-dist -f combined-shim.yml $(SKIP_PUBLISH)
-
- # Split packing from the publish step so that npm locates the correct .npmrc file.
- cd $(CLI_DIR)/../packages/turbo && pnpm pack --pack-destination=$(CLI_DIR)/../
- cd $(CLI_DIR)/../packages/create-turbo && pnpm pack --pack-destination=$(CLI_DIR)/../
- cd $(CLI_DIR)/../packages/turbo-codemod && pnpm pack --pack-destination=$(CLI_DIR)/../
- cd $(CLI_DIR)/../packages/turbo-ignore && pnpm pack --pack-destination=$(CLI_DIR)/../
- cd $(CLI_DIR)/../packages/turbo-workspaces && pnpm pack --pack-destination=$(CLI_DIR)/../
- cd $(CLI_DIR)/../packages/eslint-plugin-turbo && pnpm pack --pack-destination=$(CLI_DIR)/../
- cd $(CLI_DIR)/../packages/eslint-config-turbo && pnpm pack --pack-destination=$(CLI_DIR)/../
-
-ifneq ($(SKIP_PUBLISH),--skip-publish)
- # Publish the remaining JS packages in order to avoid race conditions.
- cd $(CLI_DIR)/../
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../turbo-$(TURBO_VERSION).tgz
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../create-turbo-$(TURBO_VERSION).tgz
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../turbo-codemod-$(TURBO_VERSION).tgz
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../turbo-ignore-$(TURBO_VERSION).tgz
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../turbo-workspaces-$(TURBO_VERSION).tgz
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../eslint-plugin-turbo-$(TURBO_VERSION).tgz
- npm publish -ddd --tag $(TURBO_TAG) $(CLI_DIR)/../eslint-config-turbo-$(TURBO_VERSION).tgz
-endif
-
-demo/lage: install
- node $(CLI_DIR)/scripts/generate.mjs lage
-
-demo/lerna: install
- node $(CLI_DIR)/scripts/generate.mjs lerna
-
-demo/nx: install
- node $(CLI_DIR)/scripts/generate.mjs nx
-
-demo/turbo: install
- node $(CLI_DIR)/scripts/generate.mjs turbo
-
-demo: demo/lage demo/lerna demo/nx demo/turbo
-
-bench/lerna: demo/lerna
- cd $(CLI_DIR)/demo/lerna && node_modules/.bin/lerna run build
-
-bench/lage: demo/lage
- cd $(CLI_DIR)/demo/lage && node_modules/.bin/lage build
-
-bench/nx: demo/nx
- cd $(CLI_DIR)/demo/nx && node_modules/.bin/nx run-many --target=build --all
-
-bench/turbo: demo/turbo turbo
- cd $(CLI_DIR)/demo/turbo && $(CLI_DIR)/turbo run test
-
-bench: bench/lerna bench/lage bench/nx bench/turbo
-
-clean: clean-go clean-build clean-demo clean-rust
-
-clean-rust:
- cargo clean
-
-clean-build:
- rm -f turbo
-
-clean-demo:
- rm -rf node_modules
- rm -rf demo
-
-# use target fixture-<some directory under integration_tests/_fixtures> to set up the testbed directory
-.PHONY=fixture-%
-fixture-%:
- $(eval $@_FIXTURE := $(@:fixture-%=%))
- @echo "fixture setup $($@_FIXTURE)"
- rm -rf testbed
- mkdir -p testbed
- ../turborepo-tests/integration/tests/_helpers/setup_monorepo.sh ./testbed $($@_FIXTURE)
-
diff --git a/cli/README.md b/cli/README.md
deleted file mode 100644
index 0cc7a7b..0000000
--- a/cli/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# `turbo` CLI
-
-Visit https://turbo.build/repo to view the full documentation.
diff --git a/cli/cmd/turbo/main.go b/cli/cmd/turbo/main.go
deleted file mode 100644
index d4155f5..0000000
--- a/cli/cmd/turbo/main.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "os"
-
- "github.com/vercel/turbo/cli/internal/cmd"
- "github.com/vercel/turbo/cli/internal/turbostate"
-)
-
-func main() {
- if len(os.Args) != 2 {
- fmt.Printf("go-turbo is expected to be invoked via turbo")
- os.Exit(1)
- }
-
- argsString := os.Args[1]
- var args turbostate.ParsedArgsFromRust
- err := json.Unmarshal([]byte(argsString), &args)
- if err != nil {
- fmt.Printf("Error unmarshalling CLI args: %v\n Arg string: %v\n", err, argsString)
- os.Exit(1)
- }
-
- exitCode := cmd.RunWithArgs(&args, turboVersion)
- os.Exit(exitCode)
-}
diff --git a/cli/cmd/turbo/version.go b/cli/cmd/turbo/version.go
deleted file mode 100644
index 3febcaa..0000000
--- a/cli/cmd/turbo/version.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package main
-
-const turboVersion = "1.9.4-canary.2"
diff --git a/cli/combined-release.yml b/cli/combined-release.yml
deleted file mode 100644
index 6b85013..0000000
--- a/cli/combined-release.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-project_name: turbo
-
-dist: dist
-
-builds:
- - id: turbo
- builder: prebuilt
- tags:
- - rust
- - staticbinary
- goos:
- - linux
- - windows
- - darwin
- goarch:
- - amd64
- - arm64
- goamd64:
- - v1
- prebuilt:
- path: dist-combined/turbo_{{ .Os }}_{{ .Arch }}{{ with .Amd64 }}_{{ .}}{{ end }}/bin/turbo{{ .Ext }}
- hooks:
- pre:
- - cmd: ./scripts/npm-native-packages/npm-native-packages.js {{ .Os }} {{ .Arch }} {{ .Version }}
- binary: bin/turbo
-checksum:
- name_template: "checksums.txt"
-snapshot:
- name_template: "{{ incpatch .Version }}"
-archives:
- - id: github
- name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
- wrap_in_directory: true
- replacements:
- amd64: 64
- format: tar.gz
- format_overrides:
- - goos: windows
- format: zip
- files:
- - LICENSE
- - README.md
- - id: npm
- name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"
- wrap_in_directory: true
- replacements:
- amd64: 64
- format: tar.gz
- files:
- - LICENSE
- - src: "scripts/npm-native-packages/build/{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}/package.json"
- dst: "workaround/.."
- strip_parent: true
- - src: "scripts/npm-native-packages/build/{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}/README.md"
- dst: "workaround/.."
- strip_parent: true
- - src: "scripts/npm-native-packages/build/{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}/bin/*"
- dst: "bin/"
- strip_parent: true
-changelog:
- sort: asc
- filters:
- exclude:
- - "^docs:"
- - "^test:"
-release:
- github:
- owner: vercel
- name: turborepo
- ids:
- - github
- prerelease: auto
- disable: true
-publishers:
- - name: npm
- ids:
- - npm
- cmd: "npm publish{{ if .Prerelease }} --tag canary{{ end }} {{ abs .ArtifactPath }}"
diff --git a/cli/combined-shim.yml b/cli/combined-shim.yml
deleted file mode 100644
index 67d9914..0000000
--- a/cli/combined-shim.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-project_name: turbo
-
-dist: dist
-
-builds:
- - id: turbo
- builder: prebuilt
- tags:
- - rust
- - staticbinary
- goos:
- - linux
- - windows
- - darwin
- goarch:
- - amd64
- - arm64
- goamd64:
- - v1
- prebuilt:
- path: dist-{{ .Os }}-{{ .Arch }}/turbo{{ .Ext }}
- hooks:
- pre:
- - cmd: ./scripts/npm-native-packages/npm-native-packages.js {{ .Os }} {{ .Arch }} {{ .Version }}
- binary: bin/turbo
-checksum:
- name_template: "checksums.txt"
-snapshot:
- name_template: "{{ incpatch .Version }}"
-archives:
- - id: github
- name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
- wrap_in_directory: true
- replacements:
- amd64: 64
- format: tar.gz
- format_overrides:
- - goos: windows
- format: zip
- files:
- - LICENSE
- - README.md
- - id: npm
- name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"
- wrap_in_directory: true
- replacements:
- amd64: 64
- format: tar.gz
- files:
- - LICENSE
- - src: "scripts/npm-native-packages/build/{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}/package.json"
- dst: "workaround/.."
- strip_parent: true
- - src: "scripts/npm-native-packages/build/{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}/README.md"
- dst: "workaround/.."
- strip_parent: true
- - src: "scripts/npm-native-packages/build/{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}/bin/*"
- dst: "bin/"
- strip_parent: true
-changelog:
- sort: asc
- filters:
- exclude:
- - "^docs:"
- - "^test:"
-release:
- github:
- owner: vercel
- name: turborepo
- ids:
- - github
- prerelease: auto
- disable: true
-publishers:
- - name: npm
- ids:
- - npm
- cmd: "npm publish{{ if .Prerelease }} --tag canary{{ end }} {{ abs .ArtifactPath }}"
diff --git a/cli/cross-release.yml b/cli/cross-release.yml
deleted file mode 100644
index 18e449f..0000000
--- a/cli/cross-release.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-project_name: turbo
-before:
- hooks:
- - make compile-protos
- - go mod tidy
-
-dist: dist-cross
-
-builds:
- - id: turbo
- main: ./cmd/turbo
- tags:
- - rust
- - staticbinary
- binary: bin/go-turbo
- flags:
- - -trimpath
- ldflags:
- - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
- mod_timestamp: "{{ .CommitTimestamp }}"
- env:
- - CGO_ENABLED=1
- hooks:
- pre:
- - cmd: make turborepo-ffi-install-{{ .Os }}-{{ .Arch }}
- output: true
- targets:
- - linux_arm64
- - linux_amd64
- - windows_amd64
- overrides:
- - goos: linux
- goarch: arm64
- ldflags: -linkmode external -extldflags="-static" -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
- env:
- - CC=zig cc -target aarch64-linux-musl
- - CXX=zig c++ -target aarch64-linux-musl
- - goos: linux
- goarch: amd64
- goamd64: v1
- ldflags: -linkmode external -extldflags="-static" -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
- env:
- - CC=zig cc -target x86_64-linux-musl
- - CXX=zig c++ -target x86_64-linux-musl
- - goos: windows
- goarch: arm64
- env:
- - CC=/llvm-mingw/llvm-mingw/bin/aarch64-w64-mingw32-gcc
- - CXX=/llvm-mingw/llvm-mingw/bin/aarch64-w64-mingw32-g++
- - goos: windows
- goarch: amd64
- goamd64: v1
- env:
- - CC=x86_64-w64-mingw32-gcc
- - CXX=x86_64-w64-mingw32-g++
-
-archives:
- - format: binary
-
-release:
- disable: true
diff --git a/cli/darwin-release.yml b/cli/darwin-release.yml
deleted file mode 100644
index ca6e8a0..0000000
--- a/cli/darwin-release.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-project_name: turbo
-before:
- hooks:
- - make compile-protos
- - go mod tidy
-
-dist: dist-darwin
-
-builds:
- - id: turbo
- main: ./cmd/turbo
- tags:
- - rust
- - staticbinary
- binary: bin/go-turbo
- hooks:
- pre:
- - cmd: make turborepo-ffi-install-{{ .Os }}-{{ .Arch }}
- output: true
- flags:
- - -trimpath
- ldflags:
- - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
- mod_timestamp: "{{ .CommitTimestamp }}"
- env:
- - CGO_ENABLED=1
- targets:
- - darwin_arm64
- - darwin_amd64
-
-archives:
- - format: binary
-
-release:
- disable: true
diff --git a/cli/fixtures/01-git-hash-object/.gitignore b/cli/fixtures/01-git-hash-object/.gitignore
deleted file mode 100644
index d8e1950..0000000
--- a/cli/fixtures/01-git-hash-object/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-"quote"
-new*line
diff --git a/cli/fixtures/01-git-hash-object/child/child.json b/cli/fixtures/01-git-hash-object/child/child.json
deleted file mode 100644
index e69de29..0000000
--- a/cli/fixtures/01-git-hash-object/child/child.json
+++ /dev/null
diff --git a/cli/fixtures/01-git-hash-object/child/grandchild/grandchild.json b/cli/fixtures/01-git-hash-object/child/grandchild/grandchild.json
deleted file mode 100644
index e69de29..0000000
--- a/cli/fixtures/01-git-hash-object/child/grandchild/grandchild.json
+++ /dev/null
diff --git a/cli/fixtures/01-git-hash-object/root.json b/cli/fixtures/01-git-hash-object/root.json
deleted file mode 100644
index e69de29..0000000
--- a/cli/fixtures/01-git-hash-object/root.json
+++ /dev/null
diff --git a/cli/go.mod b/cli/go.mod
deleted file mode 100644
index da8b7f4..0000000
--- a/cli/go.mod
+++ /dev/null
@@ -1,91 +0,0 @@
-module github.com/vercel/turbo/cli
-
-go 1.18
-
-require (
- github.com/AlecAivazis/survey/v2 v2.3.5
- github.com/DataDog/zstd v1.5.2
- github.com/Masterminds/semver v1.5.0
- github.com/adrg/xdg v0.3.3
- github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f
- github.com/briandowns/spinner v1.18.1
- github.com/cenkalti/backoff/v4 v4.1.3
- github.com/deckarep/golang-set v1.8.0
- github.com/fatih/color v1.13.0
- github.com/fsnotify/fsevents v0.1.1
- github.com/fsnotify/fsnotify v1.6.0
- github.com/gobwas/glob v0.2.3
- github.com/google/chrometracing v0.0.0-20210413150014-55fded0163e7
- github.com/google/go-cmp v0.5.8
- github.com/google/uuid v1.3.0
- github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
- github.com/hashicorp/go-gatedio v0.5.0
- github.com/hashicorp/go-hclog v1.2.1
- github.com/hashicorp/go-multierror v1.1.1
- github.com/hashicorp/go-retryablehttp v0.6.8
- github.com/iseki0/go-yarnlock v0.0.2-0.20220905015017-a2a90751cdfa
- github.com/karrick/godirwalk v1.16.1
- github.com/mattn/go-isatty v0.0.14
- github.com/mitchellh/cli v1.1.5
- github.com/mitchellh/mapstructure v1.5.0
- github.com/moby/sys/sequential v0.5.0
- github.com/muhammadmuzzammil1998/jsonc v1.0.0
- github.com/nightlyone/lockfile v1.0.0
- github.com/pkg/errors v0.9.1
- github.com/pyr-sh/dag v1.0.0
- github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f
- github.com/schollz/progressbar/v3 v3.9.0
- github.com/segmentio/ksuid v1.0.4
- github.com/spf13/cobra v1.3.0
- github.com/spf13/viper v1.12.0
- github.com/stretchr/testify v1.8.0
- github.com/yookoala/realpath v1.0.0
- golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.5.0
- google.golang.org/grpc v1.46.2
- google.golang.org/protobuf v1.28.0
- gotest.tools/v3 v3.3.0
-)
-
-require (
- github.com/Masterminds/goutils v1.1.1 // indirect
- github.com/Masterminds/semver/v3 v3.1.1 // indirect
- github.com/Masterminds/sprig/v3 v3.2.1 // indirect
- github.com/armon/go-radix v1.0.0 // indirect
- github.com/bgentry/speakeasy v0.1.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
- github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
- github.com/hashicorp/hcl v1.0.0 // indirect
- github.com/huandu/xstrings v1.3.2 // indirect
- github.com/imdario/mergo v0.3.11 // indirect
- github.com/inconshreveable/mousetrap v1.0.0 // indirect
- github.com/magiconair/properties v1.8.6 // indirect
- github.com/mattn/go-colorable v0.1.12 // indirect
- github.com/mattn/go-runewidth v0.0.13 // indirect
- github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
- github.com/mitchellh/copystructure v1.0.0 // indirect
- github.com/mitchellh/reflectwalk v1.0.1 // indirect
- github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
- github.com/pelletier/go-toml v1.9.5 // indirect
- github.com/pelletier/go-toml/v2 v2.0.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/posener/complete v1.2.3 // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
- github.com/shopspring/decimal v1.2.0 // indirect
- github.com/spf13/afero v1.8.2 // indirect
- github.com/spf13/cast v1.5.0 // indirect
- github.com/spf13/jwalterweatherman v1.1.0 // indirect
- github.com/spf13/pflag v1.0.5 // indirect
- github.com/subosito/gotenv v1.3.0 // indirect
- golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
- golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
- golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
- golang.org/x/text v0.3.7 // indirect
- google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
- gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
- gopkg.in/ini.v1 v1.66.4 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/cli/go.sum b/cli/go.sum
deleted file mode 100644
index 9c993f4..0000000
--- a/cli/go.sum
+++ /dev/null
@@ -1,952 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
-cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
-cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
-cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
-cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
-cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
-cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
-cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
-cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
-cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
-cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
-cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
-cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ=
-github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
-github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
-github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
-github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
-github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
-github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.2.1 h1:n6EPaDyLSvCEa3frruQvAiHuNp2dhBlMSmkEr+HuzGc=
-github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
-github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/adrg/xdg v0.3.3 h1:s/tV7MdqQnzB1nKY8aqHvAMD+uCiuEDzVB5HLRY849U=
-github.com/adrg/xdg v0.3.3/go.mod h1:61xAR2VZcggl2St4O9ohF5qCKe08+JDmE4VNzPFQvOQ=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f h1:NNJE6p4LchkmNfNskDUaSbrwxZzr7t2/lj2aS+q4oF0=
-github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/briandowns/spinner v1.18.1 h1:yhQmQtM1zsqFsouh09Bk/jCjd50pC3EOGsh28gLVvwY=
-github.com/briandowns/spinner v1.18.1/go.mod h1:mQak9GHqbspjC/5iUx3qMlIho8xBS/ppAL/hX5SmPJU=
-github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
-github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
-github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
-github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
-github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
-github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
-github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
-github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
-github.com/fsnotify/fsevents v0.1.1 h1:/125uxJvvoSDDBPen6yUZbil8J9ydKZnnl3TWWmvnkw=
-github.com/fsnotify/fsevents v0.1.1/go.mod h1:+d+hS27T6k5J8CRaPLKFgwKYcpS7GwW3Ule9+SC2ZRc=
-github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/chrometracing v0.0.0-20210413150014-55fded0163e7 h1:mc1AFRocuO7EtVJgn4YIg97gBJ9VjiT4+UbCAM2IS/k=
-github.com/google/chrometracing v0.0.0-20210413150014-55fded0163e7/go.mod h1:k2+go54tKjJPxWHxllhAI7WtOaxnnIaB0LjnGEsbyj0=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
-github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
-github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
-github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
-github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
-github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
-github.com/hashicorp/go-gatedio v0.5.0 h1:Jm1X5yP4yCqqWj5L1TgW7iZwCVPGtVc+mro5r/XX7Tg=
-github.com/hashicorp/go-gatedio v0.5.0/go.mod h1:Lr3t8L6IyxD3DAeaUxGcgl2JnRUpWMCsmBl4Omu/2t4=
-github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw=
-github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
-github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
-github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
-github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
-github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
-github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
-github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
-github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
-github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
-github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
-github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
-github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
-github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iseki0/go-yarnlock v0.0.2-0.20220905015017-a2a90751cdfa h1:0sf91Q+lIGU9ikSy16mNfFURM52O1RiB2fQCYEiRPBU=
-github.com/iseki0/go-yarnlock v0.0.2-0.20220905015017-a2a90751cdfa/go.mod h1:wQ9AjysVf4yTrNMlPgNbVY8s/XZcdjpMLNyNwDIj47o=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
-github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
-github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
-github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
-github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
-github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
-github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
-github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
-github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
-github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
-github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
-github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
-github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
-github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=
-github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
-github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
-github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
-github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
-github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
-github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
-github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/muhammadmuzzammil1998/jsonc v1.0.0 h1:8o5gBQn4ZA3NBA9DlTujCj2a4w0tqWrPVjDwhzkgTIs=
-github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA=
-github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
-github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
-github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
-github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
-github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/pyr-sh/dag v1.0.0 h1:hIyuIe8nvHZuwFUjTXoLJP7cN5Xr3IAQukiX2S8NAS0=
-github.com/pyr-sh/dag v1.0.0/go.mod h1:alhhyzDdT3KwVmFc+pF4uhMSfRSTbiAUMcqfrfPSs0Y=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f h1:8P2MkG70G76gnZBOPGwmMIgwBb/rESQuwsJ7K8ds4NE=
-github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
-github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
-github.com/schollz/progressbar/v3 v3.9.0 h1:k9SRNQ8KZyibz1UZOaKxnkUE3iGtmGSDt1YY9KlCYQk=
-github.com/schollz/progressbar/v3 v3.9.0/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
-github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
-github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
-github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
-github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
-github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
-github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
-github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
-github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
-github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
-github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
-github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
-github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI=
-github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/yookoala/realpath v1.0.0 h1:7OA9pj4FZd+oZDsyvXWQvjn5oBdcHRTV44PpdMSuImQ=
-github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
-golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
-golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y=
-golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
-google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
-google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
-google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
-google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
-google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
-google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
-google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
-google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
-google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
-google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
-google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
-google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
-google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
-google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
-google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
-google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
-google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
-google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I=
-google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
-google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
-google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=
-google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
-gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
-gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/cli/internal/analytics/analytics.go b/cli/internal/analytics/analytics.go
deleted file mode 100644
index 8d9a3b6..0000000
--- a/cli/internal/analytics/analytics.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package analytics
-
-import (
- "context"
- "sync"
- "time"
-
- "github.com/google/uuid"
- "github.com/hashicorp/go-hclog"
- "github.com/mitchellh/mapstructure"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-type Events = []map[string]interface{}
-
-type EventPayload = interface{}
-
-type Recorder interface {
- LogEvent(payload EventPayload)
-}
-
-type Client interface {
- Recorder
- Close()
- CloseWithTimeout(timeout time.Duration)
-}
-
-type Sink interface {
- RecordAnalyticsEvents(events Events) error
-}
-
-type nullSink struct{}
-
-func (n *nullSink) RecordAnalyticsEvents(events Events) error {
- return nil
-}
-
-// NullSink is an analytics sink to use in the event that we don't want to send
-// analytics
-var NullSink = &nullSink{}
-
-type client struct {
- ch chan<- EventPayload
- cancel func()
-
- worker *worker
-}
-
-type worker struct {
- buffer []EventPayload
- ch <-chan EventPayload
- ctx context.Context
- doneSemaphore util.Semaphore
- sessionID uuid.UUID
- sink Sink
- wg sync.WaitGroup
- logger hclog.Logger
-}
-
-const bufferThreshold = 10
-const eventTimeout = 200 * time.Millisecond
-const noTimeout = 24 * time.Hour
-
-func newWorker(ctx context.Context, ch <-chan EventPayload, sink Sink, logger hclog.Logger) *worker {
- buffer := []EventPayload{}
- sessionID := uuid.New()
- w := &worker{
- buffer: buffer,
- ch: ch,
- ctx: ctx,
- doneSemaphore: util.NewSemaphore(1),
- sessionID: sessionID,
- sink: sink,
- logger: logger,
- }
- w.doneSemaphore.Acquire()
- go w.analyticsClient()
- return w
-}
-
-func NewClient(parent context.Context, sink Sink, logger hclog.Logger) Client {
- ch := make(chan EventPayload)
- ctx, cancel := context.WithCancel(parent)
- // creates and starts the worker
- worker := newWorker(ctx, ch, sink, logger)
- s := &client{
- ch: ch,
- cancel: cancel,
- worker: worker,
- }
- return s
-}
-
-func (s *client) LogEvent(event EventPayload) {
- s.ch <- event
-}
-
-func (s *client) Close() {
- s.cancel()
- s.worker.Wait()
-}
-
-func (s *client) CloseWithTimeout(timeout time.Duration) {
- ch := make(chan struct{})
- go func() {
- s.Close()
- close(ch)
- }()
- select {
- case <-ch:
- case <-time.After(timeout):
- }
-}
-
-func (w *worker) Wait() {
- w.doneSemaphore.Acquire()
- w.wg.Wait()
-}
-
-func (w *worker) analyticsClient() {
- timeout := time.After(noTimeout)
- for {
- select {
- case e := <-w.ch:
- w.buffer = append(w.buffer, e)
- if len(w.buffer) == bufferThreshold {
- w.flush()
- timeout = time.After(noTimeout)
- } else {
- timeout = time.After(eventTimeout)
- }
- case <-timeout:
- w.flush()
- timeout = time.After(noTimeout)
- case <-w.ctx.Done():
- w.flush()
- w.doneSemaphore.Release()
- return
- }
- }
-}
-
-func (w *worker) flush() {
- if len(w.buffer) > 0 {
- w.sendEvents(w.buffer)
- w.buffer = []EventPayload{}
- }
-}
-
-func (w *worker) sendEvents(events []EventPayload) {
- w.wg.Add(1)
- go func() {
- payload, err := addSessionID(w.sessionID.String(), events)
- if err != nil {
- w.logger.Debug("failed to encode cache usage analytics", "error", err)
- }
- err = w.sink.RecordAnalyticsEvents(payload)
- if err != nil {
- w.logger.Debug("failed to record cache usage analytics", "error", err)
- }
- w.wg.Done()
- }()
-}
-
-func addSessionID(sessionID string, events []EventPayload) (Events, error) {
- eventMaps := []map[string]interface{}{}
- err := mapstructure.Decode(events, &eventMaps)
- if err != nil {
- return nil, err
- }
- for _, event := range eventMaps {
- event["sessionId"] = sessionID
- }
- return eventMaps, nil
-}
diff --git a/cli/internal/analytics/analytics_test.go b/cli/internal/analytics/analytics_test.go
deleted file mode 100644
index 0715fda..0000000
--- a/cli/internal/analytics/analytics_test.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package analytics
-
-import (
- "context"
- "sync"
- "testing"
- "time"
-
- "github.com/hashicorp/go-hclog"
-)
-
-type dummySink struct {
- events []*Events
- err error
- mu sync.Mutex
- ch chan struct{}
-}
-
-type evt struct {
- I int
-}
-
-func newDummySink() *dummySink {
- return &dummySink{
- events: []*Events{},
- ch: make(chan struct{}, 1),
- }
-}
-
-func (d *dummySink) RecordAnalyticsEvents(events Events) error {
- d.mu.Lock()
- defer d.mu.Unlock()
- // Make a copy in case a test is holding a copy too
- eventsCopy := make([]*Events, len(d.events))
- copy(eventsCopy, d.events)
- d.events = append(eventsCopy, &events)
- d.ch <- struct{}{}
- return d.err
-}
-
-func (d *dummySink) Events() []*Events {
- d.mu.Lock()
- defer d.mu.Unlock()
- return d.events
-}
-
-func (d *dummySink) ExpectImmediateMessage(t *testing.T) {
- select {
- case <-time.After(150 * time.Millisecond):
- t.Errorf("expected to not wait out the flush timeout")
- case <-d.ch:
- }
-}
-
-func (d *dummySink) ExpectTimeoutThenMessage(t *testing.T) {
- select {
- case <-d.ch:
- t.Errorf("Expected to wait out the flush timeout")
- case <-time.After(150 * time.Millisecond):
- }
- <-d.ch
-}
-
-func Test_batching(t *testing.T) {
- d := newDummySink()
- ctx := context.Background()
- c := NewClient(ctx, d, hclog.Default())
- for i := 0; i < 2; i++ {
- c.LogEvent(&evt{i})
- }
- found := d.Events()
- if len(found) != 0 {
- t.Errorf("got %v events, want 0 due to batching", len(found))
- }
- // Should timeout
- d.ExpectTimeoutThenMessage(t)
- found = d.Events()
- if len(found) != 1 {
- t.Errorf("got %v, want 1 batch to have been flushed", len(found))
- }
- payloads := *found[0]
- if len(payloads) != 2 {
- t.Errorf("got %v, want 2 payloads to have been flushed", len(payloads))
- }
-}
-
-func Test_batchingAcrossTwoBatches(t *testing.T) {
- d := newDummySink()
- ctx := context.Background()
- c := NewClient(ctx, d, hclog.Default())
- for i := 0; i < 12; i++ {
- c.LogEvent(&evt{i})
- }
- // We sent more than the batch size, expect a message immediately
- d.ExpectImmediateMessage(t)
- found := d.Events()
- if len(found) != 1 {
- t.Errorf("got %v, want 1 batch to have been flushed", len(found))
- }
- payloads := *found[0]
- if len(payloads) != 10 {
- t.Errorf("got %v, want 10 payloads to have been flushed", len(payloads))
- }
- // Should timeout second batch
- d.ExpectTimeoutThenMessage(t)
- found = d.Events()
- if len(found) != 2 {
- t.Errorf("got %v, want 2 batches to have been flushed", len(found))
- }
- payloads = *found[1]
- if len(payloads) != 2 {
- t.Errorf("got %v, want 2 payloads to have been flushed", len(payloads))
- }
-}
-
-func Test_closing(t *testing.T) {
- d := newDummySink()
- ctx := context.Background()
- c := NewClient(ctx, d, hclog.Default())
- for i := 0; i < 2; i++ {
- c.LogEvent(&evt{i})
- }
- found := d.Events()
- if len(found) != 0 {
- t.Errorf("got %v events, want 0 due to batching", len(found))
- }
- c.Close()
- found = d.Events()
- if len(found) != 1 {
- t.Errorf("got %v, want 1 batch to have been flushed", len(found))
- }
- payloads := *found[0]
- if len(payloads) != 2 {
- t.Errorf("got %v, want 2 payloads to have been flushed", len(payloads))
- }
-}
-
-func Test_closingByContext(t *testing.T) {
- d := newDummySink()
- ctx, cancel := context.WithCancel(context.Background())
- c := NewClient(ctx, d, hclog.Default())
- for i := 0; i < 2; i++ {
- c.LogEvent(&evt{i})
- }
- found := d.Events()
- if len(found) != 0 {
- t.Errorf("got %v events, want 0 due to batching", len(found))
- }
- cancel()
- d.ExpectImmediateMessage(t)
- found = d.Events()
- if len(found) != 1 {
- t.Errorf("got %v, want 1 batch to have been flushed", len(found))
- }
- payloads := *found[0]
- if len(payloads) != 2 {
- t.Errorf("got %v, want 2 payloads to have been flushed", len(payloads))
- }
-}
-
-func Test_addSessionId(t *testing.T) {
- events := []struct {
- Foo string `mapstructure:"foo"`
- }{
- {
- Foo: "foo1",
- },
- {
- Foo: "foo2",
- },
- }
- arr := make([]interface{}, len(events))
- for i, event := range events {
- arr[i] = event
- }
- sessionID := "my-uuid"
- output, err := addSessionID(sessionID, arr)
- if err != nil {
- t.Errorf("failed to encode analytics events: %v", err)
- }
- if len(output) != 2 {
- t.Errorf("len output got %v, want 2", len(output))
- }
- if output[0]["foo"] != "foo1" {
- t.Errorf("first event foo got %v, want foo1", output[0]["foo"])
- }
- for i, event := range output {
- if event["sessionId"] != "my-uuid" {
- t.Errorf("event %v sessionId got %v, want %v", i, event["sessionId"], sessionID)
- }
- }
-}
diff --git a/cli/internal/cache/async_cache.go b/cli/internal/cache/async_cache.go
deleted file mode 100644
index 0a8f467..0000000
--- a/cli/internal/cache/async_cache.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Adapted from https://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package cache
-
-import (
- "sync"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// An asyncCache is a wrapper around a Cache interface that handles incoming
-// store requests asynchronously and attempts to return immediately.
-// The requests are handled on an internal queue, if that fills up then
-// incoming requests will start to block again until it empties.
-// Retrieval requests are still handled synchronously.
-type asyncCache struct {
- requests chan cacheRequest
- realCache Cache
- wg sync.WaitGroup
-}
-
-// A cacheRequest models an incoming cache request on our queue.
-type cacheRequest struct {
- anchor turbopath.AbsoluteSystemPath
- key string
- duration int
- files []turbopath.AnchoredSystemPath
-}
-
-func newAsyncCache(realCache Cache, opts Opts) Cache {
- c := &asyncCache{
- requests: make(chan cacheRequest),
- realCache: realCache,
- }
- c.wg.Add(opts.Workers)
- for i := 0; i < opts.Workers; i++ {
- go c.run()
- }
- return c
-}
-
-func (c *asyncCache) Put(anchor turbopath.AbsoluteSystemPath, key string, duration int, files []turbopath.AnchoredSystemPath) error {
- c.requests <- cacheRequest{
- anchor: anchor,
- key: key,
- files: files,
- duration: duration,
- }
- return nil
-}
-
-func (c *asyncCache) Fetch(anchor turbopath.AbsoluteSystemPath, key string, files []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error) {
- return c.realCache.Fetch(anchor, key, files)
-}
-
-func (c *asyncCache) Exists(key string) ItemStatus {
- return c.realCache.Exists(key)
-}
-
-func (c *asyncCache) Clean(anchor turbopath.AbsoluteSystemPath) {
- c.realCache.Clean(anchor)
-}
-
-func (c *asyncCache) CleanAll() {
- c.realCache.CleanAll()
-}
-
-func (c *asyncCache) Shutdown() {
- // fmt.Println("Shutting down cache workers...")
- close(c.requests)
- c.wg.Wait()
- // fmt.Println("Shut down all cache workers")
-}
-
-// run implements the actual async logic.
-func (c *asyncCache) run() {
- for r := range c.requests {
- _ = c.realCache.Put(r.anchor, r.key, r.duration, r.files)
- }
- c.wg.Done()
-}
diff --git a/cli/internal/cache/cache.go b/cli/internal/cache/cache.go
deleted file mode 100644
index 8b74272..0000000
--- a/cli/internal/cache/cache.go
+++ /dev/null
@@ -1,317 +0,0 @@
-// Package cache abstracts storing and fetching previously run tasks
-//
-// Adapted from https://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package cache
-
-import (
- "errors"
- "sync"
-
- "github.com/vercel/turbo/cli/internal/analytics"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "golang.org/x/sync/errgroup"
-)
-
-// Cache is abstracted way to cache/fetch previously run tasks
-type Cache interface {
- // Fetch returns true if there is a cache it. It is expected to move files
- // into their correct position as a side effect
- Fetch(anchor turbopath.AbsoluteSystemPath, hash string, files []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error)
- Exists(hash string) ItemStatus
- // Put caches files for a given hash
- Put(anchor turbopath.AbsoluteSystemPath, hash string, duration int, files []turbopath.AnchoredSystemPath) error
- Clean(anchor turbopath.AbsoluteSystemPath)
- CleanAll()
- Shutdown()
-}
-
-// ItemStatus holds whether artifacts exists for a given hash on local
-// and/or remote caching server
-type ItemStatus struct {
- Local bool `json:"local"`
- Remote bool `json:"remote"`
-}
-
-const (
- // CacheSourceFS is a constant to indicate local cache hit
- CacheSourceFS = "LOCAL"
- // CacheSourceRemote is a constant to indicate remote cache hit
- CacheSourceRemote = "REMOTE"
- // CacheEventHit is a constant to indicate a cache hit
- CacheEventHit = "HIT"
- // CacheEventMiss is a constant to indicate a cache miss
- CacheEventMiss = "MISS"
-)
-
-type CacheEvent struct {
- Source string `mapstructure:"source"`
- Event string `mapstructure:"event"`
- Hash string `mapstructure:"hash"`
- Duration int `mapstructure:"duration"`
-}
-
-// DefaultLocation returns the default filesystem cache location, given a repo root
-func DefaultLocation(repoRoot turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- return repoRoot.UntypedJoin("node_modules", ".cache", "turbo")
-}
-
-// OnCacheRemoved defines a callback that the cache system calls if a particular cache
-// needs to be removed. In practice, this happens when Remote Caching has been disabled
-// the but CLI continues to try to use it.
-type OnCacheRemoved = func(cache Cache, err error)
-
-// ErrNoCachesEnabled is returned when both the filesystem and http cache are unavailable
-var ErrNoCachesEnabled = errors.New("no caches are enabled")
-
-// Opts holds configuration options for the cache
-// TODO(gsoltis): further refactor this into fs cache opts and http cache opts
-type Opts struct {
- OverrideDir string
- SkipRemote bool
- SkipFilesystem bool
- Workers int
- RemoteCacheOpts fs.RemoteCacheOptions
-}
-
-// resolveCacheDir calculates the location turbo should use to cache artifacts,
-// based on the options supplied by the user.
-func (o *Opts) resolveCacheDir(repoRoot turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- if o.OverrideDir != "" {
- return fs.ResolveUnknownPath(repoRoot, o.OverrideDir)
- }
- return DefaultLocation(repoRoot)
-}
-
-var _remoteOnlyHelp = `Ignore the local filesystem cache for all tasks. Only
-allow reading and caching artifacts using the remote cache.`
-
-// New creates a new cache
-func New(opts Opts, repoRoot turbopath.AbsoluteSystemPath, client client, recorder analytics.Recorder, onCacheRemoved OnCacheRemoved) (Cache, error) {
- c, err := newSyncCache(opts, repoRoot, client, recorder, onCacheRemoved)
- if err != nil && !errors.Is(err, ErrNoCachesEnabled) {
- return nil, err
- }
- if opts.Workers > 0 {
- return newAsyncCache(c, opts), err
- }
- return c, err
-}
-
-// newSyncCache can return an error with a usable noopCache.
-func newSyncCache(opts Opts, repoRoot turbopath.AbsoluteSystemPath, client client, recorder analytics.Recorder, onCacheRemoved OnCacheRemoved) (Cache, error) {
- // Check to see if the user has turned off particular cache implementations.
- useFsCache := !opts.SkipFilesystem
- useHTTPCache := !opts.SkipRemote
-
- // Since the above two flags are not mutually exclusive it is possible to configure
- // yourself out of having a cache. We should tell you about it but we shouldn't fail
- // your build for that reason.
- //
- // Further, since the httpCache can be removed at runtime, we need to insert a noopCache
- // as a backup if you are configured to have *just* an httpCache.
- //
- // This is reduced from (!useFsCache && !useHTTPCache) || (!useFsCache & useHTTPCache)
- useNoopCache := !useFsCache
-
- // Build up an array of cache implementations, we can only ever have 1 or 2.
- cacheImplementations := make([]Cache, 0, 2)
-
- if useFsCache {
- implementation, err := newFsCache(opts, recorder, repoRoot)
- if err != nil {
- return nil, err
- }
- cacheImplementations = append(cacheImplementations, implementation)
- }
-
- if useHTTPCache {
- implementation := newHTTPCache(opts, client, recorder)
- cacheImplementations = append(cacheImplementations, implementation)
- }
-
- if useNoopCache {
- implementation := newNoopCache()
- cacheImplementations = append(cacheImplementations, implementation)
- }
-
- // Precisely two cache implementations:
- // fsCache and httpCache OR httpCache and noopCache
- useMultiplexer := len(cacheImplementations) > 1
- if useMultiplexer {
- // We have early-returned any possible errors for this scenario.
- return &cacheMultiplexer{
- onCacheRemoved: onCacheRemoved,
- opts: opts,
- caches: cacheImplementations,
- }, nil
- }
-
- // Precisely one cache implementation: fsCache OR noopCache
- implementation := cacheImplementations[0]
- _, isNoopCache := implementation.(*noopCache)
-
- // We want to let the user know something is wonky, but we don't want
- // to trigger their build to fail.
- if isNoopCache {
- return implementation, ErrNoCachesEnabled
- }
- return implementation, nil
-}
-
-// A cacheMultiplexer multiplexes several caches into one.
-// Used when we have several active (eg. http, dir).
-type cacheMultiplexer struct {
- caches []Cache
- opts Opts
- mu sync.RWMutex
- onCacheRemoved OnCacheRemoved
-}
-
-func (mplex *cacheMultiplexer) Put(anchor turbopath.AbsoluteSystemPath, key string, duration int, files []turbopath.AnchoredSystemPath) error {
- return mplex.storeUntil(anchor, key, duration, files, len(mplex.caches))
-}
-
-type cacheRemoval struct {
- cache Cache
- err *util.CacheDisabledError
-}
-
-// storeUntil stores artifacts into higher priority caches than the given one.
-// Used after artifact retrieval to ensure we have them in eg. the directory cache after
-// downloading from the RPC cache.
-func (mplex *cacheMultiplexer) storeUntil(anchor turbopath.AbsoluteSystemPath, key string, duration int, files []turbopath.AnchoredSystemPath, stopAt int) error {
- // Attempt to store on all caches simultaneously.
- toRemove := make([]*cacheRemoval, stopAt)
- g := &errgroup.Group{}
- mplex.mu.RLock()
- for i, cache := range mplex.caches {
- if i == stopAt {
- break
- }
- c := cache
- i := i
- g.Go(func() error {
- err := c.Put(anchor, key, duration, files)
- if err != nil {
- cd := &util.CacheDisabledError{}
- if errors.As(err, &cd) {
- toRemove[i] = &cacheRemoval{
- cache: c,
- err: cd,
- }
- // we don't want this to cancel other cache actions
- return nil
- }
- return err
- }
- return nil
- })
- }
- mplex.mu.RUnlock()
-
- if err := g.Wait(); err != nil {
- return err
- }
-
- for _, removal := range toRemove {
- if removal != nil {
- mplex.removeCache(removal)
- }
- }
- return nil
-}
-
-// removeCache takes a requested removal and tries to actually remove it. However,
-// multiple requests could result in concurrent requests to remove the same cache.
-// Let one of them win and propagate the error, the rest will no-op.
-func (mplex *cacheMultiplexer) removeCache(removal *cacheRemoval) {
- mplex.mu.Lock()
- defer mplex.mu.Unlock()
- for i, cache := range mplex.caches {
- if cache == removal.cache {
- mplex.caches = append(mplex.caches[:i], mplex.caches[i+1:]...)
- mplex.onCacheRemoved(cache, removal.err)
- break
- }
- }
-}
-
-func (mplex *cacheMultiplexer) Fetch(anchor turbopath.AbsoluteSystemPath, key string, files []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error) {
- // Make a shallow copy of the caches, since storeUntil can call removeCache
- mplex.mu.RLock()
- caches := make([]Cache, len(mplex.caches))
- copy(caches, mplex.caches)
- mplex.mu.RUnlock()
-
- // We need to return a composite cache status from multiple caches
- // Initialize the empty struct so we can assign values to it. This is similar
- // to how the Exists() method works.
- combinedCacheState := ItemStatus{}
-
- // Retrieve from caches sequentially; if we did them simultaneously we could
- // easily write the same file from two goroutines at once.
- for i, cache := range caches {
- itemStatus, actualFiles, duration, err := cache.Fetch(anchor, key, files)
- ok := itemStatus.Local || itemStatus.Remote
-
- if err != nil {
- cd := &util.CacheDisabledError{}
- if errors.As(err, &cd) {
- mplex.removeCache(&cacheRemoval{
- cache: cache,
- err: cd,
- })
- }
- // We're ignoring the error in the else case, since with this cache
- // abstraction, we want to check lower priority caches rather than fail
- // the operation. Future work that plumbs UI / Logging into the cache system
- // should probably log this at least.
- }
- if ok {
- // Store this into other caches. We can ignore errors here because we know
- // we have previously successfully stored in a higher-priority cache, and so the overall
- // result is a success at fetching. Storing in lower-priority caches is an optimization.
- _ = mplex.storeUntil(anchor, key, duration, actualFiles, i)
-
- // If another cache had already set this to true, we don't need to set it again from this cache
- combinedCacheState.Local = combinedCacheState.Local || itemStatus.Local
- combinedCacheState.Remote = combinedCacheState.Remote || itemStatus.Remote
- return combinedCacheState, actualFiles, duration, err
- }
- }
-
- return ItemStatus{Local: false, Remote: false}, nil, 0, nil
-}
-
-func (mplex *cacheMultiplexer) Exists(target string) ItemStatus {
- syncCacheState := ItemStatus{}
- for _, cache := range mplex.caches {
- itemStatus := cache.Exists(target)
- syncCacheState.Local = syncCacheState.Local || itemStatus.Local
- syncCacheState.Remote = syncCacheState.Remote || itemStatus.Remote
- }
-
- return syncCacheState
-}
-
-func (mplex *cacheMultiplexer) Clean(anchor turbopath.AbsoluteSystemPath) {
- for _, cache := range mplex.caches {
- cache.Clean(anchor)
- }
-}
-
-func (mplex *cacheMultiplexer) CleanAll() {
- for _, cache := range mplex.caches {
- cache.CleanAll()
- }
-}
-
-func (mplex *cacheMultiplexer) Shutdown() {
- for _, cache := range mplex.caches {
- cache.Shutdown()
- }
-}
diff --git a/cli/internal/cache/cache_fs.go b/cli/internal/cache/cache_fs.go
deleted file mode 100644
index fb15a02..0000000
--- a/cli/internal/cache/cache_fs.go
+++ /dev/null
@@ -1,174 +0,0 @@
-// Adapted from https://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-// Package cache implements our cache abstraction.
-package cache
-
-import (
- "encoding/json"
- "fmt"
-
- "github.com/vercel/turbo/cli/internal/analytics"
- "github.com/vercel/turbo/cli/internal/cacheitem"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// fsCache is a local filesystem cache
-type fsCache struct {
- cacheDirectory turbopath.AbsoluteSystemPath
- recorder analytics.Recorder
-}
-
-// newFsCache creates a new filesystem cache
-func newFsCache(opts Opts, recorder analytics.Recorder, repoRoot turbopath.AbsoluteSystemPath) (*fsCache, error) {
- cacheDir := opts.resolveCacheDir(repoRoot)
- if err := cacheDir.MkdirAll(0775); err != nil {
- return nil, err
- }
- return &fsCache{
- cacheDirectory: cacheDir,
- recorder: recorder,
- }, nil
-}
-
-// Fetch returns true if items are cached. It moves them into position as a side effect.
-func (f *fsCache) Fetch(anchor turbopath.AbsoluteSystemPath, hash string, _ []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error) {
- uncompressedCachePath := f.cacheDirectory.UntypedJoin(hash + ".tar")
- compressedCachePath := f.cacheDirectory.UntypedJoin(hash + ".tar.zst")
-
- var actualCachePath turbopath.AbsoluteSystemPath
- if uncompressedCachePath.FileExists() {
- actualCachePath = uncompressedCachePath
- } else if compressedCachePath.FileExists() {
- actualCachePath = compressedCachePath
- } else {
- // It's not in the cache, bail now
- f.logFetch(false, hash, 0)
- return ItemStatus{Local: false}, nil, 0, nil
- }
-
- cacheItem, openErr := cacheitem.Open(actualCachePath)
- if openErr != nil {
- return ItemStatus{Local: false}, nil, 0, openErr
- }
-
- restoredFiles, restoreErr := cacheItem.Restore(anchor)
- if restoreErr != nil {
- _ = cacheItem.Close()
- return ItemStatus{Local: false}, nil, 0, restoreErr
- }
-
- meta, err := ReadCacheMetaFile(f.cacheDirectory.UntypedJoin(hash + "-meta.json"))
- if err != nil {
- _ = cacheItem.Close()
- return ItemStatus{Local: false}, nil, 0, fmt.Errorf("error reading cache metadata: %w", err)
- }
- f.logFetch(true, hash, meta.Duration)
-
- // Wait to see what happens with close.
- closeErr := cacheItem.Close()
- if closeErr != nil {
- return ItemStatus{Local: false}, restoredFiles, 0, closeErr
- }
- return ItemStatus{Local: true}, restoredFiles, meta.Duration, nil
-}
-
-func (f *fsCache) Exists(hash string) ItemStatus {
- uncompressedCachePath := f.cacheDirectory.UntypedJoin(hash + ".tar")
- compressedCachePath := f.cacheDirectory.UntypedJoin(hash + ".tar.zst")
-
- if compressedCachePath.FileExists() || uncompressedCachePath.FileExists() {
- return ItemStatus{Local: true}
- }
-
- return ItemStatus{Local: false}
-}
-
-func (f *fsCache) logFetch(hit bool, hash string, duration int) {
- var event string
- if hit {
- event = CacheEventHit
- } else {
- event = CacheEventMiss
- }
- payload := &CacheEvent{
- Source: CacheSourceFS,
- Event: event,
- Hash: hash,
- Duration: duration,
- }
- f.recorder.LogEvent(payload)
-}
-
-func (f *fsCache) Put(anchor turbopath.AbsoluteSystemPath, hash string, duration int, files []turbopath.AnchoredSystemPath) error {
- cachePath := f.cacheDirectory.UntypedJoin(hash + ".tar.zst")
- cacheItem, err := cacheitem.Create(cachePath)
- if err != nil {
- return err
- }
-
- for _, file := range files {
- err := cacheItem.AddFile(anchor, file)
- if err != nil {
- _ = cacheItem.Close()
- return err
- }
- }
-
- writeErr := WriteCacheMetaFile(f.cacheDirectory.UntypedJoin(hash+"-meta.json"), &CacheMetadata{
- Duration: duration,
- Hash: hash,
- })
-
- if writeErr != nil {
- _ = cacheItem.Close()
- return writeErr
- }
-
- return cacheItem.Close()
-}
-
-func (f *fsCache) Clean(_ turbopath.AbsoluteSystemPath) {
- fmt.Println("Not implemented yet")
-}
-
-func (f *fsCache) CleanAll() {
- fmt.Println("Not implemented yet")
-}
-
-func (f *fsCache) Shutdown() {}
-
-// CacheMetadata stores duration and hash information for a cache entry so that aggregate Time Saved calculations
-// can be made from artifacts from various caches
-type CacheMetadata struct {
- Hash string `json:"hash"`
- Duration int `json:"duration"`
-}
-
-// WriteCacheMetaFile writes cache metadata file at a path
-func WriteCacheMetaFile(path turbopath.AbsoluteSystemPath, config *CacheMetadata) error {
- jsonBytes, marshalErr := json.Marshal(config)
- if marshalErr != nil {
- return marshalErr
- }
- writeFilErr := path.WriteFile(jsonBytes, 0644)
- if writeFilErr != nil {
- return writeFilErr
- }
- return nil
-}
-
-// ReadCacheMetaFile reads cache metadata file at a path
-func ReadCacheMetaFile(path turbopath.AbsoluteSystemPath) (*CacheMetadata, error) {
- jsonBytes, readFileErr := path.ReadFile()
- if readFileErr != nil {
- return nil, readFileErr
- }
- var config CacheMetadata
- marshalErr := json.Unmarshal(jsonBytes, &config)
- if marshalErr != nil {
- return nil, marshalErr
- }
- return &config, nil
-}
diff --git a/cli/internal/cache/cache_fs_test.go b/cli/internal/cache/cache_fs_test.go
deleted file mode 100644
index 614ad86..0000000
--- a/cli/internal/cache/cache_fs_test.go
+++ /dev/null
@@ -1,253 +0,0 @@
-package cache
-
-import (
- "path/filepath"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/analytics"
- "github.com/vercel/turbo/cli/internal/cacheitem"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-type dummyRecorder struct{}
-
-func (dr *dummyRecorder) LogEvent(payload analytics.EventPayload) {}
-
-func TestPut(t *testing.T) {
- // Set up a test source and cache directory
- // The "source" directory simulates a package
- //
- // <src>/
- // b
- // child/
- // a
- // link -> ../b
- // broken -> missing
- //
- // Ensure we end up with a matching directory under a
- // "cache" directory:
- //
- // <dst>/the-hash/<src>/...
-
- src := turbopath.AbsoluteSystemPath(t.TempDir())
- childDir := src.UntypedJoin("child")
- err := childDir.MkdirAll(0775)
- assert.NilError(t, err, "Mkdir")
- aPath := childDir.UntypedJoin("a")
- aFile, err := aPath.Create()
- assert.NilError(t, err, "Create")
- _, err = aFile.WriteString("hello")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, aFile.Close(), "Close")
-
- bPath := src.UntypedJoin("b")
- bFile, err := bPath.Create()
- assert.NilError(t, err, "Create")
- _, err = bFile.WriteString("bFile")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, bFile.Close(), "Close")
-
- srcLinkPath := childDir.UntypedJoin("link")
- linkTarget := filepath.FromSlash("../b")
- assert.NilError(t, srcLinkPath.Symlink(linkTarget), "Symlink")
-
- srcBrokenLinkPath := childDir.Join("broken")
- assert.NilError(t, srcBrokenLinkPath.Symlink("missing"), "Symlink")
- circlePath := childDir.Join("circle")
- assert.NilError(t, circlePath.Symlink(filepath.FromSlash("../child")), "Symlink")
-
- files := []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("child/").ToSystemPath(), // childDir
- turbopath.AnchoredUnixPath("child/a").ToSystemPath(), // aPath,
- turbopath.AnchoredUnixPath("b").ToSystemPath(), // bPath,
- turbopath.AnchoredUnixPath("child/link").ToSystemPath(), // srcLinkPath,
- turbopath.AnchoredUnixPath("child/broken").ToSystemPath(), // srcBrokenLinkPath,
- turbopath.AnchoredUnixPath("child/circle").ToSystemPath(), // circlePath
- }
-
- dst := turbopath.AbsoluteSystemPath(t.TempDir())
- dr := &dummyRecorder{}
-
- cache := &fsCache{
- cacheDirectory: dst,
- recorder: dr,
- }
-
- hash := "the-hash"
- duration := 0
- putErr := cache.Put(src, hash, duration, files)
- assert.NilError(t, putErr, "Put")
-
- // Verify that we got the files that we're expecting
- dstCachePath := dst.UntypedJoin(hash)
-
- // This test checks outputs, so we go ahead and pull things back out.
- // Attempting to satisfy our beliefs that the change is viable with
- // as few changes to the tests as possible.
- cacheItem, openErr := cacheitem.Open(dst.UntypedJoin(hash + ".tar.zst"))
- assert.NilError(t, openErr, "Open")
-
- _, restoreErr := cacheItem.Restore(dstCachePath)
- assert.NilError(t, restoreErr, "Restore")
-
- dstAPath := dstCachePath.UntypedJoin("child", "a")
- assertFileMatches(t, aPath, dstAPath)
-
- dstBPath := dstCachePath.UntypedJoin("b")
- assertFileMatches(t, bPath, dstBPath)
-
- dstLinkPath := dstCachePath.UntypedJoin("child", "link")
- target, err := dstLinkPath.Readlink()
- assert.NilError(t, err, "Readlink")
- if target != linkTarget {
- t.Errorf("Readlink got %v, want %v", target, linkTarget)
- }
-
- dstBrokenLinkPath := dstCachePath.UntypedJoin("child", "broken")
- target, err = dstBrokenLinkPath.Readlink()
- assert.NilError(t, err, "Readlink")
- if target != "missing" {
- t.Errorf("Readlink got %v, want missing", target)
- }
-
- dstCirclePath := dstCachePath.UntypedJoin("child", "circle")
- circleLinkDest, err := dstCirclePath.Readlink()
- assert.NilError(t, err, "Readlink")
- expectedCircleLinkDest := filepath.FromSlash("../child")
- if circleLinkDest != expectedCircleLinkDest {
- t.Errorf("Cache link got %v, want %v", circleLinkDest, expectedCircleLinkDest)
- }
-
- assert.NilError(t, cacheItem.Close(), "Close")
-}
-
-func assertFileMatches(t *testing.T, orig turbopath.AbsoluteSystemPath, copy turbopath.AbsoluteSystemPath) {
- t.Helper()
- origBytes, err := orig.ReadFile()
- assert.NilError(t, err, "ReadFile")
- copyBytes, err := copy.ReadFile()
- assert.NilError(t, err, "ReadFile")
- assert.DeepEqual(t, origBytes, copyBytes)
- origStat, err := orig.Lstat()
- assert.NilError(t, err, "Lstat")
- copyStat, err := copy.Lstat()
- assert.NilError(t, err, "Lstat")
- assert.Equal(t, origStat.Mode(), copyStat.Mode())
-}
-
-func TestFetch(t *testing.T) {
- // Set up a test cache directory and target output directory
- // The "cacheDir" directory simulates a cached package
- //
- // <cacheDir>/
- // the-hash-meta.json
- // the-hash/
- // some-package/
- // b
- // child/
- // a
- // link -> ../b
- // broken -> missing
- // circle -> ../child
- //
- // Ensure we end up with a matching directory under a
- // "some-package" directory:
- //
- // "some-package"/...
-
- cacheDir := turbopath.AbsoluteSystemPath(t.TempDir())
- hash := "the-hash"
- src := cacheDir.UntypedJoin(hash, "some-package")
- err := src.MkdirAll(0775)
- assert.NilError(t, err, "mkdirAll")
-
- childDir := src.UntypedJoin("child")
- err = childDir.MkdirAll(0775)
- assert.NilError(t, err, "Mkdir")
- aPath := childDir.UntypedJoin("a")
- aFile, err := aPath.Create()
- assert.NilError(t, err, "Create")
- _, err = aFile.WriteString("hello")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, aFile.Close(), "Close")
-
- bPath := src.UntypedJoin("b")
- bFile, err := bPath.Create()
- assert.NilError(t, err, "Create")
- _, err = bFile.WriteString("bFile")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, bFile.Close(), "Close")
-
- srcLinkPath := childDir.UntypedJoin("link")
- linkTarget := filepath.FromSlash("../b")
- assert.NilError(t, srcLinkPath.Symlink(linkTarget), "Symlink")
-
- srcBrokenLinkPath := childDir.UntypedJoin("broken")
- srcBrokenLinkTarget := turbopath.AnchoredUnixPath("missing").ToSystemPath()
- assert.NilError(t, srcBrokenLinkPath.Symlink(srcBrokenLinkTarget.ToString()), "Symlink")
-
- circlePath := childDir.Join("circle")
- srcCircleLinkTarget := turbopath.AnchoredUnixPath("../child").ToSystemPath()
- assert.NilError(t, circlePath.Symlink(srcCircleLinkTarget.ToString()), "Symlink")
-
- metadataPath := cacheDir.UntypedJoin("the-hash-meta.json")
- err = metadataPath.WriteFile([]byte(`{"hash":"the-hash","duration":0}`), 0777)
- assert.NilError(t, err, "WriteFile")
-
- dr := &dummyRecorder{}
-
- cache := &fsCache{
- cacheDirectory: cacheDir,
- recorder: dr,
- }
-
- inputFiles := []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("some-package/child/").ToSystemPath(), // childDir
- turbopath.AnchoredUnixPath("some-package/child/a").ToSystemPath(), // aPath,
- turbopath.AnchoredUnixPath("some-package/b").ToSystemPath(), // bPath,
- turbopath.AnchoredUnixPath("some-package/child/link").ToSystemPath(), // srcLinkPath,
- turbopath.AnchoredUnixPath("some-package/child/broken").ToSystemPath(), // srcBrokenLinkPath,
- turbopath.AnchoredUnixPath("some-package/child/circle").ToSystemPath(), // circlePath
- }
-
- putErr := cache.Put(cacheDir.UntypedJoin(hash), hash, 0, inputFiles)
- assert.NilError(t, putErr, "Put")
-
- outputDir := turbopath.AbsoluteSystemPath(t.TempDir())
- dstOutputPath := "some-package"
- cacheStatus, files, _, err := cache.Fetch(outputDir, "the-hash", []string{})
- assert.NilError(t, err, "Fetch")
- hit := cacheStatus.Local || cacheStatus.Remote
- if !hit {
- t.Error("Fetch got false, want true")
- }
- if len(files) != len(inputFiles) {
- t.Errorf("len(files) got %v, want %v", len(files), len(inputFiles))
- }
-
- dstAPath := outputDir.UntypedJoin(dstOutputPath, "child", "a")
- assertFileMatches(t, aPath, dstAPath)
-
- dstBPath := outputDir.UntypedJoin(dstOutputPath, "b")
- assertFileMatches(t, bPath, dstBPath)
-
- dstLinkPath := outputDir.UntypedJoin(dstOutputPath, "child", "link")
- target, err := dstLinkPath.Readlink()
- assert.NilError(t, err, "Readlink")
- if target != linkTarget {
- t.Errorf("Readlink got %v, want %v", target, linkTarget)
- }
-
- // Assert that we restore broken symlinks correctly
- dstBrokenLinkPath := outputDir.UntypedJoin(dstOutputPath, "child", "broken")
- target, readlinkErr := dstBrokenLinkPath.Readlink()
- assert.NilError(t, readlinkErr, "Readlink")
- assert.Equal(t, target, srcBrokenLinkTarget.ToString())
-
- // Assert that we restore symlinks to directories correctly
- dstCirclePath := outputDir.UntypedJoin(dstOutputPath, "child", "circle")
- circleTarget, circleReadlinkErr := dstCirclePath.Readlink()
- assert.NilError(t, circleReadlinkErr, "Circle Readlink")
- assert.Equal(t, circleTarget, srcCircleLinkTarget.ToString())
-}
diff --git a/cli/internal/cache/cache_http.go b/cli/internal/cache/cache_http.go
deleted file mode 100644
index 1d345bf..0000000
--- a/cli/internal/cache/cache_http.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// Adapted from https://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package cache
-
-import (
- "archive/tar"
- "bytes"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- log "log"
- "net/http"
- "os"
- "path/filepath"
- "strconv"
- "time"
-
- "github.com/DataDog/zstd"
-
- "github.com/vercel/turbo/cli/internal/analytics"
- "github.com/vercel/turbo/cli/internal/tarpatch"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-type client interface {
- PutArtifact(hash string, body []byte, duration int, tag string) error
- FetchArtifact(hash string) (*http.Response, error)
- ArtifactExists(hash string) (*http.Response, error)
- GetTeamID() string
-}
-
-type httpCache struct {
- writable bool
- client client
- requestLimiter limiter
- recorder analytics.Recorder
- signerVerifier *ArtifactSignatureAuthentication
- repoRoot turbopath.AbsoluteSystemPath
-}
-
-type limiter chan struct{}
-
-func (l limiter) acquire() {
- l <- struct{}{}
-}
-
-func (l limiter) release() {
- <-l
-}
-
-// mtime is the time we attach for the modification time of all files.
-var mtime = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
-
-// nobody is the usual uid / gid of the 'nobody' user.
-const nobody = 65534
-
-func (cache *httpCache) Put(_ turbopath.AbsoluteSystemPath, hash string, duration int, files []turbopath.AnchoredSystemPath) error {
- // if cache.writable {
- cache.requestLimiter.acquire()
- defer cache.requestLimiter.release()
-
- r, w := io.Pipe()
- go cache.write(w, hash, files)
-
- // Read the entire artifact tar into memory so we can easily compute the signature.
- // Note: retryablehttp.NewRequest reads the files into memory anyways so there's no
- // additional overhead by doing the ioutil.ReadAll here instead.
- artifactBody, err := ioutil.ReadAll(r)
- if err != nil {
- return fmt.Errorf("failed to store files in HTTP cache: %w", err)
- }
- tag := ""
- if cache.signerVerifier.isEnabled() {
- tag, err = cache.signerVerifier.generateTag(hash, artifactBody)
- if err != nil {
- return fmt.Errorf("failed to store files in HTTP cache: %w", err)
- }
- }
- return cache.client.PutArtifact(hash, artifactBody, duration, tag)
-}
-
-// write writes a series of files into the given Writer.
-func (cache *httpCache) write(w io.WriteCloser, hash string, files []turbopath.AnchoredSystemPath) {
- defer w.Close()
- defer func() { _ = w.Close() }()
- zw := zstd.NewWriter(w)
- defer func() { _ = zw.Close() }()
- tw := tar.NewWriter(zw)
- defer func() { _ = tw.Close() }()
- for _, file := range files {
- // log.Printf("caching file %v", file)
- if err := cache.storeFile(tw, file); err != nil {
- log.Printf("[ERROR] Error uploading artifact %s to HTTP cache due to: %s", file, err)
- // TODO(jaredpalmer): How can we cancel the request at this point?
- }
- }
-}
-
-func (cache *httpCache) storeFile(tw *tar.Writer, repoRelativePath turbopath.AnchoredSystemPath) error {
- absoluteFilePath := repoRelativePath.RestoreAnchor(cache.repoRoot)
- info, err := absoluteFilePath.Lstat()
- if err != nil {
- return err
- }
- target := ""
- if info.Mode()&os.ModeSymlink != 0 {
- target, err = absoluteFilePath.Readlink()
- if err != nil {
- return err
- }
- }
- hdr, err := tarpatch.FileInfoHeader(repoRelativePath.ToUnixPath(), info, filepath.ToSlash(target))
- if err != nil {
- return err
- }
- // Ensure posix path for filename written in header.
- hdr.Name = repoRelativePath.ToUnixPath().ToString()
- // Zero out all timestamps.
- hdr.ModTime = mtime
- hdr.AccessTime = mtime
- hdr.ChangeTime = mtime
- // Strip user/group ids.
- hdr.Uid = nobody
- hdr.Gid = nobody
- hdr.Uname = "nobody"
- hdr.Gname = "nobody"
- if err := tw.WriteHeader(hdr); err != nil {
- return err
- } else if info.IsDir() || target != "" {
- return nil // nothing to write
- }
- f, err := absoluteFilePath.Open()
- if err != nil {
- return err
- }
- defer func() { _ = f.Close() }()
- _, err = io.Copy(tw, f)
- if errors.Is(err, tar.ErrWriteTooLong) {
- log.Printf("Error writing %v to tar file, info: %v, mode: %v, is regular: %v", repoRelativePath, info, info.Mode(), info.Mode().IsRegular())
- }
- return err
-}
-
-func (cache *httpCache) Fetch(_ turbopath.AbsoluteSystemPath, key string, _ []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error) {
- cache.requestLimiter.acquire()
- defer cache.requestLimiter.release()
- hit, files, duration, err := cache.retrieve(key)
- if err != nil {
- // TODO: analytics event?
- return ItemStatus{Remote: false}, files, duration, fmt.Errorf("failed to retrieve files from HTTP cache: %w", err)
- }
- cache.logFetch(hit, key, duration)
- return ItemStatus{Remote: hit}, files, duration, err
-}
-
-func (cache *httpCache) Exists(key string) ItemStatus {
- cache.requestLimiter.acquire()
- defer cache.requestLimiter.release()
- hit, err := cache.exists(key)
- if err != nil {
- return ItemStatus{Remote: false}
- }
- return ItemStatus{Remote: hit}
-}
-
-func (cache *httpCache) logFetch(hit bool, hash string, duration int) {
- var event string
- if hit {
- event = CacheEventHit
- } else {
- event = CacheEventMiss
- }
- payload := &CacheEvent{
- Source: CacheSourceRemote,
- Event: event,
- Hash: hash,
- Duration: duration,
- }
- cache.recorder.LogEvent(payload)
-}
-
-func (cache *httpCache) exists(hash string) (bool, error) {
- resp, err := cache.client.ArtifactExists(hash)
- if err != nil {
- return false, nil
- }
-
- defer func() { err = resp.Body.Close() }()
-
- if resp.StatusCode == http.StatusNotFound {
- return false, nil
- } else if resp.StatusCode != http.StatusOK {
- return false, fmt.Errorf("%s", strconv.Itoa(resp.StatusCode))
- }
- return true, err
-}
-
-func (cache *httpCache) retrieve(hash string) (bool, []turbopath.AnchoredSystemPath, int, error) {
- resp, err := cache.client.FetchArtifact(hash)
- if err != nil {
- return false, nil, 0, err
- }
- defer resp.Body.Close()
- if resp.StatusCode == http.StatusNotFound {
- return false, nil, 0, nil // doesn't exist - not an error
- } else if resp.StatusCode != http.StatusOK {
- b, _ := ioutil.ReadAll(resp.Body)
- return false, nil, 0, fmt.Errorf("%s", string(b))
- }
- // If present, extract the duration from the response.
- duration := 0
- if resp.Header.Get("x-artifact-duration") != "" {
- intVar, err := strconv.Atoi(resp.Header.Get("x-artifact-duration"))
- if err != nil {
- return false, nil, 0, fmt.Errorf("invalid x-artifact-duration header: %w", err)
- }
- duration = intVar
- }
- var tarReader io.Reader
-
- defer func() { _ = resp.Body.Close() }()
- if cache.signerVerifier.isEnabled() {
- expectedTag := resp.Header.Get("x-artifact-tag")
- if expectedTag == "" {
- // If the verifier is enabled all incoming artifact downloads must have a signature
- return false, nil, 0, errors.New("artifact verification failed: Downloaded artifact is missing required x-artifact-tag header")
- }
- b, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return false, nil, 0, fmt.Errorf("artifact verification failed: %w", err)
- }
- isValid, err := cache.signerVerifier.validate(hash, b, expectedTag)
- if err != nil {
- return false, nil, 0, fmt.Errorf("artifact verification failed: %w", err)
- }
- if !isValid {
- err = fmt.Errorf("artifact verification failed: artifact tag does not match expected tag %s", expectedTag)
- return false, nil, 0, err
- }
- // The artifact has been verified and the body can be read and untarred
- tarReader = bytes.NewReader(b)
- } else {
- tarReader = resp.Body
- }
- files, err := restoreTar(cache.repoRoot, tarReader)
- if err != nil {
- return false, nil, 0, err
- }
- return true, files, duration, nil
-}
-
-// restoreTar returns posix-style repo-relative paths of the files it
-// restored. In the future, these should likely be repo-relative system paths
-// so that they are suitable for being fed into cache.Put for other caches.
-// For now, I think this is working because windows also accepts /-delimited paths.
-func restoreTar(root turbopath.AbsoluteSystemPath, reader io.Reader) ([]turbopath.AnchoredSystemPath, error) {
- files := []turbopath.AnchoredSystemPath{}
- missingLinks := []*tar.Header{}
- zr := zstd.NewReader(reader)
- var closeError error
- defer func() { closeError = zr.Close() }()
- tr := tar.NewReader(zr)
- for {
- hdr, err := tr.Next()
- if err != nil {
- if err == io.EOF {
- for _, link := range missingLinks {
- err := restoreSymlink(root, link, true)
- if err != nil {
- return nil, err
- }
- }
-
- return files, closeError
- }
- return nil, err
- }
- // hdr.Name is always a posix-style path
- // FIXME: THIS IS A BUG.
- restoredName := turbopath.AnchoredUnixPath(hdr.Name)
- files = append(files, restoredName.ToSystemPath())
- filename := restoredName.ToSystemPath().RestoreAnchor(root)
- if isChild, err := root.ContainsPath(filename); err != nil {
- return nil, err
- } else if !isChild {
- return nil, fmt.Errorf("cannot untar file to %v", filename)
- }
- switch hdr.Typeflag {
- case tar.TypeDir:
- if err := filename.MkdirAll(0775); err != nil {
- return nil, err
- }
- case tar.TypeReg:
- if dir := filename.Dir(); dir != "." {
- if err := dir.MkdirAll(0775); err != nil {
- return nil, err
- }
- }
- if f, err := filename.OpenFile(os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.FileMode(hdr.Mode)); err != nil {
- return nil, err
- } else if _, err := io.Copy(f, tr); err != nil {
- return nil, err
- } else if err := f.Close(); err != nil {
- return nil, err
- }
- case tar.TypeSymlink:
- if err := restoreSymlink(root, hdr, false); errors.Is(err, errNonexistentLinkTarget) {
- missingLinks = append(missingLinks, hdr)
- } else if err != nil {
- return nil, err
- }
- default:
- log.Printf("Unhandled file type %d for %s", hdr.Typeflag, hdr.Name)
- }
- }
-}
-
-var errNonexistentLinkTarget = errors.New("the link target does not exist")
-
-func restoreSymlink(root turbopath.AbsoluteSystemPath, hdr *tar.Header, allowNonexistentTargets bool) error {
- // Note that hdr.Linkname is really the link target
- relativeLinkTarget := filepath.FromSlash(hdr.Linkname)
- linkFilename := root.UntypedJoin(hdr.Name)
- if err := linkFilename.EnsureDir(); err != nil {
- return err
- }
-
- // TODO: check if this is an absolute path, or if we even care
- linkTarget := linkFilename.Dir().UntypedJoin(relativeLinkTarget)
- if _, err := linkTarget.Lstat(); err != nil {
- if os.IsNotExist(err) {
- if !allowNonexistentTargets {
- return errNonexistentLinkTarget
- }
- // if we're allowing nonexistent link targets, proceed to creating the link
- } else {
- return err
- }
- }
- // Ensure that the link we're about to create doesn't already exist
- if err := linkFilename.Remove(); err != nil && !errors.Is(err, os.ErrNotExist) {
- return err
- }
- if err := linkFilename.Symlink(relativeLinkTarget); err != nil {
- return err
- }
- return nil
-}
-
-func (cache *httpCache) Clean(_ turbopath.AbsoluteSystemPath) {
- // Not possible; this implementation can only clean for a hash.
-}
-
-func (cache *httpCache) CleanAll() {
- // Also not possible.
-}
-
-func (cache *httpCache) Shutdown() {}
-
-func newHTTPCache(opts Opts, client client, recorder analytics.Recorder) *httpCache {
- return &httpCache{
- writable: true,
- client: client,
- requestLimiter: make(limiter, 20),
- recorder: recorder,
- signerVerifier: &ArtifactSignatureAuthentication{
- // TODO(Gaspar): this should use RemoteCacheOptions.TeamId once we start
- // enforcing team restrictions for repositories.
- teamId: client.GetTeamID(),
- enabled: opts.RemoteCacheOpts.Signature,
- },
- }
-}
diff --git a/cli/internal/cache/cache_http_test.go b/cli/internal/cache/cache_http_test.go
deleted file mode 100644
index d187931..0000000
--- a/cli/internal/cache/cache_http_test.go
+++ /dev/null
@@ -1,245 +0,0 @@
-package cache
-
-import (
- "archive/tar"
- "bytes"
- "errors"
- "net/http"
- "testing"
-
- "github.com/DataDog/zstd"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "gotest.tools/v3/assert"
-)
-
-type errorResp struct {
- err error
-}
-
-func (sr *errorResp) PutArtifact(hash string, body []byte, duration int, tag string) error {
- return sr.err
-}
-
-func (sr *errorResp) FetchArtifact(hash string) (*http.Response, error) {
- return nil, sr.err
-}
-
-func (sr *errorResp) ArtifactExists(hash string) (*http.Response, error) {
- return nil, sr.err
-}
-
-func (sr *errorResp) GetTeamID() string {
- return ""
-}
-
-func TestRemoteCachingDisabled(t *testing.T) {
- clientErr := &util.CacheDisabledError{
- Status: util.CachingStatusDisabled,
- Message: "Remote Caching has been disabled for this team. A team owner can enable it here: $URL",
- }
- client := &errorResp{err: clientErr}
- cache := &httpCache{
- client: client,
- requestLimiter: make(limiter, 20),
- }
- cd := &util.CacheDisabledError{}
- _, _, _, err := cache.Fetch("unused-target", "some-hash", []string{"unused", "outputs"})
- if !errors.As(err, &cd) {
- t.Errorf("cache.Fetch err got %v, want a CacheDisabled error", err)
- }
- if cd.Status != util.CachingStatusDisabled {
- t.Errorf("CacheDisabled.Status got %v, want %v", cd.Status, util.CachingStatusDisabled)
- }
-}
-
-func makeValidTar(t *testing.T) *bytes.Buffer {
- // <repoRoot>
- // my-pkg/
- // some-file
- // link-to-extra-file -> ../extra-file
- // broken-link -> ../../global-dep
- // extra-file
-
- t.Helper()
- buf := &bytes.Buffer{}
- zw := zstd.NewWriter(buf)
- defer func() {
- if err := zw.Close(); err != nil {
- t.Fatalf("failed to close gzip: %v", err)
- }
- }()
- tw := tar.NewWriter(zw)
- defer func() {
- if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar: %v", err)
- }
- }()
-
- // my-pkg
- h := &tar.Header{
- Name: "my-pkg/",
- Mode: int64(0644),
- Typeflag: tar.TypeDir,
- }
- if err := tw.WriteHeader(h); err != nil {
- t.Fatalf("failed to write header: %v", err)
- }
- // my-pkg/some-file
- contents := []byte("some-file-contents")
- h = &tar.Header{
- Name: "my-pkg/some-file",
- Mode: int64(0644),
- Typeflag: tar.TypeReg,
- Size: int64(len(contents)),
- }
- if err := tw.WriteHeader(h); err != nil {
- t.Fatalf("failed to write header: %v", err)
- }
- if _, err := tw.Write(contents); err != nil {
- t.Fatalf("failed to write file: %v", err)
- }
- // my-pkg/link-to-extra-file
- h = &tar.Header{
- Name: "my-pkg/link-to-extra-file",
- Mode: int64(0644),
- Typeflag: tar.TypeSymlink,
- Linkname: "../extra-file",
- }
- if err := tw.WriteHeader(h); err != nil {
- t.Fatalf("failed to write header: %v", err)
- }
- // my-pkg/broken-link
- h = &tar.Header{
- Name: "my-pkg/broken-link",
- Mode: int64(0644),
- Typeflag: tar.TypeSymlink,
- Linkname: "../../global-dep",
- }
- if err := tw.WriteHeader(h); err != nil {
- t.Fatalf("failed to write header: %v", err)
- }
- // extra-file
- contents = []byte("extra-file-contents")
- h = &tar.Header{
- Name: "extra-file",
- Mode: int64(0644),
- Typeflag: tar.TypeReg,
- Size: int64(len(contents)),
- }
- if err := tw.WriteHeader(h); err != nil {
- t.Fatalf("failed to write header: %v", err)
- }
- if _, err := tw.Write(contents); err != nil {
- t.Fatalf("failed to write file: %v", err)
- }
-
- return buf
-}
-
-func makeInvalidTar(t *testing.T) *bytes.Buffer {
- // contains a single file that traverses out
- // ../some-file
-
- t.Helper()
- buf := &bytes.Buffer{}
- zw := zstd.NewWriter(buf)
- defer func() {
- if err := zw.Close(); err != nil {
- t.Fatalf("failed to close gzip: %v", err)
- }
- }()
- tw := tar.NewWriter(zw)
- defer func() {
- if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar: %v", err)
- }
- }()
-
- // my-pkg/some-file
- contents := []byte("some-file-contents")
- h := &tar.Header{
- Name: "../some-file",
- Mode: int64(0644),
- Typeflag: tar.TypeReg,
- Size: int64(len(contents)),
- }
- if err := tw.WriteHeader(h); err != nil {
- t.Fatalf("failed to write header: %v", err)
- }
- if _, err := tw.Write(contents); err != nil {
- t.Fatalf("failed to write file: %v", err)
- }
- return buf
-}
-
-func TestRestoreTar(t *testing.T) {
- root := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- tar := makeValidTar(t)
-
- expectedFiles := []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("extra-file").ToSystemPath(),
- turbopath.AnchoredUnixPath("my-pkg/").ToSystemPath(),
- turbopath.AnchoredUnixPath("my-pkg/some-file").ToSystemPath(),
- turbopath.AnchoredUnixPath("my-pkg/link-to-extra-file").ToSystemPath(),
- turbopath.AnchoredUnixPath("my-pkg/broken-link").ToSystemPath(),
- }
- files, err := restoreTar(root, tar)
- assert.NilError(t, err, "readTar")
-
- expectedSet := make(util.Set)
- for _, file := range expectedFiles {
- expectedSet.Add(file.ToString())
- }
- gotSet := make(util.Set)
- for _, file := range files {
- gotSet.Add(file.ToString())
- }
- extraFiles := gotSet.Difference(expectedSet)
- if extraFiles.Len() > 0 {
- t.Errorf("got extra files: %v", extraFiles.UnsafeListOfStrings())
- }
- missingFiles := expectedSet.Difference(gotSet)
- if missingFiles.Len() > 0 {
- t.Errorf("missing expected files: %v", missingFiles.UnsafeListOfStrings())
- }
-
- // Verify file contents
- extraFile := root.UntypedJoin("extra-file")
- contents, err := extraFile.ReadFile()
- assert.NilError(t, err, "ReadFile")
- assert.DeepEqual(t, contents, []byte("extra-file-contents"))
-
- someFile := root.UntypedJoin("my-pkg", "some-file")
- contents, err = someFile.ReadFile()
- assert.NilError(t, err, "ReadFile")
- assert.DeepEqual(t, contents, []byte("some-file-contents"))
-}
-
-func TestRestoreInvalidTar(t *testing.T) {
- root := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- expectedContents := []byte("important-data")
- someFile := root.UntypedJoin("some-file")
- err := someFile.WriteFile(expectedContents, 0644)
- assert.NilError(t, err, "WriteFile")
-
- tar := makeInvalidTar(t)
- // use a child directory so that blindly untarring will squash the file
- // that we just wrote above.
- repoRoot := root.UntypedJoin("repo")
- _, err = restoreTar(repoRoot, tar)
- if err == nil {
- t.Error("expected error untarring invalid tar")
- }
-
- contents, err := someFile.ReadFile()
- assert.NilError(t, err, "ReadFile")
- assert.Equal(t, string(contents), string(expectedContents), "expected to not overwrite file")
-}
-
-// Note that testing Put will require mocking the filesystem and is not currently the most
-// interesting test. The current implementation directly returns the error from PutArtifact.
-// We should still add the test once feasible to avoid future breakage.
diff --git a/cli/internal/cache/cache_noop.go b/cli/internal/cache/cache_noop.go
deleted file mode 100644
index 80a3c23..0000000
--- a/cli/internal/cache/cache_noop.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package cache
-
-import "github.com/vercel/turbo/cli/internal/turbopath"
-
-type noopCache struct{}
-
-func newNoopCache() *noopCache {
- return &noopCache{}
-}
-
-func (c *noopCache) Put(_ turbopath.AbsoluteSystemPath, _ string, _ int, _ []turbopath.AnchoredSystemPath) error {
- return nil
-}
-func (c *noopCache) Fetch(_ turbopath.AbsoluteSystemPath, _ string, _ []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error) {
- return ItemStatus{Local: false, Remote: false}, nil, 0, nil
-}
-func (c *noopCache) Exists(_ string) ItemStatus {
- return ItemStatus{}
-}
-
-func (c *noopCache) Clean(_ turbopath.AbsoluteSystemPath) {}
-func (c *noopCache) CleanAll() {}
-func (c *noopCache) Shutdown() {}
diff --git a/cli/internal/cache/cache_signature_authentication.go b/cli/internal/cache/cache_signature_authentication.go
deleted file mode 100644
index f9fe4c0..0000000
--- a/cli/internal/cache/cache_signature_authentication.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Adapted from https://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package cache
-
-import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "hash"
- "os"
-)
-
-type ArtifactSignatureAuthentication struct {
- teamId string
- enabled bool
-}
-
-func (asa *ArtifactSignatureAuthentication) isEnabled() bool {
- return asa.enabled
-}
-
-// If the secret key is not found or the secret key length is 0, an error is returned
-// Preference is given to the environment specified secret key.
-func (asa *ArtifactSignatureAuthentication) secretKey() ([]byte, error) {
- secret := os.Getenv("TURBO_REMOTE_CACHE_SIGNATURE_KEY")
- if len(secret) == 0 {
- return nil, errors.New("signature secret key not found. You must specify a secret key in the TURBO_REMOTE_CACHE_SIGNATURE_KEY environment variable")
- }
- return []byte(secret), nil
-}
-
-func (asa *ArtifactSignatureAuthentication) generateTag(hash string, artifactBody []byte) (string, error) {
- tag, err := asa.getTagGenerator(hash)
- if err != nil {
- return "", err
- }
- tag.Write(artifactBody)
- return base64.StdEncoding.EncodeToString(tag.Sum(nil)), nil
-}
-
-func (asa *ArtifactSignatureAuthentication) getTagGenerator(hash string) (hash.Hash, error) {
- teamId := asa.teamId
- secret, err := asa.secretKey()
- if err != nil {
- return nil, err
- }
- artifactMetadata := &struct {
- Hash string `json:"hash"`
- TeamId string `json:"teamId"`
- }{
- Hash: hash,
- TeamId: teamId,
- }
- metadata, err := json.Marshal(artifactMetadata)
- if err != nil {
- return nil, err
- }
-
- // TODO(Gaspar) Support additional signing algorithms here
- h := hmac.New(sha256.New, secret)
- h.Write(metadata)
- return h, nil
-}
-
-func (asa *ArtifactSignatureAuthentication) validate(hash string, artifactBody []byte, expectedTag string) (bool, error) {
- computedTag, err := asa.generateTag(hash, artifactBody)
- if err != nil {
- return false, fmt.Errorf("failed to verify artifact tag: %w", err)
- }
- return hmac.Equal([]byte(computedTag), []byte(expectedTag)), nil
-}
-
-type StreamValidator struct {
- currentHash hash.Hash
-}
-
-func (sv *StreamValidator) Validate(expectedTag string) bool {
- computedTag := base64.StdEncoding.EncodeToString(sv.currentHash.Sum(nil))
- return hmac.Equal([]byte(computedTag), []byte(expectedTag))
-}
-
-func (sv *StreamValidator) CurrentValue() string {
- return base64.StdEncoding.EncodeToString(sv.currentHash.Sum(nil))
-}
diff --git a/cli/internal/cache/cache_signature_authentication_test.go b/cli/internal/cache/cache_signature_authentication_test.go
deleted file mode 100644
index 7f3f865..0000000
--- a/cli/internal/cache/cache_signature_authentication_test.go
+++ /dev/null
@@ -1,195 +0,0 @@
-// Adapted from ghttps://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package cache
-
-import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func Test_SecretKeySuccess(t *testing.T) {
- teamId := "team_someid"
- secretKeyEnvName := "TURBO_REMOTE_CACHE_SIGNATURE_KEY"
- secretKeyEnvValue := "my-secret-key-env"
- t.Setenv(secretKeyEnvName, secretKeyEnvValue)
-
- cases := []struct {
- name string
- asa *ArtifactSignatureAuthentication
- expectedSecretKey string
- expectedSecretKeyError bool
- }{
- {
- name: "Accepts secret key",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedSecretKey: secretKeyEnvValue,
- expectedSecretKeyError: false,
- },
- }
-
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- secretKey, err := tc.asa.secretKey()
- if tc.expectedSecretKeyError {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tc.expectedSecretKey, string(secretKey))
- }
- })
- }
-}
-
-func Test_SecretKeyErrors(t *testing.T) {
- teamId := "team_someid"
-
- // Env secret key TURBO_REMOTE_CACHE_SIGNATURE_KEY is not set
-
- cases := []struct {
- name string
- asa *ArtifactSignatureAuthentication
- expectedSecretKey string
- expectedSecretKeyError bool
- }{
- {
- name: "Secret key not defined errors",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedSecretKey: "",
- expectedSecretKeyError: true,
- },
- {
- name: "Secret key is empty errors",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedSecretKey: "",
- expectedSecretKeyError: true,
- },
- }
-
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- secretKey, err := tc.asa.secretKey()
- if tc.expectedSecretKeyError {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tc.expectedSecretKey, string(secretKey))
- }
- })
- }
-}
-
-func Test_GenerateTagAndValidate(t *testing.T) {
- teamId := "team_someid"
- hash := "the-artifact-hash"
- artifactBody := []byte("the artifact body as bytes")
- secretKeyEnvName := "TURBO_REMOTE_CACHE_SIGNATURE_KEY"
- secretKeyEnvValue := "my-secret-key-env"
- t.Setenv(secretKeyEnvName, secretKeyEnvValue)
-
- cases := []struct {
- name string
- asa *ArtifactSignatureAuthentication
- expectedTagMatches string
- expectedTagDoesNotMatch string
- }{
- {
- name: "Uses hash to generate tag",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedTagMatches: testUtilGetHMACTag(hash, teamId, artifactBody, secretKeyEnvValue),
- expectedTagDoesNotMatch: testUtilGetHMACTag("wrong-hash", teamId, artifactBody, secretKeyEnvValue),
- },
- {
- name: "Uses teamId to generate tag",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedTagMatches: testUtilGetHMACTag(hash, teamId, artifactBody, secretKeyEnvValue),
- expectedTagDoesNotMatch: testUtilGetHMACTag(hash, "wrong-teamId", artifactBody, secretKeyEnvValue),
- },
- {
- name: "Uses artifactBody to generate tag",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedTagMatches: testUtilGetHMACTag(hash, teamId, artifactBody, secretKeyEnvValue),
- expectedTagDoesNotMatch: testUtilGetHMACTag(hash, teamId, []byte("wrong-artifact-body"), secretKeyEnvValue),
- },
- {
- name: "Uses secret to generate tag",
- asa: &ArtifactSignatureAuthentication{
- teamId: teamId,
- enabled: true,
- },
- expectedTagMatches: testUtilGetHMACTag(hash, teamId, artifactBody, secretKeyEnvValue),
- expectedTagDoesNotMatch: testUtilGetHMACTag(hash, teamId, artifactBody, "wrong-secret"),
- },
- }
-
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- tag, err := tc.asa.generateTag(hash, artifactBody)
- assert.NoError(t, err)
-
- // validates the tag
- assert.Equal(t, tc.expectedTagMatches, tag)
- isValid, err := tc.asa.validate(hash, artifactBody, tc.expectedTagMatches)
- assert.NoError(t, err)
- assert.True(t, isValid)
-
- // does not validate the tag
- assert.NotEqual(t, tc.expectedTagDoesNotMatch, tag)
- isValid, err = tc.asa.validate(hash, artifactBody, tc.expectedTagDoesNotMatch)
- assert.NoError(t, err)
- assert.False(t, isValid)
-
- })
- }
-}
-
-// Test utils
-
-// Return the Base64 encoded HMAC given the artifact metadata and artifact body
-func testUtilGetHMACTag(hash string, teamId string, artifactBody []byte, secret string) string {
- artifactMetadata := &struct {
- Hash string `json:"hash"`
- TeamId string `json:"teamId"`
- }{
- Hash: hash,
- TeamId: teamId,
- }
- metadata, _ := json.Marshal(artifactMetadata)
- h := hmac.New(sha256.New, []byte(secret))
- h.Write(metadata)
- h.Write(artifactBody)
- return base64.StdEncoding.EncodeToString(h.Sum(nil))
-}
-
-func Test_Utils(t *testing.T) {
- teamId := "team_someid"
- secret := "my-secret"
- hash := "the-artifact-hash"
- artifactBody := []byte("the artifact body as bytes")
- testTag := testUtilGetHMACTag(hash, teamId, artifactBody, secret)
- expectedTag := "9Fu8YniPZ2dEBolTPQoNlFWG0LNMW8EXrBsRmf/fEHk="
- assert.True(t, hmac.Equal([]byte(testTag), []byte(expectedTag)))
-}
diff --git a/cli/internal/cache/cache_test.go b/cli/internal/cache/cache_test.go
deleted file mode 100644
index 3f17877..0000000
--- a/cli/internal/cache/cache_test.go
+++ /dev/null
@@ -1,318 +0,0 @@
-package cache
-
-import (
- "net/http"
- "reflect"
- "sync/atomic"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/analytics"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-type testCache struct {
- disabledErr *util.CacheDisabledError
- entries map[string][]turbopath.AnchoredSystemPath
-}
-
-func (tc *testCache) Fetch(_ turbopath.AbsoluteSystemPath, hash string, _ []string) (ItemStatus, []turbopath.AnchoredSystemPath, int, error) {
- if tc.disabledErr != nil {
- return ItemStatus{}, nil, 0, tc.disabledErr
- }
- foundFiles, ok := tc.entries[hash]
- if ok {
- duration := 5
- return ItemStatus{Local: true}, foundFiles, duration, nil
- }
- return ItemStatus{}, nil, 0, nil
-}
-
-func (tc *testCache) Exists(hash string) ItemStatus {
- if tc.disabledErr != nil {
- return ItemStatus{}
- }
- _, ok := tc.entries[hash]
- if ok {
- return ItemStatus{Local: true}
- }
- return ItemStatus{}
-}
-
-func (tc *testCache) Put(_ turbopath.AbsoluteSystemPath, hash string, _ int, files []turbopath.AnchoredSystemPath) error {
- if tc.disabledErr != nil {
- return tc.disabledErr
- }
- tc.entries[hash] = files
- return nil
-}
-
-func (tc *testCache) Clean(_ turbopath.AbsoluteSystemPath) {}
-func (tc *testCache) CleanAll() {}
-func (tc *testCache) Shutdown() {}
-
-func newEnabledCache() *testCache {
- return &testCache{
- entries: make(map[string][]turbopath.AnchoredSystemPath),
- }
-}
-
-func newDisabledCache() *testCache {
- return &testCache{
- disabledErr: &util.CacheDisabledError{
- Status: util.CachingStatusDisabled,
- Message: "remote caching is disabled",
- },
- }
-}
-
-func TestPutCachingDisabled(t *testing.T) {
- disabledCache := newDisabledCache()
- caches := []Cache{
- newEnabledCache(),
- disabledCache,
- newEnabledCache(),
- newEnabledCache(),
- }
- var removeCalled uint64
- mplex := &cacheMultiplexer{
- caches: caches,
- onCacheRemoved: func(cache Cache, err error) {
- atomic.AddUint64(&removeCalled, 1)
- },
- }
-
- err := mplex.Put("unused-target", "some-hash", 5, []turbopath.AnchoredSystemPath{"a-file"})
- if err != nil {
- // don't leak the cache removal
- t.Errorf("Put got error %v, want <nil>", err)
- }
-
- removes := atomic.LoadUint64(&removeCalled)
- if removes != 1 {
- t.Errorf("removes count: %v, want 1", removes)
- }
-
- mplex.mu.RLock()
- if len(mplex.caches) != 3 {
- t.Errorf("found %v caches, expected to have 3 after one was removed", len(mplex.caches))
- }
- for _, cache := range mplex.caches {
- if cache == disabledCache {
- t.Error("found disabled cache, expected it to be removed")
- }
- }
- mplex.mu.RUnlock()
-
- // subsequent Fetch should still work
- cacheStatus, _, _, err := mplex.Fetch("unused-target", "some-hash", []string{"unused", "files"})
- if err != nil {
- t.Errorf("got error fetching files: %v", err)
- }
- hit := cacheStatus.Local || cacheStatus.Remote
- if !hit {
- t.Error("failed to find previously stored files")
- }
-
- removes = atomic.LoadUint64(&removeCalled)
- if removes != 1 {
- t.Errorf("removes count: %v, want 1", removes)
- }
-}
-
-func TestExists(t *testing.T) {
- caches := []Cache{
- newEnabledCache(),
- }
-
- mplex := &cacheMultiplexer{
- caches: caches,
- }
-
- itemStatus := mplex.Exists("some-hash")
- if itemStatus.Local {
- t.Error("did not expect file to exist")
- }
-
- err := mplex.Put("unused-target", "some-hash", 5, []turbopath.AnchoredSystemPath{"a-file"})
- if err != nil {
- // don't leak the cache removal
- t.Errorf("Put got error %v, want <nil>", err)
- }
-
- itemStatus = mplex.Exists("some-hash")
- if !itemStatus.Local {
- t.Error("failed to find previously stored files")
- }
-}
-
-type fakeClient struct{}
-
-// FetchArtifact implements client
-func (*fakeClient) FetchArtifact(hash string) (*http.Response, error) {
- panic("unimplemented")
-}
-
-func (*fakeClient) ArtifactExists(hash string) (*http.Response, error) {
- panic("unimplemented")
-}
-
-// GetTeamID implements client
-func (*fakeClient) GetTeamID() string {
- return "fake-team-id"
-}
-
-// PutArtifact implements client
-func (*fakeClient) PutArtifact(hash string, body []byte, duration int, tag string) error {
- panic("unimplemented")
-}
-
-var _ client = &fakeClient{}
-
-func TestFetchCachingDisabled(t *testing.T) {
- disabledCache := newDisabledCache()
- caches := []Cache{
- newEnabledCache(),
- disabledCache,
- newEnabledCache(),
- newEnabledCache(),
- }
- var removeCalled uint64
- mplex := &cacheMultiplexer{
- caches: caches,
- onCacheRemoved: func(cache Cache, err error) {
- atomic.AddUint64(&removeCalled, 1)
- },
- }
-
- cacheStatus, _, _, err := mplex.Fetch("unused-target", "some-hash", []string{"unused", "files"})
- if err != nil {
- // don't leak the cache removal
- t.Errorf("Fetch got error %v, want <nil>", err)
- }
- hit := cacheStatus.Local || cacheStatus.Remote
- if hit {
- t.Error("hit on empty cache, expected miss")
- }
-
- removes := atomic.LoadUint64(&removeCalled)
- if removes != 1 {
- t.Errorf("removes count: %v, want 1", removes)
- }
-
- mplex.mu.RLock()
- if len(mplex.caches) != 3 {
- t.Errorf("found %v caches, expected to have 3 after one was removed", len(mplex.caches))
- }
- for _, cache := range mplex.caches {
- if cache == disabledCache {
- t.Error("found disabled cache, expected it to be removed")
- }
- }
- mplex.mu.RUnlock()
-}
-
-type nullRecorder struct{}
-
-func (nullRecorder) LogEvent(analytics.EventPayload) {}
-
-func TestNew(t *testing.T) {
- // Test will bomb if this fails, no need to specially handle the error
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- type args struct {
- opts Opts
- recorder analytics.Recorder
- onCacheRemoved OnCacheRemoved
- client fakeClient
- }
- tests := []struct {
- name string
- args args
- want Cache
- wantErr bool
- }{
- {
- name: "With no caches configured, new returns a noopCache and an error",
- args: args{
- opts: Opts{
- SkipFilesystem: true,
- SkipRemote: true,
- },
- recorder: &nullRecorder{},
- onCacheRemoved: func(Cache, error) {},
- },
- want: &noopCache{},
- wantErr: true,
- },
- {
- name: "With just httpCache configured, new returns an httpCache and a noopCache",
- args: args{
- opts: Opts{
- SkipFilesystem: true,
- RemoteCacheOpts: fs.RemoteCacheOptions{
- Signature: true,
- },
- },
- recorder: &nullRecorder{},
- onCacheRemoved: func(Cache, error) {},
- },
- want: &cacheMultiplexer{
- caches: []Cache{&httpCache{}, &noopCache{}},
- },
- wantErr: false,
- },
- {
- name: "With just fsCache configured, new returns only an fsCache",
- args: args{
- opts: Opts{
- SkipRemote: true,
- },
- recorder: &nullRecorder{},
- onCacheRemoved: func(Cache, error) {},
- },
- want: &fsCache{},
- },
- {
- name: "With both configured, new returns an fsCache and httpCache",
- args: args{
- opts: Opts{
- RemoteCacheOpts: fs.RemoteCacheOptions{
- Signature: true,
- },
- },
- recorder: &nullRecorder{},
- onCacheRemoved: func(Cache, error) {},
- },
- want: &cacheMultiplexer{
- caches: []Cache{&fsCache{}, &httpCache{}},
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got, err := New(tt.args.opts, repoRoot, &tt.args.client, tt.args.recorder, tt.args.onCacheRemoved)
- if (err != nil) != tt.wantErr {
- t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- switch multiplexer := got.(type) {
- case *cacheMultiplexer:
- want := tt.want.(*cacheMultiplexer)
- for i := range multiplexer.caches {
- if reflect.TypeOf(multiplexer.caches[i]) != reflect.TypeOf(want.caches[i]) {
- t.Errorf("New() = %v, want %v", reflect.TypeOf(multiplexer.caches[i]), reflect.TypeOf(want.caches[i]))
- }
- }
- case *fsCache:
- if reflect.TypeOf(got) != reflect.TypeOf(tt.want) {
- t.Errorf("New() = %v, want %v", reflect.TypeOf(got), reflect.TypeOf(tt.want))
- }
- case *noopCache:
- if reflect.TypeOf(got) != reflect.TypeOf(tt.want) {
- t.Errorf("New() = %v, want %v", reflect.TypeOf(got), reflect.TypeOf(tt.want))
- }
- }
- })
- }
-}
diff --git a/cli/internal/cacheitem/cacheitem.go b/cli/internal/cacheitem/cacheitem.go
deleted file mode 100644
index 2fb2c3b..0000000
--- a/cli/internal/cacheitem/cacheitem.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Package cacheitem is an abstraction over the creation and restoration of a cache
-package cacheitem
-
-import (
- "archive/tar"
- "bufio"
- "crypto/sha512"
- "errors"
- "io"
- "os"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-var (
- errMissingSymlinkTarget = errors.New("symlink restoration is delayed")
- errCycleDetected = errors.New("links in the cache are cyclic")
- errTraversal = errors.New("tar attempts to write outside of directory")
- errNameMalformed = errors.New("file name is malformed")
- errNameWindowsUnsafe = errors.New("file name is not Windows-safe")
- errUnsupportedFileType = errors.New("attempted to restore unsupported file type")
-)
-
-// CacheItem is a `tar` utility with a little bit extra.
-type CacheItem struct {
- // Path is the location on disk for the CacheItem.
- Path turbopath.AbsoluteSystemPath
- // Anchor is the position on disk at which the CacheItem will be restored.
- Anchor turbopath.AbsoluteSystemPath
-
- // For creation.
- tw *tar.Writer
- zw io.WriteCloser
- fileBuffer *bufio.Writer
- handle *os.File
- compressed bool
-}
-
-// Close any open pipes
-func (ci *CacheItem) Close() error {
- if ci.tw != nil {
- if err := ci.tw.Close(); err != nil {
- return err
- }
- }
-
- if ci.zw != nil {
- if err := ci.zw.Close(); err != nil {
- return err
- }
- }
-
- if ci.fileBuffer != nil {
- if err := ci.fileBuffer.Flush(); err != nil {
- return err
- }
- }
-
- if ci.handle != nil {
- if err := ci.handle.Close(); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// GetSha returns the SHA-512 hash for the CacheItem.
-func (ci *CacheItem) GetSha() ([]byte, error) {
- sha := sha512.New()
- if _, err := io.Copy(sha, ci.handle); err != nil {
- return nil, err
- }
-
- return sha.Sum(nil), nil
-}
diff --git a/cli/internal/cacheitem/create.go b/cli/internal/cacheitem/create.go
deleted file mode 100644
index ce5b1c8..0000000
--- a/cli/internal/cacheitem/create.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package cacheitem
-
-import (
- "archive/tar"
- "bufio"
- "io"
- "os"
- "strings"
- "time"
-
- "github.com/DataDog/zstd"
-
- "github.com/moby/sys/sequential"
- "github.com/vercel/turbo/cli/internal/tarpatch"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// Create makes a new CacheItem at the specified path.
-func Create(path turbopath.AbsoluteSystemPath) (*CacheItem, error) {
- handle, err := path.OpenFile(os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
- if err != nil {
- return nil, err
- }
-
- cacheItem := &CacheItem{
- Path: path,
- handle: handle,
- compressed: strings.HasSuffix(path.ToString(), ".zst"),
- }
-
- cacheItem.init()
- return cacheItem, nil
-}
-
-// init prepares the CacheItem for writing.
-// Wires all the writers end-to-end:
-// tar.Writer -> zstd.Writer -> fileBuffer -> file
-func (ci *CacheItem) init() {
- fileBuffer := bufio.NewWriterSize(ci.handle, 2^20) // Flush to disk in 1mb chunks.
-
- var tw *tar.Writer
- if ci.compressed {
- zw := zstd.NewWriter(fileBuffer)
- tw = tar.NewWriter(zw)
- ci.zw = zw
- } else {
- tw = tar.NewWriter(fileBuffer)
- }
-
- ci.tw = tw
- ci.fileBuffer = fileBuffer
-}
-
-// AddFile adds a user-cached item to the tar.
-func (ci *CacheItem) AddFile(fsAnchor turbopath.AbsoluteSystemPath, filePath turbopath.AnchoredSystemPath) error {
- // Calculate the fully-qualified path to the file to read it.
- sourcePath := filePath.RestoreAnchor(fsAnchor)
-
- // We grab the FileInfo which tar.FileInfoHeader accepts.
- fileInfo, lstatErr := sourcePath.Lstat()
- if lstatErr != nil {
- return lstatErr
- }
-
- // Determine if we need to populate the additional link argument to tar.FileInfoHeader.
- var link string
- if fileInfo.Mode()&os.ModeSymlink != 0 {
- linkTarget, readlinkErr := sourcePath.Readlink()
- if readlinkErr != nil {
- return readlinkErr
- }
- link = linkTarget
- }
-
- // Normalize the path within the cache.
- cacheDestinationName := filePath.ToUnixPath()
-
- // Generate the the header.
- // We do not use header generation from stdlib because it can throw an error.
- header, headerErr := tarpatch.FileInfoHeader(cacheDestinationName, fileInfo, link)
- if headerErr != nil {
- return headerErr
- }
-
- // Throw an error if trying to create a cache that contains a type we don't support.
- if (header.Typeflag != tar.TypeReg) && (header.Typeflag != tar.TypeDir) && (header.Typeflag != tar.TypeSymlink) {
- return errUnsupportedFileType
- }
-
- // Consistent creation.
- header.Uid = 0
- header.Gid = 0
- header.AccessTime = time.Unix(0, 0)
- header.ModTime = time.Unix(0, 0)
- header.ChangeTime = time.Unix(0, 0)
-
- // Always write the header.
- if err := ci.tw.WriteHeader(header); err != nil {
- return err
- }
-
- // If there is a body to be written, do so.
- if header.Typeflag == tar.TypeReg && header.Size > 0 {
- // Windows has a distinct "sequential read" opening mode.
- // We use a library that will switch to this mode for Windows.
- sourceFile, sourceErr := sequential.OpenFile(sourcePath.ToString(), os.O_RDONLY, 0777)
- if sourceErr != nil {
- return sourceErr
- }
-
- if _, err := io.Copy(ci.tw, sourceFile); err != nil {
- return err
- }
-
- return sourceFile.Close()
- }
-
- return nil
-}
diff --git a/cli/internal/cacheitem/create_test.go b/cli/internal/cacheitem/create_test.go
deleted file mode 100644
index 97eeb01..0000000
--- a/cli/internal/cacheitem/create_test.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package cacheitem
-
-import (
- "encoding/hex"
- "io/fs"
- "os"
- "runtime"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-type createFileDefinition struct {
- Path turbopath.AnchoredSystemPath
- Linkname string
- fs.FileMode
-}
-
-func createEntry(t *testing.T, anchor turbopath.AbsoluteSystemPath, fileDefinition createFileDefinition) error {
- t.Helper()
- if fileDefinition.FileMode.IsDir() {
- return createDir(t, anchor, fileDefinition)
- } else if fileDefinition.FileMode&os.ModeSymlink != 0 {
- return createSymlink(t, anchor, fileDefinition)
- } else if fileDefinition.FileMode&os.ModeNamedPipe != 0 {
- return createFifo(t, anchor, fileDefinition)
- } else {
- return createFile(t, anchor, fileDefinition)
- }
-}
-
-func createDir(t *testing.T, anchor turbopath.AbsoluteSystemPath, fileDefinition createFileDefinition) error {
- t.Helper()
- path := fileDefinition.Path.RestoreAnchor(anchor)
- mkdirAllErr := path.MkdirAllMode(fileDefinition.FileMode & 0777)
- assert.NilError(t, mkdirAllErr, "MkdirAll")
- return mkdirAllErr
-}
-func createFile(t *testing.T, anchor turbopath.AbsoluteSystemPath, fileDefinition createFileDefinition) error {
- t.Helper()
- path := fileDefinition.Path.RestoreAnchor(anchor)
- writeErr := path.WriteFile([]byte("file contents"), fileDefinition.FileMode&0777)
- assert.NilError(t, writeErr, "WriteFile")
- return writeErr
-}
-func createSymlink(t *testing.T, anchor turbopath.AbsoluteSystemPath, fileDefinition createFileDefinition) error {
- t.Helper()
- path := fileDefinition.Path.RestoreAnchor(anchor)
- symlinkErr := path.Symlink(fileDefinition.Linkname)
- assert.NilError(t, symlinkErr, "Symlink")
- lchmodErr := path.Lchmod(fileDefinition.FileMode & 0777)
- assert.NilError(t, lchmodErr, "Lchmod")
- return symlinkErr
-}
-
-func TestCreate(t *testing.T) {
- tests := []struct {
- name string
- files []createFileDefinition
- wantDarwin string
- wantUnix string
- wantWindows string
- wantErr error
- }{
- {
- name: "hello world",
- files: []createFileDefinition{
- {
- Path: turbopath.AnchoredSystemPath("hello world.txt"),
- FileMode: 0 | 0644,
- },
- },
- wantDarwin: "4f39f1cab23906f3b89f313392ef7c26f2586e1c15fa6b577cce640c4781d082817927b4875a5413bc23e1248f0b198218998d70e7336e8b1244542ba446ca07",
- wantUnix: "4f39f1cab23906f3b89f313392ef7c26f2586e1c15fa6b577cce640c4781d082817927b4875a5413bc23e1248f0b198218998d70e7336e8b1244542ba446ca07",
- wantWindows: "e304d1ba8c51209f97bd11dabf27ca06996b70a850db592343942c49480de47bcbb4b7131fb3dd4d7564021d3bc0e648919e4876572b46ac1da97fca92b009c5",
- },
- {
- name: "links",
- files: []createFileDefinition{
- {
- Path: turbopath.AnchoredSystemPath("one"),
- Linkname: "two",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Path: turbopath.AnchoredSystemPath("two"),
- Linkname: "three",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Path: turbopath.AnchoredSystemPath("three"),
- Linkname: "real",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Path: turbopath.AnchoredSystemPath("real"),
- FileMode: 0 | 0644,
- },
- },
- wantDarwin: "07278fdf37db4b212352367f391377bd6bac8f361dd834ae5522d809539bcf3b34d046873c1b45876d7372251446bb12c32f9fa9824914c4a1a01f6d7a206702",
- wantUnix: "07278fdf37db4b212352367f391377bd6bac8f361dd834ae5522d809539bcf3b34d046873c1b45876d7372251446bb12c32f9fa9824914c4a1a01f6d7a206702",
- wantWindows: "d4dac527e40860ee1ba3fdf2b9b12a1eba385050cf4f5877558dd531f0ecf2a06952fd5f88b852ad99e010943ed7b7f1437b727796369524e85f0c06f25d62c9",
- },
- {
- name: "subdirectory",
- files: []createFileDefinition{
- {
- Path: turbopath.AnchoredSystemPath("parent"),
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Path: turbopath.AnchoredSystemPath("parent/child"),
- FileMode: 0 | 0644,
- },
- },
- wantDarwin: "b513eea231daa84245d1d23d99fc398ccf17166ca49754ffbdcc1a3269cd75b7ad176a9c7095ff2481f71dca9fc350189747035f13d53b3a864e4fe35165233f",
- wantUnix: "b513eea231daa84245d1d23d99fc398ccf17166ca49754ffbdcc1a3269cd75b7ad176a9c7095ff2481f71dca9fc350189747035f13d53b3a864e4fe35165233f",
- wantWindows: "a8c3cba54e4dc214d3b21c3fa284d4032fe317d2f88943159efd5d16f3551ab53fae5c92ebf8acdd1bdb85d1238510b7938772cb11a0daa1b72b5e0f2700b5c7",
- },
- {
- name: "symlink permissions",
- files: []createFileDefinition{
- {
- Path: turbopath.AnchoredSystemPath("one"),
- Linkname: "two",
- FileMode: 0 | os.ModeSymlink | 0644,
- },
- },
- wantDarwin: "3ea9d8a4581a0c2ba77557c72447b240c5ac622edcdac570a0bf597c276c2917b4ea73e6c373bbac593a480e396845651fa4b51e049531ff5d44c0adb807c2d9",
- wantUnix: "99d953cbe1c0d8545e6f8382208fcefe14bcbefe39872f7b6310da14ac195b9a1b04b6d7b4b56f01a27216176193344a92488f99e124fcd68693f313f7137a1c",
- wantWindows: "a4b1dc5c296f8ac4c9124727c1d84d70f72872c7bb4ced6d83ee312889e822baf1eaa72f88e624fb1aac4339d0a1f766ede77eabd2e4524eb26e89f883dc479d",
- },
- {
- name: "unsupported types error",
- files: []createFileDefinition{
- {
- Path: turbopath.AnchoredSystemPath("fifo"),
- FileMode: 0 | os.ModeNamedPipe | 0644,
- },
- },
- wantErr: errUnsupportedFileType,
- },
- }
- for _, tt := range tests {
- getTestFunc := func(compressed bool) func(t *testing.T) {
- return func(t *testing.T) {
- inputDir := turbopath.AbsoluteSystemPath(t.TempDir())
- archiveDir := turbopath.AbsoluteSystemPath(t.TempDir())
- var archivePath turbopath.AbsoluteSystemPath
- if compressed {
- archivePath = turbopath.AnchoredSystemPath("out.tar.zst").RestoreAnchor(archiveDir)
- } else {
- archivePath = turbopath.AnchoredSystemPath("out.tar").RestoreAnchor(archiveDir)
- }
-
- cacheItem, cacheCreateErr := Create(archivePath)
- assert.NilError(t, cacheCreateErr, "Cache Create")
-
- for _, file := range tt.files {
- createErr := createEntry(t, inputDir, file)
- if createErr != nil {
- assert.ErrorIs(t, createErr, tt.wantErr)
- assert.NilError(t, cacheItem.Close(), "Close")
- return
- }
-
- addFileError := cacheItem.AddFile(inputDir, file.Path)
- if addFileError != nil {
- assert.ErrorIs(t, addFileError, tt.wantErr)
- assert.NilError(t, cacheItem.Close(), "Close")
- return
- }
- }
-
- assert.NilError(t, cacheItem.Close(), "Cache Close")
-
- // We only check for repeatability on compressed caches.
- if compressed {
- openedCacheItem, openedCacheItemErr := Open(archivePath)
- assert.NilError(t, openedCacheItemErr, "Cache Open")
-
- // We actually only need to compare the generated SHA.
- // That ensures we got the same output. (Effectively snapshots.)
- // This must be called after `Close` because both `tar` and `gzip` have footers.
- shaOne, shaOneErr := openedCacheItem.GetSha()
- assert.NilError(t, shaOneErr, "GetSha")
- snapshot := hex.EncodeToString(shaOne)
-
- switch runtime.GOOS {
- case "darwin":
- assert.Equal(t, snapshot, tt.wantDarwin, "Got expected hash.")
- case "windows":
- assert.Equal(t, snapshot, tt.wantWindows, "Got expected hash.")
- default:
- assert.Equal(t, snapshot, tt.wantUnix, "Got expected hash.")
- }
- assert.NilError(t, openedCacheItem.Close(), "Close")
- }
- }
- }
- t.Run(tt.name, getTestFunc(false))
- t.Run(tt.name+"zst", getTestFunc(true))
- }
-}
diff --git a/cli/internal/cacheitem/create_unix_test.go b/cli/internal/cacheitem/create_unix_test.go
deleted file mode 100644
index 812d1eb..0000000
--- a/cli/internal/cacheitem/create_unix_test.go
+++ /dev/null
@@ -1,20 +0,0 @@
-//go:build darwin || linux
-// +build darwin linux
-
-package cacheitem
-
-import (
- "syscall"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func createFifo(t *testing.T, anchor turbopath.AbsoluteSystemPath, fileDefinition createFileDefinition) error {
- t.Helper()
- path := fileDefinition.Path.RestoreAnchor(anchor)
- fifoErr := syscall.Mknod(path.ToString(), syscall.S_IFIFO|0666, 0)
- assert.NilError(t, fifoErr, "FIFO")
- return fifoErr
-}
diff --git a/cli/internal/cacheitem/create_windows_test.go b/cli/internal/cacheitem/create_windows_test.go
deleted file mode 100644
index 2cbb8b9..0000000
--- a/cli/internal/cacheitem/create_windows_test.go
+++ /dev/null
@@ -1,14 +0,0 @@
-//go:build windows
-// +build windows
-
-package cacheitem
-
-import (
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-func createFifo(t *testing.T, anchor turbopath.AbsoluteSystemPath, fileDefinition createFileDefinition) error {
- return errUnsupportedFileType
-}
diff --git a/cli/internal/cacheitem/filepath.go b/cli/internal/cacheitem/filepath.go
deleted file mode 100644
index 4fd1681..0000000
--- a/cli/internal/cacheitem/filepath.go
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cacheitem
-
-import "os"
-
-const _separator = os.PathSeparator
-
-// A lazybuf is a lazily constructed path buffer.
-// It supports append, reading previously appended bytes,
-// and retrieving the final string. It does not allocate a buffer
-// to hold the output until that output diverges from s.
-type lazybuf struct {
- path string
- buf []byte
- w int
- volAndPath string
- volLen int
-}
-
-func (b *lazybuf) index(i int) byte {
- if b.buf != nil {
- return b.buf[i]
- }
- return b.path[i]
-}
-
-func (b *lazybuf) append(c byte) {
- if b.buf == nil {
- if b.w < len(b.path) && b.path[b.w] == c {
- b.w++
- return
- }
- b.buf = make([]byte, len(b.path))
- copy(b.buf, b.path[:b.w])
- }
- b.buf[b.w] = c
- b.w++
-}
-
-func (b *lazybuf) string() string {
- if b.buf == nil {
- return b.volAndPath[:b.volLen+b.w]
- }
- return b.volAndPath[:b.volLen] + string(b.buf[:b.w])
-}
-
-// Clean is extracted from stdlib and removes `FromSlash` processing
-// of the stdlib version.
-//
-// Clean returns the shortest path name equivalent to path
-// by purely lexical processing. It applies the following rules
-// iteratively until no further processing can be done:
-//
-// 1. Replace multiple Separator elements with a single one.
-// 2. Eliminate each . path name element (the current directory).
-// 3. Eliminate each inner .. path name element (the parent directory)
-// along with the non-.. element that precedes it.
-// 4. Eliminate .. elements that begin a rooted path:
-// that is, replace "/.." by "/" at the beginning of a path,
-// assuming Separator is '/'.
-//
-// The returned path ends in a slash only if it represents a root directory,
-// such as "/" on Unix or `C:\` on Windows.
-//
-// Finally, any occurrences of slash are replaced by Separator.
-//
-// If the result of this process is an empty string, Clean
-// returns the string ".".
-//
-// See also Rob Pike, “Lexical File Names in Plan 9 or
-// Getting Dot-Dot Right,”
-// https://9p.io/sys/doc/lexnames.html
-func Clean(path string) string {
- originalPath := path
- volLen := volumeNameLen(path)
- path = path[volLen:]
- if path == "" {
- if volLen > 1 && originalPath[1] != ':' {
- // should be UNC
- // ORIGINAL: return FromSlash(originalPath)
- return originalPath
- }
- return originalPath + "."
- }
- rooted := os.IsPathSeparator(path[0])
-
- // Invariants:
- // reading from path; r is index of next byte to process.
- // writing to buf; w is index of next byte to write.
- // dotdot is index in buf where .. must stop, either because
- // it is the leading slash or it is a leading ../../.. prefix.
- n := len(path)
- out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
- r, dotdot := 0, 0
- if rooted {
- out.append(_separator)
- r, dotdot = 1, 1
- }
-
- for r < n {
- switch {
- case os.IsPathSeparator(path[r]):
- // empty path element
- r++
- case path[r] == '.' && r+1 == n:
- // . element
- r++
- case path[r] == '.' && os.IsPathSeparator(path[r+1]):
- // ./ element
- r++
-
- for r < len(path) && os.IsPathSeparator(path[r]) {
- r++
- }
- if out.w == 0 && volumeNameLen(path[r:]) > 0 {
- // When joining prefix "." and an absolute path on Windows,
- // the prefix should not be removed.
- out.append('.')
- }
- case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
- // .. element: remove to last separator
- r += 2
- switch {
- case out.w > dotdot:
- // can backtrack
- out.w--
- for out.w > dotdot && !os.IsPathSeparator(out.index(out.w)) {
- out.w--
- }
- case !rooted:
- // cannot backtrack, but not rooted, so append .. element.
- if out.w > 0 {
- out.append(_separator)
- }
- out.append('.')
- out.append('.')
- dotdot = out.w
- }
- default:
- // real path element.
- // add slash if needed
- if rooted && out.w != 1 || !rooted && out.w != 0 {
- out.append(_separator)
- }
- // copy element
- for ; r < n && !os.IsPathSeparator(path[r]); r++ {
- out.append(path[r])
- }
- }
- }
-
- // Turn empty string into "."
- if out.w == 0 {
- out.append('.')
- }
-
- // ORIGINAL: return FromSlash(out.string())
- return out.string()
-}
diff --git a/cli/internal/cacheitem/filepath_unix.go b/cli/internal/cacheitem/filepath_unix.go
deleted file mode 100644
index d0f6786..0000000
--- a/cli/internal/cacheitem/filepath_unix.go
+++ /dev/null
@@ -1,14 +0,0 @@
-//go:build !windows
-// +build !windows
-
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cacheitem
-
-// volumeNameLen returns length of the leading volume name on Windows.
-// It returns 0 elsewhere.
-func volumeNameLen(path string) int {
- return 0
-}
diff --git a/cli/internal/cacheitem/filepath_windows.go b/cli/internal/cacheitem/filepath_windows.go
deleted file mode 100644
index 2c3b852..0000000
--- a/cli/internal/cacheitem/filepath_windows.go
+++ /dev/null
@@ -1,50 +0,0 @@
-//go:build windows
-// +build windows
-
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cacheitem
-
-func isSlash(c uint8) bool {
- return c == '\\' || c == '/'
-}
-
-// volumeNameLen returns length of the leading volume name on Windows.
-// It returns 0 elsewhere.
-func volumeNameLen(path string) int {
- if len(path) < 2 {
- return 0
- }
- // with drive letter
- c := path[0]
- if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
- return 2
- }
- // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
- if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
- !isSlash(path[2]) && path[2] != '.' {
- // first, leading `\\` and next shouldn't be `\`. its server name.
- for n := 3; n < l-1; n++ {
- // second, next '\' shouldn't be repeated.
- if isSlash(path[n]) {
- n++
- // third, following something characters. its share name.
- if !isSlash(path[n]) {
- if path[n] == '.' {
- break
- }
- for ; n < l; n++ {
- if isSlash(path[n]) {
- break
- }
- }
- return n
- }
- break
- }
- }
- }
- return 0
-}
diff --git a/cli/internal/cacheitem/restore.go b/cli/internal/cacheitem/restore.go
deleted file mode 100644
index 347b996..0000000
--- a/cli/internal/cacheitem/restore.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package cacheitem
-
-import (
- "archive/tar"
- "errors"
- "io"
- "os"
- "runtime"
- "strings"
-
- "github.com/DataDog/zstd"
-
- "github.com/moby/sys/sequential"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// Open returns an existing CacheItem at the specified path.
-func Open(path turbopath.AbsoluteSystemPath) (*CacheItem, error) {
- handle, err := sequential.OpenFile(path.ToString(), os.O_RDONLY, 0777)
- if err != nil {
- return nil, err
- }
-
- return &CacheItem{
- Path: path,
- handle: handle,
- compressed: strings.HasSuffix(path.ToString(), ".zst"),
- }, nil
-}
-
-// Restore extracts a cache to a specified disk location.
-func (ci *CacheItem) Restore(anchor turbopath.AbsoluteSystemPath) ([]turbopath.AnchoredSystemPath, error) {
- var tr *tar.Reader
- var closeError error
-
- // We're reading a tar, possibly wrapped in zstd.
- if ci.compressed {
- zr := zstd.NewReader(ci.handle)
-
- // The `Close` function for compression effectively just returns the singular
- // error field on the decompressor instance. This is extremely unlikely to be
- // set without triggering one of the numerous other errors, but we should still
- // handle that possible edge case.
- defer func() { closeError = zr.Close() }()
- tr = tar.NewReader(zr)
- } else {
- tr = tar.NewReader(ci.handle)
- }
-
- // On first attempt to restore it's possible that a link target doesn't exist.
- // Save them and topsort them.
- var symlinks []*tar.Header
-
- restored := make([]turbopath.AnchoredSystemPath, 0)
-
- restorePointErr := anchor.MkdirAll(0755)
- if restorePointErr != nil {
- return nil, restorePointErr
- }
-
- // We're going to make the following two assumptions here for "fast" path restoration:
- // - All directories are enumerated in the `tar`.
- // - The contents of the tar are enumerated depth-first.
- //
- // This allows us to avoid:
- // - Attempts at recursive creation of directories.
- // - Repetitive `lstat` on restore of a file.
- //
- // Violating these assumptions won't cause things to break but we're only going to maintain
- // an `lstat` cache for the current tree. If you violate these assumptions and the current
- // cache does not apply for your path, it will clobber and re-start from the common
- // shared prefix.
- dirCache := &cachedDirTree{
- anchorAtDepth: []turbopath.AbsoluteSystemPath{anchor},
- }
-
- for {
- header, trErr := tr.Next()
- if trErr == io.EOF {
- // The end, time to restore any missing links.
- symlinksRestored, symlinksErr := topologicallyRestoreSymlinks(dirCache, anchor, symlinks, tr)
- restored = append(restored, symlinksRestored...)
- if symlinksErr != nil {
- return restored, symlinksErr
- }
-
- break
- }
- if trErr != nil {
- return restored, trErr
- }
-
- // The reader will not advance until tr.Next is called.
- // We can treat this as file metadata + body reader.
-
- // Attempt to place the file on disk.
- file, restoreErr := restoreEntry(dirCache, anchor, header, tr)
- if restoreErr != nil {
- if errors.Is(restoreErr, errMissingSymlinkTarget) {
- // Links get one shot to be valid, then they're accumulated, DAG'd, and restored on delay.
- symlinks = append(symlinks, header)
- continue
- }
- return restored, restoreErr
- }
- restored = append(restored, file)
- }
-
- return restored, closeError
-}
-
-// restoreRegular is the entry point for all things read from the tar.
-func restoreEntry(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, header *tar.Header, reader *tar.Reader) (turbopath.AnchoredSystemPath, error) {
- // We're permissive on creation, but restrictive on restoration.
- // There is no need to prevent the cache creation in any case.
- // And on restoration, if we fail, we simply run the task.
- switch header.Typeflag {
- case tar.TypeDir:
- return restoreDirectory(dirCache, anchor, header)
- case tar.TypeReg:
- return restoreRegular(dirCache, anchor, header, reader)
- case tar.TypeSymlink:
- return restoreSymlink(dirCache, anchor, header)
- default:
- return "", errUnsupportedFileType
- }
-}
-
-// canonicalizeName returns either an AnchoredSystemPath or an error.
-func canonicalizeName(name string) (turbopath.AnchoredSystemPath, error) {
- // Assuming this was a `turbo`-created input, we currently have an AnchoredUnixPath.
- // Assuming this is malicious input we don't really care if we do the wrong thing.
- wellFormed, windowsSafe := checkName(name)
-
- // Determine if the future filename is a well-formed AnchoredUnixPath
- if !wellFormed {
- return "", errNameMalformed
- }
-
- // Determine if the AnchoredUnixPath is safe to be used on Windows
- if runtime.GOOS == "windows" && !windowsSafe {
- return "", errNameWindowsUnsafe
- }
-
- // Directories will have a trailing slash. Remove it.
- noTrailingSlash := strings.TrimSuffix(name, "/")
-
- // Okay, we're all set here.
- return turbopath.AnchoredUnixPathFromUpstream(noTrailingSlash).ToSystemPath(), nil
-}
-
-// checkName returns `wellFormed, windowsSafe` via inspection of separators and traversal
-func checkName(name string) (bool, bool) {
- length := len(name)
-
- // Name is of length 0.
- if length == 0 {
- return false, false
- }
-
- wellFormed := true
- windowsSafe := true
-
- // Name is:
- // - "."
- // - ".."
- if wellFormed && (name == "." || name == "..") {
- wellFormed = false
- }
-
- // Name starts with:
- // - `/`
- // - `./`
- // - `../`
- if wellFormed && (strings.HasPrefix(name, "/") || strings.HasPrefix(name, "./") || strings.HasPrefix(name, "../")) {
- wellFormed = false
- }
-
- // Name ends in:
- // - `/.`
- // - `/..`
- if wellFormed && (strings.HasSuffix(name, "/.") || strings.HasSuffix(name, "/..")) {
- wellFormed = false
- }
-
- // Name contains:
- // - `//`
- // - `/./`
- // - `/../`
- if wellFormed && (strings.Contains(name, "//") || strings.Contains(name, "/./") || strings.Contains(name, "/../")) {
- wellFormed = false
- }
-
- // Name contains: `\`
- if strings.ContainsRune(name, '\\') {
- windowsSafe = false
- }
-
- return wellFormed, windowsSafe
-}
diff --git a/cli/internal/cacheitem/restore_directory.go b/cli/internal/cacheitem/restore_directory.go
deleted file mode 100644
index 4704d66..0000000
--- a/cli/internal/cacheitem/restore_directory.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package cacheitem
-
-import (
- "archive/tar"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// restoreDirectory restores a directory.
-func restoreDirectory(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, header *tar.Header) (turbopath.AnchoredSystemPath, error) {
- processedName, err := canonicalizeName(header.Name)
- if err != nil {
- return "", err
- }
-
- // We need to traverse `processedName` from base to root split at
- // `os.Separator` to make sure we don't end up following a symlink
- // outside of the restore path.
-
- // Create the directory.
- if err := safeMkdirAll(dirCache, anchor, processedName, header.Mode); err != nil {
- return "", err
- }
-
- return processedName, nil
-}
-
-type cachedDirTree struct {
- anchorAtDepth []turbopath.AbsoluteSystemPath
- prefix []turbopath.RelativeSystemPath
-}
-
-func (cr *cachedDirTree) getStartingPoint(path turbopath.AnchoredSystemPath) (turbopath.AbsoluteSystemPath, []turbopath.RelativeSystemPath) {
- pathSegmentStrings := strings.Split(path.ToString(), string(os.PathSeparator))
- pathSegments := make([]turbopath.RelativeSystemPath, len(pathSegmentStrings))
- for index, pathSegmentString := range pathSegmentStrings {
- pathSegments[index] = turbopath.RelativeSystemPathFromUpstream(pathSegmentString)
- }
-
- i := 0
- for i = 0; i < len(cr.prefix) && i < len(pathSegments); i++ {
- if pathSegments[i] != cr.prefix[i] {
- break
- }
- }
-
- // 0: root anchor, can't remove it.
- cr.anchorAtDepth = cr.anchorAtDepth[:i+1]
-
- // 0: first prefix.
- cr.prefix = cr.prefix[:i]
-
- return cr.anchorAtDepth[i], pathSegments[i:]
-}
-
-func (cr *cachedDirTree) Update(anchor turbopath.AbsoluteSystemPath, newSegment turbopath.RelativeSystemPath) {
- cr.anchorAtDepth = append(cr.anchorAtDepth, anchor)
- cr.prefix = append(cr.prefix, newSegment)
-}
-
-// safeMkdirAll creates all directories, assuming that the leaf node is a directory.
-// FIXME: Recheck the symlink cache before creating a directory.
-func safeMkdirAll(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, processedName turbopath.AnchoredSystemPath, mode int64) error {
- // Iterate through path segments by os.Separator, appending them onto the anchor.
- // Check to see if that path segment is a symlink with a target outside of anchor.
-
- // Pull the iteration starting point from thie directory cache.
- calculatedAnchor, pathSegments := dirCache.getStartingPoint(processedName)
- for _, segment := range pathSegments {
- calculatedAnchor, checkPathErr := checkPath(anchor, calculatedAnchor, segment)
- // We hit an existing directory or absolute path that was invalid.
- if checkPathErr != nil {
- return checkPathErr
- }
-
- // Otherwise we continue and check the next segment.
- dirCache.Update(calculatedAnchor, segment)
- }
-
- // If we have made it here we know that it is safe to call os.MkdirAll
- // on the Join of anchor and processedName.
- //
- // This could _still_ error, but we don't care.
- return processedName.RestoreAnchor(anchor).MkdirAll(os.FileMode(mode))
-}
-
-// checkPath ensures that the resolved path (if restoring symlinks).
-// It makes sure to never traverse outside of the anchor.
-func checkPath(originalAnchor turbopath.AbsoluteSystemPath, accumulatedAnchor turbopath.AbsoluteSystemPath, segment turbopath.RelativeSystemPath) (turbopath.AbsoluteSystemPath, error) {
- // Check if the segment itself is sneakily an absolute path...
- // (looking at you, Windows. CON, AUX...)
- if filepath.IsAbs(segment.ToString()) {
- return "", errTraversal
- }
-
- // Find out if this portion of the path is a symlink.
- combinedPath := accumulatedAnchor.Join(segment)
- fileInfo, err := combinedPath.Lstat()
-
- // Getting an error here means we failed to stat the path.
- // Assume that means we're safe and continue.
- if err != nil {
- return combinedPath, nil
- }
-
- // Find out if we have a symlink.
- isSymlink := fileInfo.Mode()&os.ModeSymlink != 0
-
- // If we don't have a symlink it's safe.
- if !isSymlink {
- return combinedPath, nil
- }
-
- // Check to see if the symlink targets outside of the originalAnchor.
- // We don't do eval symlinks because we could find ourself in a totally
- // different place.
-
- // 1. Get the target.
- linkTarget, readLinkErr := combinedPath.Readlink()
- if readLinkErr != nil {
- return "", readLinkErr
- }
-
- // 2. See if the target is absolute.
- if filepath.IsAbs(linkTarget) {
- absoluteLinkTarget := turbopath.AbsoluteSystemPathFromUpstream(linkTarget)
- if originalAnchor.HasPrefix(absoluteLinkTarget) {
- return absoluteLinkTarget, nil
- }
- return "", errTraversal
- }
-
- // 3. Target is relative (or absolute Windows on a Unix device)
- relativeLinkTarget := turbopath.RelativeSystemPathFromUpstream(linkTarget)
- computedTarget := accumulatedAnchor.UntypedJoin(linkTarget)
- if computedTarget.HasPrefix(originalAnchor) {
- // Need to recurse and make sure the target doesn't link out.
- return checkPath(originalAnchor, accumulatedAnchor, relativeLinkTarget)
- }
- return "", errTraversal
-}
diff --git a/cli/internal/cacheitem/restore_directory_test.go b/cli/internal/cacheitem/restore_directory_test.go
deleted file mode 100644
index f75bd47..0000000
--- a/cli/internal/cacheitem/restore_directory_test.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package cacheitem
-
-import (
- "reflect"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-func Test_cachedDirTree_getStartingPoint(t *testing.T) {
- testDir := turbopath.AbsoluteSystemPath("")
- tests := []struct {
- name string
-
- // STATE
- cachedDirTree cachedDirTree
-
- // INPUT
- path turbopath.AnchoredSystemPath
-
- // OUTPUT
- calculatedAnchor turbopath.AbsoluteSystemPath
- pathSegments []turbopath.RelativeSystemPath
- }{
- {
- name: "hello world",
- cachedDirTree: cachedDirTree{
- anchorAtDepth: []turbopath.AbsoluteSystemPath{testDir},
- prefix: []turbopath.RelativeSystemPath{},
- },
- path: turbopath.AnchoredUnixPath("hello/world").ToSystemPath(),
- calculatedAnchor: testDir,
- pathSegments: []turbopath.RelativeSystemPath{"hello", "world"},
- },
- {
- name: "has a cache",
- cachedDirTree: cachedDirTree{
- anchorAtDepth: []turbopath.AbsoluteSystemPath{
- testDir,
- testDir.UntypedJoin("hello"),
- },
- prefix: []turbopath.RelativeSystemPath{"hello"},
- },
- path: turbopath.AnchoredUnixPath("hello/world").ToSystemPath(),
- calculatedAnchor: testDir.UntypedJoin("hello"),
- pathSegments: []turbopath.RelativeSystemPath{"world"},
- },
- {
- name: "ask for yourself",
- cachedDirTree: cachedDirTree{
- anchorAtDepth: []turbopath.AbsoluteSystemPath{
- testDir,
- testDir.UntypedJoin("hello"),
- testDir.UntypedJoin("hello", "world"),
- },
- prefix: []turbopath.RelativeSystemPath{"hello", "world"},
- },
- path: turbopath.AnchoredUnixPath("hello/world").ToSystemPath(),
- calculatedAnchor: testDir.UntypedJoin("hello", "world"),
- pathSegments: []turbopath.RelativeSystemPath{},
- },
- {
- name: "three layer cake",
- cachedDirTree: cachedDirTree{
- anchorAtDepth: []turbopath.AbsoluteSystemPath{
- testDir,
- testDir.UntypedJoin("hello"),
- testDir.UntypedJoin("hello", "world"),
- },
- prefix: []turbopath.RelativeSystemPath{"hello", "world"},
- },
- path: turbopath.AnchoredUnixPath("hello/world/again").ToSystemPath(),
- calculatedAnchor: testDir.UntypedJoin("hello", "world"),
- pathSegments: []turbopath.RelativeSystemPath{"again"},
- },
- {
- name: "outside of cache hierarchy",
- cachedDirTree: cachedDirTree{
- anchorAtDepth: []turbopath.AbsoluteSystemPath{
- testDir,
- testDir.UntypedJoin("hello"),
- testDir.UntypedJoin("hello", "world"),
- },
- prefix: []turbopath.RelativeSystemPath{"hello", "world"},
- },
- path: turbopath.AnchoredUnixPath("somewhere/else").ToSystemPath(),
- calculatedAnchor: testDir,
- pathSegments: []turbopath.RelativeSystemPath{"somewhere", "else"},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- cr := tt.cachedDirTree
- calculatedAnchor, pathSegments := cr.getStartingPoint(tt.path)
- if !reflect.DeepEqual(calculatedAnchor, tt.calculatedAnchor) {
- t.Errorf("cachedDirTree.getStartingPoint() calculatedAnchor = %v, want %v", calculatedAnchor, tt.calculatedAnchor)
- }
- if !reflect.DeepEqual(pathSegments, tt.pathSegments) {
- t.Errorf("cachedDirTree.getStartingPoint() pathSegments = %v, want %v", pathSegments, tt.pathSegments)
- }
- })
- }
-}
diff --git a/cli/internal/cacheitem/restore_regular.go b/cli/internal/cacheitem/restore_regular.go
deleted file mode 100644
index ed8946e..0000000
--- a/cli/internal/cacheitem/restore_regular.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package cacheitem
-
-import (
- "archive/tar"
- "io"
- "os"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// restoreRegular restores a file.
-func restoreRegular(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, header *tar.Header, reader *tar.Reader) (turbopath.AnchoredSystemPath, error) {
- // Assuming this was a `turbo`-created input, we currently have an AnchoredUnixPath.
- // Assuming this is malicious input we don't really care if we do the wrong thing.
- processedName, err := canonicalizeName(header.Name)
- if err != nil {
- return "", err
- }
-
- // We need to traverse `processedName` from base to root split at
- // `os.Separator` to make sure we don't end up following a symlink
- // outside of the restore path.
- if err := safeMkdirFile(dirCache, anchor, processedName, header.Mode); err != nil {
- return "", err
- }
-
- // Create the file.
- if f, err := processedName.RestoreAnchor(anchor).OpenFile(os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.FileMode(header.Mode)); err != nil {
- return "", err
- } else if _, err := io.Copy(f, reader); err != nil {
- return "", err
- } else if err := f.Close(); err != nil {
- return "", err
- }
- return processedName, nil
-}
-
-// safeMkdirAll creates all directories, assuming that the leaf node is a file.
-func safeMkdirFile(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, processedName turbopath.AnchoredSystemPath, mode int64) error {
- isRootFile := processedName.Dir() == "."
- if !isRootFile {
- return safeMkdirAll(dirCache, anchor, processedName.Dir(), 0755)
- }
-
- return nil
-}
diff --git a/cli/internal/cacheitem/restore_symlink.go b/cli/internal/cacheitem/restore_symlink.go
deleted file mode 100644
index 4cb29f5..0000000
--- a/cli/internal/cacheitem/restore_symlink.go
+++ /dev/null
@@ -1,180 +0,0 @@
-package cacheitem
-
-import (
- "archive/tar"
- "io/fs"
- "os"
- "path/filepath"
-
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// restoreSymlink restores a symlink and errors if the target is missing.
-func restoreSymlink(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, header *tar.Header) (turbopath.AnchoredSystemPath, error) {
- processedName, canonicalizeNameErr := canonicalizeName(header.Name)
- if canonicalizeNameErr != nil {
- return "", canonicalizeNameErr
- }
-
- // Check to see if the target exists.
- processedLinkname := canonicalizeLinkname(anchor, processedName, header.Linkname)
- if _, err := os.Lstat(processedLinkname); err != nil {
- return "", errMissingSymlinkTarget
- }
-
- return actuallyRestoreSymlink(dirCache, anchor, processedName, header)
-}
-
-// restoreSymlinkMissingTarget restores a symlink and does not error if the target is missing.
-func restoreSymlinkMissingTarget(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, header *tar.Header) (turbopath.AnchoredSystemPath, error) {
- processedName, canonicalizeNameErr := canonicalizeName(header.Name)
- if canonicalizeNameErr != nil {
- return "", canonicalizeNameErr
- }
-
- return actuallyRestoreSymlink(dirCache, anchor, processedName, header)
-}
-
-func actuallyRestoreSymlink(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, processedName turbopath.AnchoredSystemPath, header *tar.Header) (turbopath.AnchoredSystemPath, error) {
- // We need to traverse `processedName` from base to root split at
- // `os.Separator` to make sure we don't end up following a symlink
- // outside of the restore path.
- if err := safeMkdirFile(dirCache, anchor, processedName, header.Mode); err != nil {
- return "", err
- }
-
- // Specify where we restoring this symlink.
- symlinkFrom := processedName.RestoreAnchor(anchor)
-
- // Remove any existing object at that location.
- // If it errors we'll catch it on creation.
- _ = symlinkFrom.Remove()
-
- // Create the symlink.
- // Explicitly uses the _original_ header.Linkname as the target.
- // This does not support file names with `\` in them in a cross-platform manner.
- symlinkErr := symlinkFrom.Symlink(header.Linkname)
- if symlinkErr != nil {
- return "", symlinkErr
- }
-
- // Darwin allows you to change the permissions of a symlink.
- lchmodErr := symlinkFrom.Lchmod(fs.FileMode(header.Mode))
- if lchmodErr != nil {
- return "", lchmodErr
- }
-
- return processedName, nil
-}
-
-// topologicallyRestoreSymlinks ensures that targets of symlinks are created in advance
-// of the things that link to them. It does this by topologically sorting all
-// of the symlinks. This also enables us to ensure we do not create cycles.
-func topologicallyRestoreSymlinks(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, symlinks []*tar.Header, tr *tar.Reader) ([]turbopath.AnchoredSystemPath, error) {
- restored := make([]turbopath.AnchoredSystemPath, 0)
- lookup := make(map[string]*tar.Header)
-
- var g dag.AcyclicGraph
- for _, header := range symlinks {
- processedName, err := canonicalizeName(header.Name)
- processedSourcename := canonicalizeLinkname(anchor, processedName, processedName.ToString())
- processedLinkname := canonicalizeLinkname(anchor, processedName, header.Linkname)
- if err != nil {
- return nil, err
- }
- g.Add(processedSourcename)
- g.Add(processedLinkname)
- g.Connect(dag.BasicEdge(processedLinkname, processedSourcename))
- lookup[processedSourcename] = header
- }
-
- cycles := g.Cycles()
- if cycles != nil {
- return restored, errCycleDetected
- }
-
- roots := make(dag.Set)
- for _, v := range g.Vertices() {
- if g.UpEdges(v).Len() == 0 {
- roots.Add(v)
- }
- }
-
- walkFunc := func(vertex dag.Vertex, depth int) error {
- key, ok := vertex.(string)
- if !ok {
- return nil
- }
- header, exists := lookup[key]
- if !exists {
- return nil
- }
-
- file, restoreErr := restoreSymlinkMissingTarget(dirCache, anchor, header)
- if restoreErr != nil {
- return restoreErr
- }
-
- restored = append(restored, file)
- return nil
- }
-
- walkError := g.DepthFirstWalk(roots, walkFunc)
- if walkError != nil {
- return restored, walkError
- }
-
- return restored, nil
-}
-
-// canonicalizeLinkname determines (lexically) what the resolved path on the
-// system will be when linkname is restored verbatim.
-func canonicalizeLinkname(anchor turbopath.AbsoluteSystemPath, processedName turbopath.AnchoredSystemPath, linkname string) string {
- // We don't know _anything_ about linkname. It could be any of:
- //
- // - Absolute Unix Path
- // - Absolute Windows Path
- // - Relative Unix Path
- // - Relative Windows Path
- //
- // We also can't _truly_ distinguish if the path is Unix or Windows.
- // Take for example: `/Users/turbobot/weird-filenames/\foo\/lol`
- // It is a valid file on Unix, but if we do slash conversion it breaks.
- // Or `i\am\a\normal\unix\file\but\super\nested\on\windows`.
- //
- // We also can't safely assume that paths in link targets on one platform
- // should be treated as targets for that platform. The author may be
- // generating an artifact that should work on Windows on a Unix device.
- //
- // Given all of that, our best option is to restore link targets _verbatim_.
- // No modification, no slash conversion.
- //
- // In order to DAG sort them, however, we do need to canonicalize them.
- // We canonicalize them as if we're restoring them verbatim.
- //
- // 0. We've extracted a version of `Clean` from stdlib which does nothing but
- // separator and traversal collapsing.
- cleanedLinkname := Clean(linkname)
-
- // 1. Check to see if the link target is absolute _on the current platform_.
- // If it is an absolute path it's canonical by rule.
- if filepath.IsAbs(cleanedLinkname) {
- return cleanedLinkname
- }
-
- // Remaining options:
- // - Absolute (other platform) Path
- // - Relative Unix Path
- // - Relative Windows Path
- //
- // At this point we simply assume that it's a relative path—no matter
- // which separators appear in it and where they appear, We can't do
- // anything else because the OS will also treat it like that when it is
- // a link target.
- //
- // We manually join these to avoid calls to stdlib's `Clean`.
- source := processedName.RestoreAnchor(anchor)
- canonicalized := source.Dir().ToString() + string(os.PathSeparator) + cleanedLinkname
- return Clean(canonicalized)
-}
diff --git a/cli/internal/cacheitem/restore_test.go b/cli/internal/cacheitem/restore_test.go
deleted file mode 100644
index a0a33d6..0000000
--- a/cli/internal/cacheitem/restore_test.go
+++ /dev/null
@@ -1,1493 +0,0 @@
-package cacheitem
-
-import (
- "archive/tar"
- "errors"
- "fmt"
- "io"
- "io/fs"
- "os"
- "path/filepath"
- "reflect"
- "runtime"
- "syscall"
- "testing"
-
- "github.com/DataDog/zstd"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-type tarFile struct {
- Body string
- *tar.Header
-}
-
-type restoreFile struct {
- Name turbopath.AnchoredUnixPath
- Linkname string
- fs.FileMode
-}
-
-// generateTar is used specifically to generate tar files that Turborepo would
-// rarely or never encounter without malicious or pathological inputs. We use it
-// to make sure that we respond well in these scenarios during restore attempts.
-func generateTar(t *testing.T, files []tarFile) turbopath.AbsoluteSystemPath {
- t.Helper()
- testDir := turbopath.AbsoluteSystemPath(t.TempDir())
- testArchivePath := testDir.UntypedJoin("out.tar")
-
- handle, handleCreateErr := testArchivePath.Create()
- assert.NilError(t, handleCreateErr, "os.Create")
-
- tw := tar.NewWriter(handle)
-
- for _, file := range files {
- if file.Header.Typeflag == tar.TypeReg {
- file.Header.Size = int64(len(file.Body))
- }
-
- writeHeaderErr := tw.WriteHeader(file.Header)
- assert.NilError(t, writeHeaderErr, "tw.WriteHeader")
-
- _, writeErr := tw.Write([]byte(file.Body))
- assert.NilError(t, writeErr, "tw.Write")
- }
-
- twCloseErr := tw.Close()
- assert.NilError(t, twCloseErr, "tw.Close")
-
- handleCloseErr := handle.Close()
- assert.NilError(t, handleCloseErr, "handle.Close")
-
- return testArchivePath
-}
-
-// compressTar splits the compression of a tar file so that we don't
-// accidentally diverge in tar creation while still being able to test
-// restoration from tar and from .tar.zst.
-func compressTar(t *testing.T, archivePath turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- t.Helper()
-
- inputHandle, inputHandleOpenErr := archivePath.Open()
- assert.NilError(t, inputHandleOpenErr, "os.Open")
-
- outputPath := archivePath + ".zst"
- outputHandle, outputHandleCreateErr := outputPath.Create()
- assert.NilError(t, outputHandleCreateErr, "os.Create")
-
- zw := zstd.NewWriter(outputHandle)
- _, copyError := io.Copy(zw, inputHandle)
- assert.NilError(t, copyError, "io.Copy")
-
- zwCloseErr := zw.Close()
- assert.NilError(t, zwCloseErr, "zw.Close")
-
- inputHandleCloseErr := inputHandle.Close()
- assert.NilError(t, inputHandleCloseErr, "inputHandle.Close")
-
- outputHandleCloseErr := outputHandle.Close()
- assert.NilError(t, outputHandleCloseErr, "outputHandle.Close")
-
- return outputPath
-}
-
-func generateAnchor(t *testing.T) turbopath.AbsoluteSystemPath {
- t.Helper()
- testDir := turbopath.AbsoluteSystemPath(t.TempDir())
- anchorPoint := testDir.UntypedJoin("anchor")
-
- mkdirErr := anchorPoint.Mkdir(0777)
- assert.NilError(t, mkdirErr, "Mkdir")
-
- return anchorPoint
-}
-
-func assertFileExists(t *testing.T, anchor turbopath.AbsoluteSystemPath, diskFile restoreFile) {
- t.Helper()
- // If we have gotten here we can assume this to be true.
- processedName := diskFile.Name.ToSystemPath()
- fullName := processedName.RestoreAnchor(anchor)
- fileInfo, err := fullName.Lstat()
- assert.NilError(t, err, "Lstat")
-
- assert.Equal(t, fileInfo.Mode()&fs.ModePerm, diskFile.FileMode&fs.ModePerm, "File has the expected permissions: "+processedName)
- assert.Equal(t, fileInfo.Mode()|fs.ModePerm, diskFile.FileMode|fs.ModePerm, "File has the expected mode.")
-
- if diskFile.FileMode&os.ModeSymlink != 0 {
- linkname, err := fullName.Readlink()
- assert.NilError(t, err, "Readlink")
-
- // We restore Linkname verbatim.
- assert.Equal(t, linkname, diskFile.Linkname, "Link target matches.")
- }
-}
-
-func TestOpen(t *testing.T) {
- type wantErr struct {
- unix error
- windows error
- }
- type wantOutput struct {
- unix []turbopath.AnchoredSystemPath
- windows []turbopath.AnchoredSystemPath
- }
- type wantFiles struct {
- unix []restoreFile
- windows []restoreFile
- }
- tests := []struct {
- name string
- tarFiles []tarFile
- wantOutput wantOutput
- wantFiles wantFiles
- wantErr wantErr
- }{
- {
- name: "cache optimized",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "one/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/three/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/three/file-one",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/three/file-two",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/a/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/a/file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/b/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/b/file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "one",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/three",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/three/file-one",
- FileMode: 0644,
- },
- {
- Name: "one/two/three/file-two",
- FileMode: 0644,
- },
- {
- Name: "one/two/a",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/a/file",
- FileMode: 0644,
- },
- {
- Name: "one/two/b",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/b/file",
- FileMode: 0644,
- },
- },
- windows: []restoreFile{
- {
- Name: "one",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/three",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/three/file-one",
- FileMode: 0666,
- },
- {
- Name: "one/two/three/file-two",
- FileMode: 0666,
- },
- {
- Name: "one/two/a",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/a/file",
- FileMode: 0666,
- },
- {
- Name: "one/two/b",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/b/file",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{
- "one",
- "one/two",
- "one/two/three",
- "one/two/three/file-one",
- "one/two/three/file-two",
- "one/two/a",
- "one/two/a/file",
- "one/two/b",
- "one/two/b/file",
- }.ToSystemPathArray(),
- },
- },
- {
- name: "pathological cache works",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "one/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/a/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/b/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/three/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/a/file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/b/file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/three/file-one",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/three/file-two",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "one",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/three",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/three/file-one",
- FileMode: 0644,
- },
- {
- Name: "one/two/three/file-two",
- FileMode: 0644,
- },
- {
- Name: "one/two/a",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/a/file",
- FileMode: 0644,
- },
- {
- Name: "one/two/b",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "one/two/b/file",
- FileMode: 0644,
- },
- },
- windows: []restoreFile{
- {
- Name: "one",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/three",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/three/file-one",
- FileMode: 0666,
- },
- {
- Name: "one/two/three/file-two",
- FileMode: 0666,
- },
- {
- Name: "one/two/a",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/a/file",
- FileMode: 0666,
- },
- {
- Name: "one/two/b",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "one/two/b/file",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{
- "one",
- "one/two",
- "one/two/a",
- "one/two/b",
- "one/two/three",
- "one/two/a/file",
- "one/two/b/file",
- "one/two/three/file-one",
- "one/two/three/file-two",
- }.ToSystemPathArray(),
- },
- },
- {
- name: "hello world",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "target",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "target",
- },
- {
- Header: &tar.Header{
- Name: "source",
- Linkname: "target",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "source",
- Linkname: "target",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Name: "target",
- FileMode: 0644,
- },
- },
- windows: []restoreFile{
- {
- Name: "source",
- Linkname: "target",
- FileMode: 0 | os.ModeSymlink | 0666,
- },
- {
- Name: "target",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"target", "source"}.ToSystemPathArray(),
- },
- },
- {
- name: "nested file",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "folder/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "folder/file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "file",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "folder",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "folder/file",
- FileMode: 0644,
- },
- },
- windows: []restoreFile{
- {
- Name: "folder",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "folder/file",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"folder", "folder/file"}.ToSystemPathArray(),
- },
- },
- {
- name: "nested symlink",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "folder/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "folder/symlink",
- Linkname: "../",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "folder/symlink/folder-sibling",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "folder-sibling",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "folder",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "folder/symlink",
- FileMode: 0 | os.ModeSymlink | 0777,
- Linkname: "../",
- },
- {
- Name: "folder/symlink/folder-sibling",
- FileMode: 0644,
- },
- {
- Name: "folder-sibling",
- FileMode: 0644,
- },
- },
- windows: []restoreFile{
- {
- Name: "folder",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "folder/symlink",
- FileMode: 0 | os.ModeSymlink | 0666,
- Linkname: "..\\",
- },
- {
- Name: "folder/symlink/folder-sibling",
- FileMode: 0666,
- },
- {
- Name: "folder-sibling",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"folder", "folder/symlink", "folder/symlink/folder-sibling"}.ToSystemPathArray(),
- },
- },
- {
- name: "pathological symlinks",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "one",
- Linkname: "two",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "two",
- Linkname: "three",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "three",
- Linkname: "real",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "real",
- Typeflag: tar.TypeReg,
- Mode: 0755,
- },
- Body: "real",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "one",
- Linkname: "two",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Name: "two",
- Linkname: "three",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Name: "three",
- Linkname: "real",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Name: "real",
- FileMode: 0 | 0755,
- },
- },
- windows: []restoreFile{
- {
- Name: "one",
- Linkname: "two",
- FileMode: 0 | os.ModeSymlink | 0666,
- },
- {
- Name: "two",
- Linkname: "three",
- FileMode: 0 | os.ModeSymlink | 0666,
- },
- {
- Name: "three",
- Linkname: "real",
- FileMode: 0 | os.ModeSymlink | 0666,
- },
- {
- Name: "real",
- FileMode: 0 | 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"real", "three", "two", "one"}.ToSystemPathArray(),
- },
- },
- {
- name: "place file at dir location",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "folder-not-file/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "folder-not-file/subfile",
- Typeflag: tar.TypeReg,
- Mode: 0755,
- },
- Body: "subfile",
- },
- {
- Header: &tar.Header{
- Name: "folder-not-file",
- Typeflag: tar.TypeReg,
- Mode: 0755,
- },
- Body: "this shouldn't work",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "folder-not-file",
- FileMode: 0 | os.ModeDir | 0755,
- },
- {
- Name: "folder-not-file/subfile",
- FileMode: 0755,
- },
- },
- windows: []restoreFile{
- {
- Name: "folder-not-file",
- FileMode: 0 | os.ModeDir | 0777,
- },
- {
- Name: "folder-not-file/subfile",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"folder-not-file", "folder-not-file/subfile"}.ToSystemPathArray(),
- },
- wantErr: wantErr{
- unix: syscall.EISDIR,
- windows: syscall.EISDIR,
- },
- },
- // {
- // name: "missing symlink with file at subdir",
- // tarFiles: []tarFile{
- // {
- // Header: &tar.Header{
- // Name: "one",
- // Linkname: "two",
- // Typeflag: tar.TypeSymlink,
- // Mode: 0777,
- // },
- // },
- // {
- // Header: &tar.Header{
- // Name: "one/file",
- // Typeflag: tar.TypeReg,
- // Mode: 0755,
- // },
- // Body: "file",
- // },
- // },
- // wantFiles: wantFiles{
- // unix: []restoreFile{
- // {
- // Name: "one",
- // Linkname: "two",
- // FileMode: 0 | os.ModeSymlink | 0777,
- // },
- // },
- // },
- // wantOutput: wantOutput{
- // unix: turbopath.AnchoredUnixPathArray{"one"}.ToSystemPathArray(),
- // windows: nil,
- // },
- // wantErr: wantErr{
- // unix: os.ErrExist,
- // windows: os.ErrExist,
- // },
- // },
- {
- name: "symlink cycle",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "one",
- Linkname: "two",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "two",
- Linkname: "three",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "three",
- Linkname: "one",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{},
- },
- wantOutput: wantOutput{
- unix: []turbopath.AnchoredSystemPath{},
- },
- wantErr: wantErr{
- unix: errCycleDetected,
- windows: errCycleDetected,
- },
- },
- {
- name: "symlink clobber",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "one",
- Linkname: "two",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "one",
- Linkname: "three",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "one",
- Linkname: "real",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "real",
- Typeflag: tar.TypeReg,
- Mode: 0755,
- },
- Body: "real",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "one",
- Linkname: "real",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- {
- Name: "real",
- FileMode: 0755,
- },
- },
- windows: []restoreFile{
- {
- Name: "one",
- Linkname: "real",
- FileMode: 0 | os.ModeSymlink | 0666,
- },
- {
- Name: "real",
- FileMode: 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"real", "one"}.ToSystemPathArray(),
- },
- },
- {
- name: "symlink traversal",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "escape",
- Linkname: "../",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "escape/file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "file",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "escape",
- Linkname: "../",
- FileMode: 0 | os.ModeSymlink | 0777,
- },
- },
- windows: []restoreFile{
- {
- Name: "escape",
- Linkname: "..\\",
- FileMode: 0 | os.ModeSymlink | 0666,
- },
- },
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"escape"}.ToSystemPathArray(),
- },
- wantErr: wantErr{
- unix: errTraversal,
- windows: errTraversal,
- },
- },
- {
- name: "Double indirection: file",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "up",
- Linkname: "../",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "link",
- Linkname: "up",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "link/outside-file",
- Typeflag: tar.TypeReg,
- Mode: 0755,
- },
- },
- },
- wantErr: wantErr{unix: errTraversal, windows: errTraversal},
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{
- "up",
- "link",
- }.ToSystemPathArray(),
- },
- },
- {
- name: "Double indirection: folder",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "up",
- Linkname: "../",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "link",
- Linkname: "up",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "link/level-one/level-two/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- },
- wantErr: wantErr{unix: errTraversal, windows: errTraversal},
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{
- "up",
- "link",
- }.ToSystemPathArray(),
- },
- },
- {
- name: "name traversal",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "../escape",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "file",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{},
- },
- wantOutput: wantOutput{
- unix: []turbopath.AnchoredSystemPath{},
- },
- wantErr: wantErr{
- unix: errNameMalformed,
- windows: errNameMalformed,
- },
- },
- {
- name: "windows unsafe",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "back\\slash\\file",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "file",
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{
- {
- Name: "back\\slash\\file",
- FileMode: 0644,
- },
- },
- windows: []restoreFile{},
- },
- wantOutput: wantOutput{
- unix: turbopath.AnchoredUnixPathArray{"back\\slash\\file"}.ToSystemPathArray(),
- windows: turbopath.AnchoredUnixPathArray{}.ToSystemPathArray(),
- },
- wantErr: wantErr{
- unix: nil,
- windows: errNameWindowsUnsafe,
- },
- },
- {
- name: "fifo (and others) unsupported",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "fifo",
- Typeflag: tar.TypeFifo,
- },
- },
- },
- wantFiles: wantFiles{
- unix: []restoreFile{},
- },
- wantOutput: wantOutput{
- unix: []turbopath.AnchoredSystemPath{},
- },
- wantErr: wantErr{
- unix: errUnsupportedFileType,
- windows: errUnsupportedFileType,
- },
- },
- }
- for _, tt := range tests {
- getTestFunc := func(compressed bool) func(t *testing.T) {
- return func(t *testing.T) {
- var archivePath turbopath.AbsoluteSystemPath
- if compressed {
- archivePath = compressTar(t, generateTar(t, tt.tarFiles))
- } else {
- archivePath = generateTar(t, tt.tarFiles)
- }
- anchor := generateAnchor(t)
-
- cacheItem, err := Open(archivePath)
- assert.NilError(t, err, "Open")
-
- restoreOutput, restoreErr := cacheItem.Restore(anchor)
- var desiredErr error
- if runtime.GOOS == "windows" {
- desiredErr = tt.wantErr.windows
- } else {
- desiredErr = tt.wantErr.unix
- }
- if desiredErr != nil {
- if !errors.Is(restoreErr, desiredErr) {
- t.Errorf("wanted err: %v, got err: %v", tt.wantErr, restoreErr)
- }
- } else {
- assert.NilError(t, restoreErr, "Restore")
- }
-
- outputComparison := tt.wantOutput.unix
- if runtime.GOOS == "windows" && tt.wantOutput.windows != nil {
- outputComparison = tt.wantOutput.windows
- }
-
- if !reflect.DeepEqual(restoreOutput, outputComparison) {
- t.Errorf("Restore() = %v, want %v", restoreOutput, outputComparison)
- }
-
- // Check files on disk.
- filesComparison := tt.wantFiles.unix
- if runtime.GOOS == "windows" && tt.wantFiles.windows != nil {
- filesComparison = tt.wantFiles.windows
- }
- for _, diskFile := range filesComparison {
- assertFileExists(t, anchor, diskFile)
- }
-
- assert.NilError(t, cacheItem.Close(), "Close")
- }
- }
- t.Run(tt.name+"zst", getTestFunc(true))
- t.Run(tt.name, getTestFunc(false))
- }
-}
-
-func Test_checkName(t *testing.T) {
- tests := []struct {
- path string
- wellFormed bool
- windowsSafe bool
- }{
- // Empty
- {
- path: "",
- wellFormed: false,
- windowsSafe: false,
- },
- // Bad prefix
- {
- path: ".",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "..",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "/",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "./",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "../",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad prefix, suffixed
- {
- path: "/a",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "./a",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "../a",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad Suffix
- {
- path: "/.",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "/..",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad Suffix, with prefix
- {
- path: "a/.",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "a/..",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad middle
- {
- path: "//",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "/./",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "/../",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad middle, prefixed
- {
- path: "a//",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "a/./",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "a/../",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad middle, suffixed
- {
- path: "//a",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "/./a",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "/../a",
- wellFormed: false,
- windowsSafe: true,
- },
- // Bad middle, wrapped
- {
- path: "a//a",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "a/./a",
- wellFormed: false,
- windowsSafe: true,
- },
- {
- path: "a/../a",
- wellFormed: false,
- windowsSafe: true,
- },
- // False positive tests
- {
- path: "...",
- wellFormed: true,
- windowsSafe: true,
- },
- {
- path: ".../a",
- wellFormed: true,
- windowsSafe: true,
- },
- {
- path: "a/...",
- wellFormed: true,
- windowsSafe: true,
- },
- {
- path: "a/.../a",
- wellFormed: true,
- windowsSafe: true,
- },
- {
- path: ".../...",
- wellFormed: true,
- windowsSafe: true,
- },
- }
- for _, tt := range tests {
- t.Run(fmt.Sprintf("Path: \"%v\"", tt.path), func(t *testing.T) {
- wellFormed, windowsSafe := checkName(tt.path)
- if wellFormed != tt.wellFormed || windowsSafe != tt.windowsSafe {
- t.Errorf("\nwantOutput: checkName(\"%v\") wellFormed = %v, windowsSafe %v\ngot: checkName(\"%v\") wellFormed = %v, windowsSafe %v", tt.path, tt.wellFormed, tt.windowsSafe, tt.path, wellFormed, windowsSafe)
- }
- })
- }
-}
-
-func Test_canonicalizeLinkname(t *testing.T) {
- // We're lying that this thing is absolute, but that's not relevant for tests.
- anchor := turbopath.AbsoluteSystemPath(filepath.Join("path", "to", "anchor"))
-
- tests := []struct {
- name string
- processedName turbopath.AnchoredSystemPath
- linkname string
- canonicalUnix string
- canonicalWindows string
- }{
- {
- name: "hello world",
- processedName: turbopath.AnchoredSystemPath("source"),
- linkname: "target",
- canonicalUnix: "path/to/anchor/target",
- canonicalWindows: "path\\to\\anchor\\target",
- },
- {
- name: "Unix path subdirectory traversal",
- processedName: turbopath.AnchoredUnixPath("child/source").ToSystemPath(),
- linkname: "../sibling/target",
- canonicalUnix: "path/to/anchor/sibling/target",
- canonicalWindows: "path\\to\\anchor\\sibling\\target",
- },
- {
- name: "Windows path subdirectory traversal",
- processedName: turbopath.AnchoredUnixPath("child/source").ToSystemPath(),
- linkname: "..\\sibling\\target",
- canonicalUnix: "path/to/anchor/child/..\\sibling\\target",
- canonicalWindows: "path\\to\\anchor\\sibling\\target",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- canonical := tt.canonicalUnix
- if runtime.GOOS == "windows" {
- canonical = tt.canonicalWindows
- }
- if got := canonicalizeLinkname(anchor, tt.processedName, tt.linkname); got != canonical {
- t.Errorf("canonicalizeLinkname() = %v, want %v", got, canonical)
- }
- })
- }
-}
-
-func Test_canonicalizeName(t *testing.T) {
- tests := []struct {
- name string
- fileName string
- want turbopath.AnchoredSystemPath
- wantErr error
- }{
- {
- name: "hello world",
- fileName: "test.txt",
- want: "test.txt",
- },
- {
- name: "directory",
- fileName: "something/",
- want: "something",
- },
- {
- name: "malformed name",
- fileName: "//",
- want: "",
- wantErr: errNameMalformed,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got, err := canonicalizeName(tt.fileName)
- if tt.wantErr != nil && !errors.Is(err, tt.wantErr) {
- t.Errorf("canonicalizeName() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("canonicalizeName() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestCacheItem_Restore(t *testing.T) {
- tests := []struct {
- name string
- tarFiles []tarFile
- want []turbopath.AnchoredSystemPath
- }{
- {
- name: "duplicate restores",
- tarFiles: []tarFile{
- {
- Header: &tar.Header{
- Name: "target",
- Typeflag: tar.TypeReg,
- Mode: 0644,
- },
- Body: "target",
- },
- {
- Header: &tar.Header{
- Name: "source",
- Linkname: "target",
- Typeflag: tar.TypeSymlink,
- Mode: 0777,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- {
- Header: &tar.Header{
- Name: "one/two/",
- Typeflag: tar.TypeDir,
- Mode: 0755,
- },
- },
- },
- want: turbopath.AnchoredUnixPathArray{"target", "source", "one", "one/two"}.ToSystemPathArray(),
- },
- }
- for _, tt := range tests {
- getTestFunc := func(compressed bool) func(t *testing.T) {
- return func(t *testing.T) {
- var archivePath turbopath.AbsoluteSystemPath
- if compressed {
- archivePath = compressTar(t, generateTar(t, tt.tarFiles))
- } else {
- archivePath = generateTar(t, tt.tarFiles)
- }
- anchor := generateAnchor(t)
-
- cacheItem, err := Open(archivePath)
- assert.NilError(t, err, "Open")
-
- restoreOutput, restoreErr := cacheItem.Restore(anchor)
- if !reflect.DeepEqual(restoreOutput, tt.want) {
- t.Errorf("#1 CacheItem.Restore() = %v, want %v", restoreOutput, tt.want)
- }
- assert.NilError(t, restoreErr, "Restore #1")
- assert.NilError(t, cacheItem.Close(), "Close")
-
- cacheItem2, err2 := Open(archivePath)
- assert.NilError(t, err2, "Open")
-
- restoreOutput2, restoreErr2 := cacheItem2.Restore(anchor)
- if !reflect.DeepEqual(restoreOutput2, tt.want) {
- t.Errorf("#2 CacheItem.Restore() = %v, want %v", restoreOutput2, tt.want)
- }
- assert.NilError(t, restoreErr2, "Restore #2")
- assert.NilError(t, cacheItem2.Close(), "Close")
- }
- }
- t.Run(tt.name+"zst", getTestFunc(true))
- t.Run(tt.name, getTestFunc(false))
- }
-}
diff --git a/cli/internal/chrometracing/chrometracing.go b/cli/internal/chrometracing/chrometracing.go
deleted file mode 100644
index d9325fd..0000000
--- a/cli/internal/chrometracing/chrometracing.go
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package chrometracing writes per-process Chrome trace_event files that can be
-// loaded into chrome://tracing.
-package chrometracing
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
-
- "github.com/google/chrometracing/traceinternal"
-)
-
-var trace = struct {
- start time.Time
- pid uint64
-
- fileMu sync.Mutex
- file *os.File
-}{
- pid: uint64(os.Getpid()),
-}
-
-var out = setup(false)
-
-// Path returns the full path of the chrome://tracing trace_event file for
-// display in log messages.
-func Path() string { return out }
-
-// EnableTracing turns on tracing, regardless of running in a test or
-// not. Tracing is enabled by default if the CHROMETRACING_DIR environment
-// variable is present and non-empty.
-func EnableTracing() {
- trace.fileMu.Lock()
- alreadyEnabled := trace.file != nil
- trace.fileMu.Unlock()
- if alreadyEnabled {
- return
- }
- out = setup(true)
-}
-
-func setup(overrideEnable bool) string {
- inTest := os.Getenv("TEST_TMPDIR") != ""
- explicitlyEnabled := os.Getenv("CHROMETRACING_DIR") != ""
- enableTracing := inTest || explicitlyEnabled || overrideEnable
- if !enableTracing {
- return ""
- }
-
- var err error
- dir := os.Getenv("TEST_UNDECLARED_OUTPUTS_DIR")
- if dir == "" {
- dir = os.Getenv("CHROMETRACING_DIR")
- }
- if dir == "" {
- dir = os.TempDir()
- }
- fn := filepath.Join(dir, fmt.Sprintf("%s.%d.trace", filepath.Base(os.Args[0]), trace.pid))
- trace.file, err = os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0644)
- if err != nil {
- // Using the log package from func init results in an error message
- // being printed.
- fmt.Fprintf(os.Stderr, "continuing without tracing: %v\n", err)
- return ""
- }
-
- // We only ever open a JSON array. Ending the array is optional as per
- // go/trace_event so that not cleanly finished traces can still be read.
- trace.file.Write([]byte{'['})
- trace.start = time.Now()
-
- writeEvent(&traceinternal.ViewerEvent{
- Name: "process_name",
- Phase: "M", // Metadata Event
- Pid: trace.pid,
- Tid: trace.pid,
- Arg: struct {
- Name string `json:"name"`
- }{
- Name: strings.Join(os.Args, " "),
- },
- })
- return fn
-}
-
-func writeEvent(ev *traceinternal.ViewerEvent) {
- b, err := json.Marshal(&ev)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- return
- }
- trace.fileMu.Lock()
- defer trace.fileMu.Unlock()
- if _, err = trace.file.Write(b); err != nil {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- return
- }
- if _, err = trace.file.Write([]byte{',', '\n'}); err != nil {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- return
- }
-}
-
-const (
- begin = "B"
- end = "E"
-)
-
-// A PendingEvent represents an ongoing unit of work. The begin trace event has
-// already been written, and calling Done will write the end trace event.
-type PendingEvent struct {
- name string
- tid uint64
-}
-
-// Done writes the end trace event for this unit of work.
-func (pe *PendingEvent) Done() {
- if pe == nil || pe.name == "" || trace.file == nil {
- return
- }
- writeEvent(&traceinternal.ViewerEvent{
- Name: pe.name,
- Phase: end,
- Pid: trace.pid,
- Tid: pe.tid,
- Time: float64(time.Since(trace.start).Microseconds()),
- })
- releaseTid(pe.tid)
-}
-
-// Event logs a unit of work. To instrument a Go function, use e.g.:
-//
-// func calcPi() {
-// defer chrometracing.Event("calculate pi").Done()
-// // …
-// }
-//
-// For more finely-granular traces, use e.g.:
-//
-// for _, cmd := range commands {
-// ev := chrometracing.Event("initialize " + cmd.Name)
-// cmd.Init()
-// ev.Done()
-// }
-func Event(name string) *PendingEvent {
- if trace.file == nil {
- return &PendingEvent{}
- }
- tid := tid()
- writeEvent(&traceinternal.ViewerEvent{
- Name: name,
- Phase: begin,
- Pid: trace.pid,
- Tid: tid,
- Time: float64(time.Since(trace.start).Microseconds()),
- })
- return &PendingEvent{
- name: name,
- tid: tid,
- }
-}
-
-// tids is a chrome://tracing thread id pool. Go does not permit accessing the
-// goroutine id, so we need to maintain our own identifier. The chrome://tracing
-// file format requires a numeric thread id, so we just increment whenever we
-// need a thread id, and reuse the ones no longer in use.
-//
-// In practice, parallelized sections of the code (many goroutines) end up using
-// only as few thread ids as are concurrently in use, and the rest of the events
-// mirror the code call stack nicely. See e.g. http://screen/7MPcAcvXQNUE3JZ
-var tids struct {
- sync.Mutex
-
- // We allocate chrome://tracing thread ids based on the index of the
- // corresponding entry in the used slice.
- used []bool
-
- // next points to the earliest unused tid to consider for the next tid to
- // hand out. This is purely a performance optimization to avoid O(n) slice
- // iteration.
- next int
-}
-
-func tid() uint64 {
- tids.Lock()
- defer tids.Unlock()
- // re-use released tids if any
- for t := tids.next; t < len(tids.used); t++ {
- if !tids.used[t] {
- tids.used[t] = true
- tids.next = t + 1
- return uint64(t)
- }
- }
- // allocate a new tid
- t := len(tids.used)
- tids.used = append(tids.used, true)
- tids.next = t + 1
- return uint64(t)
-}
-
-func releaseTid(t uint64) {
- tids.Lock()
- defer tids.Unlock()
- tids.used[int(t)] = false
- if tids.next > int(t) {
- tids.next = int(t)
- }
-}
diff --git a/cli/internal/chrometracing/chrometracing_close.go b/cli/internal/chrometracing/chrometracing_close.go
deleted file mode 100644
index 1b3a7b9..0000000
--- a/cli/internal/chrometracing/chrometracing_close.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package chrometracing
-
-// Close overwrites the trailing (,\n) with (]\n) and closes the trace file.
-// Close is implemented in a separate file to keep a separation between custom
-// code and upstream from github.com/google/chrometracing. Additionally, we can
-// enable linting for code we author, while leaving upstream code alone.
-func Close() error {
- trace.fileMu.Lock()
- defer trace.fileMu.Unlock()
- // Seek backwards two bytes (,\n)
- if _, err := trace.file.Seek(-2, 1); err != nil {
- return err
- }
- // Write 1 byte, ']', leaving the trailing '\n' in place
- if _, err := trace.file.Write([]byte{']'}); err != nil {
- return err
- }
- // Force the filesystem to write to disk
- if err := trace.file.Sync(); err != nil {
- return err
- }
- if err := trace.file.Close(); err != nil {
- return err
- }
- return nil
-}
diff --git a/cli/internal/ci/ci.go b/cli/internal/ci/ci.go
deleted file mode 100644
index a22ad78..0000000
--- a/cli/internal/ci/ci.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Package ci is a simple utility to check if a program is being executed in common CI/CD/PaaS vendors.
-// This is a partial port of https://github.com/watson/ci-info
-package ci
-
-import "os"
-
-var isCI = os.Getenv("BUILD_ID") != "" || os.Getenv("BUILD_NUMBER") != "" || os.Getenv("CI") != "" || os.Getenv("CI_APP_ID") != "" || os.Getenv("CI_BUILD_ID") != "" || os.Getenv("CI_BUILD_NUMBER") != "" || os.Getenv("CI_NAME") != "" || os.Getenv("CONTINUOUS_INTEGRATION") != "" || os.Getenv("RUN_ID") != "" || os.Getenv("TEAMCITY_VERSION") != "" || false
-
-// IsCi returns true if the program is executing in a CI/CD environment
-func IsCi() bool {
- return isCI
-}
-
-// Name returns the name of the CI vendor
-func Name() string {
- return Info().Name
-}
-
-// Constant returns the name of the CI vendor as a constant
-func Constant() string {
- return Info().Constant
-}
-
-// Info returns information about a CI vendor
-func Info() Vendor {
- // check both the env var key and value
- for _, env := range Vendors {
- if env.EvalEnv != nil {
- for name, value := range env.EvalEnv {
- if os.Getenv(name) == value {
- return env
- }
- }
- } else {
- // check for any of the listed env var keys, with any value
- if env.Env.Any != nil && len(env.Env.Any) > 0 {
- for _, envVar := range env.Env.Any {
- if os.Getenv(envVar) != "" {
- return env
- }
- }
- // check for all of the listed env var keys, with any value
- } else if env.Env.All != nil && len(env.Env.All) > 0 {
- all := true
- for _, envVar := range env.Env.All {
- if os.Getenv(envVar) == "" {
- all = false
- break
- }
- }
- if all {
- return env
- }
- }
- }
- }
- return Vendor{}
-}
diff --git a/cli/internal/ci/ci_test.go b/cli/internal/ci/ci_test.go
deleted file mode 100644
index 333ff61..0000000
--- a/cli/internal/ci/ci_test.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package ci
-
-import (
- "os"
- "reflect"
- "strings"
- "testing"
-)
-
-func getVendor(name string) Vendor {
- for _, v := range Vendors {
- if v.Name == name {
- return v
- }
- }
- return Vendor{}
-}
-
-func TestInfo(t *testing.T) {
- tests := []struct {
- name string
- setEnv []string
- want Vendor
- }{
- {
- name: "AppVeyor",
- setEnv: []string{"APPVEYOR"},
- want: getVendor("AppVeyor"),
- },
- {
- name: "Vercel",
- setEnv: []string{"VERCEL", "NOW_BUILDER"},
- want: getVendor("Vercel"),
- },
- {
- name: "Render",
- setEnv: []string{"RENDER"},
- want: getVendor("Render"),
- },
- {
- name: "Netlify",
- setEnv: []string{"NETLIFY"},
- want: getVendor("Netlify CI"),
- },
- {
- name: "Jenkins",
- setEnv: []string{"BUILD_ID", "JENKINS_URL"},
- want: getVendor("Jenkins"),
- },
- {
- name: "Jenkins - failing",
- setEnv: []string{"BUILD_ID"},
- want: getVendor(""),
- },
- {
- name: "GitHub Actions",
- setEnv: []string{"GITHUB_ACTIONS"},
- want: getVendor("GitHub Actions"),
- },
- {
- name: "Codeship",
- setEnv: []string{"CI_NAME=codeship"},
- want: getVendor("Codeship"),
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- // unset existing envs
- liveCi := ""
- if Name() == "GitHub Actions" {
- liveCi = os.Getenv("GITHUB_ACTIONS")
- err := os.Unsetenv("GITHUB_ACTIONS")
- if err != nil {
- t.Errorf("Error un-setting GITHUB_ACTIONS env: %s", err)
- }
- }
- // set envs
- for _, env := range tt.setEnv {
- envParts := strings.Split(env, "=")
- val := "some value"
- if len(envParts) > 1 {
- val = envParts[1]
- }
- err := os.Setenv(envParts[0], val)
- if err != nil {
- t.Errorf("Error setting %s for %s test", envParts[0], tt.name)
- }
- defer os.Unsetenv(envParts[0]) //nolint errcheck
-
- }
- // run test
- if got := Info(); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("Info() = %v, want %v", got, tt.want)
- }
-
- // reset env
- if Name() == "GitHub Actions" {
- err := os.Setenv("GITHUB_ACTIONS", liveCi)
- if err != nil {
- t.Errorf("Error re-setting GITHUB_ACTIONS env: %s", err)
- }
- }
- })
- }
-}
diff --git a/cli/internal/ci/vendors.go b/cli/internal/ci/vendors.go
deleted file mode 100644
index 13bce77..0000000
--- a/cli/internal/ci/vendors.go
+++ /dev/null
@@ -1,253 +0,0 @@
-package ci
-
-type vendorEnvs struct {
- Any []string
- All []string
-}
-
-// Vendor describes a CI/CD vendor execution environment
-type Vendor struct {
- // Name is the name of the vendor
- Name string
- // Constant is the environment variable prefix used by the vendor
- Constant string
- // Env is one or many environment variables that can be used to quickly determine the vendor (using simple os.Getenv(env) check)
- Env vendorEnvs
- // EvalEnv is key/value map of environment variables that can be used to quickly determine the vendor
- EvalEnv map[string]string
-}
-
-// Vendors is a list of common CI/CD vendors (from https://github.com/watson/ci-info/blob/master/vendors.json)
-var Vendors = []Vendor{
- {
- Name: "Appcircle",
- Constant: "APPCIRCLE",
- Env: vendorEnvs{Any: []string{"AC_APPCIRCLE"}},
- },
- {
- Name: "AppVeyor",
- Constant: "APPVEYOR",
- Env: vendorEnvs{Any: []string{"APPVEYOR"}},
- },
- {
- Name: "AWS CodeBuild",
- Constant: "CODEBUILD",
- Env: vendorEnvs{Any: []string{"CODEBUILD_BUILD_ARN"}},
- },
- {
- Name: "Azure Pipelines",
- Constant: "AZURE_PIPELINES",
- Env: vendorEnvs{Any: []string{"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"}},
- },
- {
- Name: "Bamboo",
- Constant: "BAMBOO",
- Env: vendorEnvs{Any: []string{"bamboo_planKey"}},
- },
- {
- Name: "Bitbucket Pipelines",
- Constant: "BITBUCKET",
- Env: vendorEnvs{Any: []string{"BITBUCKET_COMMIT"}},
- },
- {
- Name: "Bitrise",
- Constant: "BITRISE",
- Env: vendorEnvs{Any: []string{"BITRISE_IO"}},
- },
- {
- Name: "Buddy",
- Constant: "BUDDY",
- Env: vendorEnvs{Any: []string{"BUDDY_WORKSPACE_ID"}},
- },
- {
- Name: "Buildkite",
- Constant: "BUILDKITE",
- Env: vendorEnvs{Any: []string{"BUILDKITE"}},
- },
- {
- Name: "CircleCI",
- Constant: "CIRCLE",
- Env: vendorEnvs{Any: []string{"CIRCLECI"}},
- },
- {
- Name: "Cirrus CI",
- Constant: "CIRRUS",
- Env: vendorEnvs{Any: []string{"CIRRUS_CI"}},
- },
- {
- Name: "Codefresh",
- Constant: "CODEFRESH",
- Env: vendorEnvs{Any: []string{"CF_BUILD_ID"}},
- },
- {
- Name: "Codemagic",
- Constant: "CODEMAGIC",
- Env: vendorEnvs{Any: []string{"CM_BUILD_ID"}},
- },
- {
- Name: "Codeship",
- Constant: "CODESHIP",
- EvalEnv: map[string]string{
- "CI_NAME": "codeship",
- },
- },
- {
- Name: "Drone",
- Constant: "DRONE",
- Env: vendorEnvs{Any: []string{"DRONE"}},
- },
- {
- Name: "dsari",
- Constant: "DSARI",
- Env: vendorEnvs{Any: []string{"DSARI"}},
- },
- {
- Name: "Expo Application Services",
- Constant: "EAS",
- Env: vendorEnvs{Any: []string{"EAS_BUILD"}},
- },
- {
- Name: "GitHub Actions",
- Constant: "GITHUB_ACTIONS",
- Env: vendorEnvs{Any: []string{"GITHUB_ACTIONS"}},
- },
- {
- Name: "GitLab CI",
- Constant: "GITLAB",
- Env: vendorEnvs{Any: []string{"GITLAB_CI"}},
- },
- {
- Name: "GoCD",
- Constant: "GOCD",
- Env: vendorEnvs{Any: []string{"GO_PIPELINE_LABEL"}},
- },
- {
- Name: "Google Cloud Build",
- Constant: "GOOGLE_CLOUD_BUILD",
- Env: vendorEnvs{Any: []string{"BUILDER_OUTPUT"}},
- },
- {
- Name: "LayerCI",
- Constant: "LAYERCI",
- Env: vendorEnvs{Any: []string{"LAYERCI"}},
- },
- {
- Name: "Gerrit",
- Constant: "GERRIT",
- Env: vendorEnvs{Any: []string{"GERRIT_PROJECT"}},
- },
- {
- Name: "Hudson",
- Constant: "HUDSON",
- Env: vendorEnvs{Any: []string{"HUDSON"}},
- },
- {
- Name: "Jenkins",
- Constant: "JENKINS",
- Env: vendorEnvs{All: []string{"JENKINS_URL", "BUILD_ID"}},
- },
- {
- Name: "Magnum CI",
- Constant: "MAGNUM",
- Env: vendorEnvs{Any: []string{"MAGNUM"}},
- },
- {
- Name: "Netlify CI",
- Constant: "NETLIFY",
- Env: vendorEnvs{Any: []string{"NETLIFY"}},
- },
- {
- Name: "Nevercode",
- Constant: "NEVERCODE",
- Env: vendorEnvs{Any: []string{"NEVERCODE"}},
- },
- {
- Name: "ReleaseHub",
- Constant: "RELEASEHUB",
- Env: vendorEnvs{Any: []string{"RELEASE_BUILD_ID"}},
- },
- {
- Name: "Render",
- Constant: "RENDER",
- Env: vendorEnvs{Any: []string{"RENDER"}},
- },
- {
- Name: "Sail CI",
- Constant: "SAIL",
- Env: vendorEnvs{Any: []string{"SAILCI"}},
- },
- {
- Name: "Screwdriver",
- Constant: "SCREWDRIVER",
- Env: vendorEnvs{Any: []string{"SCREWDRIVER"}},
- },
- {
- Name: "Semaphore",
- Constant: "SEMAPHORE",
- Env: vendorEnvs{Any: []string{"SEMAPHORE"}},
- },
- {
- Name: "Shippable",
- Constant: "SHIPPABLE",
- Env: vendorEnvs{Any: []string{"SHIPPABLE"}},
- },
- {
- Name: "Solano CI",
- Constant: "SOLANO",
- Env: vendorEnvs{Any: []string{"TDDIUM"}},
- },
- {
- Name: "Sourcehut",
- Constant: "SOURCEHUT",
- EvalEnv: map[string]string{
- "CI_NAME": "sourcehut",
- },
- },
- {
- Name: "Strider CD",
- Constant: "STRIDER",
- Env: vendorEnvs{Any: []string{"STRIDER"}},
- },
- {
- Name: "TaskCluster",
- Constant: "TASKCLUSTER",
- Env: vendorEnvs{All: []string{"TASK_ID", "RUN_ID"}},
- },
- {
- Name: "TeamCity",
- Constant: "TEAMCITY",
- Env: vendorEnvs{Any: []string{"TEAMCITY_VERSION"}},
- },
- {
- Name: "Travis CI",
- Constant: "TRAVIS",
- Env: vendorEnvs{Any: []string{"TRAVIS"}},
- },
- {
- Name: "Vercel",
- Constant: "VERCEL",
- Env: vendorEnvs{Any: []string{"NOW_BUILDER", "VERCEL"}},
- },
- {
- Name: "Visual Studio App Center",
- Constant: "APPCENTER",
- Env: vendorEnvs{Any: []string{"APPCENTER"}},
- },
- {
- Name: "Woodpecker",
- Constant: "WOODPECKER",
- EvalEnv: map[string]string{
- "CI": "woodpecker",
- },
- },
- {
- Name: "Xcode Cloud",
- Constant: "XCODE_CLOUD",
- Env: vendorEnvs{Any: []string{"CI_XCODE_PROJECT"}},
- },
- {
- Name: "Xcode Server",
- Constant: "XCODE_SERVER",
- Env: vendorEnvs{Any: []string{"XCS"}},
- },
-}
diff --git a/cli/internal/client/analytics.go b/cli/internal/client/analytics.go
deleted file mode 100644
index 71381f0..0000000
--- a/cli/internal/client/analytics.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package client
-
-import (
- "encoding/json"
-)
-
-// RecordAnalyticsEvents is a specific method for POSTing events to Vercel
-func (c *APIClient) RecordAnalyticsEvents(events []map[string]interface{}) error {
- body, err := json.Marshal(events)
- if err != nil {
- return err
-
- }
-
- // We don't care about the response here
- if _, err := c.JSONPost("/v8/artifacts/events", body); err != nil {
- return err
- }
-
- return nil
-}
diff --git a/cli/internal/client/cache.go b/cli/internal/client/cache.go
deleted file mode 100644
index 11ad87a..0000000
--- a/cli/internal/client/cache.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package client
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
-
- "github.com/hashicorp/go-retryablehttp"
- "github.com/vercel/turbo/cli/internal/ci"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// PutArtifact uploads an artifact associated with a given hash string to the remote cache
-func (c *APIClient) PutArtifact(hash string, artifactBody []byte, duration int, tag string) error {
- if err := c.okToRequest(); err != nil {
- return err
- }
- params := url.Values{}
- c.addTeamParam(&params)
- // only add a ? if it's actually needed (makes logging cleaner)
- encoded := params.Encode()
- if encoded != "" {
- encoded = "?" + encoded
- }
-
- requestURL := c.makeURL("/v8/artifacts/" + hash + encoded)
- allowAuth := true
- if c.usePreflight {
- resp, latestRequestURL, err := c.doPreflight(requestURL, http.MethodPut, "Content-Type, x-artifact-duration, Authorization, User-Agent, x-artifact-tag")
- if err != nil {
- return fmt.Errorf("pre-flight request failed before trying to store in HTTP cache: %w", err)
- }
- requestURL = latestRequestURL
- headers := resp.Header.Get("Access-Control-Allow-Headers")
- allowAuth = strings.Contains(strings.ToLower(headers), strings.ToLower("Authorization"))
- }
-
- req, err := retryablehttp.NewRequest(http.MethodPut, requestURL, artifactBody)
- req.Header.Set("Content-Type", "application/octet-stream")
- req.Header.Set("x-artifact-duration", fmt.Sprintf("%v", duration))
- if allowAuth {
- req.Header.Set("Authorization", "Bearer "+c.token)
- }
- req.Header.Set("User-Agent", c.userAgent())
- if ci.IsCi() {
- req.Header.Set("x-artifact-client-ci", ci.Constant())
- }
- if tag != "" {
- req.Header.Set("x-artifact-tag", tag)
- }
- if err != nil {
- return fmt.Errorf("[WARNING] Invalid cache URL: %w", err)
- }
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return fmt.Errorf("[ERROR] Failed to store files in HTTP cache: %w", err)
- }
- defer func() { _ = resp.Body.Close() }()
- if resp.StatusCode == http.StatusForbidden {
- return c.handle403(resp.Body)
- }
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("[ERROR] Failed to store files in HTTP cache: %s against URL %s", resp.Status, requestURL)
- }
- return nil
-}
-
-// FetchArtifact attempts to retrieve the build artifact with the given hash from the remote cache
-func (c *APIClient) FetchArtifact(hash string) (*http.Response, error) {
- return c.getArtifact(hash, http.MethodGet)
-}
-
-// ArtifactExists attempts to determine if the build artifact with the given hash exists in the Remote Caching server
-func (c *APIClient) ArtifactExists(hash string) (*http.Response, error) {
- return c.getArtifact(hash, http.MethodHead)
-}
-
-// getArtifact attempts to retrieve the build artifact with the given hash from the remote cache
-func (c *APIClient) getArtifact(hash string, httpMethod string) (*http.Response, error) {
- if httpMethod != http.MethodHead && httpMethod != http.MethodGet {
- return nil, fmt.Errorf("invalid httpMethod %v, expected GET or HEAD", httpMethod)
- }
-
- if err := c.okToRequest(); err != nil {
- return nil, err
- }
- params := url.Values{}
- c.addTeamParam(&params)
- // only add a ? if it's actually needed (makes logging cleaner)
- encoded := params.Encode()
- if encoded != "" {
- encoded = "?" + encoded
- }
-
- requestURL := c.makeURL("/v8/artifacts/" + hash + encoded)
- allowAuth := true
- if c.usePreflight {
- resp, latestRequestURL, err := c.doPreflight(requestURL, http.MethodGet, "Authorization, User-Agent")
- if err != nil {
- return nil, fmt.Errorf("pre-flight request failed before trying to fetch files in HTTP cache: %w", err)
- }
- requestURL = latestRequestURL
- headers := resp.Header.Get("Access-Control-Allow-Headers")
- allowAuth = strings.Contains(strings.ToLower(headers), strings.ToLower("Authorization"))
- }
-
- req, err := retryablehttp.NewRequest(httpMethod, requestURL, nil)
- if allowAuth {
- req.Header.Set("Authorization", "Bearer "+c.token)
- }
- req.Header.Set("User-Agent", c.userAgent())
- if err != nil {
- return nil, fmt.Errorf("invalid cache URL: %w", err)
- }
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return nil, fmt.Errorf("failed to fetch artifact: %v", err)
- } else if resp.StatusCode == http.StatusForbidden {
- err = c.handle403(resp.Body)
- _ = resp.Body.Close()
- return nil, err
- }
- return resp, nil
-}
-
-func (c *APIClient) handle403(body io.Reader) error {
- raw, err := ioutil.ReadAll(body)
- if err != nil {
- return fmt.Errorf("failed to read response %v", err)
- }
- apiError := &apiError{}
- err = json.Unmarshal(raw, apiError)
- if err != nil {
- return fmt.Errorf("failed to read response (%v): %v", string(raw), err)
- }
- disabledErr, err := apiError.cacheDisabled()
- if err != nil {
- return err
- }
- return disabledErr
-}
-
-type apiError struct {
- Code string `json:"code"`
- Message string `json:"message"`
-}
-
-func (ae *apiError) cacheDisabled() (*util.CacheDisabledError, error) {
- if strings.HasPrefix(ae.Code, "remote_caching_") {
- statusString := ae.Code[len("remote_caching_"):]
- status, err := util.CachingStatusFromString(statusString)
- if err != nil {
- return nil, err
- }
- return &util.CacheDisabledError{
- Status: status,
- Message: ae.Message,
- }, nil
- }
- return nil, fmt.Errorf("unknown status %v: %v", ae.Code, ae.Message)
-}
diff --git a/cli/internal/client/client.go b/cli/internal/client/client.go
deleted file mode 100644
index 822b2df..0000000
--- a/cli/internal/client/client.go
+++ /dev/null
@@ -1,309 +0,0 @@
-// Package client implements some interfaces and convenience methods to interact with Vercel APIs and Remote Cache
-package client
-
-import (
- "context"
- "crypto/x509"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "runtime"
- "strings"
- "sync/atomic"
- "time"
-
- "github.com/hashicorp/go-hclog"
- "github.com/hashicorp/go-retryablehttp"
- "github.com/vercel/turbo/cli/internal/ci"
-)
-
-// APIClient is the main interface for making network requests to Vercel
-type APIClient struct {
- // The api's base URL
- baseURL string
- token string
- turboVersion string
-
- // Must be used via atomic package
- currentFailCount uint64
- HTTPClient *retryablehttp.Client
- teamID string
- teamSlug string
- // Whether or not to send preflight requests before uploads
- usePreflight bool
-}
-
-// ErrTooManyFailures is returned from remote cache API methods after `maxRemoteFailCount` errors have occurred
-var ErrTooManyFailures = errors.New("skipping HTTP Request, too many failures have occurred")
-
-// _maxRemoteFailCount is the number of failed requests before we stop trying to upload/download
-// artifacts to the remote cache
-const _maxRemoteFailCount = uint64(3)
-
-// SetToken updates the APIClient's Token
-func (c *APIClient) SetToken(token string) {
- c.token = token
-}
-
-// RemoteConfig holds the authentication and endpoint details for the API client
-type RemoteConfig struct {
- Token string
- TeamID string
- TeamSlug string
- APIURL string
-}
-
-// Opts holds values for configuring the behavior of the API client
-type Opts struct {
- UsePreflight bool
- Timeout uint64
-}
-
-// ClientTimeout Exported ClientTimeout used in run.go
-const ClientTimeout uint64 = 20
-
-// NewClient creates a new APIClient
-func NewClient(remoteConfig RemoteConfig, logger hclog.Logger, turboVersion string, opts Opts) *APIClient {
- client := &APIClient{
- baseURL: remoteConfig.APIURL,
- turboVersion: turboVersion,
- HTTPClient: &retryablehttp.Client{
- HTTPClient: &http.Client{
- Timeout: time.Duration(opts.Timeout) * time.Second,
- },
- RetryWaitMin: 2 * time.Second,
- RetryWaitMax: 10 * time.Second,
- RetryMax: 2,
- Backoff: retryablehttp.DefaultBackoff,
- Logger: logger,
- },
- token: remoteConfig.Token,
- teamID: remoteConfig.TeamID,
- teamSlug: remoteConfig.TeamSlug,
- usePreflight: opts.UsePreflight,
- }
- client.HTTPClient.CheckRetry = client.checkRetry
- return client
-}
-
-// hasUser returns true if we have credentials for a user
-func (c *APIClient) hasUser() bool {
- return c.token != ""
-}
-
-// IsLinked returns true if we have a user and linked team
-func (c *APIClient) IsLinked() bool {
- return c.hasUser() && (c.teamID != "" || c.teamSlug != "")
-}
-
-// GetTeamID returns the currently configured team id
-func (c *APIClient) GetTeamID() string {
- return c.teamID
-}
-
-func (c *APIClient) retryCachePolicy(resp *http.Response, err error) (bool, error) {
- if err != nil {
- if errors.As(err, &x509.UnknownAuthorityError{}) {
- // Don't retry if the error was due to TLS cert verification failure.
- atomic.AddUint64(&c.currentFailCount, 1)
- return false, err
- }
- atomic.AddUint64(&c.currentFailCount, 1)
- return true, nil
- }
-
- // 429 Too Many Requests is recoverable. Sometimes the server puts
- // a Retry-After response header to indicate when the server is
- // available to start processing request from client.
- if resp.StatusCode == http.StatusTooManyRequests {
- atomic.AddUint64(&c.currentFailCount, 1)
- return true, nil
- }
-
- // Check the response code. We retry on 500-range responses to allow
- // the server time to recover, as 500's are typically not permanent
- // errors and may relate to outages on the server side. This will catch
- // invalid response codes as well, like 0 and 999.
- if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) {
- atomic.AddUint64(&c.currentFailCount, 1)
- return true, fmt.Errorf("unexpected HTTP status %s", resp.Status)
- }
-
- // swallow the error and stop retrying
- return false, nil
-}
-
-func (c *APIClient) checkRetry(ctx context.Context, resp *http.Response, err error) (bool, error) {
- // do not retry on context.Canceled or context.DeadlineExceeded
- if ctx.Err() != nil {
- atomic.AddUint64(&c.currentFailCount, 1)
- return false, ctx.Err()
- }
-
- // we're squashing the error from the request and substituting any error that might come
- // from our retry policy.
- shouldRetry, err := c.retryCachePolicy(resp, err)
- if shouldRetry {
- // Our policy says it's ok to retry, but we need to check the failure count
- if retryErr := c.okToRequest(); retryErr != nil {
- return false, retryErr
- }
- }
- return shouldRetry, err
-}
-
-// okToRequest returns nil if it's ok to make a request, and returns the error to
-// return to the caller if a request is not allowed
-func (c *APIClient) okToRequest() error {
- if atomic.LoadUint64(&c.currentFailCount) < _maxRemoteFailCount {
- return nil
- }
- return ErrTooManyFailures
-}
-
-func (c *APIClient) makeURL(endpoint string) string {
- return fmt.Sprintf("%v%v", c.baseURL, endpoint)
-}
-
-func (c *APIClient) userAgent() string {
- return fmt.Sprintf("turbo %v %v %v (%v)", c.turboVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
-}
-
-// doPreflight returns response with closed body, latest request url, and any errors to the caller
-func (c *APIClient) doPreflight(requestURL string, requestMethod string, requestHeaders string) (*http.Response, string, error) {
- req, err := retryablehttp.NewRequest(http.MethodOptions, requestURL, nil)
- req.Header.Set("User-Agent", c.userAgent())
- req.Header.Set("Access-Control-Request-Method", requestMethod)
- req.Header.Set("Access-Control-Request-Headers", requestHeaders)
- req.Header.Set("Authorization", "Bearer "+c.token)
- if err != nil {
- return nil, requestURL, fmt.Errorf("[WARNING] Invalid cache URL: %w", err)
- }
-
- // If resp is not nil, ignore any errors
- // because most likely unimportant for preflight to handle.
- // Let follow-up request handle potential errors.
- resp, err := c.HTTPClient.Do(req)
- if resp == nil {
- return resp, requestURL, err
- }
- defer resp.Body.Close() //nolint:golint,errcheck // nothing to do
- // The client will continue following 307, 308 redirects until it hits
- // max redirects, gets an error, or gets a normal response.
- // Get the url from the Location header or get the url used in the last
- // request (could have changed after following redirects).
- // Note that net/http client does not continue redirecting the preflight
- // request with the OPTIONS method for 301, 302, and 303 redirects.
- // See golang/go Issue 18570.
- if locationURL, err := resp.Location(); err == nil {
- requestURL = locationURL.String()
- } else {
- requestURL = resp.Request.URL.String()
- }
- return resp, requestURL, nil
-}
-
-func (c *APIClient) addTeamParam(params *url.Values) {
- if c.teamID != "" && strings.HasPrefix(c.teamID, "team_") {
- params.Add("teamId", c.teamID)
- }
- if c.teamSlug != "" {
- params.Add("slug", c.teamSlug)
- }
-}
-
-// JSONPatch sends a byte array (json.marshalled payload) to a given endpoint with PATCH
-func (c *APIClient) JSONPatch(endpoint string, body []byte) ([]byte, error) {
- resp, err := c.request(endpoint, http.MethodPatch, body)
- if err != nil {
- return nil, err
- }
-
- rawResponse, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, fmt.Errorf("failed to read response %v", err)
- }
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("%s", string(rawResponse))
- }
-
- return rawResponse, nil
-}
-
-// JSONPost sends a byte array (json.marshalled payload) to a given endpoint with POST
-func (c *APIClient) JSONPost(endpoint string, body []byte) ([]byte, error) {
- resp, err := c.request(endpoint, http.MethodPost, body)
- if err != nil {
- return nil, err
- }
-
- rawResponse, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, fmt.Errorf("failed to read response %v", err)
- }
-
- // For non 200/201 status codes, return the response body as an error
- if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
- return nil, fmt.Errorf("%s", string(rawResponse))
- }
-
- return rawResponse, nil
-}
-
-func (c *APIClient) request(endpoint string, method string, body []byte) (*http.Response, error) {
- if err := c.okToRequest(); err != nil {
- return nil, err
- }
-
- params := url.Values{}
- c.addTeamParam(&params)
- encoded := params.Encode()
- if encoded != "" {
- encoded = "?" + encoded
- }
-
- requestURL := c.makeURL(endpoint + encoded)
-
- allowAuth := true
- if c.usePreflight {
- resp, latestRequestURL, err := c.doPreflight(requestURL, method, "Authorization, User-Agent")
- if err != nil {
- return nil, fmt.Errorf("pre-flight request failed before trying to fetch files in HTTP cache: %w", err)
- }
-
- requestURL = latestRequestURL
- headers := resp.Header.Get("Access-Control-Allow-Headers")
- allowAuth = strings.Contains(strings.ToLower(headers), strings.ToLower("Authorization"))
- }
-
- req, err := retryablehttp.NewRequest(method, requestURL, body)
- if err != nil {
- return nil, err
- }
-
- // Set headers
- req.Header.Set("Content-Type", "application/json")
- req.Header.Set("User-Agent", c.userAgent())
-
- if allowAuth {
- req.Header.Set("Authorization", "Bearer "+c.token)
- }
-
- if ci.IsCi() {
- req.Header.Set("x-artifact-client-ci", ci.Constant())
- }
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return nil, err
- }
-
- // If there isn't a response, something else probably went wrong
- if resp == nil {
- return nil, fmt.Errorf("response from %s is nil, something went wrong", requestURL)
- }
-
- return resp, nil
-}
diff --git a/cli/internal/client/client_test.go b/cli/internal/client/client_test.go
deleted file mode 100644
index 36ff3fb..0000000
--- a/cli/internal/client/client_test.go
+++ /dev/null
@@ -1,159 +0,0 @@
-package client
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "io/ioutil"
- "net/http"
- "net/http/httptest"
- "reflect"
- "testing"
-
- "github.com/google/uuid"
- "github.com/hashicorp/go-hclog"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-func Test_sendToServer(t *testing.T) {
- ch := make(chan []byte, 1)
- ts := httptest.NewServer(
- http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- defer req.Body.Close()
- b, err := ioutil.ReadAll(req.Body)
- if err != nil {
- t.Errorf("failed to read request %v", err)
- }
- ch <- b
- w.WriteHeader(200)
- w.Write([]byte{})
- }))
- defer ts.Close()
-
- remoteConfig := RemoteConfig{
- TeamSlug: "my-team-slug",
- APIURL: ts.URL,
- Token: "my-token",
- }
- apiClient := NewClient(remoteConfig, hclog.Default(), "v1", Opts{})
-
- myUUID, err := uuid.NewUUID()
- if err != nil {
- t.Errorf("failed to create uuid %v", err)
- }
- events := []map[string]interface{}{
- {
- "sessionId": myUUID.String(),
- "hash": "foo",
- "source": "LOCAL",
- "event": "hit",
- },
- {
- "sessionId": myUUID.String(),
- "hash": "bar",
- "source": "REMOTE",
- "event": "MISS",
- },
- }
-
- apiClient.RecordAnalyticsEvents(events)
-
- body := <-ch
-
- result := []map[string]interface{}{}
- err = json.Unmarshal(body, &result)
- if err != nil {
- t.Errorf("unmarshalling body %v", err)
- }
- if !reflect.DeepEqual(events, result) {
- t.Errorf("roundtrip got %v, want %v", result, events)
- }
-}
-
-func Test_PutArtifact(t *testing.T) {
- ch := make(chan []byte, 1)
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- defer req.Body.Close()
- b, err := ioutil.ReadAll(req.Body)
- if err != nil {
- t.Errorf("failed to read request %v", err)
- }
- ch <- b
- w.WriteHeader(200)
- w.Write([]byte{})
- }))
- defer ts.Close()
-
- // Set up test expected values
- remoteConfig := RemoteConfig{
- TeamSlug: "my-team-slug",
- APIURL: ts.URL,
- Token: "my-token",
- }
- apiClient := NewClient(remoteConfig, hclog.Default(), "v1", Opts{})
- expectedArtifactBody := []byte("My string artifact")
-
- // Test Put Artifact
- apiClient.PutArtifact("hash", expectedArtifactBody, 500, "")
- testBody := <-ch
- if !bytes.Equal(expectedArtifactBody, testBody) {
- t.Errorf("Handler read '%v', wants '%v'", testBody, expectedArtifactBody)
- }
-
-}
-
-func Test_PutWhenCachingDisabled(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- defer func() { _ = req.Body.Close() }()
- w.WriteHeader(403)
- _, _ = w.Write([]byte("{\"code\": \"remote_caching_disabled\",\"message\":\"caching disabled\"}"))
- }))
- defer ts.Close()
-
- // Set up test expected values
- remoteConfig := RemoteConfig{
- TeamSlug: "my-team-slug",
- APIURL: ts.URL,
- Token: "my-token",
- }
- apiClient := NewClient(remoteConfig, hclog.Default(), "v1", Opts{})
- expectedArtifactBody := []byte("My string artifact")
- // Test Put Artifact
- err := apiClient.PutArtifact("hash", expectedArtifactBody, 500, "")
- cd := &util.CacheDisabledError{}
- if !errors.As(err, &cd) {
- t.Errorf("expected cache disabled error, got %v", err)
- }
- if cd.Status != util.CachingStatusDisabled {
- t.Errorf("caching status: expected %v, got %v", util.CachingStatusDisabled, cd.Status)
- }
-}
-
-func Test_FetchWhenCachingDisabled(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- defer func() { _ = req.Body.Close() }()
- w.WriteHeader(403)
- _, _ = w.Write([]byte("{\"code\": \"remote_caching_disabled\",\"message\":\"caching disabled\"}"))
- }))
- defer ts.Close()
-
- // Set up test expected values
- remoteConfig := RemoteConfig{
- TeamSlug: "my-team-slug",
- APIURL: ts.URL,
- Token: "my-token",
- }
- apiClient := NewClient(remoteConfig, hclog.Default(), "v1", Opts{})
- // Test Put Artifact
- resp, err := apiClient.FetchArtifact("hash")
- cd := &util.CacheDisabledError{}
- if !errors.As(err, &cd) {
- t.Errorf("expected cache disabled error, got %v", err)
- }
- if cd.Status != util.CachingStatusDisabled {
- t.Errorf("caching status: expected %v, got %v", util.CachingStatusDisabled, cd.Status)
- }
- if resp != nil {
- t.Errorf("response got %v, want <nil>", resp)
- }
-}
diff --git a/cli/internal/cmd/root.go b/cli/internal/cmd/root.go
deleted file mode 100644
index d8d0e33..0000000
--- a/cli/internal/cmd/root.go
+++ /dev/null
@@ -1,157 +0,0 @@
-// Package cmd holds the root cobra command for turbo
-package cmd
-
-import (
- "context"
- "fmt"
- "os"
- "runtime/pprof"
- "runtime/trace"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/daemon"
- "github.com/vercel/turbo/cli/internal/process"
- "github.com/vercel/turbo/cli/internal/prune"
- "github.com/vercel/turbo/cli/internal/run"
- "github.com/vercel/turbo/cli/internal/signals"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-func initializeOutputFiles(helper *cmdutil.Helper, parsedArgs *turbostate.ParsedArgsFromRust) error {
- if parsedArgs.Trace != "" {
- cleanup, err := createTraceFile(parsedArgs.Trace)
- if err != nil {
- return fmt.Errorf("failed to create trace file: %v", err)
- }
- helper.RegisterCleanup(cleanup)
- }
- if parsedArgs.Heap != "" {
- cleanup, err := createHeapFile(parsedArgs.Heap)
- if err != nil {
- return fmt.Errorf("failed to create heap file: %v", err)
- }
- helper.RegisterCleanup(cleanup)
- }
- if parsedArgs.CPUProfile != "" {
- cleanup, err := createCpuprofileFile(parsedArgs.CPUProfile)
- if err != nil {
- return fmt.Errorf("failed to create CPU profile file: %v", err)
- }
- helper.RegisterCleanup(cleanup)
- }
-
- return nil
-}
-
-// RunWithArgs runs turbo with the ParsedArgsFromRust that is passed from the Rust side.
-func RunWithArgs(args *turbostate.ParsedArgsFromRust, turboVersion string) int {
- util.InitPrintf()
- // TODO: replace this with a context
- signalWatcher := signals.NewWatcher()
- helper := cmdutil.NewHelper(turboVersion, args)
- ctx := context.Background()
-
- err := initializeOutputFiles(helper, args)
- if err != nil {
- fmt.Printf("%v", err)
- return 1
- }
- defer helper.Cleanup(args)
-
- doneCh := make(chan struct{})
- var execErr error
- go func() {
- command := args.Command
- if command.Daemon != nil {
- execErr = daemon.ExecuteDaemon(ctx, helper, signalWatcher, args)
- } else if command.Prune != nil {
- execErr = prune.ExecutePrune(helper, args)
- } else if command.Run != nil {
- execErr = run.ExecuteRun(ctx, helper, signalWatcher, args)
- } else {
- execErr = fmt.Errorf("unknown command: %v", command)
- }
-
- close(doneCh)
- }()
-
- // Wait for either our command to finish, in which case we need to clean up,
- // or to receive a signal, in which case the signal handler above does the cleanup
- select {
- case <-doneCh:
- // We finished whatever task we were running
- signalWatcher.Close()
- exitErr := &process.ChildExit{}
- if errors.As(execErr, &exitErr) {
- return exitErr.ExitCode
- } else if execErr != nil {
- fmt.Printf("Turbo error: %v\n", execErr)
- return 1
- }
- return 0
- case <-signalWatcher.Done():
- // We caught a signal, which already called the close handlers
- return 1
- }
-}
-
-type profileCleanup func() error
-
-// Close implements io.Close for profileCleanup
-func (pc profileCleanup) Close() error {
- return pc()
-}
-
-// To view a CPU trace, use "go tool trace [file]". Note that the trace
-// viewer doesn't work under Windows Subsystem for Linux for some reason.
-func createTraceFile(traceFile string) (profileCleanup, error) {
- f, err := os.Create(traceFile)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to create trace file: %v", traceFile)
- }
- if err := trace.Start(f); err != nil {
- return nil, errors.Wrap(err, "failed to start tracing")
- }
- return func() error {
- trace.Stop()
- return f.Close()
- }, nil
-}
-
-// To view a heap trace, use "go tool pprof [file]" and type "top". You can
-// also drop it into https://speedscope.app and use the "left heavy" or
-// "sandwich" view modes.
-func createHeapFile(heapFile string) (profileCleanup, error) {
- f, err := os.Create(heapFile)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to create heap file: %v", heapFile)
- }
- return func() error {
- if err := pprof.WriteHeapProfile(f); err != nil {
- // we don't care if we fail to close the file we just failed to write to
- _ = f.Close()
- return errors.Wrapf(err, "failed to write heap file: %v", heapFile)
- }
- return f.Close()
- }, nil
-}
-
-// To view a CPU profile, drop the file into https://speedscope.app.
-// Note: Running the CPU profiler doesn't work under Windows subsystem for
-// Linux. The profiler has to be built for native Windows and run using the
-// command prompt instead.
-func createCpuprofileFile(cpuprofileFile string) (profileCleanup, error) {
- f, err := os.Create(cpuprofileFile)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to create cpuprofile file: %v", cpuprofileFile)
- }
- if err := pprof.StartCPUProfile(f); err != nil {
- return nil, errors.Wrap(err, "failed to start CPU profiling")
- }
- return func() error {
- pprof.StopCPUProfile()
- return f.Close()
- }, nil
-}
diff --git a/cli/internal/cmdutil/cmdutil.go b/cli/internal/cmdutil/cmdutil.go
deleted file mode 100644
index 0b02392..0000000
--- a/cli/internal/cmdutil/cmdutil.go
+++ /dev/null
@@ -1,245 +0,0 @@
-// Package cmdutil holds functionality to run turbo via cobra. That includes flag parsing and configuration
-// of components common to all subcommands
-package cmdutil
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "sync"
-
- "github.com/hashicorp/go-hclog"
-
- "github.com/fatih/color"
- "github.com/mitchellh/cli"
- "github.com/vercel/turbo/cli/internal/client"
- "github.com/vercel/turbo/cli/internal/config"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "github.com/vercel/turbo/cli/internal/ui"
-)
-
-const (
- // _envLogLevel is the environment log level
- _envLogLevel = "TURBO_LOG_LEVEL"
-)
-
-// Helper is a struct used to hold configuration values passed via flag, env vars,
-// config files, etc. It is not intended for direct use by turbo commands, it drives
-// the creation of CmdBase, which is then used by the commands themselves.
-type Helper struct {
- // TurboVersion is the version of turbo that is currently executing
- TurboVersion string
-
- // for logging
- verbosity int
-
- rawRepoRoot string
-
- clientOpts client.Opts
-
- // UserConfigPath is the path to where we expect to find
- // a user-specific config file, if one is present. Public
- // to allow overrides in tests
- UserConfigPath turbopath.AbsoluteSystemPath
-
- cleanupsMu sync.Mutex
- cleanups []io.Closer
-}
-
-// RegisterCleanup saves a function to be run after turbo execution,
-// even if the command that runs returns an error
-func (h *Helper) RegisterCleanup(cleanup io.Closer) {
- h.cleanupsMu.Lock()
- defer h.cleanupsMu.Unlock()
- h.cleanups = append(h.cleanups, cleanup)
-}
-
-// Cleanup runs the register cleanup handlers. It requires the flags
-// to the root command so that it can construct a UI if necessary
-func (h *Helper) Cleanup(cliConfig *turbostate.ParsedArgsFromRust) {
- h.cleanupsMu.Lock()
- defer h.cleanupsMu.Unlock()
- var ui cli.Ui
- for _, cleanup := range h.cleanups {
- if err := cleanup.Close(); err != nil {
- if ui == nil {
- ui = h.getUI(cliConfig)
- }
- ui.Warn(fmt.Sprintf("failed cleanup: %v", err))
- }
- }
-}
-
-func (h *Helper) getUI(cliConfig *turbostate.ParsedArgsFromRust) cli.Ui {
- colorMode := ui.GetColorModeFromEnv()
- if cliConfig.GetNoColor() {
- colorMode = ui.ColorModeSuppressed
- }
- if cliConfig.GetColor() {
- colorMode = ui.ColorModeForced
- }
- return ui.BuildColoredUi(colorMode)
-}
-
-func (h *Helper) getLogger() (hclog.Logger, error) {
- var level hclog.Level
- switch h.verbosity {
- case 0:
- if v := os.Getenv(_envLogLevel); v != "" {
- level = hclog.LevelFromString(v)
- if level == hclog.NoLevel {
- return nil, fmt.Errorf("%s value %q is not a valid log level", _envLogLevel, v)
- }
- } else {
- level = hclog.NoLevel
- }
- case 1:
- level = hclog.Info
- case 2:
- level = hclog.Debug
- case 3:
- level = hclog.Trace
- default:
- level = hclog.Trace
- }
- // Default output is nowhere unless we enable logging.
- output := ioutil.Discard
- color := hclog.ColorOff
- if level != hclog.NoLevel {
- output = os.Stderr
- color = hclog.AutoColor
- }
-
- return hclog.New(&hclog.LoggerOptions{
- Name: "turbo",
- Level: level,
- Color: color,
- Output: output,
- }), nil
-}
-
-// NewHelper returns a new helper instance to hold configuration values for the root
-// turbo command.
-func NewHelper(turboVersion string, args *turbostate.ParsedArgsFromRust) *Helper {
- return &Helper{
- TurboVersion: turboVersion,
- UserConfigPath: config.DefaultUserConfigPath(),
- verbosity: args.Verbosity,
- }
-}
-
-// GetCmdBase returns a CmdBase instance configured with values from this helper.
-// It additionally returns a mechanism to set an error, so
-func (h *Helper) GetCmdBase(cliConfig *turbostate.ParsedArgsFromRust) (*CmdBase, error) {
- // terminal is for color/no-color output
- terminal := h.getUI(cliConfig)
- // logger is configured with verbosity level using --verbosity flag from end users
- logger, err := h.getLogger()
- if err != nil {
- return nil, err
- }
- cwdRaw, err := cliConfig.GetCwd()
- if err != nil {
- return nil, err
- }
- cwd, err := fs.GetCwd(cwdRaw)
- if err != nil {
- return nil, err
- }
- repoRoot := fs.ResolveUnknownPath(cwd, h.rawRepoRoot)
- repoRoot, err = repoRoot.EvalSymlinks()
- if err != nil {
- return nil, err
- }
- repoConfig, err := config.ReadRepoConfigFile(config.GetRepoConfigPath(repoRoot), cliConfig)
- if err != nil {
- return nil, err
- }
- userConfig, err := config.ReadUserConfigFile(h.UserConfigPath, cliConfig)
- if err != nil {
- return nil, err
- }
- remoteConfig := repoConfig.GetRemoteConfig(userConfig.Token())
- if remoteConfig.Token == "" && ui.IsCI {
- vercelArtifactsToken := os.Getenv("VERCEL_ARTIFACTS_TOKEN")
- vercelArtifactsOwner := os.Getenv("VERCEL_ARTIFACTS_OWNER")
- if vercelArtifactsToken != "" {
- remoteConfig.Token = vercelArtifactsToken
- }
- if vercelArtifactsOwner != "" {
- remoteConfig.TeamID = vercelArtifactsOwner
- }
- }
-
- // Primacy: Arg > Env
- timeout, err := cliConfig.GetRemoteCacheTimeout()
- if err == nil {
- h.clientOpts.Timeout = timeout
- } else {
- val, ok := os.LookupEnv("TURBO_REMOTE_CACHE_TIMEOUT")
- if ok {
- number, err := strconv.ParseUint(val, 10, 64)
- if err == nil {
- h.clientOpts.Timeout = number
- }
- }
- }
-
- apiClient := client.NewClient(
- remoteConfig,
- logger,
- h.TurboVersion,
- h.clientOpts,
- )
-
- return &CmdBase{
- UI: terminal,
- Logger: logger,
- RepoRoot: repoRoot,
- APIClient: apiClient,
- RepoConfig: repoConfig,
- UserConfig: userConfig,
- RemoteConfig: remoteConfig,
- TurboVersion: h.TurboVersion,
- }, nil
-}
-
-// CmdBase encompasses configured components common to all turbo commands.
-type CmdBase struct {
- UI cli.Ui
- Logger hclog.Logger
- RepoRoot turbopath.AbsoluteSystemPath
- APIClient *client.APIClient
- RepoConfig *config.RepoConfig
- UserConfig *config.UserConfig
- RemoteConfig client.RemoteConfig
- TurboVersion string
-}
-
-// LogError prints an error to the UI
-func (b *CmdBase) LogError(format string, args ...interface{}) {
- err := fmt.Errorf(format, args...)
- b.Logger.Error("error", err)
- b.UI.Error(fmt.Sprintf("%s%s", ui.ERROR_PREFIX, color.RedString(" %v", err)))
-}
-
-// LogWarning logs an error and outputs it to the UI.
-func (b *CmdBase) LogWarning(prefix string, err error) {
- b.Logger.Warn(prefix, "warning", err)
-
- if prefix != "" {
- prefix = " " + prefix + ": "
- }
-
- b.UI.Warn(fmt.Sprintf("%s%s%s", ui.WARNING_PREFIX, prefix, color.YellowString(" %v", err)))
-}
-
-// LogInfo logs an message and outputs it to the UI.
-func (b *CmdBase) LogInfo(msg string) {
- b.Logger.Info(msg)
- b.UI.Info(fmt.Sprintf("%s%s", ui.InfoPrefix, color.WhiteString(" %v", msg)))
-}
diff --git a/cli/internal/cmdutil/cmdutil_test.go b/cli/internal/cmdutil/cmdutil_test.go
deleted file mode 100644
index 4e6cf70..0000000
--- a/cli/internal/cmdutil/cmdutil_test.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package cmdutil
-
-import (
- "os"
- "testing"
- "time"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "gotest.tools/v3/assert"
-)
-
-func TestTokenEnvVar(t *testing.T) {
- // Set up an empty config so we're just testing environment variables
- userConfigPath := fs.AbsoluteSystemPathFromUpstream(t.TempDir()).UntypedJoin("turborepo", "config.json")
- expectedPrefix := "my-token"
- vars := []string{"TURBO_TOKEN", "VERCEL_ARTIFACTS_TOKEN"}
- for _, v := range vars {
- t.Run(v, func(t *testing.T) {
- t.Cleanup(func() {
- _ = os.Unsetenv(v)
- })
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- }
- h := NewHelper("test-version", args)
- h.UserConfigPath = userConfigPath
-
- expectedToken := expectedPrefix + v
- err := os.Setenv(v, expectedToken)
- if err != nil {
- t.Fatalf("setenv %v", err)
- }
-
- base, err := h.GetCmdBase(args)
- if err != nil {
- t.Fatalf("failed to get command base %v", err)
- }
- assert.Equal(t, base.RemoteConfig.Token, expectedToken)
- })
- }
-}
-
-func TestRemoteCacheTimeoutEnvVar(t *testing.T) {
- key := "TURBO_REMOTE_CACHE_TIMEOUT"
- expectedTimeout := "600"
- t.Run(key, func(t *testing.T) {
- t.Cleanup(func() {
- _ = os.Unsetenv(key)
- })
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- }
- h := NewHelper("test-version", args)
-
- err := os.Setenv(key, expectedTimeout)
- if err != nil {
- t.Fatalf("setenv %v", err)
- }
-
- base, err := h.GetCmdBase(args)
- if err != nil {
- t.Fatalf("failed to get command base %v", err)
- }
- assert.Equal(t, base.APIClient.HTTPClient.HTTPClient.Timeout, time.Duration(600)*time.Second)
- })
-}
-
-func TestRemoteCacheTimeoutFlag(t *testing.T) {
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- RemoteCacheTimeout: 599,
- }
- h := NewHelper("test-version", args)
-
- base, err := h.GetCmdBase(args)
- if err != nil {
- t.Fatalf("failed to get command base %v", err)
- }
-
- assert.Equal(t, base.APIClient.HTTPClient.HTTPClient.Timeout, time.Duration(599)*time.Second)
-}
-
-func TestRemoteCacheTimeoutPrimacy(t *testing.T) {
- key := "TURBO_REMOTE_CACHE_TIMEOUT"
- value := "2"
-
- t.Run(key, func(t *testing.T) {
- t.Cleanup(func() {
- _ = os.Unsetenv(key)
- })
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- RemoteCacheTimeout: 1,
- }
- h := NewHelper("test-version", args)
-
- err := os.Setenv(key, value)
- if err != nil {
- t.Fatalf("setenv %v", err)
- }
-
- base, err := h.GetCmdBase(args)
- if err != nil {
- t.Fatalf("failed to get command base %v", err)
- }
- assert.Equal(t, base.APIClient.HTTPClient.HTTPClient.Timeout, time.Duration(1)*time.Second)
- })
-}
diff --git a/cli/internal/colorcache/colorcache.go b/cli/internal/colorcache/colorcache.go
deleted file mode 100644
index 08a15e8..0000000
--- a/cli/internal/colorcache/colorcache.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package colorcache
-
-import (
- "sync"
-
- "github.com/vercel/turbo/cli/internal/util"
-
- "github.com/fatih/color"
-)
-
-type colorFn = func(format string, a ...interface{}) string
-
-func getTerminalPackageColors() []colorFn {
- return []colorFn{color.CyanString, color.MagentaString, color.GreenString, color.YellowString, color.BlueString}
-}
-
-type ColorCache struct {
- mu sync.Mutex
- index int
- TermColors []colorFn
- Cache map[interface{}]colorFn
-}
-
-// New creates an instance of ColorCache with helpers for adding colors to task outputs
-func New() *ColorCache {
- return &ColorCache{
- TermColors: getTerminalPackageColors(),
- index: 0,
- Cache: make(map[interface{}]colorFn),
- }
-}
-
-// colorForKey returns a color function for a given package name
-func (c *ColorCache) colorForKey(key string) colorFn {
- c.mu.Lock()
- defer c.mu.Unlock()
- colorFn, ok := c.Cache[key]
- if ok {
- return colorFn
- }
- c.index++
- colorFn = c.TermColors[util.PositiveMod(c.index, len(c.TermColors))] // 5 possible colors
- c.Cache[key] = colorFn
- return colorFn
-}
-
-// PrefixWithColor returns a string consisting of the provided prefix in a consistent
-// color based on the cacheKey
-func (c *ColorCache) PrefixWithColor(cacheKey string, prefix string) string {
- colorFn := c.colorForKey(cacheKey)
- if prefix != "" {
- return colorFn("%s: ", prefix)
- }
-
- return ""
-}
diff --git a/cli/internal/config/config_file.go b/cli/internal/config/config_file.go
deleted file mode 100644
index d3118b8..0000000
--- a/cli/internal/config/config_file.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package config
-
-import (
- "os"
-
- "github.com/spf13/viper"
- "github.com/vercel/turbo/cli/internal/client"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/turbostate"
-)
-
-// RepoConfig is a configuration object for the logged-in turborepo.com user
-type RepoConfig struct {
- repoViper *viper.Viper
- path turbopath.AbsoluteSystemPath
-}
-
-// LoginURL returns the configured URL for authenticating the user
-func (rc *RepoConfig) LoginURL() string {
- return rc.repoViper.GetString("loginurl")
-}
-
-// SetTeamID sets the teamID and clears the slug, since it may have been from an old team
-func (rc *RepoConfig) SetTeamID(teamID string) error {
- // Note that we can't use viper.Set to set a nil value, we have to merge it in
- newVals := map[string]interface{}{
- "teamid": teamID,
- "teamslug": nil,
- }
- if err := rc.repoViper.MergeConfigMap(newVals); err != nil {
- return err
- }
- return rc.write()
-}
-
-// GetRemoteConfig produces the necessary values for an API client configuration
-func (rc *RepoConfig) GetRemoteConfig(token string) client.RemoteConfig {
- return client.RemoteConfig{
- Token: token,
- TeamID: rc.repoViper.GetString("teamid"),
- TeamSlug: rc.repoViper.GetString("teamslug"),
- APIURL: rc.repoViper.GetString("apiurl"),
- }
-}
-
-// Internal call to save this config data to the user config file.
-func (rc *RepoConfig) write() error {
- if err := rc.path.EnsureDir(); err != nil {
- return err
- }
- return rc.repoViper.WriteConfig()
-}
-
-// Delete deletes the config file. This repo config shouldn't be used
-// afterwards, it needs to be re-initialized
-func (rc *RepoConfig) Delete() error {
- return rc.path.Remove()
-}
-
-// UserConfig is a wrapper around the user-specific configuration values
-// for Turborepo.
-type UserConfig struct {
- userViper *viper.Viper
- path turbopath.AbsoluteSystemPath
-}
-
-// Token returns the Bearer token for this user if it exists
-func (uc *UserConfig) Token() string {
- return uc.userViper.GetString("token")
-}
-
-// SetToken saves a Bearer token for this user, writing it to the
-// user config file, creating it if necessary
-func (uc *UserConfig) SetToken(token string) error {
- // Technically Set works here, due to how overrides work, but use merge for consistency
- if err := uc.userViper.MergeConfigMap(map[string]interface{}{"token": token}); err != nil {
- return err
- }
- return uc.write()
-}
-
-// Internal call to save this config data to the user config file.
-func (uc *UserConfig) write() error {
- if err := uc.path.EnsureDir(); err != nil {
- return err
- }
- return uc.userViper.WriteConfig()
-}
-
-// Delete deletes the config file. This user config shouldn't be used
-// afterwards, it needs to be re-initialized
-func (uc *UserConfig) Delete() error {
- return uc.path.Remove()
-}
-
-// ReadUserConfigFile creates a UserConfig using the
-// specified path as the user config file. Note that the path or its parents
-// do not need to exist. On a write to this configuration, they will be created.
-func ReadUserConfigFile(path turbopath.AbsoluteSystemPath, cliConfig *turbostate.ParsedArgsFromRust) (*UserConfig, error) {
- userViper := viper.New()
- userViper.SetConfigFile(path.ToString())
- userViper.SetConfigType("json")
- userViper.SetEnvPrefix("turbo")
- userViper.MustBindEnv("token")
-
- token, err := cliConfig.GetToken()
- if err != nil {
- return nil, err
- }
- if token != "" {
- userViper.Set("token", token)
- }
-
- if err := userViper.ReadInConfig(); err != nil && !os.IsNotExist(err) {
- return nil, err
- }
- return &UserConfig{
- userViper: userViper,
- path: path,
- }, nil
-}
-
-// DefaultUserConfigPath returns the default platform-dependent place that
-// we store the user-specific configuration.
-func DefaultUserConfigPath() turbopath.AbsoluteSystemPath {
- return fs.GetUserConfigDir().UntypedJoin("config.json")
-}
-
-const (
- _defaultAPIURL = "https://vercel.com/api"
- _defaultLoginURL = "https://vercel.com"
-)
-
-// ReadRepoConfigFile creates a RepoConfig using the
-// specified path as the repo config file. Note that the path or its
-// parents do not need to exist. On a write to this configuration, they
-// will be created.
-func ReadRepoConfigFile(path turbopath.AbsoluteSystemPath, cliConfig *turbostate.ParsedArgsFromRust) (*RepoConfig, error) {
- repoViper := viper.New()
- repoViper.SetConfigFile(path.ToString())
- repoViper.SetConfigType("json")
- repoViper.SetEnvPrefix("turbo")
- repoViper.MustBindEnv("apiurl", "TURBO_API")
- repoViper.MustBindEnv("loginurl", "TURBO_LOGIN")
- repoViper.MustBindEnv("teamslug", "TURBO_TEAM")
- repoViper.MustBindEnv("teamid")
- repoViper.SetDefault("apiurl", _defaultAPIURL)
- repoViper.SetDefault("loginurl", _defaultLoginURL)
-
- login, err := cliConfig.GetLogin()
- if err != nil {
- return nil, err
- }
- if login != "" {
- repoViper.Set("loginurl", login)
- }
-
- api, err := cliConfig.GetAPI()
- if err != nil {
- return nil, err
- }
- if api != "" {
- repoViper.Set("apiurl", api)
- }
-
- team, err := cliConfig.GetTeam()
- if err != nil {
- return nil, err
- }
- if team != "" {
- repoViper.Set("teamslug", team)
- }
-
- if err := repoViper.ReadInConfig(); err != nil && !os.IsNotExist(err) {
- return nil, err
- }
- // If team was set via commandline, don't read the teamId from the config file, as it
- // won't necessarily match.
- if team != "" {
- repoViper.Set("teamid", "")
- }
- return &RepoConfig{
- repoViper: repoViper,
- path: path,
- }, nil
-}
-
-// GetRepoConfigPath reads the user-specific configuration values
-func GetRepoConfigPath(repoRoot turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- return repoRoot.UntypedJoin(".turbo", "config.json")
-}
diff --git a/cli/internal/config/config_file_test.go b/cli/internal/config/config_file_test.go
deleted file mode 100644
index 7a19108..0000000
--- a/cli/internal/config/config_file_test.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package config
-
-import (
- "fmt"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "gotest.tools/v3/assert"
-)
-
-func TestReadRepoConfigWhenMissing(t *testing.T) {
- testDir := fs.AbsoluteSystemPathFromUpstream(t.TempDir()).UntypedJoin("config.json")
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- }
-
- config, err := ReadRepoConfigFile(testDir, args)
- if err != nil {
- t.Errorf("got error reading non-existent config file: %v, want <nil>", err)
- }
- if config == nil {
- t.Error("got <nil>, wanted config value")
- }
-}
-
-func TestReadRepoConfigSetTeamAndAPIFlag(t *testing.T) {
- testConfigFile := fs.AbsoluteSystemPathFromUpstream(t.TempDir()).UntypedJoin("turborepo", "config.json")
-
- slug := "my-team-slug"
- apiURL := "http://my-login-url"
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- Team: slug,
- API: apiURL,
- }
-
- teamID := "some-id"
- assert.NilError(t, testConfigFile.EnsureDir(), "EnsureDir")
- assert.NilError(t, testConfigFile.WriteFile([]byte(fmt.Sprintf(`{"teamId":"%v"}`, teamID)), 0644), "WriteFile")
-
- config, err := ReadRepoConfigFile(testConfigFile, args)
- if err != nil {
- t.Errorf("ReadRepoConfigFile err got %v, want <nil>", err)
- }
- remoteConfig := config.GetRemoteConfig("")
- if remoteConfig.TeamID != "" {
- t.Errorf("TeamID got %v, want <empty string>", remoteConfig.TeamID)
- }
- if remoteConfig.TeamSlug != slug {
- t.Errorf("TeamSlug got %v, want %v", remoteConfig.TeamSlug, slug)
- }
- if remoteConfig.APIURL != apiURL {
- t.Errorf("APIURL got %v, want %v", remoteConfig.APIURL, apiURL)
- }
-}
-
-func TestRepoConfigIncludesDefaults(t *testing.T) {
- testConfigFile := fs.AbsoluteSystemPathFromUpstream(t.TempDir()).UntypedJoin("turborepo", "config.json")
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- }
-
- expectedTeam := "my-team"
-
- assert.NilError(t, testConfigFile.EnsureDir(), "EnsureDir")
- assert.NilError(t, testConfigFile.WriteFile([]byte(fmt.Sprintf(`{"teamSlug":"%v"}`, expectedTeam)), 0644), "WriteFile")
-
- config, err := ReadRepoConfigFile(testConfigFile, args)
- if err != nil {
- t.Errorf("ReadRepoConfigFile err got %v, want <nil>", err)
- }
-
- remoteConfig := config.GetRemoteConfig("")
- if remoteConfig.APIURL != _defaultAPIURL {
- t.Errorf("api url got %v, want %v", remoteConfig.APIURL, _defaultAPIURL)
- }
- if remoteConfig.TeamSlug != expectedTeam {
- t.Errorf("team slug got %v, want %v", remoteConfig.TeamSlug, expectedTeam)
- }
-}
-
-func TestWriteRepoConfig(t *testing.T) {
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- testConfigFile := repoRoot.UntypedJoin(".turbo", "config.json")
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- }
-
- expectedTeam := "my-team"
-
- assert.NilError(t, testConfigFile.EnsureDir(), "EnsureDir")
- assert.NilError(t, testConfigFile.WriteFile([]byte(fmt.Sprintf(`{"teamSlug":"%v"}`, expectedTeam)), 0644), "WriteFile")
-
- initial, err := ReadRepoConfigFile(testConfigFile, args)
- assert.NilError(t, err, "GetRepoConfig")
- // setting the teamID should clear the slug, since it may have been from an old team
- expectedTeamID := "my-team-id"
- err = initial.SetTeamID(expectedTeamID)
- assert.NilError(t, err, "SetTeamID")
-
- config, err := ReadRepoConfigFile(testConfigFile, args)
- if err != nil {
- t.Errorf("ReadRepoConfig err got %v, want <nil>", err)
- }
-
- remoteConfig := config.GetRemoteConfig("")
- if remoteConfig.TeamSlug != "" {
- t.Errorf("Expected TeamSlug to be cleared, got %v", remoteConfig.TeamSlug)
- }
- if remoteConfig.TeamID != expectedTeamID {
- t.Errorf("TeamID got %v, want %v", remoteConfig.TeamID, expectedTeamID)
- }
-}
-
-func TestWriteUserConfig(t *testing.T) {
- configPath := fs.AbsoluteSystemPathFromUpstream(t.TempDir()).UntypedJoin("turborepo", "config.json")
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- }
-
- // Non-existent config file should get empty values
- userConfig, err := ReadUserConfigFile(configPath, args)
- assert.NilError(t, err, "readUserConfigFile")
- assert.Equal(t, userConfig.Token(), "")
- assert.Equal(t, userConfig.path, configPath)
-
- expectedToken := "my-token"
- err = userConfig.SetToken(expectedToken)
- assert.NilError(t, err, "SetToken")
-
- config, err := ReadUserConfigFile(configPath, args)
- assert.NilError(t, err, "readUserConfigFile")
- assert.Equal(t, config.Token(), expectedToken)
-
- err = config.Delete()
- assert.NilError(t, err, "deleteConfigFile")
- assert.Equal(t, configPath.FileExists(), false, "config file should be deleted")
-
- final, err := ReadUserConfigFile(configPath, args)
- assert.NilError(t, err, "readUserConfigFile")
- assert.Equal(t, final.Token(), "")
- assert.Equal(t, configPath.FileExists(), false, "config file should be deleted")
-}
-
-func TestUserConfigFlags(t *testing.T) {
- configPath := fs.AbsoluteSystemPathFromUpstream(t.TempDir()).UntypedJoin("turborepo", "config.json")
- args := &turbostate.ParsedArgsFromRust{
- CWD: "",
- Token: "my-token",
- }
-
- userConfig, err := ReadUserConfigFile(configPath, args)
- assert.NilError(t, err, "readUserConfigFile")
- assert.Equal(t, userConfig.Token(), "my-token")
- assert.Equal(t, userConfig.path, configPath)
-}
diff --git a/cli/internal/context/context.go b/cli/internal/context/context.go
deleted file mode 100644
index 2376d2d..0000000
--- a/cli/internal/context/context.go
+++ /dev/null
@@ -1,480 +0,0 @@
-package context
-
-import (
- "fmt"
- "path/filepath"
- "sort"
- "strings"
- "sync"
-
- "github.com/hashicorp/go-multierror"
- "github.com/vercel/turbo/cli/internal/core"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/packagemanager"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-
- "github.com/Masterminds/semver"
- mapset "github.com/deckarep/golang-set"
- "github.com/pyr-sh/dag"
- "golang.org/x/sync/errgroup"
-)
-
-// Warnings Error type for errors that don't prevent the creation of a functional Context
-type Warnings struct {
- warns *multierror.Error
- mu sync.Mutex
-}
-
-var _ error = (*Warnings)(nil)
-
-func (w *Warnings) Error() string {
- return w.warns.Error()
-}
-
-func (w *Warnings) errorOrNil() error {
- if w.warns != nil {
- return w
- }
- return nil
-}
-
-func (w *Warnings) append(err error) {
- w.mu.Lock()
- defer w.mu.Unlock()
- w.warns = multierror.Append(w.warns, err)
-}
-
-// Context of the CLI
-type Context struct {
- // WorkspaceInfos contains the contents of package.json for every workspace
- // TODO(gsoltis): should the RootPackageJSON be included in WorkspaceInfos?
- WorkspaceInfos workspace.Catalog
-
- // WorkspaceNames is all the names of the workspaces
- WorkspaceNames []string
-
- // WorkspaceGraph is a graph of workspace dependencies
- // (based on package.json dependencies and devDependencies)
- WorkspaceGraph dag.AcyclicGraph
-
- // RootNode is a sigil identifying the root workspace
- RootNode string
-
- // Lockfile is a struct to read the lockfile based on the package manager
- Lockfile lockfile.Lockfile
-
- // PackageManager is an abstraction for all the info a package manager
- // can give us about the repo.
- PackageManager *packagemanager.PackageManager
-
- // Used to arbitrate access to the graph. We parallelise most build operations
- // and Go maps aren't natively threadsafe so this is needed.
- mutex sync.Mutex
-}
-
-// Splits "npm:^1.2.3" and "github:foo/bar.git" into a protocol part and a version part.
-func parseDependencyProtocol(version string) (string, string) {
- parts := strings.Split(version, ":")
- if len(parts) == 1 {
- return "", parts[0]
- }
-
- return parts[0], strings.Join(parts[1:], ":")
-}
-
-func isProtocolExternal(protocol string) bool {
- // The npm protocol for yarn by default still uses the workspace package if the workspace
- // version is in a compatible semver range. See https://github.com/yarnpkg/berry/discussions/4015
- // For now, we will just assume if the npm protocol is being used and the version matches
- // its an internal dependency which matches the existing behavior before this additional
- // logic was added.
-
- // TODO: extend this to support the `enableTransparentWorkspaces` yarn option
- return protocol != "" && protocol != "npm"
-}
-
-func isWorkspaceReference(packageVersion string, dependencyVersion string, cwd string, rootpath string) bool {
- protocol, dependencyVersion := parseDependencyProtocol(dependencyVersion)
-
- if protocol == "workspace" {
- // TODO: Since support at the moment is non-existent for workspaces that contain multiple
- // versions of the same package name, just assume its a match and don't check the range
- // for an exact match.
- return true
- } else if protocol == "file" || protocol == "link" {
- abs, err := filepath.Abs(filepath.Join(cwd, dependencyVersion))
- if err != nil {
- // Default to internal if we have the package but somehow cannot get the path
- // TODO(gsoltis): log this?
- return true
- }
- isWithinRepo, err := fs.DirContainsPath(rootpath, filepath.FromSlash(abs))
- if err != nil {
- // Default to internal if we have the package but somehow cannot get the path
- // TODO(gsoltis): log this?
- return true
- }
- return isWithinRepo
- } else if isProtocolExternal(protocol) {
- // Other protocols are assumed to be external references ("github:", etc)
- return false
- } else if dependencyVersion == "*" {
- return true
- }
-
- // If we got this far, then we need to check the workspace package version to see it satisfies
- // the dependencies range to determin whether or not its an internal or external dependency.
-
- constraint, constraintErr := semver.NewConstraint(dependencyVersion)
- pkgVersion, packageVersionErr := semver.NewVersion(packageVersion)
- if constraintErr != nil || packageVersionErr != nil {
- // For backwards compatibility with existing behavior, if we can't parse the version then we
- // treat the dependency as an internal package reference and swallow the error.
-
- // TODO: some package managers also support tags like "latest". Does extra handling need to be
- // added for this corner-case
- return true
- }
-
- return constraint.Check(pkgVersion)
-}
-
-// SinglePackageGraph constructs a Context instance from a single package.
-func SinglePackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON) (*Context, error) {
- workspaceInfos := workspace.Catalog{
- PackageJSONs: map[string]*fs.PackageJSON{util.RootPkgName: rootPackageJSON},
- TurboConfigs: map[string]*fs.TurboJSON{},
- }
- c := &Context{
- WorkspaceInfos: workspaceInfos,
- RootNode: core.ROOT_NODE_NAME,
- }
- c.WorkspaceGraph.Connect(dag.BasicEdge(util.RootPkgName, core.ROOT_NODE_NAME))
- packageManager, err := packagemanager.GetPackageManager(repoRoot, rootPackageJSON)
- if err != nil {
- return nil, err
- }
- c.PackageManager = packageManager
- return c, nil
-}
-
-// BuildPackageGraph constructs a Context instance with information about the package dependency graph
-func BuildPackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON) (*Context, error) {
- c := &Context{}
- rootpath := repoRoot.ToStringDuringMigration()
- c.WorkspaceInfos = workspace.Catalog{
- PackageJSONs: map[string]*fs.PackageJSON{},
- TurboConfigs: map[string]*fs.TurboJSON{},
- }
- c.RootNode = core.ROOT_NODE_NAME
-
- var warnings Warnings
-
- packageManager, err := packagemanager.GetPackageManager(repoRoot, rootPackageJSON)
- if err != nil {
- return nil, err
- }
- c.PackageManager = packageManager
-
- if lockfile, err := c.PackageManager.ReadLockfile(repoRoot, rootPackageJSON); err != nil {
- warnings.append(err)
- } else {
- c.Lockfile = lockfile
- }
-
- if err := c.resolveWorkspaceRootDeps(rootPackageJSON, &warnings); err != nil {
- // TODO(Gaspar) was this the intended return error?
- return nil, fmt.Errorf("could not resolve workspaces: %w", err)
- }
-
- // Get the workspaces from the package manager.
- // workspaces are absolute paths
- workspaces, err := c.PackageManager.GetWorkspaces(repoRoot)
-
- if err != nil {
- return nil, fmt.Errorf("workspace configuration error: %w", err)
- }
-
- // We will parse all package.json's simultaneously. We use a
- // wait group because we cannot fully populate the graph (the next step)
- // until all parsing is complete
- parseJSONWaitGroup := &errgroup.Group{}
- for _, workspace := range workspaces {
- pkgJSONPath := fs.UnsafeToAbsoluteSystemPath(workspace)
- parseJSONWaitGroup.Go(func() error {
- return c.parsePackageJSON(repoRoot, pkgJSONPath)
- })
- }
-
- if err := parseJSONWaitGroup.Wait(); err != nil {
- return nil, err
- }
- populateGraphWaitGroup := &errgroup.Group{}
- for _, pkg := range c.WorkspaceInfos.PackageJSONs {
- pkg := pkg
- populateGraphWaitGroup.Go(func() error {
- return c.populateWorkspaceGraphForPackageJSON(pkg, rootpath, pkg.Name, &warnings)
- })
- }
-
- if err := populateGraphWaitGroup.Wait(); err != nil {
- return nil, err
- }
- // Resolve dependencies for the root package. We override the vertexName in the graph
- // for the root package, since it can have an arbitrary name. We need it to have our
- // RootPkgName so that we can identify it as the root later on.
- err = c.populateWorkspaceGraphForPackageJSON(rootPackageJSON, rootpath, util.RootPkgName, &warnings)
- if err != nil {
- return nil, fmt.Errorf("failed to resolve dependencies for root package: %v", err)
- }
- c.WorkspaceInfos.PackageJSONs[util.RootPkgName] = rootPackageJSON
-
- return c, warnings.errorOrNil()
-}
-
-func (c *Context) resolveWorkspaceRootDeps(rootPackageJSON *fs.PackageJSON, warnings *Warnings) error {
- pkg := rootPackageJSON
- pkg.UnresolvedExternalDeps = make(map[string]string)
- for dep, version := range pkg.DevDependencies {
- pkg.UnresolvedExternalDeps[dep] = version
- }
- for dep, version := range pkg.OptionalDependencies {
- pkg.UnresolvedExternalDeps[dep] = version
- }
- for dep, version := range pkg.Dependencies {
- pkg.UnresolvedExternalDeps[dep] = version
- }
- if c.Lockfile != nil {
- depSet, err := lockfile.TransitiveClosure(
- pkg.Dir.ToUnixPath(),
- pkg.UnresolvedExternalDeps,
- c.Lockfile,
- )
- if err != nil {
- warnings.append(err)
- // Return early to skip using results of incomplete dep graph resolution
- return nil
- }
- pkg.TransitiveDeps = make([]lockfile.Package, 0, depSet.Cardinality())
- for _, v := range depSet.ToSlice() {
- dep := v.(lockfile.Package)
- pkg.TransitiveDeps = append(pkg.TransitiveDeps, dep)
- }
- sort.Sort(lockfile.ByKey(pkg.TransitiveDeps))
- hashOfExternalDeps, err := fs.HashObject(pkg.TransitiveDeps)
- if err != nil {
- return err
- }
- pkg.ExternalDepsHash = hashOfExternalDeps
- } else {
- pkg.TransitiveDeps = []lockfile.Package{}
- pkg.ExternalDepsHash = ""
- }
-
- return nil
-}
-
-// populateWorkspaceGraphForPackageJSON fills in the edges for the dependencies of the given package
-// that are within the monorepo, as well as collecting and hashing the dependencies of the package
-// that are not within the monorepo. The vertexName is used to override the package name in the graph.
-// This can happen when adding the root package, which can have an arbitrary name.
-func (c *Context) populateWorkspaceGraphForPackageJSON(pkg *fs.PackageJSON, rootpath string, vertexName string, warnings *Warnings) error {
- c.mutex.Lock()
- defer c.mutex.Unlock()
- depMap := make(map[string]string)
- internalDepsSet := make(dag.Set)
- externalUnresolvedDepsSet := make(dag.Set)
- pkg.UnresolvedExternalDeps = make(map[string]string)
-
- for dep, version := range pkg.DevDependencies {
- depMap[dep] = version
- }
-
- for dep, version := range pkg.OptionalDependencies {
- depMap[dep] = version
- }
-
- for dep, version := range pkg.Dependencies {
- depMap[dep] = version
- }
-
- // split out internal vs. external deps
- for depName, depVersion := range depMap {
- if item, ok := c.WorkspaceInfos.PackageJSONs[depName]; ok && isWorkspaceReference(item.Version, depVersion, pkg.Dir.ToStringDuringMigration(), rootpath) {
- internalDepsSet.Add(depName)
- c.WorkspaceGraph.Connect(dag.BasicEdge(vertexName, depName))
- } else {
- externalUnresolvedDepsSet.Add(depName)
- }
- }
-
- for _, name := range externalUnresolvedDepsSet.List() {
- name := name.(string)
- if item, ok := pkg.DevDependencies[name]; ok {
- pkg.UnresolvedExternalDeps[name] = item
- }
-
- if item, ok := pkg.OptionalDependencies[name]; ok {
- pkg.UnresolvedExternalDeps[name] = item
- }
-
- if item, ok := pkg.Dependencies[name]; ok {
- pkg.UnresolvedExternalDeps[name] = item
- }
- }
-
- externalDeps, err := lockfile.TransitiveClosure(
- pkg.Dir.ToUnixPath(),
- pkg.UnresolvedExternalDeps,
- c.Lockfile,
- )
- if err != nil {
- warnings.append(err)
- // reset external deps to original state
- externalDeps = mapset.NewSet()
- }
-
- // when there are no internal dependencies, we need to still add these leafs to the graph
- if internalDepsSet.Len() == 0 {
- c.WorkspaceGraph.Connect(dag.BasicEdge(pkg.Name, core.ROOT_NODE_NAME))
- }
- pkg.TransitiveDeps = make([]lockfile.Package, 0, externalDeps.Cardinality())
- for _, dependency := range externalDeps.ToSlice() {
- dependency := dependency.(lockfile.Package)
- pkg.TransitiveDeps = append(pkg.TransitiveDeps, dependency)
- }
- pkg.InternalDeps = make([]string, 0, internalDepsSet.Len())
- for _, v := range internalDepsSet.List() {
- pkg.InternalDeps = append(pkg.InternalDeps, fmt.Sprintf("%v", v))
- }
- sort.Strings(pkg.InternalDeps)
- sort.Sort(lockfile.ByKey(pkg.TransitiveDeps))
- hashOfExternalDeps, err := fs.HashObject(pkg.TransitiveDeps)
- if err != nil {
- return err
- }
- pkg.ExternalDepsHash = hashOfExternalDeps
- return nil
-}
-
-func (c *Context) parsePackageJSON(repoRoot turbopath.AbsoluteSystemPath, pkgJSONPath turbopath.AbsoluteSystemPath) error {
- c.mutex.Lock()
- defer c.mutex.Unlock()
-
- if pkgJSONPath.FileExists() {
- pkg, err := fs.ReadPackageJSON(pkgJSONPath)
- if err != nil {
- return fmt.Errorf("parsing %s: %w", pkgJSONPath, err)
- }
-
- relativePkgJSONPath, err := repoRoot.PathTo(pkgJSONPath)
- if err != nil {
- return err
- }
- c.WorkspaceGraph.Add(pkg.Name)
- pkg.PackageJSONPath = turbopath.AnchoredSystemPathFromUpstream(relativePkgJSONPath)
- pkg.Dir = turbopath.AnchoredSystemPathFromUpstream(filepath.Dir(relativePkgJSONPath))
- if c.WorkspaceInfos.PackageJSONs[pkg.Name] != nil {
- existing := c.WorkspaceInfos.PackageJSONs[pkg.Name]
- return fmt.Errorf("Failed to add workspace \"%s\" from %s, it already exists at %s", pkg.Name, pkg.Dir, existing.Dir)
- }
- c.WorkspaceInfos.PackageJSONs[pkg.Name] = pkg
- c.WorkspaceNames = append(c.WorkspaceNames, pkg.Name)
- }
- return nil
-}
-
-// InternalDependencies finds all dependencies required by the slice of starting
-// packages, as well as the starting packages themselves.
-func (c *Context) InternalDependencies(start []string) ([]string, error) {
- vertices := make(dag.Set)
- for _, v := range start {
- vertices.Add(v)
- }
- s := make(dag.Set)
- memoFunc := func(v dag.Vertex, d int) error {
- s.Add(v)
- return nil
- }
-
- if err := c.WorkspaceGraph.DepthFirstWalk(vertices, memoFunc); err != nil {
- return nil, err
- }
-
- // Use for loop so we can coerce to string
- // .List() returns a list of interface{} types, but
- // we know they are strings.
- targets := make([]string, 0, s.Len())
- for _, dep := range s.List() {
- targets = append(targets, dep.(string))
- }
- sort.Strings(targets)
-
- return targets, nil
-}
-
-// ChangedPackages returns a list of changed packages based on the contents of a previous lockfile
-// This assumes that none of the package.json in the workspace change, it is
-// the responsibility of the caller to verify this.
-func (c *Context) ChangedPackages(previousLockfile lockfile.Lockfile) ([]string, error) {
- if lockfile.IsNil(previousLockfile) || lockfile.IsNil(c.Lockfile) {
- return nil, fmt.Errorf("Cannot detect changed packages without previous and current lockfile")
- }
-
- didPackageChange := func(pkgName string, pkg *fs.PackageJSON) bool {
- previousDeps, err := lockfile.TransitiveClosure(
- pkg.Dir.ToUnixPath(),
- pkg.UnresolvedExternalDeps,
- previousLockfile,
- )
- if err != nil || previousDeps.Cardinality() != len(pkg.TransitiveDeps) {
- return true
- }
-
- prevExternalDeps := make([]lockfile.Package, 0, previousDeps.Cardinality())
- for _, d := range previousDeps.ToSlice() {
- prevExternalDeps = append(prevExternalDeps, d.(lockfile.Package))
- }
- sort.Sort(lockfile.ByKey(prevExternalDeps))
-
- for i := range prevExternalDeps {
- if prevExternalDeps[i] != pkg.TransitiveDeps[i] {
- return true
- }
- }
- return false
- }
-
- changedPkgs := make([]string, 0, len(c.WorkspaceInfos.PackageJSONs))
-
- // check if prev and current have "global" changes e.g. lockfile bump
- globalChange := c.Lockfile.GlobalChange(previousLockfile)
-
- for pkgName, pkg := range c.WorkspaceInfos.PackageJSONs {
- if globalChange {
- break
- }
- if didPackageChange(pkgName, pkg) {
- if pkgName == util.RootPkgName {
- globalChange = true
- } else {
- changedPkgs = append(changedPkgs, pkgName)
- }
- }
- }
-
- if globalChange {
- changedPkgs = make([]string, 0, len(c.WorkspaceInfos.PackageJSONs))
- for pkgName := range c.WorkspaceInfos.PackageJSONs {
- changedPkgs = append(changedPkgs, pkgName)
- }
- sort.Strings(changedPkgs)
- return changedPkgs, nil
- }
-
- sort.Strings(changedPkgs)
- return changedPkgs, nil
-}
diff --git a/cli/internal/context/context_test.go b/cli/internal/context/context_test.go
deleted file mode 100644
index 692c0a8..0000000
--- a/cli/internal/context/context_test.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package context
-
-import (
- "os"
- "path/filepath"
- "regexp"
- "testing"
-
- testifyAssert "github.com/stretchr/testify/assert"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-func Test_isWorkspaceReference(t *testing.T) {
- rootpath, err := filepath.Abs(filepath.FromSlash("/some/repo"))
- if err != nil {
- t.Fatalf("failed to create absolute root path %v", err)
- }
- pkgDir, err := filepath.Abs(filepath.FromSlash("/some/repo/packages/libA"))
- if err != nil {
- t.Fatalf("failed to create absolute pkgDir %v", err)
- }
- tests := []struct {
- name string
- packageVersion string
- dependencyVersion string
- want bool
- }{
- {
- name: "handles exact match",
- packageVersion: "1.2.3",
- dependencyVersion: "1.2.3",
- want: true,
- },
- {
- name: "handles semver range satisfied",
- packageVersion: "1.2.3",
- dependencyVersion: "^1.0.0",
- want: true,
- },
- {
- name: "handles semver range not-satisfied",
- packageVersion: "2.3.4",
- dependencyVersion: "^1.0.0",
- want: false,
- },
- {
- name: "handles workspace protocol with version",
- packageVersion: "1.2.3",
- dependencyVersion: "workspace:1.2.3",
- want: true,
- },
- {
- name: "handles workspace protocol with relative path",
- packageVersion: "1.2.3",
- dependencyVersion: "workspace:../other-package/",
- want: true,
- },
- {
- name: "handles npm protocol with satisfied semver range",
- packageVersion: "1.2.3",
- dependencyVersion: "npm:^1.2.3",
- want: true, // default in yarn is to use the workspace version unless `enableTransparentWorkspaces: true`. This isn't currently being checked.
- },
- {
- name: "handles npm protocol with non-satisfied semver range",
- packageVersion: "2.3.4",
- dependencyVersion: "npm:^1.2.3",
- want: false,
- },
- {
- name: "handles pre-release versions",
- packageVersion: "1.2.3",
- dependencyVersion: "1.2.2-alpha-1234abcd.0",
- want: false,
- },
- {
- name: "handles non-semver package version",
- packageVersion: "sometag",
- dependencyVersion: "1.2.3",
- want: true, // for backwards compatability with the code before versions were verified
- },
- {
- name: "handles non-semver package version",
- packageVersion: "1.2.3",
- dependencyVersion: "sometag",
- want: true, // for backwards compatability with the code before versions were verified
- },
- {
- name: "handles file:... inside repo",
- packageVersion: "1.2.3",
- dependencyVersion: "file:../libB",
- want: true, // this is a sibling package
- },
- {
- name: "handles file:... outside repo",
- packageVersion: "1.2.3",
- dependencyVersion: "file:../../../otherproject",
- want: false, // this is not within the repo root
- },
- {
- name: "handles link:... inside repo",
- packageVersion: "1.2.3",
- dependencyVersion: "link:../libB",
- want: true, // this is a sibling package
- },
- {
- name: "handles link:... outside repo",
- packageVersion: "1.2.3",
- dependencyVersion: "link:../../../otherproject",
- want: false, // this is not within the repo root
- },
- {
- name: "handles development versions",
- packageVersion: "0.0.0-development",
- dependencyVersion: "*",
- want: true, // "*" should always match
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := isWorkspaceReference(tt.packageVersion, tt.dependencyVersion, pkgDir, rootpath)
- if got != tt.want {
- t.Errorf("isWorkspaceReference(%v, %v, %v, %v) got = %v, want %v", tt.packageVersion, tt.dependencyVersion, pkgDir, rootpath, got, tt.want)
- }
- })
- }
-}
-
-func TestBuildPackageGraph_DuplicateNames(t *testing.T) {
- path := getTestDir(t, "dupe-workspace-names")
- pkgJSON := &fs.PackageJSON{
- Name: "dupe-workspace-names",
- PackageManager: "pnpm@7.15.0",
- }
-
- _, actualErr := BuildPackageGraph(path, pkgJSON)
-
- // Not asserting the full error message, because it includes a path with slashes and backslashes
- // getting the regex incantation to check that is not worth it.
- // We have to use regex because the actual error may be different depending on which workspace was
- // added first and which one was second, causing the error.
- testifyAssert.Regexp(t, regexp.MustCompile("^Failed to add workspace \"same-name\".+$"), actualErr)
-}
-
-// This is duplicated from fs.turbo_json_test.go.
-// I wasn't able to pull it into a helper file/package because
-// it requires the `fs` package and it would cause cyclical dependencies
-// when used in turbo_json_test.go and would require more changes to fix that.
-func getTestDir(t *testing.T, testName string) turbopath.AbsoluteSystemPath {
- defaultCwd, err := os.Getwd()
- if err != nil {
- t.Errorf("failed to get cwd: %v", err)
- }
- cwd, err := fs.CheckedToAbsoluteSystemPath(defaultCwd)
- if err != nil {
- t.Fatalf("cwd is not an absolute directory %v: %v", defaultCwd, err)
- }
-
- return cwd.UntypedJoin("testdata", testName)
-}
diff --git a/cli/internal/context/testdata/dupe-workspace-names/apps/a/package.json b/cli/internal/context/testdata/dupe-workspace-names/apps/a/package.json
deleted file mode 100644
index 94301a3..0000000
--- a/cli/internal/context/testdata/dupe-workspace-names/apps/a/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "same-name",
- "dependencies": {
- "ui": "workspace:*"
- }
-}
diff --git a/cli/internal/context/testdata/dupe-workspace-names/apps/b/package.json b/cli/internal/context/testdata/dupe-workspace-names/apps/b/package.json
deleted file mode 100644
index 94301a3..0000000
--- a/cli/internal/context/testdata/dupe-workspace-names/apps/b/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "same-name",
- "dependencies": {
- "ui": "workspace:*"
- }
-}
diff --git a/cli/internal/context/testdata/dupe-workspace-names/package.json b/cli/internal/context/testdata/dupe-workspace-names/package.json
deleted file mode 100644
index 3bf7403..0000000
--- a/cli/internal/context/testdata/dupe-workspace-names/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "dupe-workspace-names",
- "workspaces": [
- "apps/*"
- ],
- "packageManager": "pnpm@7.15.0"
-}
diff --git a/cli/internal/context/testdata/dupe-workspace-names/packages/ui/package.json b/cli/internal/context/testdata/dupe-workspace-names/packages/ui/package.json
deleted file mode 100644
index 1cd75b5..0000000
--- a/cli/internal/context/testdata/dupe-workspace-names/packages/ui/package.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "name": "ui"
-}
diff --git a/cli/internal/context/testdata/dupe-workspace-names/pnpm-lock.yaml b/cli/internal/context/testdata/dupe-workspace-names/pnpm-lock.yaml
deleted file mode 100644
index 0909cde..0000000
--- a/cli/internal/context/testdata/dupe-workspace-names/pnpm-lock.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-lockfileVersion: 5.4
-
-importers:
-
- .:
- specifiers: {}
-
- apps/a:
- specifiers:
- ui: workspace:*
- dependencies:
- ui: link:../../packages/ui
-
- apps/b:
- specifiers:
- ui: workspace:*
- dependencies:
- ui: link:../../packages/ui
-
- packages/ui:
- specifiers: {}
diff --git a/cli/internal/context/testdata/dupe-workspace-names/pnpm-workspace.yaml b/cli/internal/context/testdata/dupe-workspace-names/pnpm-workspace.yaml
deleted file mode 100644
index 3ff5faa..0000000
--- a/cli/internal/context/testdata/dupe-workspace-names/pnpm-workspace.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-packages:
- - "apps/*"
- - "packages/*"
diff --git a/cli/internal/core/engine.go b/cli/internal/core/engine.go
deleted file mode 100644
index 7f08ea8..0000000
--- a/cli/internal/core/engine.go
+++ /dev/null
@@ -1,591 +0,0 @@
-package core
-
-import (
- "errors"
- "fmt"
- "os"
- "sort"
- "strings"
- "sync/atomic"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/graph"
- "github.com/vercel/turbo/cli/internal/util"
-
- "github.com/pyr-sh/dag"
-)
-
-const ROOT_NODE_NAME = "___ROOT___"
-
-// Task is a higher level struct that contains the underlying TaskDefinition
-// but also some adjustments to it, based on business logic.
-type Task struct {
- Name string
- // TaskDefinition contains the config for the task from turbo.json
- TaskDefinition fs.TaskDefinition
-}
-
-type Visitor = func(taskID string) error
-
-// Engine contains both the DAG for the packages and the tasks and implements the methods to execute tasks in them
-type Engine struct {
- // TaskGraph is a graph of package-tasks
- TaskGraph *dag.AcyclicGraph
- PackageTaskDeps map[string][]string
- rootEnabledTasks util.Set
-
- // completeGraph is the CompleteGraph. We need this to look up the Pipeline, etc.
- completeGraph *graph.CompleteGraph
- // isSinglePackage is used to load turbo.json correctly
- isSinglePackage bool
-}
-
-// NewEngine creates a new engine given a topologic graph of workspace package names
-func NewEngine(
- completeGraph *graph.CompleteGraph,
- isSinglePackage bool,
-) *Engine {
- return &Engine{
- completeGraph: completeGraph,
- TaskGraph: &dag.AcyclicGraph{},
- PackageTaskDeps: map[string][]string{},
- rootEnabledTasks: make(util.Set),
- isSinglePackage: isSinglePackage,
- }
-}
-
-// EngineBuildingOptions help construct the TaskGraph
-type EngineBuildingOptions struct {
- // Packages in the execution scope, if nil, all packages will be considered in scope
- Packages []string
- // TaskNames in the execution scope, if nil, all tasks will be executed
- TaskNames []string
- // Restrict execution to only the listed task names
- TasksOnly bool
-}
-
-// EngineExecutionOptions controls a single walk of the task graph
-type EngineExecutionOptions struct {
- // Parallel is whether to run tasks in parallel
- Parallel bool
- // Concurrency is the number of concurrent tasks that can be executed
- Concurrency int
-}
-
-// Execute executes the pipeline, constructing an internal task graph and walking it accordingly.
-func (e *Engine) Execute(visitor Visitor, opts EngineExecutionOptions) []error {
- var sema = util.NewSemaphore(opts.Concurrency)
- var errored int32
- return e.TaskGraph.Walk(func(v dag.Vertex) error {
- // If something has already errored, short-circuit.
- // There is a race here between concurrent tasks. However, if there is not a
- // dependency edge between them, we are not required to have a strict order
- // between them, so a failed task can fail to short-circuit a concurrent
- // task that happened to be starting at the same time.
- if atomic.LoadInt32(&errored) != 0 {
- return nil
- }
- // Each vertex in the graph is a taskID (package#task format)
- taskID := dag.VertexName(v)
-
- // Always return if it is the root node
- if strings.Contains(taskID, ROOT_NODE_NAME) {
- return nil
- }
-
- // Acquire the semaphore unless parallel
- if !opts.Parallel {
- sema.Acquire()
- defer sema.Release()
- }
-
- if err := visitor(taskID); err != nil {
- // We only ever flip from false to true, so we don't need to compare and swap the atomic
- atomic.StoreInt32(&errored, 1)
- return err
- }
- return nil
- })
-}
-
-// MissingTaskError is a specialized Error thrown in the case that we can't find a task.
-// We want to allow this error when getting task definitions, so we have to special case it.
-type MissingTaskError struct {
- workspaceName string
- taskID string
- taskName string
-}
-
-func (m *MissingTaskError) Error() string {
- return fmt.Sprintf("Could not find \"%s\" or \"%s\" in workspace \"%s\"", m.taskName, m.taskID, m.workspaceName)
-}
-
-func (e *Engine) getTaskDefinition(pkg string, taskName string, taskID string) (*Task, error) {
- pipeline, err := e.completeGraph.GetPipelineFromWorkspace(pkg, e.isSinglePackage)
-
- if err != nil {
- if pkg != util.RootPkgName {
- // If there was no turbo.json in the workspace, fallback to the root turbo.json
- if errors.Is(err, os.ErrNotExist) {
- return e.getTaskDefinition(util.RootPkgName, taskName, taskID)
- }
-
- // otherwise bubble it up
- return nil, err
- }
-
- return nil, err
- }
-
- if task, ok := pipeline[taskID]; ok {
- return &Task{
- Name: taskName,
- TaskDefinition: task.GetTaskDefinition(),
- }, nil
- }
-
- if task, ok := pipeline[taskName]; ok {
- return &Task{
- Name: taskName,
- TaskDefinition: task.GetTaskDefinition(),
- }, nil
- }
-
- // An error here means turbo.json exists, but didn't define the task.
- // Fallback to the root pipeline to find the task.
- if pkg != util.RootPkgName {
- return e.getTaskDefinition(util.RootPkgName, taskName, taskID)
- }
-
- // Return this as a custom type so we can ignore it specifically
- return nil, &MissingTaskError{
- taskName: taskName,
- taskID: taskID,
- workspaceName: pkg,
- }
-}
-
-// Prepare constructs the Task Graph for a list of packages and tasks
-func (e *Engine) Prepare(options *EngineBuildingOptions) error {
- pkgs := options.Packages
- taskNames := options.TaskNames
- tasksOnly := options.TasksOnly
-
- // If there are no affected packages, we don't need to go through all this work
- // we can just exit early.
- // TODO(mehulkar): but we still need to validate bad task names?
- if len(pkgs) == 0 {
- return nil
- }
-
- traversalQueue := []string{}
-
- // get a set of taskNames passed in. we'll remove the ones that have a definition
- missing := util.SetFromStrings(taskNames)
-
- // Get a list of entry points into our TaskGraph.
- // We do this by taking the input taskNames, and pkgs
- // and creating a queue of taskIDs that we can traverse and gather dependencies from.
- for _, pkg := range pkgs {
- for _, taskName := range taskNames {
- taskID := util.GetTaskId(pkg, taskName)
-
- // Look up the task in the package
- foundTask, err := e.getTaskDefinition(pkg, taskName, taskID)
-
- // We can skip MissingTaskErrors because we'll validate against them later
- // Return all other errors
- if err != nil {
- var e *MissingTaskError
- if errors.As(err, &e) {
- // Initially, non-package tasks are not required to exist, as long as some
- // package in the list packages defines it as a package-task. Dependencies
- // *are* required to have a definition.
- continue
- }
-
- return err
- }
-
- // If we found a task definition, remove it from the missing list
- if foundTask != nil {
- // delete taskName if it was found
- missing.Delete(taskName)
-
- // Even if a task definition was found, we _only_ want to add it as an entry point to
- // the task graph (i.e. the traversalQueue), if it's:
- // - A task from the non-root workspace (i.e. tasks from every other workspace)
- // - A task that we *know* is rootEnabled task (in which case, the root workspace is acceptable)
- isRootPkg := pkg == util.RootPkgName
- if !isRootPkg || e.rootEnabledTasks.Includes(taskName) {
- traversalQueue = append(traversalQueue, taskID)
- }
- }
- }
- }
-
- visited := make(util.Set)
-
- // validate that all tasks passed were found
- missingList := missing.UnsafeListOfStrings()
- sort.Strings(missingList)
-
- if len(missingList) > 0 {
- return fmt.Errorf("Could not find the following tasks in project: %s", strings.Join(missingList, ", "))
- }
-
- // Things get appended to traversalQueue inside this loop, so we use the len() check instead of range.
- for len(traversalQueue) > 0 {
- // pop off the first item from the traversalQueue
- taskID := traversalQueue[0]
- traversalQueue = traversalQueue[1:]
-
- pkg, taskName := util.GetPackageTaskFromId(taskID)
-
- if pkg == util.RootPkgName && !e.rootEnabledTasks.Includes(taskName) {
- return fmt.Errorf("%v needs an entry in turbo.json before it can be depended on because it is a task run from the root package", taskID)
- }
-
- if pkg != ROOT_NODE_NAME {
- if _, ok := e.completeGraph.WorkspaceInfos.PackageJSONs[pkg]; !ok {
- // If we have a pkg it should be in WorkspaceInfos.
- // If we're hitting this error something has gone wrong earlier when building WorkspaceInfos
- // or the workspace really doesn't exist and turbo.json is misconfigured.
- return fmt.Errorf("Could not find workspace \"%s\" from task \"%s\" in project", pkg, taskID)
- }
- }
-
- taskDefinitions, err := e.getTaskDefinitionChain(taskID, taskName)
- if err != nil {
- return err
- }
-
- taskDefinition, err := fs.MergeTaskDefinitions(taskDefinitions)
- if err != nil {
- return err
- }
-
- // Skip this iteration of the loop if we've already seen this taskID
- if visited.Includes(taskID) {
- continue
- }
-
- visited.Add(taskID)
-
- // Put this taskDefinition into the Graph so we can look it up later during execution.
- e.completeGraph.TaskDefinitions[taskID] = taskDefinition
-
- topoDeps := util.SetFromStrings(taskDefinition.TopologicalDependencies)
- deps := make(util.Set)
- isPackageTask := util.IsPackageTask(taskName)
-
- for _, dependency := range taskDefinition.TaskDependencies {
- // If the current task is a workspace-specific task (including root Task)
- // and its dependency is _also_ a workspace-specific task, we need to add
- // a reference to this dependency directly into the engine.
- // TODO @mehulkar: Why do we need this?
- if isPackageTask && util.IsPackageTask(dependency) {
- if err := e.AddDep(dependency, taskName); err != nil {
- return err
- }
- } else {
- // For non-workspace-specific dependencies, we attach a reference to
- // the task that is added into the engine.
- deps.Add(dependency)
- }
- }
-
- // Filter down the tasks if there's a filter in place
- // https: //turbo.build/repo/docs/reference/command-line-reference#--only
- if tasksOnly {
- deps = deps.Filter(func(d interface{}) bool {
- for _, target := range taskNames {
- return fmt.Sprintf("%v", d) == target
- }
- return false
- })
- topoDeps = topoDeps.Filter(func(d interface{}) bool {
- for _, target := range taskNames {
- return fmt.Sprintf("%v", d) == target
- }
- return false
- })
- }
-
- toTaskID := taskID
-
- // hasTopoDeps will be true if the task depends on any tasks from dependency packages
- // E.g. `dev: { dependsOn: [^dev] }`
- hasTopoDeps := topoDeps.Len() > 0 && e.completeGraph.WorkspaceGraph.DownEdges(pkg).Len() > 0
-
- // hasDeps will be true if the task depends on any tasks from its own package
- // E.g. `build: { dependsOn: [dev] }`
- hasDeps := deps.Len() > 0
-
- // hasPackageTaskDeps will be true if this is a workspace-specific task, and
- // it depends on another workspace-specific tasks
- // E.g. `my-package#build: { dependsOn: [my-package#beforebuild] }`.
- hasPackageTaskDeps := false
- if _, ok := e.PackageTaskDeps[toTaskID]; ok {
- hasPackageTaskDeps = true
- }
-
- if hasTopoDeps {
- depPkgs := e.completeGraph.WorkspaceGraph.DownEdges(pkg)
- for _, from := range topoDeps.UnsafeListOfStrings() {
- // add task dep from all the package deps within repo
- for depPkg := range depPkgs {
- fromTaskID := util.GetTaskId(depPkg, from)
- e.TaskGraph.Add(fromTaskID)
- e.TaskGraph.Add(toTaskID)
- e.TaskGraph.Connect(dag.BasicEdge(toTaskID, fromTaskID))
- traversalQueue = append(traversalQueue, fromTaskID)
- }
- }
- }
-
- if hasDeps {
- for _, from := range deps.UnsafeListOfStrings() {
- fromTaskID := util.GetTaskId(pkg, from)
- e.TaskGraph.Add(fromTaskID)
- e.TaskGraph.Add(toTaskID)
- e.TaskGraph.Connect(dag.BasicEdge(toTaskID, fromTaskID))
- traversalQueue = append(traversalQueue, fromTaskID)
- }
- }
-
- if hasPackageTaskDeps {
- if pkgTaskDeps, ok := e.PackageTaskDeps[toTaskID]; ok {
- for _, fromTaskID := range pkgTaskDeps {
- e.TaskGraph.Add(fromTaskID)
- e.TaskGraph.Add(toTaskID)
- e.TaskGraph.Connect(dag.BasicEdge(toTaskID, fromTaskID))
- traversalQueue = append(traversalQueue, fromTaskID)
- }
- }
- }
-
- // Add the root node into the graph
- if !hasDeps && !hasTopoDeps && !hasPackageTaskDeps {
- e.TaskGraph.Add(ROOT_NODE_NAME)
- e.TaskGraph.Add(toTaskID)
- e.TaskGraph.Connect(dag.BasicEdge(toTaskID, ROOT_NODE_NAME))
- }
- }
-
- return nil
-}
-
-// AddTask adds root tasks to the engine so they can be looked up later.
-func (e *Engine) AddTask(taskName string) {
- if util.IsPackageTask(taskName) {
- pkg, taskName := util.GetPackageTaskFromId(taskName)
- if pkg == util.RootPkgName {
- e.rootEnabledTasks.Add(taskName)
- }
- }
-}
-
-// AddDep adds tuples from+to task ID combos in tuple format so they can be looked up later.
-func (e *Engine) AddDep(fromTaskID string, toTaskID string) error {
- fromPkg, _ := util.GetPackageTaskFromId(fromTaskID)
- if fromPkg != ROOT_NODE_NAME && fromPkg != util.RootPkgName && !e.completeGraph.WorkspaceGraph.HasVertex(fromPkg) {
- return fmt.Errorf("found reference to unknown package: %v in task %v", fromPkg, fromTaskID)
- }
-
- if _, ok := e.PackageTaskDeps[toTaskID]; !ok {
- e.PackageTaskDeps[toTaskID] = []string{}
- }
-
- e.PackageTaskDeps[toTaskID] = append(e.PackageTaskDeps[toTaskID], fromTaskID)
-
- return nil
-}
-
-// ValidatePersistentDependencies checks if any task dependsOn persistent tasks and throws
-// an error if that task is actually implemented
-func (e *Engine) ValidatePersistentDependencies(graph *graph.CompleteGraph, concurrency int) error {
- var validationError error
- persistentCount := 0
-
- // Adding in a lock because otherwise walking the graph can introduce a data race
- // (reproducible with `go test -race`)
- var sema = util.NewSemaphore(1)
-
- errs := e.TaskGraph.Walk(func(v dag.Vertex) error {
- vertexName := dag.VertexName(v) // vertexName is a taskID
-
- // No need to check the root node if that's where we are.
- if strings.Contains(vertexName, ROOT_NODE_NAME) {
- return nil
- }
-
- // Aquire a lock, because otherwise walking this group can cause a race condition
- // writing to the same validationError var defined outside the Walk(). This shows
- // up when running tests with the `-race` flag.
- sema.Acquire()
- defer sema.Release()
-
- currentTaskDefinition, currentTaskExists := e.completeGraph.TaskDefinitions[vertexName]
- if currentTaskExists && currentTaskDefinition.Persistent {
- persistentCount++
- }
-
- currentPackageName, currentTaskName := util.GetPackageTaskFromId(vertexName)
-
- // For each "downEdge" (i.e. each task that _this_ task dependsOn)
- // check if the downEdge is a Persistent task, and if it actually has the script implemented
- // in that package's package.json
- for dep := range e.TaskGraph.DownEdges(vertexName) {
- depTaskID := dep.(string)
- // No need to check the root node
- if strings.Contains(depTaskID, ROOT_NODE_NAME) {
- return nil
- }
-
- // Parse the taskID of this dependency task
- packageName, taskName := util.GetPackageTaskFromId(depTaskID)
-
- // Get the Task Definition so we can check if it is Persistent
- depTaskDefinition, taskExists := e.completeGraph.TaskDefinitions[depTaskID]
-
- if !taskExists {
- return fmt.Errorf("Cannot find task definition for %v in package %v", depTaskID, packageName)
- }
-
- // Get information about the package
- pkg, pkgExists := graph.WorkspaceInfos.PackageJSONs[packageName]
- if !pkgExists {
- return fmt.Errorf("Cannot find package %v", packageName)
- }
- _, hasScript := pkg.Scripts[taskName]
-
- // If both conditions are true set a value and break out of checking the dependencies
- if depTaskDefinition.Persistent && hasScript {
- validationError = fmt.Errorf(
- "\"%s\" is a persistent task, \"%s\" cannot depend on it",
- util.GetTaskId(packageName, taskName),
- util.GetTaskId(currentPackageName, currentTaskName),
- )
-
- break
- }
- }
-
- return nil
- })
-
- for _, err := range errs {
- return fmt.Errorf("Validation failed: %v", err)
- }
-
- if validationError != nil {
- return validationError
- } else if persistentCount >= concurrency {
- return fmt.Errorf("You have %v persistent tasks but `turbo` is configured for concurrency of %v. Set --concurrency to at least %v", persistentCount, concurrency, persistentCount+1)
- }
-
- return nil
-}
-
-// getTaskDefinitionChain gets a set of TaskDefinitions that apply to the taskID.
-// These definitions should be merged by the consumer.
-func (e *Engine) getTaskDefinitionChain(taskID string, taskName string) ([]fs.BookkeepingTaskDefinition, error) {
- // Start a list of TaskDefinitions we've found for this TaskID
- taskDefinitions := []fs.BookkeepingTaskDefinition{}
-
- rootPipeline, err := e.completeGraph.GetPipelineFromWorkspace(util.RootPkgName, e.isSinglePackage)
- if err != nil {
- // It should be very unlikely that we can't find a root pipeline. Even for single package repos
- // the pipeline is synthesized from package.json, so there should be _something_ here.
- return nil, err
- }
-
- // Look for the taskDefinition in the root pipeline.
- if rootTaskDefinition, err := rootPipeline.GetTask(taskID, taskName); err == nil {
- taskDefinitions = append(taskDefinitions, *rootTaskDefinition)
- }
-
- // If we're in a single package repo, we can just exit with the TaskDefinition in the root pipeline
- // since there are no workspaces, and we don't need to follow any extends keys.
- if e.isSinglePackage {
- if len(taskDefinitions) == 0 {
- return nil, fmt.Errorf("Could not find \"%s\" in root turbo.json", taskID)
- }
- return taskDefinitions, nil
- }
-
- // If the taskID is a root task (e.g. //#build), we don't need to look
- // for a workspace task, since these can only be defined in the root turbo.json.
- taskIDPackage, _ := util.GetPackageTaskFromId(taskID)
- if taskIDPackage != util.RootPkgName && taskIDPackage != ROOT_NODE_NAME {
- // If there is an error, we can ignore it, since turbo.json config is not required in the workspace.
- if workspaceTurboJSON, err := e.completeGraph.GetTurboConfigFromWorkspace(taskIDPackage, e.isSinglePackage); err != nil {
- // swallow the error where the config file doesn't exist, but bubble up other things
- if !errors.Is(err, os.ErrNotExist) {
- return nil, err
- }
- } else {
- // Run some validations on a workspace turbo.json. Note that these validations are on
- // the whole struct, and not relevant to the taskID we're looking at right now.
- validationErrors := workspaceTurboJSON.Validate([]fs.TurboJSONValidation{
- validateNoPackageTaskSyntax,
- validateExtends,
- })
-
- if len(validationErrors) > 0 {
- fullError := errors.New("Invalid turbo.json")
- for _, validationErr := range validationErrors {
- fullError = fmt.Errorf("%w\n - %s", fullError, validationErr)
- }
-
- return nil, fullError
- }
-
- // If there are no errors, we can (try to) add the TaskDefinition to our list.
- if workspaceDefinition, ok := workspaceTurboJSON.Pipeline[taskName]; ok {
- taskDefinitions = append(taskDefinitions, workspaceDefinition)
- }
- }
- }
-
- if len(taskDefinitions) == 0 {
- return nil, fmt.Errorf("Could not find \"%s\" in root turbo.json or \"%s\" workspace", taskID, taskIDPackage)
- }
-
- return taskDefinitions, nil
-}
-
-func validateNoPackageTaskSyntax(turboJSON *fs.TurboJSON) []error {
- errors := []error{}
-
- for taskIDOrName := range turboJSON.Pipeline {
- if util.IsPackageTask(taskIDOrName) {
- taskName := util.StripPackageName(taskIDOrName)
- errors = append(errors, fmt.Errorf("\"%s\". Use \"%s\" instead", taskIDOrName, taskName))
- }
- }
-
- return errors
-}
-
-func validateExtends(turboJSON *fs.TurboJSON) []error {
- extendErrors := []error{}
- extends := turboJSON.Extends
- // TODO(mehulkar): Enable extending from more than one workspace.
- if len(extends) > 1 {
- extendErrors = append(extendErrors, fmt.Errorf("You can only extend from the root workspace"))
- }
-
- // We don't support this right now
- if len(extends) == 0 {
- extendErrors = append(extendErrors, fmt.Errorf("No \"extends\" key found"))
- }
-
- // TODO(mehulkar): Enable extending from non-root workspace.
- if len(extends) == 1 && extends[0] != util.RootPkgName {
- extendErrors = append(extendErrors, fmt.Errorf("You can only extend from the root workspace"))
- }
-
- return extendErrors
-}
diff --git a/cli/internal/core/engine_test.go b/cli/internal/core/engine_test.go
deleted file mode 100644
index a92264d..0000000
--- a/cli/internal/core/engine_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package core
-
-import (
- "errors"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/graph"
- "github.com/vercel/turbo/cli/internal/workspace"
- "gotest.tools/v3/assert"
-
- "github.com/pyr-sh/dag"
-)
-
-func TestShortCircuiting(t *testing.T) {
- var workspaceGraph dag.AcyclicGraph
- workspaceGraph.Add("a")
- workspaceGraph.Add("b")
- workspaceGraph.Add("c")
- // Dependencies: a -> b -> c
- workspaceGraph.Connect(dag.BasicEdge("a", "b"))
- workspaceGraph.Connect(dag.BasicEdge("b", "c"))
-
- buildTask := &fs.BookkeepingTaskDefinition{}
- err := buildTask.UnmarshalJSON([]byte("{\"dependsOn\": [\"^build\"]}"))
- assert.NilError(t, err, "BookkeepingTaskDefinition unmarshall")
-
- pipeline := map[string]fs.BookkeepingTaskDefinition{
- "build": *buildTask,
- }
-
- p := NewEngine(&graph.CompleteGraph{
- WorkspaceGraph: workspaceGraph,
- Pipeline: pipeline,
- TaskDefinitions: map[string]*fs.TaskDefinition{},
- WorkspaceInfos: workspace.Catalog{
- PackageJSONs: map[string]*fs.PackageJSON{
- "//": {},
- "a": {},
- "b": {},
- "c": {},
- },
- TurboConfigs: map[string]*fs.TurboJSON{
- "//": {
- Pipeline: pipeline,
- },
- },
- },
- }, false)
-
- p.AddTask("build")
-
- err = p.Prepare(&EngineBuildingOptions{
- Packages: []string{"a", "b", "c"},
- TaskNames: []string{"build"},
- TasksOnly: false,
- })
-
- if err != nil {
- t.Fatalf("%v", err)
- }
-
- executed := map[string]bool{
- "a#build": false,
- "b#build": false,
- "c#build": false,
- }
- expectedErr := errors.New("an error occurred")
- // b#build is going to error, we expect to not execute a#build, which depends on b
- testVisitor := func(taskID string) error {
- println(taskID)
- executed[taskID] = true
- if taskID == "b#build" {
- return expectedErr
- }
- return nil
- }
-
- errs := p.Execute(testVisitor, EngineExecutionOptions{
- Concurrency: 10,
- })
- assert.Equal(t, len(errs), 1)
- assert.Equal(t, errs[0], expectedErr)
-
- assert.Equal(t, executed["c#build"], true)
- assert.Equal(t, executed["b#build"], true)
- assert.Equal(t, executed["a#build"], false)
-}
diff --git a/cli/internal/daemon/connector/connector.go b/cli/internal/daemon/connector/connector.go
deleted file mode 100644
index d05ef59..0000000
--- a/cli/internal/daemon/connector/connector.go
+++ /dev/null
@@ -1,391 +0,0 @@
-package connector
-
-import (
- "context"
- "fmt"
- "io/fs"
- "os"
- "os/exec"
- "time"
-
- "github.com/cenkalti/backoff/v4"
- "github.com/hashicorp/go-hclog"
- "github.com/nightlyone/lockfile"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbodprotocol"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/credentials/insecure"
- "google.golang.org/grpc/status"
-)
-
-var (
- // ErrFailedToStart is returned when the daemon process cannot be started
- ErrFailedToStart = errors.New("daemon could not be started")
- // ErrVersionMismatch is returned when the daemon process was spawned by a different version than the connecting client
- ErrVersionMismatch = errors.New("daemon version does not match client version")
- errConnectionFailure = errors.New("could not connect to daemon")
- // ErrTooManyAttempts is returned when the client fails to connect too many times
- ErrTooManyAttempts = errors.New("reached maximum number of attempts contacting daemon")
- // ErrDaemonNotRunning is returned when the client cannot contact the daemon and has
- // been instructed not to attempt to start a new daemon
- ErrDaemonNotRunning = errors.New("the daemon is not running")
-)
-
-// Opts is the set of configurable options for the client connection,
-// including some options to be passed through to the daemon process if
-// it needs to be started.
-type Opts struct {
- ServerTimeout time.Duration
- DontStart bool // if true, don't attempt to start the daemon
- DontKill bool // if true, don't attempt to kill the daemon
-}
-
-// Client represents a connection to the daemon process
-type Client struct {
- turbodprotocol.TurbodClient
- *grpc.ClientConn
- SockPath turbopath.AbsoluteSystemPath
- PidPath turbopath.AbsoluteSystemPath
- LogPath turbopath.AbsoluteSystemPath
-}
-
-// Connector instances are used to create a connection to turbo's daemon process
-// The daemon will be started , or killed and restarted, if necessary
-type Connector struct {
- Logger hclog.Logger
- Bin string
- Opts Opts
- SockPath turbopath.AbsoluteSystemPath
- PidPath turbopath.AbsoluteSystemPath
- LogPath turbopath.AbsoluteSystemPath
- TurboVersion string
-}
-
-// ConnectionError is returned in the error case from connect. It wraps the underlying
-// cause and adds a message with the relevant files for the user to check.
-type ConnectionError struct {
- SockPath turbopath.AbsoluteSystemPath
- PidPath turbopath.AbsoluteSystemPath
- LogPath turbopath.AbsoluteSystemPath
- cause error
-}
-
-func (ce *ConnectionError) Error() string {
- return fmt.Sprintf(`connection to turbo daemon process failed. Please ensure the following:
- - the process identified by the pid in the file at %v is not running, and remove %v
- - check the logs at %v
- - the unix domain socket at %v has been removed
- You can also run without the daemon process by passing --no-daemon`, ce.PidPath, ce.PidPath, ce.LogPath, ce.SockPath)
-}
-
-// Unwrap allows a connection error to work with standard library "errors" and compatible packages
-func (ce *ConnectionError) Unwrap() error {
- return ce.cause
-}
-
-func (c *Connector) wrapConnectionError(err error) error {
- return &ConnectionError{
- SockPath: c.SockPath,
- PidPath: c.PidPath,
- LogPath: c.LogPath,
- cause: err,
- }
-}
-
-// lockFile returns a pointer to where a lockfile should be.
-// lockfile.New does not perform IO and the only error it produces
-// is in the case a non-absolute path was provided. We're guaranteeing an
-// turbopath.AbsoluteSystemPath, so an error here is an indication of a bug and
-// we should crash.
-func (c *Connector) lockFile() lockfile.Lockfile {
- lockFile, err := lockfile.New(c.PidPath.ToString())
- if err != nil {
- panic(err)
- }
- return lockFile
-}
-
-func (c *Connector) addr() string {
- // grpc special-cases parsing of unix:<path> urls
- // to avoid url.Parse. This lets us pass through our absolute
- // paths unmodified, even on windows.
- // See code here: https://github.com/grpc/grpc-go/blob/d83070ec0d9043f713b6a63e1963c593b447208c/internal/transport/http_util.go#L392
- return fmt.Sprintf("unix:%v", c.SockPath.ToString())
-}
-
-// We defer to the daemon's pid file as the locking mechanism.
-// If it doesn't exist, we will attempt to start the daemon.
-// If the daemon has a different version, ask it to shut down.
-// If the pid file exists but we can't connect, try to kill
-// the daemon.
-// If we can't cause the daemon to remove the pid file, report
-// an error to the user that includes the file location so that
-// they can resolve it.
-const (
- _maxAttempts = 3
- _shutdownTimeout = 1 * time.Second
- _socketPollTimeout = 1 * time.Second
-)
-
-// killLiveServer tells a running server to shut down. This method is also responsible
-// for closing this client connection.
-func (c *Connector) killLiveServer(ctx context.Context, client *Client, serverPid int) error {
- defer func() { _ = client.Close() }()
-
- _, err := client.Shutdown(ctx, &turbodprotocol.ShutdownRequest{})
- if err != nil {
- c.Logger.Error(fmt.Sprintf("failed to shutdown running daemon. attempting to force it closed: %v", err))
- return c.killDeadServer(serverPid)
- }
- // Wait for the server to gracefully exit
- err = backoff.Retry(func() error {
- lockFile := c.lockFile()
- owner, err := lockFile.GetOwner()
- if os.IsNotExist(err) {
- // If there is no pid more file, we can conclude that the daemon successfully
- // exited and cleaned up after itself.
- return nil
- } else if err != nil {
- // some other error occurred getting the lockfile owner
- return backoff.Permanent(err)
- } else if owner.Pid == serverPid {
- // // We're still waiting for the server to shut down
- return errNeedsRetry
- }
- // if there's no error and the lockfile has a new pid, someone else must've started a new daemon.
- // Consider the old one killed and move on.
- return nil
- }, backoffWithTimeout(_shutdownTimeout))
- if errors.Is(err, errNeedsRetry) {
- c.Logger.Error(fmt.Sprintf("daemon did not exit after %v, attempting to force it closed", _shutdownTimeout.String()))
- return c.killDeadServer(serverPid)
- } else if err != nil {
- return err
- }
- return nil
-}
-
-func (c *Connector) killDeadServer(pid int) error {
- // currently the only error that this constructor returns is
- // in the case that you don't provide an absolute path.
- // Given that we require an absolute path as input, this should
- // hopefully never happen.
- lockFile := c.lockFile()
- process, err := lockFile.GetOwner()
- if err == nil {
- // Check that this is the same process that we failed to connect to.
- // Otherwise, connectInternal will loop around again and start with whatever
- // new process has the pid file.
- if process.Pid == pid {
- // we have a process that we need to kill
- // TODO(gsoltis): graceful kill? the process is already not responding to requests,
- // but it could be in the middle of a graceful shutdown. Probably should let it clean
- // itself up, and report an error and defer to a force-kill by the user
- if err := process.Kill(); err != nil {
- return err
- }
- }
- return nil
- } else if errors.Is(err, os.ErrNotExist) {
- // There's no pid file. Someone else killed it. Returning no error will cause the
- // connectInternal to loop around and try the connection again.
- return nil
- }
- return err
-}
-
-// Connect attempts to create a connection to a turbo daemon.
-// Retries and daemon restarts are built in. If this fails,
-// it is unlikely to succeed after an automated retry.
-func (c *Connector) Connect(ctx context.Context) (*Client, error) {
- client, err := c.connectInternal(ctx)
- if err != nil {
- return nil, c.wrapConnectionError(err)
- }
- return client, nil
-}
-
-func (c *Connector) connectInternal(ctx context.Context) (*Client, error) {
- // for each attempt, we:
- // 1. try to find or start a daemon process, getting its pid
- // 2. wait for the unix domain socket file to appear
- // 3. connect to the unix domain socket. Note that this connection is not validated
- // 4. send a hello message. This validates the connection as a side effect of
- // negotiating versions, which currently requires exact match.
- // In the event of a live, but incompatible server, we attempt to shut it down and start
- // a new one. In the event of an unresponsive server, we attempt to kill the process
- // identified by the pid file, with the hope that it will clean up after itself.
- // Failures include details about where to find logs, the pid file, and the socket file.
- for i := 0; i < _maxAttempts; i++ {
- serverPid, err := c.getOrStartDaemon()
- if err != nil {
- // If we fail to even start the daemon process, return immediately, we're unlikely
- // to succeed without user intervention
- return nil, err
- }
- if err := c.waitForSocket(); errors.Is(err, ErrFailedToStart) {
- // If we didn't see the socket file, try again. It's possible that
- // the daemon encountered an transitory error
- continue
- } else if err != nil {
- return nil, err
- }
- client, err := c.getClientConn()
- if err != nil {
- return nil, err
- }
- if err := c.sendHello(ctx, client); err == nil {
- // We connected and negotiated a version, we're all set
- return client, nil
- } else if errors.Is(err, ErrVersionMismatch) {
- // We don't want to knock down a perfectly fine daemon in a status check.
- if c.Opts.DontKill {
- return nil, err
- }
-
- // We now know we aren't going to return this client,
- // but killLiveServer still needs it to send the Shutdown request.
- // killLiveServer will close the client when it is done with it.
- if err := c.killLiveServer(ctx, client, serverPid); err != nil {
- return nil, err
- }
- // Loops back around and tries again.
- } else if errors.Is(err, errConnectionFailure) {
- // close the client, see if we can kill the stale daemon
- _ = client.Close()
- if err := c.killDeadServer(serverPid); err != nil {
- return nil, err
- }
- // if we successfully killed the dead server, loop around and try again
- } else if err != nil {
- // Some other error occurred, close the client and
- // report the error to the user
- if closeErr := client.Close(); closeErr != nil {
- // In the event that we fail to close the client, bundle that error along also.
- // Keep the original error in the error chain, as it's more likely to be useful
- // or needed for matching on later.
- err = errors.Wrapf(err, "also failed to close client connection: %v", closeErr)
- }
- return nil, err
- }
- }
- return nil, ErrTooManyAttempts
-}
-
-// getOrStartDaemon returns the PID of the daemon process on success. It may start
-// the daemon if it doesn't find one running.
-func (c *Connector) getOrStartDaemon() (int, error) {
- lockFile := c.lockFile()
- daemonProcess, getDaemonProcessErr := lockFile.GetOwner()
- if getDaemonProcessErr != nil {
- // If we're in a clean state this isn't an "error" per se.
- // We attempt to start a daemon.
- if errors.Is(getDaemonProcessErr, fs.ErrNotExist) {
- if c.Opts.DontStart {
- return 0, ErrDaemonNotRunning
- }
- pid, startDaemonErr := c.startDaemon()
- if startDaemonErr != nil {
- return 0, startDaemonErr
- }
- return pid, nil
- }
-
- // We could have hit any number of errors.
- // - Failed to read the file for permission reasons.
- // - User emptied the file's contents.
- // - etc.
- return 0, errors.Wrapf(getDaemonProcessErr, "An issue was encountered with the pid file. Please remove it and try again: %v", c.PidPath)
- }
-
- return daemonProcess.Pid, nil
-}
-
-func (c *Connector) getClientConn() (*Client, error) {
- creds := insecure.NewCredentials()
- conn, err := grpc.Dial(c.addr(), grpc.WithTransportCredentials(creds))
- if err != nil {
- return nil, err
- }
- tc := turbodprotocol.NewTurbodClient(conn)
- return &Client{
- TurbodClient: tc,
- ClientConn: conn,
- SockPath: c.SockPath,
- PidPath: c.PidPath,
- LogPath: c.LogPath,
- }, nil
-}
-
-func (c *Connector) sendHello(ctx context.Context, client turbodprotocol.TurbodClient) error {
- _, err := client.Hello(ctx, &turbodprotocol.HelloRequest{
- Version: c.TurboVersion,
- // TODO: add session id
- })
- status := status.Convert(err)
- switch status.Code() {
- case codes.OK:
- return nil
- case codes.FailedPrecondition:
- return ErrVersionMismatch
- case codes.Unavailable:
- return errConnectionFailure
- default:
- return err
- }
-}
-
-var errNeedsRetry = errors.New("retry the operation")
-
-// backoffWithTimeout returns an exponential backoff, starting at 2ms and doubling until
-// the specific timeout has elapsed. Note that backoff instances are stateful, so we need
-// a new one each time we do a Retry.
-func backoffWithTimeout(timeout time.Duration) *backoff.ExponentialBackOff {
- return &backoff.ExponentialBackOff{
- Multiplier: 2,
- InitialInterval: 2 * time.Millisecond,
- MaxElapsedTime: timeout,
- Clock: backoff.SystemClock,
- Stop: backoff.Stop,
- }
-}
-
-// waitForSocket waits for the unix domain socket to appear
-func (c *Connector) waitForSocket() error {
- // Note that we don't care if this is our daemon
- // or not. We started a process, but someone else could beat
- // use to listening. That's fine, we'll check the version
- // later.
- err := backoff.Retry(func() error {
- if !c.SockPath.FileExists() {
- return errNeedsRetry
- }
- return nil
- }, backoffWithTimeout(_socketPollTimeout))
- if errors.Is(err, errNeedsRetry) {
- return ErrFailedToStart
- } else if err != nil {
- return err
- }
- return nil
-}
-
-// startDaemon starts the daemon and returns the pid for the new process
-func (c *Connector) startDaemon() (int, error) {
- args := []string{"daemon"}
- if c.Opts.ServerTimeout != 0 {
- args = append(args, fmt.Sprintf("--idle-time=%v", c.Opts.ServerTimeout.String()))
- }
- c.Logger.Debug(fmt.Sprintf("starting turbod binary %v", c.Bin))
- cmd := exec.Command(c.Bin, args...)
- // For the daemon to have its own process group id so that any attempts
- // to kill it and its process tree don't kill this client.
- cmd.SysProcAttr = getSysProcAttrs()
- err := cmd.Start()
- if err != nil {
- return 0, err
- }
- return cmd.Process.Pid, nil
-}
diff --git a/cli/internal/daemon/connector/connector_test.go b/cli/internal/daemon/connector/connector_test.go
deleted file mode 100644
index 62b4504..0000000
--- a/cli/internal/daemon/connector/connector_test.go
+++ /dev/null
@@ -1,256 +0,0 @@
-package connector
-
-import (
- "context"
- "errors"
- "net"
- "os/exec"
- "runtime"
- "strconv"
- "testing"
-
- "github.com/hashicorp/go-hclog"
- "github.com/nightlyone/lockfile"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbodprotocol"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/credentials/insecure"
- "google.golang.org/grpc/status"
- "google.golang.org/grpc/test/bufconn"
- "gotest.tools/v3/assert"
-)
-
-// testBin returns a platform-appropriate executable to run node.
-// Node works here as an arbitrary process to start, since it's
-// required for turbo development. It will obviously not implement
-// our grpc service, use a mockServer instance where that's needed.
-func testBin() string {
- if runtime.GOOS == "windows" {
- return "node.exe"
- }
- return "node"
-}
-
-func getUnixSocket(dir turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- return dir.UntypedJoin("turbod-test.sock")
-}
-
-func getPidFile(dir turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- return dir.UntypedJoin("turbod-test.pid")
-}
-
-func TestGetOrStartDaemonInvalidPIDFile(t *testing.T) {
- logger := hclog.Default()
- dir := t.TempDir()
- dirPath := fs.AbsoluteSystemPathFromUpstream(dir)
-
- pidPath := getPidFile(dirPath)
- writeFileErr := pidPath.WriteFile(nil, 0777)
- assert.NilError(t, writeFileErr, "WriteFile")
-
- c := &Connector{
- Logger: logger,
- Opts: Opts{},
- PidPath: pidPath,
- }
-
- pid, err := c.getOrStartDaemon()
- assert.Equal(t, pid, 0)
- assert.ErrorContains(t, err, "issue was encountered with the pid file")
-}
-
-func TestConnectFailsWithoutGrpcServer(t *testing.T) {
- // We aren't starting a server that is going to write
- // to our socket file, so we should see a series of connection
- // failures, followed by ErrTooManyAttempts
- logger := hclog.Default()
- dir := t.TempDir()
- dirPath := fs.AbsoluteSystemPathFromUpstream(dir)
-
- sockPath := getUnixSocket(dirPath)
- pidPath := getPidFile(dirPath)
- ctx := context.Background()
- bin := testBin()
- c := &Connector{
- Logger: logger,
- Bin: bin,
- Opts: Opts{},
- SockPath: sockPath,
- PidPath: pidPath,
- }
- // Note that we expect ~3s here, for 3 attempts with a timeout of 1s
- _, err := c.connectInternal(ctx)
- assert.ErrorIs(t, err, ErrTooManyAttempts)
-}
-
-func TestKillDeadServerNoPid(t *testing.T) {
- logger := hclog.Default()
- dir := t.TempDir()
- dirPath := fs.AbsoluteSystemPathFromUpstream(dir)
-
- sockPath := getUnixSocket(dirPath)
- pidPath := getPidFile(dirPath)
- c := &Connector{
- Logger: logger,
- Bin: "nonexistent",
- Opts: Opts{},
- SockPath: sockPath,
- PidPath: pidPath,
- }
-
- err := c.killDeadServer(99999)
- assert.NilError(t, err, "killDeadServer")
-}
-
-func TestKillDeadServerNoProcess(t *testing.T) {
- logger := hclog.Default()
- dir := t.TempDir()
- dirPath := fs.AbsoluteSystemPathFromUpstream(dir)
-
- sockPath := getUnixSocket(dirPath)
- pidPath := getPidFile(dirPath)
- // Simulate the socket already existing, with no live daemon
- err := sockPath.WriteFile([]byte("junk"), 0644)
- assert.NilError(t, err, "WriteFile")
- err = pidPath.WriteFile([]byte("99999"), 0644)
- assert.NilError(t, err, "WriteFile")
- c := &Connector{
- Logger: logger,
- Bin: "nonexistent",
- Opts: Opts{},
- SockPath: sockPath,
- PidPath: pidPath,
- }
-
- err = c.killDeadServer(99999)
- assert.ErrorIs(t, err, lockfile.ErrDeadOwner)
- stillExists := pidPath.FileExists()
- if !stillExists {
- t.Error("pidPath should still exist, expected the user to clean it up")
- }
-}
-
-func TestKillDeadServerWithProcess(t *testing.T) {
- logger := hclog.Default()
- dir := t.TempDir()
- dirPath := fs.AbsoluteSystemPathFromUpstream(dir)
-
- sockPath := getUnixSocket(dirPath)
- pidPath := getPidFile(dirPath)
- // Simulate the socket already existing, with no live daemon
- err := sockPath.WriteFile([]byte("junk"), 0644)
- assert.NilError(t, err, "WriteFile")
- bin := testBin()
- cmd := exec.Command(bin)
- err = cmd.Start()
- assert.NilError(t, err, "cmd.Start")
- pid := cmd.Process.Pid
- if pid == 0 {
- t.Fatalf("failed to start process %v", bin)
- }
-
- err = pidPath.WriteFile([]byte(strconv.Itoa(pid)), 0644)
- assert.NilError(t, err, "WriteFile")
- c := &Connector{
- Logger: logger,
- Bin: "nonexistent",
- Opts: Opts{},
- SockPath: sockPath,
- PidPath: pidPath,
- }
-
- err = c.killDeadServer(pid)
- assert.NilError(t, err, "killDeadServer")
- stillExists := pidPath.FileExists()
- if !stillExists {
- t.Error("pidPath no longer exists, expected client to not clean it up")
- }
- err = cmd.Wait()
- exitErr := &exec.ExitError{}
- if !errors.As(err, &exitErr) {
- t.Errorf("expected an exit error from %v, got %v", bin, err)
- }
-}
-
-type mockServer struct {
- turbodprotocol.UnimplementedTurbodServer
- helloErr error
- shutdownResp *turbodprotocol.ShutdownResponse
- pidFile turbopath.AbsoluteSystemPath
-}
-
-// Simulates server exiting by cleaning up the pid file
-func (s *mockServer) Shutdown(ctx context.Context, req *turbodprotocol.ShutdownRequest) (*turbodprotocol.ShutdownResponse, error) {
- if err := s.pidFile.Remove(); err != nil {
- return nil, err
- }
- return s.shutdownResp, nil
-}
-
-func (s *mockServer) Hello(ctx context.Context, req *turbodprotocol.HelloRequest) (*turbodprotocol.HelloResponse, error) {
- if req.Version == "" {
- return nil, errors.New("missing version")
- }
- return nil, s.helloErr
-}
-
-func TestKillLiveServer(t *testing.T) {
- logger := hclog.Default()
- dir := t.TempDir()
- dirPath := fs.AbsoluteSystemPathFromUpstream(dir)
-
- sockPath := getUnixSocket(dirPath)
- pidPath := getPidFile(dirPath)
- err := pidPath.WriteFile([]byte("99999"), 0644)
- assert.NilError(t, err, "WriteFile")
-
- ctx := context.Background()
- c := &Connector{
- Logger: logger,
- Bin: "nonexistent",
- Opts: Opts{},
- SockPath: sockPath,
- PidPath: pidPath,
- TurboVersion: "some-version",
- }
-
- st := status.New(codes.FailedPrecondition, "version mismatch")
- mock := &mockServer{
- shutdownResp: &turbodprotocol.ShutdownResponse{},
- helloErr: st.Err(),
- pidFile: pidPath,
- }
- lis := bufconn.Listen(1024 * 1024)
- grpcServer := grpc.NewServer()
- turbodprotocol.RegisterTurbodServer(grpcServer, mock)
- go func(t *testing.T) {
- if err := grpcServer.Serve(lis); err != nil {
- t.Logf("server closed: %v", err)
- }
- }(t)
-
- conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) {
- return lis.Dial()
- }), grpc.WithTransportCredentials(insecure.NewCredentials()))
- assert.NilError(t, err, "DialContext")
- turboClient := turbodprotocol.NewTurbodClient(conn)
- client := &Client{
- TurbodClient: turboClient,
- ClientConn: conn,
- }
- err = c.sendHello(ctx, client)
- if !errors.Is(err, ErrVersionMismatch) {
- t.Errorf("sendHello error got %v, want %v", err, ErrVersionMismatch)
- }
- err = c.killLiveServer(ctx, client, 99999)
- assert.NilError(t, err, "killLiveServer")
- // Expect the pid file and socket files to have been cleaned up
- if pidPath.FileExists() {
- t.Errorf("expected pid file to have been deleted: %v", pidPath)
- }
- if sockPath.FileExists() {
- t.Errorf("expected socket file to have been deleted: %v", sockPath)
- }
-}
diff --git a/cli/internal/daemon/connector/fork.go b/cli/internal/daemon/connector/fork.go
deleted file mode 100644
index 8a6d01d..0000000
--- a/cli/internal/daemon/connector/fork.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package connector
-
-import "syscall"
-
-// getSysProcAttrs returns the platform-specific attributes we want to
-// use while forking the daemon process. Currently this is limited to
-// forcing a new process group
-func getSysProcAttrs() *syscall.SysProcAttr {
- return &syscall.SysProcAttr{
- Setpgid: true,
- }
-}
diff --git a/cli/internal/daemon/connector/fork_windows.go b/cli/internal/daemon/connector/fork_windows.go
deleted file mode 100644
index b9d6e77..0000000
--- a/cli/internal/daemon/connector/fork_windows.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build windows
-// +build windows
-
-package connector
-
-import "syscall"
-
-// getSysProcAttrs returns the platform-specific attributes we want to
-// use while forking the daemon process. Currently this is limited to
-// forcing a new process group
-func getSysProcAttrs() *syscall.SysProcAttr {
- return &syscall.SysProcAttr{
- CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
- }
-}
diff --git a/cli/internal/daemon/daemon.go b/cli/internal/daemon/daemon.go
deleted file mode 100644
index 81d5283..0000000
--- a/cli/internal/daemon/daemon.go
+++ /dev/null
@@ -1,307 +0,0 @@
-package daemon
-
-import (
- "context"
- "crypto/sha256"
- "encoding/hex"
- "fmt"
- "io"
- "net"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
- "github.com/hashicorp/go-hclog"
- "github.com/nightlyone/lockfile"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/daemon/connector"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/server"
- "github.com/vercel/turbo/cli/internal/signals"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
-)
-
-type daemon struct {
- logger hclog.Logger
- repoRoot turbopath.AbsoluteSystemPath
- timeout time.Duration
- reqCh chan struct{}
- timedOutCh chan struct{}
-}
-
-func getRepoHash(repoRoot turbopath.AbsoluteSystemPath) string {
- pathHash := sha256.Sum256([]byte(repoRoot.ToString()))
- // We grab a substring of the hash because there is a 108-character limit on the length
- // of a filepath for unix domain socket.
- return hex.EncodeToString(pathHash[:])[:16]
-}
-
-func getDaemonFileRoot(repoRoot turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- tempDir := fs.TempDir("turbod")
- hexHash := getRepoHash(repoRoot)
- return tempDir.UntypedJoin(hexHash)
-}
-
-func getLogFilePath(repoRoot turbopath.AbsoluteSystemPath) (turbopath.AbsoluteSystemPath, error) {
- hexHash := getRepoHash(repoRoot)
- base := repoRoot.Base()
- logFilename := fmt.Sprintf("%v-%v.log", hexHash, base)
-
- logsDir := fs.GetTurboDataDir().UntypedJoin("logs")
- return logsDir.UntypedJoin(logFilename), nil
-}
-
-func getUnixSocket(repoRoot turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- root := getDaemonFileRoot(repoRoot)
- return root.UntypedJoin("turbod.sock")
-}
-
-func getPidFile(repoRoot turbopath.AbsoluteSystemPath) turbopath.AbsoluteSystemPath {
- root := getDaemonFileRoot(repoRoot)
- return root.UntypedJoin("turbod.pid")
-}
-
-// logError logs an error and outputs it to the UI.
-func (d *daemon) logError(err error) {
- d.logger.Error(fmt.Sprintf("error %v", err))
-}
-
-// we're only appending, and we're creating the file if it doesn't exist.
-// we do not need to read the log file.
-var _logFileFlags = os.O_WRONLY | os.O_APPEND | os.O_CREATE
-
-// ExecuteDaemon executes the root daemon command
-func ExecuteDaemon(ctx context.Context, helper *cmdutil.Helper, signalWatcher *signals.Watcher, args *turbostate.ParsedArgsFromRust) error {
- base, err := helper.GetCmdBase(args)
- if err != nil {
- return err
- }
- if args.TestRun {
- base.UI.Info("Daemon test run successful")
- return nil
- }
-
- idleTimeout := 4 * time.Hour
- if args.Command.Daemon.IdleTimeout != "" {
- idleTimeout, err = time.ParseDuration(args.Command.Daemon.IdleTimeout)
- if err != nil {
- return err
- }
- }
-
- logFilePath, err := getLogFilePath(base.RepoRoot)
- if err != nil {
- return err
- }
- if err := logFilePath.EnsureDir(); err != nil {
- return err
- }
- logFile, err := logFilePath.OpenFile(_logFileFlags, 0644)
- if err != nil {
- return err
- }
- defer func() { _ = logFile.Close() }()
- logger := hclog.New(&hclog.LoggerOptions{
- Output: io.MultiWriter(logFile, os.Stdout),
- Level: hclog.Info,
- Color: hclog.ColorOff,
- Name: "turbod",
- })
-
- d := &daemon{
- logger: logger,
- repoRoot: base.RepoRoot,
- timeout: idleTimeout,
- reqCh: make(chan struct{}),
- timedOutCh: make(chan struct{}),
- }
- serverName := getRepoHash(base.RepoRoot)
- turboServer, err := server.New(serverName, d.logger.Named("rpc server"), base.RepoRoot, base.TurboVersion, logFilePath)
- if err != nil {
- d.logError(err)
- return err
- }
- defer func() { _ = turboServer.Close() }()
- err = d.runTurboServer(ctx, turboServer, signalWatcher)
- if err != nil {
- d.logError(err)
- return err
- }
- return nil
-}
-
-var errInactivityTimeout = errors.New("turbod shut down from inactivity")
-
-// tryAcquirePidfileLock attempts to ensure that only one daemon is running from the given pid file path
-// at a time. If this process fails to write its PID to the lockfile, it must exit.
-func tryAcquirePidfileLock(pidPath turbopath.AbsoluteSystemPath) (lockfile.Lockfile, error) {
- if err := pidPath.EnsureDir(); err != nil {
- return "", err
- }
- lockFile, err := lockfile.New(pidPath.ToString())
- if err != nil {
- // lockfile.New should only return an error if it wasn't given an absolute path.
- // We are attempting to use the type system to enforce that we are passing an
- // absolute path. An error here likely means a bug, and we should crash.
- panic(err)
- }
- if err := lockFile.TryLock(); err != nil {
- return "", err
- }
- return lockFile, nil
-}
-
-type rpcServer interface {
- Register(grpcServer server.GRPCServer)
-}
-
-func (d *daemon) runTurboServer(parentContext context.Context, rpcServer rpcServer, signalWatcher *signals.Watcher) error {
- ctx, cancel := context.WithCancel(parentContext)
- defer cancel()
- pidPath := getPidFile(d.repoRoot)
- lock, err := tryAcquirePidfileLock(pidPath)
- if err != nil {
- return errors.Wrapf(err, "failed to lock the pid file at %v. Is another turbo daemon running?", lock)
- }
- // When we're done serving, clean up the pid file.
- // Also, if *this* goroutine panics, make sure we unlock the pid file.
- defer func() {
- if err := lock.Unlock(); err != nil {
- d.logger.Error(errors.Wrapf(err, "failed unlocking pid file at %v", lock).Error())
- }
- }()
- // This handler runs in request goroutines. If a request causes a panic,
- // this handler will get called after a call to recover(), meaning we are
- // no longer panicking. We return a server error and cancel our context,
- // which triggers a shutdown of the server.
- panicHandler := func(thePanic interface{}) error {
- cancel()
- d.logger.Error(fmt.Sprintf("Caught panic %v", thePanic))
- return status.Error(codes.Internal, "server panicked")
- }
-
- // If we have the lock, assume that we are the owners of the socket file,
- // whether it already exists or not. That means we are free to remove it.
- sockPath := getUnixSocket(d.repoRoot)
- if err := sockPath.Remove(); err != nil && !errors.Is(err, os.ErrNotExist) {
- return err
- }
- d.logger.Debug(fmt.Sprintf("Using socket path %v (%v)\n", sockPath, len(sockPath)))
- lis, err := net.Listen("unix", sockPath.ToString())
- if err != nil {
- return err
- }
- // We don't need to explicitly close 'lis', the grpc server will handle that
- s := grpc.NewServer(
- grpc.ChainUnaryInterceptor(
- d.onRequest,
- grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandler(panicHandler)),
- ),
- )
- go d.timeoutLoop(ctx)
-
- rpcServer.Register(s)
- errCh := make(chan error)
- go func(errCh chan<- error) {
- if err := s.Serve(lis); err != nil {
- errCh <- err
- }
- close(errCh)
- }(errCh)
-
- // Note that we aren't deferring s.GracefulStop here because we also need
- // to drain the error channel, which isn't guaranteed to happen until
- // the server has stopped. That in turn may depend on GracefulStop being
- // called.
- // Future work could restructure this to make that simpler.
- var exitErr error
- select {
- case err, ok := <-errCh:
- // The server exited
- if ok {
- exitErr = err
- }
- case <-d.timedOutCh:
- // This is the inactivity timeout case
- exitErr = errInactivityTimeout
- s.GracefulStop()
- case <-ctx.Done():
- // If a request handler panics, it will cancel this context
- s.GracefulStop()
- case <-signalWatcher.Done():
- // This is fired if caught a signal
- s.GracefulStop()
- }
- // Wait for the server to exit, if it hasn't already.
- // When it does, this channel will close. We don't
- // care about the error in this scenario because we've
- // either requested a close via cancelling the context,
- // an inactivity timeout, or caught a signal.
- for range errCh {
- }
- return exitErr
-}
-
-func (d *daemon) onRequest(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
- d.reqCh <- struct{}{}
- return handler(ctx, req)
-}
-
-func (d *daemon) timeoutLoop(ctx context.Context) {
- timeoutCh := time.After(d.timeout)
-outer:
- for {
- select {
- case <-d.reqCh:
- timeoutCh = time.After(d.timeout)
- case <-timeoutCh:
- close(d.timedOutCh)
- break outer
- case <-ctx.Done():
- break outer
- }
- }
-}
-
-// ClientOpts re-exports connector.Ops to encapsulate the connector package
-type ClientOpts = connector.Opts
-
-// Client re-exports connector.Client to encapsulate the connector package
-type Client = connector.Client
-
-// GetClient returns a client that can be used to interact with the daemon
-func GetClient(ctx context.Context, repoRoot turbopath.AbsoluteSystemPath, logger hclog.Logger, turboVersion string, opts ClientOpts) (*Client, error) {
- sockPath := getUnixSocket(repoRoot)
- pidPath := getPidFile(repoRoot)
- logPath, err := getLogFilePath(repoRoot)
- if err != nil {
- return nil, err
- }
- bin, err := os.Executable()
- if err != nil {
- return nil, err
- }
- // The Go binary can no longer be called directly, so we need to route back to the rust wrapper
- if strings.HasSuffix(bin, "go-turbo") {
- bin = filepath.Join(filepath.Dir(bin), "turbo")
- } else if strings.HasSuffix(bin, "go-turbo.exe") {
- bin = filepath.Join(filepath.Dir(bin), "turbo.exe")
- }
- c := &connector.Connector{
- Logger: logger.Named("TurbodClient"),
- Bin: bin,
- Opts: opts,
- SockPath: sockPath,
- PidPath: pidPath,
- LogPath: logPath,
- TurboVersion: turboVersion,
- }
- return c.Connect(ctx)
-}
diff --git a/cli/internal/daemon/daemon_test.go b/cli/internal/daemon/daemon_test.go
deleted file mode 100644
index 66a714d..0000000
--- a/cli/internal/daemon/daemon_test.go
+++ /dev/null
@@ -1,262 +0,0 @@
-package daemon
-
-import (
- "context"
- "errors"
- "os/exec"
- "runtime"
- "strconv"
- "sync"
- "testing"
- "time"
-
- "github.com/hashicorp/go-hclog"
- "github.com/nightlyone/lockfile"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/server"
- "github.com/vercel/turbo/cli/internal/signals"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials/insecure"
- "google.golang.org/grpc/test/grpc_testing"
- "gotest.tools/v3/assert"
-)
-
-// testBin returns a platform-appropriate node binary.
-// We need some process to be running and findable by the
-// lockfile library, and we don't particularly care what it is.
-// Since node is required for turbo development, it makes a decent
-// candidate.
-func testBin() string {
- if runtime.GOOS == "windows" {
- return "node.exe"
- }
- return "node"
-}
-
-func TestPidFileLock(t *testing.T) {
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- pidPath := getPidFile(repoRoot)
- // the lockfile library handles removing pids from dead owners
- _, err := tryAcquirePidfileLock(pidPath)
- assert.NilError(t, err, "acquirePidLock")
-
- // Start up a node process and fake a pid file for it.
- // Ensure that we can't start the daemon while the node process is live
- bin := testBin()
- node := exec.Command(bin)
- err = node.Start()
- assert.NilError(t, err, "Start")
- stopNode := func() error {
- if err := node.Process.Kill(); err != nil {
- return err
- }
- // We expect an error from node, we just sent a kill signal
- _ = node.Wait()
- return nil
- }
- // In case we fail the test, still try to kill the node process
- t.Cleanup(func() { _ = stopNode() })
- nodePid := node.Process.Pid
- err = pidPath.WriteFile([]byte(strconv.Itoa(nodePid)), 0644)
- assert.NilError(t, err, "WriteFile")
-
- _, err = tryAcquirePidfileLock(pidPath)
- assert.ErrorIs(t, err, lockfile.ErrBusy)
-
- // Stop the node process, but leave the pid file there
- // This simulates a crash
- err = stopNode()
- assert.NilError(t, err, "stopNode")
- // the lockfile library handles removing pids from dead owners
- _, err = tryAcquirePidfileLock(pidPath)
- assert.NilError(t, err, "acquirePidLock")
-}
-
-type testRPCServer struct {
- grpc_testing.UnimplementedTestServiceServer
- registered chan struct{}
-}
-
-func (ts *testRPCServer) EmptyCall(ctx context.Context, req *grpc_testing.Empty) (*grpc_testing.Empty, error) {
- panic("intended to panic")
-}
-
-func (ts *testRPCServer) Register(grpcServer server.GRPCServer) {
- grpc_testing.RegisterTestServiceServer(grpcServer, ts)
- ts.registered <- struct{}{}
-}
-
-func newTestRPCServer() *testRPCServer {
- return &testRPCServer{
- registered: make(chan struct{}, 1),
- }
-}
-
-func waitForFile(t *testing.T, filename turbopath.AbsoluteSystemPath, timeout time.Duration) {
- t.Helper()
- deadline := time.After(timeout)
-outer:
- for !filename.FileExists() {
- select {
- case <-deadline:
- break outer
- case <-time.After(10 * time.Millisecond):
- }
- }
- if !filename.FileExists() {
- t.Errorf("timed out waiting for %v to exist after %v", filename, timeout)
- }
-}
-
-func TestDaemonLifecycle(t *testing.T) {
- logger := hclog.Default()
- logger.SetLevel(hclog.Debug)
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- ts := newTestRPCServer()
- watcher := signals.NewWatcher()
- ctx, cancel := context.WithCancel(context.Background())
-
- d := &daemon{
- logger: logger,
- repoRoot: repoRoot,
- timeout: 10 * time.Second,
- reqCh: make(chan struct{}),
- timedOutCh: make(chan struct{}),
- }
-
- var serverErr error
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- serverErr = d.runTurboServer(ctx, ts, watcher)
- wg.Done()
- }()
-
- sockPath := getUnixSocket(repoRoot)
- waitForFile(t, sockPath, 30*time.Second)
- pidPath := getPidFile(repoRoot)
- waitForFile(t, pidPath, 1*time.Second)
- cancel()
- wg.Wait()
- assert.NilError(t, serverErr, "runTurboServer")
- if sockPath.FileExists() {
- t.Errorf("%v still exists, should have been cleaned up", sockPath)
- }
- if pidPath.FileExists() {
- t.Errorf("%v still exists, should have been cleaned up", sockPath)
- }
-}
-
-func TestTimeout(t *testing.T) {
- logger := hclog.Default()
- logger.SetLevel(hclog.Debug)
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- ts := newTestRPCServer()
- watcher := signals.NewWatcher()
- ctx := context.Background()
-
- d := &daemon{
- logger: logger,
- repoRoot: repoRoot,
- timeout: 5 * time.Millisecond,
- reqCh: make(chan struct{}),
- timedOutCh: make(chan struct{}),
- }
- err := d.runTurboServer(ctx, ts, watcher)
- if !errors.Is(err, errInactivityTimeout) {
- t.Errorf("server error got %v, want %v", err, errInactivityTimeout)
- }
-}
-
-func TestCaughtSignal(t *testing.T) {
- logger := hclog.Default()
- logger.SetLevel(hclog.Debug)
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- ts := newTestRPCServer()
- watcher := signals.NewWatcher()
- ctx := context.Background()
-
- d := &daemon{
- logger: logger,
- repoRoot: repoRoot,
- timeout: 5 * time.Second,
- reqCh: make(chan struct{}),
- timedOutCh: make(chan struct{}),
- }
- errCh := make(chan error)
- go func() {
- err := d.runTurboServer(ctx, ts, watcher)
- errCh <- err
- }()
- <-ts.registered
- // grpc doesn't provide a signal to know when the server is serving.
- // So while this call to Close can race with the call to grpc.Server.Serve, if we've
- // registered with the turboserver, we've registered all of our
- // signal handlers as well. We just may or may not be serving when Close()
- // is called. It shouldn't matter for the purposes of this test:
- // Either we are serving, and Serve will return with nil when GracefulStop is
- // called, or we aren't serving yet, and the subsequent call to Serve will
- // immediately return with grpc.ErrServerStopped. So, both nil and grpc.ErrServerStopped
- // are acceptable outcomes for runTurboServer. Any other error, or a timeout, is a
- // failure.
- watcher.Close()
-
- err := <-errCh
- pidPath := getPidFile(repoRoot)
- if pidPath.FileExists() {
- t.Errorf("expected to clean up %v, but it still exists", pidPath)
- }
- // We'll either get nil or ErrServerStopped, depending on whether
- // or not we close the signal watcher before grpc.Server.Serve was
- // called.
- if err != nil && !errors.Is(err, grpc.ErrServerStopped) {
- t.Errorf("runTurboServer got err %v, want nil or ErrServerStopped", err)
- }
-}
-
-func TestCleanupOnPanic(t *testing.T) {
- logger := hclog.Default()
- logger.SetLevel(hclog.Debug)
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- ts := newTestRPCServer()
- watcher := signals.NewWatcher()
- ctx := context.Background()
-
- d := &daemon{
- logger: logger,
- repoRoot: repoRoot,
- timeout: 5 * time.Second,
- reqCh: make(chan struct{}),
- timedOutCh: make(chan struct{}),
- }
- errCh := make(chan error)
- go func() {
- err := d.runTurboServer(ctx, ts, watcher)
- errCh <- err
- }()
- <-ts.registered
-
- creds := insecure.NewCredentials()
- sockFile := getUnixSocket(repoRoot)
- conn, err := grpc.Dial("unix://"+sockFile.ToString(), grpc.WithTransportCredentials(creds))
- assert.NilError(t, err, "Dial")
-
- client := grpc_testing.NewTestServiceClient(conn)
- _, err = client.EmptyCall(ctx, &grpc_testing.Empty{})
- if err == nil {
- t.Error("nil error")
- }
- // wait for the server to finish
- <-errCh
-
- pidPath := getPidFile(repoRoot)
- if pidPath.FileExists() {
- t.Errorf("expected to clean up %v, but it still exists", pidPath)
- }
-}
diff --git a/cli/internal/daemonclient/daemonclient.go b/cli/internal/daemonclient/daemonclient.go
deleted file mode 100644
index c415cd3..0000000
--- a/cli/internal/daemonclient/daemonclient.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Package daemonclient is a wrapper around a grpc client
-// to talk to turbod
-package daemonclient
-
-import (
- "context"
-
- "github.com/vercel/turbo/cli/internal/daemon/connector"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbodprotocol"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// DaemonClient provides access to higher-level functionality from the daemon to a turbo run.
-type DaemonClient struct {
- client *connector.Client
-}
-
-// Status provides details about the daemon's status
-type Status struct {
- UptimeMs uint64 `json:"uptimeMs"`
- LogFile turbopath.AbsoluteSystemPath `json:"logFile"`
- PidFile turbopath.AbsoluteSystemPath `json:"pidFile"`
- SockFile turbopath.AbsoluteSystemPath `json:"sockFile"`
-}
-
-// New creates a new instance of a DaemonClient.
-func New(client *connector.Client) *DaemonClient {
- return &DaemonClient{
- client: client,
- }
-}
-
-// GetChangedOutputs implements runcache.OutputWatcher.GetChangedOutputs
-func (d *DaemonClient) GetChangedOutputs(ctx context.Context, hash string, repoRelativeOutputGlobs []string) ([]string, error) {
- resp, err := d.client.GetChangedOutputs(ctx, &turbodprotocol.GetChangedOutputsRequest{
- Hash: hash,
- OutputGlobs: repoRelativeOutputGlobs,
- })
- if err != nil {
- return nil, err
- }
-
- return resp.ChangedOutputGlobs, nil
-}
-
-// NotifyOutputsWritten implements runcache.OutputWatcher.NotifyOutputsWritten
-func (d *DaemonClient) NotifyOutputsWritten(ctx context.Context, hash string, repoRelativeOutputGlobs fs.TaskOutputs) error {
- _, err := d.client.NotifyOutputsWritten(ctx, &turbodprotocol.NotifyOutputsWrittenRequest{
- Hash: hash,
- OutputGlobs: repoRelativeOutputGlobs.Inclusions,
- OutputExclusionGlobs: repoRelativeOutputGlobs.Exclusions,
- })
- return err
-}
-
-// Status returns the DaemonStatus from the daemon
-func (d *DaemonClient) Status(ctx context.Context) (*Status, error) {
- resp, err := d.client.Status(ctx, &turbodprotocol.StatusRequest{})
- if err != nil {
- return nil, err
- }
- daemonStatus := resp.DaemonStatus
- return &Status{
- UptimeMs: daemonStatus.UptimeMsec,
- LogFile: d.client.LogPath,
- PidFile: d.client.PidPath,
- SockFile: d.client.SockPath,
- }, nil
-}
diff --git a/cli/internal/doublestar/doublestar.go b/cli/internal/doublestar/doublestar.go
deleted file mode 100644
index 6fa05f1..0000000
--- a/cli/internal/doublestar/doublestar.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-package doublestar
-
-import (
- "path"
-)
-
-// ErrBadPattern indicates a pattern was malformed.
-var ErrBadPattern = path.ErrBadPattern
diff --git a/cli/internal/doublestar/doublestar_test.go b/cli/internal/doublestar/doublestar_test.go
deleted file mode 100644
index 512f8b7..0000000
--- a/cli/internal/doublestar/doublestar_test.go
+++ /dev/null
@@ -1,557 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-
-// This file is mostly copied from Go's path/match_test.go
-
-package doublestar
-
-import (
- "io/fs"
- "log"
- "os"
- "path"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
-)
-
-type MatchTest struct {
- pattern, testPath string // a pattern and path to test the pattern on
- shouldMatch bool // true if the pattern should match the path
- expectedErr error // an expected error
- isStandard bool // pattern doesn't use any doublestar features
- testOnDisk bool // true: test pattern against files in "test" directory
- numResults int // number of glob results if testing on disk
- winNumResults int // number of glob results on Windows
-}
-
-// Tests which contain escapes and symlinks will not work on Windows
-var onWindows = runtime.GOOS == "windows"
-
-var matchTests = []MatchTest{
- {"*", "", true, nil, true, false, 0, 0},
- {"*", "/", false, nil, true, false, 0, 0},
- {"/*", "/", true, nil, true, false, 0, 0},
- {"/*", "/debug/", false, nil, true, false, 0, 0},
- {"/*", "//", false, nil, true, false, 0, 0},
- {"abc", "abc", true, nil, true, true, 1, 1},
- {"*", "abc", true, nil, true, true, 19, 15},
- {"*c", "abc", true, nil, true, true, 2, 2},
- {"*/", "a/", true, nil, true, false, 0, 0},
- {"a*", "a", true, nil, true, true, 9, 9},
- {"a*", "abc", true, nil, true, true, 9, 9},
- {"a*", "ab/c", false, nil, true, true, 9, 9},
- {"a*/b", "abc/b", true, nil, true, true, 2, 2},
- {"a*/b", "a/c/b", false, nil, true, true, 2, 2},
- {"a*b*c*d*e*", "axbxcxdxe", true, nil, true, true, 3, 3},
- {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil, true, true, 2, 2},
- {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil, true, true, 2, 2},
- {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil, true, true, 2, 2},
- {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil, true, true, 2, 2},
- {"a*b?c*x", "abxbbxdbxebxczzx", true, nil, true, true, 2, 2},
- {"a*b?c*x", "abxbbxdbxebxczzy", false, nil, true, true, 2, 2},
- {"ab[c]", "abc", true, nil, true, true, 1, 1},
- {"ab[b-d]", "abc", true, nil, true, true, 1, 1},
- {"ab[e-g]", "abc", false, nil, true, true, 0, 0},
- {"ab[^c]", "abc", false, nil, true, true, 0, 0},
- {"ab[^b-d]", "abc", false, nil, true, true, 0, 0},
- {"ab[^e-g]", "abc", true, nil, true, true, 1, 1},
- {"a\\*b", "ab", false, nil, true, true, 0, 0},
- {"a?b", "a☺b", true, nil, true, true, 1, 1},
- {"a[^a]b", "a☺b", true, nil, true, true, 1, 1},
- {"a[!a]b", "a☺b", true, nil, false, true, 1, 1},
- {"a???b", "a☺b", false, nil, true, true, 0, 0},
- {"a[^a][^a][^a]b", "a☺b", false, nil, true, true, 0, 0},
- {"[a-ζ]*", "α", true, nil, true, true, 17, 15},
- {"*[a-ζ]", "A", false, nil, true, true, 17, 15},
- {"a?b", "a/b", false, nil, true, true, 1, 1},
- {"a*b", "a/b", false, nil, true, true, 1, 1},
- {"[\\]a]", "]", true, nil, true, !onWindows, 2, 2},
- {"[\\-]", "-", true, nil, true, !onWindows, 1, 1},
- {"[x\\-]", "x", true, nil, true, !onWindows, 2, 2},
- {"[x\\-]", "-", true, nil, true, !onWindows, 2, 2},
- {"[x\\-]", "z", false, nil, true, !onWindows, 2, 2},
- {"[\\-x]", "x", true, nil, true, !onWindows, 2, 2},
- {"[\\-x]", "-", true, nil, true, !onWindows, 2, 2},
- {"[\\-x]", "a", false, nil, true, !onWindows, 2, 2},
- {"[]a]", "]", false, ErrBadPattern, true, true, 0, 0},
- // doublestar, like bash, allows these when path.Match() does not
- {"[-]", "-", true, nil, false, !onWindows, 1, 0},
- {"[x-]", "x", true, nil, false, true, 2, 1},
- {"[x-]", "-", true, nil, false, !onWindows, 2, 1},
- {"[x-]", "z", false, nil, false, true, 2, 1},
- {"[-x]", "x", true, nil, false, true, 2, 1},
- {"[-x]", "-", true, nil, false, !onWindows, 2, 1},
- {"[-x]", "a", false, nil, false, true, 2, 1},
- {"[a-b-d]", "a", true, nil, false, true, 3, 2},
- {"[a-b-d]", "b", true, nil, false, true, 3, 2},
- {"[a-b-d]", "-", true, nil, false, !onWindows, 3, 2},
- {"[a-b-d]", "c", false, nil, false, true, 3, 2},
- {"[a-b-x]", "x", true, nil, false, true, 4, 3},
- {"\\", "a", false, ErrBadPattern, true, !onWindows, 0, 0},
- {"[", "a", false, ErrBadPattern, true, true, 0, 0},
- {"[^", "a", false, ErrBadPattern, true, true, 0, 0},
- {"[^bc", "a", false, ErrBadPattern, true, true, 0, 0},
- {"a[", "a", false, ErrBadPattern, true, true, 0, 0},
- {"a[", "ab", false, ErrBadPattern, true, true, 0, 0},
- {"ad[", "ab", false, ErrBadPattern, true, true, 0, 0},
- {"*x", "xxx", true, nil, true, true, 4, 4},
- {"[abc]", "b", true, nil, true, true, 3, 3},
- {"**", "", true, nil, false, false, 38, 38},
- {"a/**", "a", true, nil, false, true, 7, 7},
- {"a/**", "a/", true, nil, false, false, 7, 7},
- {"a/**", "a/b", true, nil, false, true, 7, 7},
- {"a/**", "a/b/c", true, nil, false, true, 7, 7},
- // These tests differ since we've disabled walking symlinks
- {"**/c", "c", true, nil, false, true, 4, 4},
- {"**/c", "b/c", true, nil, false, true, 4, 4},
- {"**/c", "a/b/c", true, nil, false, true, 4, 4},
- {"**/c", "a/b", false, nil, false, true, 4, 4},
- {"**/c", "abcd", false, nil, false, true, 4, 4},
- {"**/c", "a/abc", false, nil, false, true, 4, 4},
- {"a/**/b", "a/b", true, nil, false, true, 2, 2},
- {"a/**/c", "a/b/c", true, nil, false, true, 2, 2},
- {"a/**/d", "a/b/c/d", true, nil, false, true, 1, 1},
- {"a/\\**", "a/b/c", false, nil, false, !onWindows, 0, 0},
- {"a/\\[*\\]", "a/bc", false, nil, true, !onWindows, 0, 0},
- // this is an odd case: filepath.Glob() will return results
- {"a//b/c", "a/b/c", false, nil, true, false, 0, 0},
- {"a/b/c", "a/b//c", false, nil, true, true, 1, 1},
- // also odd: Glob + filepath.Glob return results
- {"a/", "a", false, nil, true, false, 0, 0},
- {"ab{c,d}", "abc", true, nil, false, true, 1, 1},
- {"ab{c,d,*}", "abcde", true, nil, false, true, 5, 5},
- {"ab{c,d}[", "abcd", false, ErrBadPattern, false, true, 0, 0},
- {"a{,bc}", "a", true, nil, false, true, 2, 2},
- {"a{,bc}", "abc", true, nil, false, true, 2, 2},
- {"a/{b/c,c/b}", "a/b/c", true, nil, false, true, 2, 2},
- {"a/{b/c,c/b}", "a/c/b", true, nil, false, true, 2, 2},
- {"{a/{b,c},abc}", "a/b", true, nil, false, true, 3, 3},
- {"{a/{b,c},abc}", "a/c", true, nil, false, true, 3, 3},
- {"{a/{b,c},abc}", "abc", true, nil, false, true, 3, 3},
- {"{a/{b,c},abc}", "a/b/c", false, nil, false, true, 3, 3},
- {"{a/ab*}", "a/abc", true, nil, false, true, 1, 1},
- {"{a/*}", "a/b", true, nil, false, true, 3, 3},
- {"{a/abc}", "a/abc", true, nil, false, true, 1, 1},
- {"{a/b,a/c}", "a/c", true, nil, false, true, 2, 2},
- {"abc/**", "abc/b", true, nil, false, true, 3, 3},
- {"**/abc", "abc", true, nil, false, true, 2, 2},
- {"abc**", "abc/b", false, nil, false, true, 3, 3},
- {"**/*.txt", "abc/【test】.txt", true, nil, false, true, 1, 1},
- {"**/【*", "abc/【test】.txt", true, nil, false, true, 1, 1},
- // unfortunately, io/fs can't handle this, so neither can Glob =(
- {"broken-symlink", "broken-symlink", true, nil, true, false, 1, 1},
- // We don't care about matching a particular file, we want to verify
- // that we don't traverse the symlink
- {"working-symlink/c/*", "working-symlink/c/d", true, nil, true, !onWindows, 1, 1},
- {"working-sym*/*", "irrelevant", false, nil, false, !onWindows, 0, 0},
- {"b/**/f", "irrelevant", false, nil, false, !onWindows, 0, 0},
-}
-
-func TestValidatePattern(t *testing.T) {
- for idx, tt := range matchTests {
- testValidatePatternWith(t, idx, tt)
- }
-}
-
-func testValidatePatternWith(t *testing.T, idx int, tt MatchTest) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("#%v. Validate(%#q) panicked: %#v", idx, tt.pattern, r)
- }
- }()
-
- result := ValidatePattern(tt.pattern)
- if result != (tt.expectedErr == nil) {
- t.Errorf("#%v. ValidatePattern(%#q) = %v want %v", idx, tt.pattern, result, !result)
- }
-}
-
-func TestMatch(t *testing.T) {
- for idx, tt := range matchTests {
- // Since Match() always uses "/" as the separator, we
- // don't need to worry about the tt.testOnDisk flag
- testMatchWith(t, idx, tt)
- }
-}
-
-func testMatchWith(t *testing.T, idx int, tt MatchTest) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("#%v. Match(%#q, %#q) panicked: %#v", idx, tt.pattern, tt.testPath, r)
- }
- }()
-
- // Match() always uses "/" as the separator
- ok, err := Match(tt.pattern, tt.testPath)
- if ok != tt.shouldMatch || err != tt.expectedErr {
- t.Errorf("#%v. Match(%#q, %#q) = %v, %v want %v, %v", idx, tt.pattern, tt.testPath, ok, err, tt.shouldMatch, tt.expectedErr)
- }
-
- if tt.isStandard {
- stdOk, stdErr := path.Match(tt.pattern, tt.testPath)
- if ok != stdOk || !compareErrors(err, stdErr) {
- t.Errorf("#%v. Match(%#q, %#q) != path.Match(...). Got %v, %v want %v, %v", idx, tt.pattern, tt.testPath, ok, err, stdOk, stdErr)
- }
- }
-}
-
-func BenchmarkMatch(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard {
- _, _ = Match(tt.pattern, tt.testPath)
- }
- }
- }
-}
-
-func BenchmarkGoMatch(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard {
- _, _ = path.Match(tt.pattern, tt.testPath)
- }
- }
- }
-}
-
-func TestPathMatch(t *testing.T) {
- for idx, tt := range matchTests {
- // Even though we aren't actually matching paths on disk, we are using
- // PathMatch() which will use the system's separator. As a result, any
- // patterns that might cause problems on-disk need to also be avoided
- // here in this test.
- if tt.testOnDisk {
- testPathMatchWith(t, idx, tt)
- }
- }
-}
-
-func testPathMatchWith(t *testing.T, idx int, tt MatchTest) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("#%v. Match(%#q, %#q) panicked: %#v", idx, tt.pattern, tt.testPath, r)
- }
- }()
-
- pattern := filepath.FromSlash(tt.pattern)
- testPath := filepath.FromSlash(tt.testPath)
- ok, err := PathMatch(pattern, testPath)
- if ok != tt.shouldMatch || err != tt.expectedErr {
- t.Errorf("#%v. PathMatch(%#q, %#q) = %v, %v want %v, %v", idx, pattern, testPath, ok, err, tt.shouldMatch, tt.expectedErr)
- }
-
- if tt.isStandard {
- stdOk, stdErr := filepath.Match(pattern, testPath)
- if ok != stdOk || !compareErrors(err, stdErr) {
- t.Errorf("#%v. PathMatch(%#q, %#q) != filepath.Match(...). Got %v, %v want %v, %v", idx, pattern, testPath, ok, err, stdOk, stdErr)
- }
- }
-}
-
-func TestPathMatchFake(t *testing.T) {
- // This test fakes that our path separator is `\\` so we can test what it
- // would be like on Windows - obviously, we don't need to do that if we
- // actually _are_ on Windows, since TestPathMatch will cover it.
- if onWindows {
- return
- }
-
- for idx, tt := range matchTests {
- // Even though we aren't actually matching paths on disk, we are using
- // PathMatch() which will use the system's separator. As a result, any
- // patterns that might cause problems on-disk need to also be avoided
- // here in this test.
- if tt.testOnDisk && tt.pattern != "\\" {
- testPathMatchFakeWith(t, idx, tt)
- }
- }
-}
-
-func testPathMatchFakeWith(t *testing.T, idx int, tt MatchTest) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("#%v. Match(%#q, %#q) panicked: %#v", idx, tt.pattern, tt.testPath, r)
- }
- }()
-
- pattern := strings.ReplaceAll(tt.pattern, "/", "\\")
- testPath := strings.ReplaceAll(tt.testPath, "/", "\\")
- ok, err := matchWithSeparator(pattern, testPath, '\\', true)
- if ok != tt.shouldMatch || err != tt.expectedErr {
- t.Errorf("#%v. PathMatch(%#q, %#q) = %v, %v want %v, %v", idx, pattern, testPath, ok, err, tt.shouldMatch, tt.expectedErr)
- }
-}
-
-func BenchmarkPathMatch(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard && tt.testOnDisk {
- pattern := filepath.FromSlash(tt.pattern)
- testPath := filepath.FromSlash(tt.testPath)
- _, _ = PathMatch(pattern, testPath)
- }
- }
- }
-}
-
-func BenchmarkGoPathMatch(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard && tt.testOnDisk {
- pattern := filepath.FromSlash(tt.pattern)
- testPath := filepath.FromSlash(tt.testPath)
- _, _ = filepath.Match(pattern, testPath)
- }
- }
- }
-}
-
-func TestGlob(t *testing.T) {
- fsys := os.DirFS("test")
- for idx, tt := range matchTests {
- if tt.testOnDisk {
- testGlobWith(t, idx, tt, fsys)
- }
- }
-}
-
-func testGlobWith(t *testing.T, idx int, tt MatchTest, fsys fs.FS) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("#%v. Glob(%#q) panicked: %#v", idx, tt.pattern, r)
- }
- }()
-
- matches, err := Glob(fsys, tt.pattern)
- verifyGlobResults(t, idx, "Glob", tt, fsys, matches, err)
-}
-
-func TestGlobWalk(t *testing.T) {
- fsys := os.DirFS("test")
- for idx, tt := range matchTests {
- if tt.testOnDisk {
- testGlobWalkWith(t, idx, tt, fsys)
- }
- }
-}
-
-func testGlobWalkWith(t *testing.T, idx int, tt MatchTest, fsys fs.FS) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("#%v. Glob(%#q) panicked: %#v", idx, tt.pattern, r)
- }
- }()
-
- var matches []string
- err := GlobWalk(fsys, tt.pattern, func(p string, d fs.DirEntry) error {
- matches = append(matches, p)
- return nil
- })
- verifyGlobResults(t, idx, "GlobWalk", tt, fsys, matches, err)
-}
-
-func verifyGlobResults(t *testing.T, idx int, fn string, tt MatchTest, fsys fs.FS, matches []string, err error) {
- numResults := tt.numResults
- if onWindows {
- numResults = tt.winNumResults
- }
- if len(matches) != numResults {
- t.Errorf("#%v. %v(%#q) = %#v - should have %#v results", idx, fn, tt.pattern, matches, tt.numResults)
- }
- if inSlice(tt.testPath, matches) != tt.shouldMatch {
- if tt.shouldMatch {
- t.Errorf("#%v. %v(%#q) = %#v - doesn't contain %v, but should", idx, fn, tt.pattern, matches, tt.testPath)
- } else {
- t.Errorf("#%v. %v(%#q) = %#v - contains %v, but shouldn't", idx, fn, tt.pattern, matches, tt.testPath)
- }
- }
- if err != tt.expectedErr {
- t.Errorf("#%v. %v(%#q) has error %v, but should be %v", idx, fn, tt.pattern, err, tt.expectedErr)
- }
-
- if tt.isStandard {
- stdMatches, stdErr := fs.Glob(fsys, tt.pattern)
- if !compareSlices(matches, stdMatches) || !compareErrors(err, stdErr) {
- t.Errorf("#%v. %v(%#q) != fs.Glob(...). Got %#v, %v want %#v, %v", idx, fn, tt.pattern, matches, err, stdMatches, stdErr)
- }
- }
-}
-
-func BenchmarkGlob(b *testing.B) {
- fsys := os.DirFS("test")
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard && tt.testOnDisk {
- _, _ = Glob(fsys, tt.pattern)
- }
- }
- }
-}
-
-func BenchmarkGlobWalk(b *testing.B) {
- fsys := os.DirFS("test")
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard && tt.testOnDisk {
- _ = GlobWalk(fsys, tt.pattern, func(p string, d fs.DirEntry) error {
- return nil
- })
- }
- }
- }
-}
-
-func BenchmarkGoGlob(b *testing.B) {
- fsys := os.DirFS("test")
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for _, tt := range matchTests {
- if tt.isStandard && tt.testOnDisk {
- _, _ = fs.Glob(fsys, tt.pattern)
- }
- }
- }
-}
-
-func compareErrors(a, b error) bool {
- if a == nil {
- return b == nil
- }
- return b != nil
-}
-
-func inSlice(s string, a []string) bool {
- for _, i := range a {
- if i == s {
- return true
- }
- }
- return false
-}
-
-func compareSlices(a, b []string) bool {
- if len(a) != len(b) {
- return false
- }
-
- diff := make(map[string]int, len(a))
-
- for _, x := range a {
- diff[x]++
- }
-
- for _, y := range b {
- if _, ok := diff[y]; !ok {
- return false
- }
-
- diff[y]--
- if diff[y] == 0 {
- delete(diff, y)
- }
- }
-
- return len(diff) == 0
-}
-
-func mkdirp(parts ...string) {
- dirs := path.Join(parts...)
- err := os.MkdirAll(dirs, 0755)
- if err != nil {
- log.Fatalf("Could not create test directories %v: %v\n", dirs, err)
- }
-}
-
-func touch(parts ...string) {
- filename := path.Join(parts...)
- f, err := os.Create(filename)
- if err != nil {
- log.Fatalf("Could not create test file %v: %v\n", filename, err)
- }
- _ = f.Close()
-}
-
-func symlink(oldname, newname string) {
- // since this will only run on non-windows, we can assume "/" as path separator
- err := os.Symlink(oldname, newname)
- if err != nil && !os.IsExist(err) {
- log.Fatalf("Could not create symlink %v -> %v: %v\n", oldname, newname, err)
- }
-}
-
-func TestGlobSorted(t *testing.T) {
- fsys := os.DirFS("test")
- expected := []string{"a", "abc", "abcd", "abcde", "abxbbxdbxebxczzx", "abxbbxdbxebxczzy", "axbxcxdxe", "axbxcxdxexxx", "a☺b"}
- matches, err := Glob(fsys, "a*")
- if err != nil {
- t.Errorf("Unexpected error %v", err)
- return
- }
-
- if len(matches) != len(expected) {
- t.Errorf("Glob returned %#v; expected %#v", matches, expected)
- return
- }
- for idx, match := range matches {
- if match != expected[idx] {
- t.Errorf("Glob returned %#v; expected %#v", matches, expected)
- return
- }
- }
-}
-
-func TestMain(m *testing.M) {
- // create the test directory
- mkdirp("test", "a", "b", "c")
- mkdirp("test", "a", "c")
- mkdirp("test", "abc")
- mkdirp("test", "axbxcxdxe", "xxx")
- mkdirp("test", "axbxcxdxexxx")
- mkdirp("test", "b")
-
- // create test files
- touch("test", "a", "abc")
- touch("test", "a", "b", "c", "d")
- touch("test", "a", "c", "b")
- touch("test", "abc", "b")
- touch("test", "abcd")
- touch("test", "abcde")
- touch("test", "abxbbxdbxebxczzx")
- touch("test", "abxbbxdbxebxczzy")
- touch("test", "axbxcxdxe", "f")
- touch("test", "axbxcxdxe", "xxx", "f")
- touch("test", "axbxcxdxexxx", "f")
- touch("test", "axbxcxdxexxx", "fff")
- touch("test", "a☺b")
- touch("test", "b", "c")
- touch("test", "c")
- touch("test", "x")
- touch("test", "xxx")
- touch("test", "z")
- touch("test", "α")
- touch("test", "abc", "【test】.txt")
-
- if !onWindows {
- // these files/symlinks won't work on Windows
- touch("test", "-")
- touch("test", "]")
- symlink("../axbxcxdxe/", "test/b/symlink-dir")
- symlink("/tmp/nonexistant-file-20160902155705", "test/broken-symlink")
- symlink("a/b", "test/working-symlink")
- }
-
- // os.Exit(m.Run())
- exitCode := m.Run()
- _ = os.RemoveAll("test")
- os.Exit(exitCode)
-}
diff --git a/cli/internal/doublestar/glob.go b/cli/internal/doublestar/glob.go
deleted file mode 100644
index eee8920..0000000
--- a/cli/internal/doublestar/glob.go
+++ /dev/null
@@ -1,393 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-package doublestar
-
-import (
- "io/fs"
- "path"
-)
-
-// Glob returns the names of all files matching pattern or nil if there is no
-// matching file. The syntax of pattern is the same as in Match(). The pattern
-// may describe hierarchical names such as usr/*/bin/ed.
-//
-// Glob ignores file system errors such as I/O errors reading directories.
-// The only possible returned error is ErrBadPattern, reporting that the
-// pattern is malformed.
-//
-// Note: this is meant as a drop-in replacement for io/fs.Glob(). Like
-// io/fs.Glob(), this function assumes that your pattern uses `/` as the path
-// separator even if that's not correct for your OS (like Windows). If you
-// aren't sure if that's the case, you can use filepath.ToSlash() on your
-// pattern before calling Glob().
-//
-// Like `io/fs.Glob()`, patterns containing `/./`, `/../`, or starting with `/`
-// will return no results and no errors. You can use SplitPattern to divide a
-// pattern into a base path (to initialize an `FS` object) and pattern.
-func Glob(fsys fs.FS, pattern string) ([]string, error) {
- if !ValidatePattern(pattern) {
- return nil, ErrBadPattern
- }
- if hasMidDoubleStar(pattern) {
- // If the pattern has a `**` anywhere but the very end, GlobWalk is more
- // performant because it can get away with less allocations. If the pattern
- // ends in a `**`, both methods are pretty much the same, but Glob has a
- // _very_ slight advantage because of lower function call overhead.
- var matches []string
- err := doGlobWalk(fsys, pattern, true, func(p string, d fs.DirEntry) error {
- matches = append(matches, p)
- return nil
- })
- return matches, err
- }
- return doGlob(fsys, pattern, nil, true)
-}
-
-// Does the actual globbin'
-func doGlob(fsys fs.FS, pattern string, m []string, firstSegment bool) ([]string, error) {
- matches := m
- patternStart := indexMeta(pattern)
- if patternStart == -1 {
- // pattern doesn't contain any meta characters - does a file matching the
- // pattern exist?
- if exists(fsys, pattern) {
- matches = append(matches, pattern)
- }
- return matches, nil
- }
-
- dir := "."
- splitIdx := lastIndexSlashOrAlt(pattern)
- if splitIdx != -1 {
- if pattern[splitIdx] == '}' {
- openingIdx := indexMatchedOpeningAlt(pattern[:splitIdx])
- if openingIdx == -1 {
- // if there's no matching opening index, technically Match() will treat
- // an unmatched `}` as nothing special, so... we will, too!
- splitIdx = lastIndexSlash(pattern[:splitIdx])
- } else {
- // otherwise, we have to handle the alts:
- return globAlts(fsys, pattern, openingIdx, splitIdx, matches, firstSegment)
- }
- }
-
- dir = pattern[:splitIdx]
- pattern = pattern[splitIdx+1:]
- }
-
- // if `splitIdx` is less than `patternStart`, we know `dir` has no meta
- // characters. They would be equal if they are both -1, which means `dir`
- // will be ".", and we know that doesn't have meta characters either.
- if splitIdx <= patternStart {
- return globDir(fsys, dir, pattern, matches, firstSegment)
- }
-
- var dirs []string
- var err error
- dirs, err = doGlob(fsys, dir, matches, false)
- if err != nil {
- return nil, err
- }
- for _, d := range dirs {
- matches, err = globDir(fsys, d, pattern, matches, firstSegment)
- if err != nil {
- return nil, err
- }
- }
-
- return matches, nil
-}
-
-// handle alts in the glob pattern - `openingIdx` and `closingIdx` are the
-// indexes of `{` and `}`, respectively
-func globAlts(fsys fs.FS, pattern string, openingIdx, closingIdx int, m []string, firstSegment bool) ([]string, error) {
- matches := m
-
- var dirs []string
- startIdx := 0
- afterIdx := closingIdx + 1
- splitIdx := lastIndexSlashOrAlt(pattern[:openingIdx])
- if splitIdx == -1 || pattern[splitIdx] == '}' {
- // no common prefix
- dirs = []string{""}
- } else {
- // our alts have a common prefix that we can process first
- var err error
- dirs, err = doGlob(fsys, pattern[:splitIdx], matches, false)
- if err != nil {
- return nil, err
- }
-
- startIdx = splitIdx + 1
- }
-
- for _, d := range dirs {
- patIdx := openingIdx + 1
- altResultsStartIdx := len(matches)
- thisResultStartIdx := altResultsStartIdx
- for patIdx < closingIdx {
- nextIdx := indexNextAlt(pattern[patIdx:closingIdx], true)
- if nextIdx == -1 {
- nextIdx = closingIdx
- } else {
- nextIdx += patIdx
- }
-
- alt := buildAlt(d, pattern, startIdx, openingIdx, patIdx, nextIdx, afterIdx)
- var err error
- matches, err = doGlob(fsys, alt, matches, firstSegment)
- if err != nil {
- return nil, err
- }
-
- matchesLen := len(matches)
- if altResultsStartIdx != thisResultStartIdx && thisResultStartIdx != matchesLen {
- // Alts can result in matches that aren't sorted, or, worse, duplicates
- // (consider the trivial pattern `path/to/{a,*}`). Since doGlob returns
- // sorted results, we can do a sort of in-place merge and remove
- // duplicates. But, we only need to do this if this isn't the first alt
- // (ie, `altResultsStartIdx != thisResultsStartIdx`) and if the latest
- // alt actually added some matches (`thisResultStartIdx !=
- // len(matches)`)
- matches = sortAndRemoveDups(matches, altResultsStartIdx, thisResultStartIdx, matchesLen)
-
- // length of matches may have changed
- thisResultStartIdx = len(matches)
- } else {
- thisResultStartIdx = matchesLen
- }
-
- patIdx = nextIdx + 1
- }
- }
-
- return matches, nil
-}
-
-// find files/subdirectories in the given `dir` that match `pattern`
-func globDir(fsys fs.FS, dir, pattern string, matches []string, canMatchFiles bool) ([]string, error) {
- m := matches
-
- if pattern == "" {
- // pattern can be an empty string if the original pattern ended in a slash,
- // in which case, we should just return dir, but only if it actually exists
- // and it's a directory (or a symlink to a directory)
- if isPathDir(fsys, dir) {
- m = append(m, dir)
- }
- return m, nil
- }
-
- if pattern == "**" {
- m = globDoubleStar(fsys, dir, m, canMatchFiles)
- return m, nil
- }
-
- dirs, err := fs.ReadDir(fsys, dir)
- if err != nil {
- // ignore IO errors
- return m, nil
- }
-
- var matched bool
- for _, info := range dirs {
- name := info.Name()
- if canMatchFiles || isDir(fsys, dir, name, info) {
- matched, err = matchWithSeparator(pattern, name, '/', false)
- if err != nil {
- return nil, err
- }
- if matched {
- m = append(m, path.Join(dir, name))
- }
- }
- }
-
- return m, nil
-}
-
-func globDoubleStar(fsys fs.FS, dir string, matches []string, canMatchFiles bool) []string {
- dirs, err := fs.ReadDir(fsys, dir)
- if err != nil {
- // ignore IO errors
- return matches
- }
-
- // `**` can match *this* dir, so add it
- matches = append(matches, dir)
- for _, info := range dirs {
- name := info.Name()
- if isDir(fsys, dir, name, info) {
- matches = globDoubleStar(fsys, path.Join(dir, name), matches, canMatchFiles)
- } else if canMatchFiles {
- matches = append(matches, path.Join(dir, name))
- }
- }
-
- return matches
-}
-
-// Returns true if the pattern has a doublestar in the middle of the pattern.
-// In this case, GlobWalk is faster because it can get away with less
-// allocations. However, Glob has a _very_ slight edge if the pattern ends in
-// `**`.
-func hasMidDoubleStar(p string) bool {
- // subtract 3: 2 because we want to return false if the pattern ends in `**`
- // (Glob is _very_ slightly faster in that case), and the extra 1 because our
- // loop checks p[i] and p[i+1].
- l := len(p) - 3
- for i := 0; i < l; i++ {
- if p[i] == '\\' {
- // escape next byte
- i++
- } else if p[i] == '*' && p[i+1] == '*' {
- return true
- }
- }
- return false
-}
-
-// Returns the index of the first unescaped meta character, or negative 1.
-func indexMeta(s string) int {
- var c byte
- l := len(s)
- for i := 0; i < l; i++ {
- c = s[i]
- if c == '*' || c == '?' || c == '[' || c == '{' {
- return i
- } else if c == '\\' {
- // skip next byte
- i++
- }
- }
- return -1
-}
-
-// Returns the index of the last unescaped slash or closing alt (`}`) in the
-// string, or negative 1.
-func lastIndexSlashOrAlt(s string) int {
- for i := len(s) - 1; i >= 0; i-- {
- if (s[i] == '/' || s[i] == '}') && (i == 0 || s[i-1] != '\\') {
- return i
- }
- }
- return -1
-}
-
-// Returns the index of the last unescaped slash in the string, or negative 1.
-func lastIndexSlash(s string) int {
- for i := len(s) - 1; i >= 0; i-- {
- if s[i] == '/' && (i == 0 || s[i-1] != '\\') {
- return i
- }
- }
- return -1
-}
-
-// Assuming the byte after the end of `s` is a closing `}`, this function will
-// find the index of the matching `{`. That is, it'll skip over any nested `{}`
-// and account for escaping.
-func indexMatchedOpeningAlt(s string) int {
- alts := 1
- for i := len(s) - 1; i >= 0; i-- {
- if s[i] == '}' && (i == 0 || s[i-1] != '\\') {
- alts++
- } else if s[i] == '{' && (i == 0 || s[i-1] != '\\') {
- if alts--; alts == 0 {
- return i
- }
- }
- }
- return -1
-}
-
-// Returns true if the path exists
-func exists(fsys fs.FS, name string) bool {
- if _, err := fs.Stat(fsys, name); err != nil {
- return false
- }
- return true
-}
-
-// Returns true if the path is a directory, or a symlink to a directory
-func isPathDir(fsys fs.FS, name string) bool {
- info, err := fs.Stat(fsys, name)
- if err != nil {
- return false
- }
- return info.IsDir()
-}
-
-// Returns whether or not the given DirEntry is a directory. If the DirEntry
-// represents a symbolic link, return false
-func isDir(fsys fs.FS, dir string, name string, info fs.DirEntry) bool {
- if (info.Type() & fs.ModeSymlink) > 0 {
- return false
- }
- return info.IsDir()
-}
-
-// Builds a string from an alt
-func buildAlt(prefix, pattern string, startIdx, openingIdx, currentIdx, nextIdx, afterIdx int) string {
- // pattern:
- // ignored/start{alts,go,here}remaining - len = 36
- // | | | | ^--- afterIdx = 27
- // | | | \--------- nextIdx = 21
- // | | \----------- currentIdx = 19
- // | \----------------- openingIdx = 13
- // \---------------------- startIdx = 8
- //
- // result:
- // prefix/startgoremaining - len = 7 + 5 + 2 + 9 = 23
- var buf []byte
- patLen := len(pattern)
- size := (openingIdx - startIdx) + (nextIdx - currentIdx) + (patLen - afterIdx)
- if prefix != "" {
- buf = make([]byte, 0, size+len(prefix)+1)
- buf = append(buf, prefix...)
- buf = append(buf, '/')
- } else {
- buf = make([]byte, 0, size)
- }
- buf = append(buf, pattern[startIdx:openingIdx]...)
- buf = append(buf, pattern[currentIdx:nextIdx]...)
- if afterIdx < patLen {
- buf = append(buf, pattern[afterIdx:]...)
- }
- return string(buf)
-}
-
-// Running alts can produce results that are not sorted, and, worse, can cause
-// duplicates (consider the trivial pattern `path/to/{a,*}`). Since we know
-// each run of doGlob is sorted, we can basically do the "merge" step of a
-// merge sort in-place.
-func sortAndRemoveDups(matches []string, idx1, idx2, l int) []string {
- var tmp string
- for ; idx1 < idx2; idx1++ {
- if matches[idx1] < matches[idx2] {
- // order is correct
- continue
- } else if matches[idx1] > matches[idx2] {
- // need to swap and then re-sort matches above idx2
- tmp = matches[idx1]
- matches[idx1] = matches[idx2]
-
- shft := idx2 + 1
- for ; shft < l && matches[shft] < tmp; shft++ {
- matches[shft-1] = matches[shft]
- }
- matches[shft-1] = tmp
- } else {
- // duplicate - shift matches above idx2 down one and decrement l
- for shft := idx2 + 1; shft < l; shft++ {
- matches[shft-1] = matches[shft]
- }
- if l--; idx2 == l {
- // nothing left to do... matches[idx2:] must have been full of dups
- break
- }
- }
- }
- return matches[:l]
-}
diff --git a/cli/internal/doublestar/globwalk.go b/cli/internal/doublestar/globwalk.go
deleted file mode 100644
index 6caec3e..0000000
--- a/cli/internal/doublestar/globwalk.go
+++ /dev/null
@@ -1,277 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-package doublestar
-
-import (
- "io/fs"
- "path"
-)
-
-// GlobWalkFunc is a callback function for GlobWalk(). If the function returns an error, GlobWalk
-// will end immediately and return the same error.
-type GlobWalkFunc func(path string, d fs.DirEntry) error
-
-// GlobWalk calls the callback function `fn` for every file matching pattern.
-// The syntax of pattern is the same as in Match() and the behavior is the same
-// as Glob(), with regard to limitations (such as patterns containing `/./`,
-// `/../`, or starting with `/`). The pattern may describe hierarchical names
-// such as usr/*/bin/ed.
-//
-// GlobWalk may have a small performance benefit over Glob if you do not need a
-// slice of matches because it can avoid allocating memory for the matches.
-// Additionally, GlobWalk gives you access to the `fs.DirEntry` objects for
-// each match, and lets you quit early by returning a non-nil error from your
-// callback function.
-//
-// GlobWalk ignores file system errors such as I/O errors reading directories.
-// GlobWalk may return ErrBadPattern, reporting that the pattern is malformed.
-// Additionally, if the callback function `fn` returns an error, GlobWalk will
-// exit immediately and return that error.
-//
-// Like Glob(), this function assumes that your pattern uses `/` as the path
-// separator even if that's not correct for your OS (like Windows). If you
-// aren't sure if that's the case, you can use filepath.ToSlash() on your
-// pattern before calling GlobWalk().
-func GlobWalk(fsys fs.FS, pattern string, fn GlobWalkFunc) error {
- if !ValidatePattern(pattern) {
- return ErrBadPattern
- }
- return doGlobWalk(fsys, pattern, true, fn)
-}
-
-// Actually execute GlobWalk
-func doGlobWalk(fsys fs.FS, pattern string, firstSegment bool, fn GlobWalkFunc) error {
- patternStart := indexMeta(pattern)
- if patternStart == -1 {
- // pattern doesn't contain any meta characters - does a file matching the
- // pattern exist?
- info, err := fs.Stat(fsys, pattern)
- if err == nil {
- err = fn(pattern, newDirEntryFromFileInfo(info))
- return err
- }
- // ignore IO errors
- return nil
- }
-
- dir := "."
- splitIdx := lastIndexSlashOrAlt(pattern)
- if splitIdx != -1 {
- if pattern[splitIdx] == '}' {
- openingIdx := indexMatchedOpeningAlt(pattern[:splitIdx])
- if openingIdx == -1 {
- // if there's no matching opening index, technically Match() will treat
- // an unmatched `}` as nothing special, so... we will, too!
- splitIdx = lastIndexSlash(pattern[:splitIdx])
- } else {
- // otherwise, we have to handle the alts:
- return globAltsWalk(fsys, pattern, openingIdx, splitIdx, firstSegment, fn)
- }
- }
-
- dir = pattern[:splitIdx]
- pattern = pattern[splitIdx+1:]
- }
-
- // if `splitIdx` is less than `patternStart`, we know `dir` has no meta
- // characters. They would be equal if they are both -1, which means `dir`
- // will be ".", and we know that doesn't have meta characters either.
- if splitIdx <= patternStart {
- return globDirWalk(fsys, dir, pattern, firstSegment, fn)
- }
-
- return doGlobWalk(fsys, dir, false, func(p string, d fs.DirEntry) error {
- if err := globDirWalk(fsys, p, pattern, firstSegment, fn); err != nil {
- return err
- }
- return nil
- })
-}
-
-// handle alts in the glob pattern - `openingIdx` and `closingIdx` are the
-// indexes of `{` and `}`, respectively
-func globAltsWalk(fsys fs.FS, pattern string, openingIdx, closingIdx int, firstSegment bool, fn GlobWalkFunc) error {
- var matches []dirEntryWithFullPath
- startIdx := 0
- afterIdx := closingIdx + 1
- splitIdx := lastIndexSlashOrAlt(pattern[:openingIdx])
- if splitIdx == -1 || pattern[splitIdx] == '}' {
- // no common prefix
- var err error
- matches, err = doGlobAltsWalk(fsys, "", pattern, startIdx, openingIdx, closingIdx, afterIdx, firstSegment, matches)
- if err != nil {
- return err
- }
- } else {
- // our alts have a common prefix that we can process first
- startIdx = splitIdx + 1
- err := doGlobWalk(fsys, pattern[:splitIdx], false, func(p string, d fs.DirEntry) (e error) {
- matches, e = doGlobAltsWalk(fsys, p, pattern, startIdx, openingIdx, closingIdx, afterIdx, firstSegment, matches)
- return e
- })
- if err != nil {
- return err
- }
- }
-
- for _, m := range matches {
- if err := fn(m.Path, m.Entry); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// runs actual matching for alts
-func doGlobAltsWalk(fsys fs.FS, d, pattern string, startIdx, openingIdx, closingIdx, afterIdx int, firstSegment bool, m []dirEntryWithFullPath) ([]dirEntryWithFullPath, error) {
- matches := m
- matchesLen := len(m)
- patIdx := openingIdx + 1
- for patIdx < closingIdx {
- nextIdx := indexNextAlt(pattern[patIdx:closingIdx], true)
- if nextIdx == -1 {
- nextIdx = closingIdx
- } else {
- nextIdx += patIdx
- }
-
- alt := buildAlt(d, pattern, startIdx, openingIdx, patIdx, nextIdx, afterIdx)
- err := doGlobWalk(fsys, alt, firstSegment, func(p string, d fs.DirEntry) error {
- // insertion sort, ignoring dups
- insertIdx := matchesLen
- for insertIdx > 0 && matches[insertIdx-1].Path > p {
- insertIdx--
- }
- if insertIdx > 0 && matches[insertIdx-1].Path == p {
- // dup
- return nil
- }
-
- // append to grow the slice, then insert
- entry := dirEntryWithFullPath{d, p}
- matches = append(matches, entry)
- for i := matchesLen; i > insertIdx; i-- {
- matches[i] = matches[i-1]
- }
- matches[insertIdx] = entry
- matchesLen++
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- patIdx = nextIdx + 1
- }
-
- return matches, nil
-}
-
-func globDirWalk(fsys fs.FS, dir, pattern string, canMatchFiles bool, fn GlobWalkFunc) error {
- if pattern == "" {
- // pattern can be an empty string if the original pattern ended in a slash,
- // in which case, we should just return dir, but only if it actually exists
- // and it's a directory (or a symlink to a directory)
- info, err := fs.Stat(fsys, dir)
- if err != nil || !info.IsDir() {
- return nil
- }
- return fn(dir, newDirEntryFromFileInfo(info))
- }
-
- if pattern == "**" {
- // `**` can match *this* dir
- info, err := fs.Stat(fsys, dir)
- if err != nil || !info.IsDir() {
- return nil
- }
- if err = fn(dir, newDirEntryFromFileInfo(info)); err != nil {
- return err
- }
- return globDoubleStarWalk(fsys, dir, canMatchFiles, fn)
- }
-
- dirs, err := fs.ReadDir(fsys, dir)
- if err != nil {
- // ignore IO errors
- return nil
- }
-
- var matched bool
- for _, info := range dirs {
- name := info.Name()
- if canMatchFiles || isDir(fsys, dir, name, info) {
- matched, err = matchWithSeparator(pattern, name, '/', false)
- if err != nil {
- return err
- }
- if matched {
- if err = fn(path.Join(dir, name), info); err != nil {
- return err
- }
- }
- }
- }
-
- return nil
-}
-
-func globDoubleStarWalk(fsys fs.FS, dir string, canMatchFiles bool, fn GlobWalkFunc) error {
- dirs, err := fs.ReadDir(fsys, dir)
- if err != nil {
- // ignore IO errors
- return nil
- }
-
- // `**` can match *this* dir, so add it
- for _, info := range dirs {
- name := info.Name()
- if isDir(fsys, dir, name, info) {
- p := path.Join(dir, name)
- if e := fn(p, info); e != nil {
- return e
- }
- if e := globDoubleStarWalk(fsys, p, canMatchFiles, fn); e != nil {
- return e
- }
- } else if canMatchFiles {
- if e := fn(path.Join(dir, name), info); e != nil {
- return e
- }
- }
- }
-
- return nil
-}
-
-type dirEntryFromFileInfo struct {
- fi fs.FileInfo
-}
-
-func (d *dirEntryFromFileInfo) Name() string {
- return d.fi.Name()
-}
-
-func (d *dirEntryFromFileInfo) IsDir() bool {
- return d.fi.IsDir()
-}
-
-func (d *dirEntryFromFileInfo) Type() fs.FileMode {
- return d.fi.Mode().Type()
-}
-
-func (d *dirEntryFromFileInfo) Info() (fs.FileInfo, error) {
- return d.fi, nil
-}
-
-func newDirEntryFromFileInfo(fi fs.FileInfo) fs.DirEntry {
- return &dirEntryFromFileInfo{fi}
-}
-
-type dirEntryWithFullPath struct {
- Entry fs.DirEntry
- Path string
-}
diff --git a/cli/internal/doublestar/match.go b/cli/internal/doublestar/match.go
deleted file mode 100644
index d8c9536..0000000
--- a/cli/internal/doublestar/match.go
+++ /dev/null
@@ -1,377 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-package doublestar
-
-import (
- "path/filepath"
- "unicode/utf8"
-)
-
-// Match reports whether name matches the shell pattern.
-// The pattern syntax is:
-//
-// pattern:
-// { term }
-// term:
-// '*' matches any sequence of non-path-separators
-// '/**/' matches zero or more directories
-// '?' matches any single non-path-separator character
-// '[' [ '^' '!' ] { character-range } ']'
-// character class (must be non-empty)
-// starting with `^` or `!` negates the class
-// '{' { term } [ ',' { term } ... ] '}'
-// alternatives
-// c matches character c (c != '*', '?', '\\', '[')
-// '\\' c matches character c
-//
-// character-range:
-// c matches character c (c != '\\', '-', ']')
-// '\\' c matches character c
-// lo '-' hi matches character c for lo <= c <= hi
-//
-// Match returns true if `name` matches the file name `pattern`. `name` and
-// `pattern` are split on forward slash (`/`) characters and may be relative or
-// absolute.
-//
-// Match requires pattern to match all of name, not just a substring.
-// The only possible returned error is ErrBadPattern, when pattern
-// is malformed.
-//
-// A doublestar (`**`) should appear surrounded by path separators such as
-// `/**/`. A mid-pattern doublestar (`**`) behaves like bash's globstar
-// option: a pattern such as `path/to/**.txt` would return the same results as
-// `path/to/*.txt`. The pattern you're looking for is `path/to/**/*.txt`.
-//
-// Note: this is meant as a drop-in replacement for path.Match() which
-// always uses '/' as the path separator. If you want to support systems
-// which use a different path separator (such as Windows), what you want
-// is PathMatch(). Alternatively, you can run filepath.ToSlash() on both
-// pattern and name and then use this function.
-func Match(pattern, name string) (bool, error) {
- return matchWithSeparator(pattern, name, '/', true)
-}
-
-// PathMatch returns true if `name` matches the file name `pattern`. The
-// difference between Match and PathMatch is that PathMatch will automatically
-// use your system's path separator to split `name` and `pattern`. On systems
-// where the path separator is `'\'`, escaping will be disabled.
-//
-// Note: this is meant as a drop-in replacement for filepath.Match(). It
-// assumes that both `pattern` and `name` are using the system's path
-// separator. If you can't be sure of that, use filepath.ToSlash() on both
-// `pattern` and `name`, and then use the Match() function instead.
-func PathMatch(pattern, name string) (bool, error) {
- return matchWithSeparator(pattern, name, filepath.Separator, true)
-}
-
-func matchWithSeparator(pattern, name string, separator rune, validate bool) (matched bool, err error) {
- doublestarPatternBacktrack := -1
- doublestarNameBacktrack := -1
- starPatternBacktrack := -1
- starNameBacktrack := -1
- patIdx := 0
- nameIdx := 0
- patLen := len(pattern)
- nameLen := len(name)
- startOfSegment := true
-MATCH:
- for nameIdx < nameLen {
- if patIdx < patLen {
- switch pattern[patIdx] {
- case '*':
- if patIdx++; patIdx < patLen && pattern[patIdx] == '*' {
- // doublestar - must begin with a path separator, otherwise we'll
- // treat it like a single star like bash
- patIdx++
- if startOfSegment {
- if patIdx >= patLen {
- // pattern ends in `/**`: return true
- return true, nil
- }
-
- // doublestar must also end with a path separator, otherwise we're
- // just going to treat the doublestar as a single star like bash
- patRune, patRuneLen := utf8.DecodeRuneInString(pattern[patIdx:])
- if patRune == separator {
- patIdx += patRuneLen
-
- doublestarPatternBacktrack = patIdx
- doublestarNameBacktrack = nameIdx
- starPatternBacktrack = -1
- starNameBacktrack = -1
- continue
- }
- }
- }
- startOfSegment = false
-
- starPatternBacktrack = patIdx
- starNameBacktrack = nameIdx
- continue
-
- case '?':
- startOfSegment = false
- nameRune, nameRuneLen := utf8.DecodeRuneInString(name[nameIdx:])
- if nameRune == separator {
- // `?` cannot match the separator
- break
- }
-
- patIdx++
- nameIdx += nameRuneLen
- continue
-
- case '[':
- startOfSegment = false
- if patIdx++; patIdx >= patLen {
- // class didn't end
- return false, ErrBadPattern
- }
- nameRune, nameRuneLen := utf8.DecodeRuneInString(name[nameIdx:])
-
- matched := false
- negate := pattern[patIdx] == '!' || pattern[patIdx] == '^'
- if negate {
- patIdx++
- }
-
- if patIdx >= patLen || pattern[patIdx] == ']' {
- // class didn't end or empty character class
- return false, ErrBadPattern
- }
-
- last := utf8.MaxRune
- for patIdx < patLen && pattern[patIdx] != ']' {
- patRune, patRuneLen := utf8.DecodeRuneInString(pattern[patIdx:])
- patIdx += patRuneLen
-
- // match a range
- if last < utf8.MaxRune && patRune == '-' && patIdx < patLen && pattern[patIdx] != ']' {
- if pattern[patIdx] == '\\' {
- // next character is escaped
- patIdx++
- }
- patRune, patRuneLen = utf8.DecodeRuneInString(pattern[patIdx:])
- patIdx += patRuneLen
-
- if last <= nameRune && nameRune <= patRune {
- matched = true
- break
- }
-
- // didn't match range - reset `last`
- last = utf8.MaxRune
- continue
- }
-
- // not a range - check if the next rune is escaped
- if patRune == '\\' {
- patRune, patRuneLen = utf8.DecodeRuneInString(pattern[patIdx:])
- patIdx += patRuneLen
- }
-
- // check if the rune matches
- if patRune == nameRune {
- matched = true
- break
- }
-
- // no matches yet
- last = patRune
- }
-
- if matched == negate {
- // failed to match - if we reached the end of the pattern, that means
- // we never found a closing `]`
- if patIdx >= patLen {
- return false, ErrBadPattern
- }
- break
- }
-
- closingIdx := indexUnescapedByte(pattern[patIdx:], ']', true)
- if closingIdx == -1 {
- // no closing `]`
- return false, ErrBadPattern
- }
-
- patIdx += closingIdx + 1
- nameIdx += nameRuneLen
- continue
-
- case '{':
- // Note: removed 'startOfSegment = false' here.
- // This block is guaranteed to return, so assigning it was useless
- // and triggering a lint error
- patIdx++
- closingIdx := indexMatchedClosingAlt(pattern[patIdx:], separator != '\\')
- if closingIdx == -1 {
- // no closing `}`
- return false, ErrBadPattern
- }
- closingIdx += patIdx
-
- for {
- commaIdx := indexNextAlt(pattern[patIdx:closingIdx], separator != '\\')
- if commaIdx == -1 {
- break
- }
- commaIdx += patIdx
-
- result, err := matchWithSeparator(pattern[patIdx:commaIdx]+pattern[closingIdx+1:], name[nameIdx:], separator, validate)
- if result || err != nil {
- return result, err
- }
-
- patIdx = commaIdx + 1
- }
- return matchWithSeparator(pattern[patIdx:closingIdx]+pattern[closingIdx+1:], name[nameIdx:], separator, validate)
-
- case '\\':
- if separator != '\\' {
- // next rune is "escaped" in the pattern - literal match
- if patIdx++; patIdx >= patLen {
- // pattern ended
- return false, ErrBadPattern
- }
- }
- fallthrough
-
- default:
- patRune, patRuneLen := utf8.DecodeRuneInString(pattern[patIdx:])
- nameRune, nameRuneLen := utf8.DecodeRuneInString(name[nameIdx:])
- if patRune != nameRune {
- if separator != '\\' && patIdx > 0 && pattern[patIdx-1] == '\\' {
- // if this rune was meant to be escaped, we need to move patIdx
- // back to the backslash before backtracking or validating below
- patIdx--
- }
- break
- }
-
- patIdx += patRuneLen
- nameIdx += nameRuneLen
- startOfSegment = patRune == separator
- continue
- }
- }
-
- if starPatternBacktrack >= 0 {
- // `*` backtrack, but only if the `name` rune isn't the separator
- nameRune, nameRuneLen := utf8.DecodeRuneInString(name[starNameBacktrack:])
- if nameRune != separator {
- starNameBacktrack += nameRuneLen
- patIdx = starPatternBacktrack
- nameIdx = starNameBacktrack
- startOfSegment = false
- continue
- }
- }
-
- if doublestarPatternBacktrack >= 0 {
- // `**` backtrack, advance `name` past next separator
- nameIdx = doublestarNameBacktrack
- for nameIdx < nameLen {
- nameRune, nameRuneLen := utf8.DecodeRuneInString(name[nameIdx:])
- nameIdx += nameRuneLen
- if nameRune == separator {
- doublestarNameBacktrack = nameIdx
- patIdx = doublestarPatternBacktrack
- startOfSegment = true
- continue MATCH
- }
- }
- }
-
- if validate && patIdx < patLen && !doValidatePattern(pattern[patIdx:], separator) {
- return false, ErrBadPattern
- }
- return false, nil
- }
-
- if nameIdx < nameLen {
- // we reached the end of `pattern` before the end of `name`
- return false, nil
- }
-
- // we've reached the end of `name`; we've successfully matched if we've also
- // reached the end of `pattern`, or if the rest of `pattern` can match a
- // zero-length string
- return isZeroLengthPattern(pattern[patIdx:], separator)
-}
-
-func isZeroLengthPattern(pattern string, separator rune) (ret bool, err error) {
- // `/**` is a special case - a pattern such as `path/to/a/**` *should* match
- // `path/to/a` because `a` might be a directory
- if pattern == "" || pattern == "*" || pattern == "**" || pattern == string(separator)+"**" {
- return true, nil
- }
-
- if pattern[0] == '{' {
- closingIdx := indexMatchedClosingAlt(pattern[1:], separator != '\\')
- if closingIdx == -1 {
- // no closing '}'
- return false, ErrBadPattern
- }
- closingIdx++
-
- patIdx := 1
- for {
- commaIdx := indexNextAlt(pattern[patIdx:closingIdx], separator != '\\')
- if commaIdx == -1 {
- break
- }
- commaIdx += patIdx
-
- ret, err = isZeroLengthPattern(pattern[patIdx:commaIdx]+pattern[closingIdx+1:], separator)
- if ret || err != nil {
- return
- }
-
- patIdx = commaIdx + 1
- }
- return isZeroLengthPattern(pattern[patIdx:closingIdx]+pattern[closingIdx+1:], separator)
- }
-
- // no luck - validate the rest of the pattern
- if !doValidatePattern(pattern, separator) {
- return false, ErrBadPattern
- }
- return false, nil
-}
-
-// Finds the index of the first unescaped byte `c`, or negative 1.
-func indexUnescapedByte(s string, c byte, allowEscaping bool) int {
- l := len(s)
- for i := 0; i < l; i++ {
- if allowEscaping && s[i] == '\\' {
- // skip next byte
- i++
- } else if s[i] == c {
- return i
- }
- }
- return -1
-}
-
-// Assuming the byte before the beginning of `s` is an opening `{`, this
-// function will find the index of the matching `}`. That is, it'll skip over
-// any nested `{}` and account for escaping
-func indexMatchedClosingAlt(s string, allowEscaping bool) int {
- alts := 1
- l := len(s)
- for i := 0; i < l; i++ {
- if allowEscaping && s[i] == '\\' {
- // skip next byte
- i++
- } else if s[i] == '{' {
- alts++
- } else if s[i] == '}' {
- if alts--; alts == 0 {
- return i
- }
- }
- }
- return -1
-}
diff --git a/cli/internal/doublestar/utils.go b/cli/internal/doublestar/utils.go
deleted file mode 100644
index 7236cd0..0000000
--- a/cli/internal/doublestar/utils.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-package doublestar
-
-// SplitPattern is a utility function. Given a pattern, SplitPattern will
-// return two strings: the first string is everything up to the last slash
-// (`/`) that appears _before_ any unescaped "meta" characters (ie, `*?[{`).
-// The second string is everything after that slash. For example, given the
-// pattern:
-//
-// ../../path/to/meta*/**
-// ^----------- split here
-//
-// SplitPattern returns "../../path/to" and "meta*/**". This is useful for
-// initializing os.DirFS() to call Glob() because Glob() will silently fail if
-// your pattern includes `/./` or `/../`. For example:
-//
-// base, pattern := SplitPattern("../../path/to/meta*/**")
-// fsys := os.DirFS(base)
-// matches, err := Glob(fsys, pattern)
-//
-// If SplitPattern cannot find somewhere to split the pattern (for example,
-// `meta*/**`), it will return "." and the unaltered pattern (`meta*/**` in
-// this example).
-//
-// Of course, it is your responsibility to decide if the returned base path is
-// "safe" in the context of your application. Perhaps you could use Match() to
-// validate against a list of approved base directories?
-func SplitPattern(p string) (string, string) {
- base := "."
- pattern := p
-
- splitIdx := -1
- for i := 0; i < len(p); i++ {
- c := p[i]
- if c == '\\' {
- i++
- } else if c == '/' {
- splitIdx = i
- } else if c == '*' || c == '?' || c == '[' || c == '{' {
- break
- }
- }
-
- if splitIdx >= 0 {
- return p[:splitIdx], p[splitIdx+1:]
- }
-
- return base, pattern
-}
-
-// Finds the next comma, but ignores any commas that appear inside nested `{}`.
-// Assumes that each opening bracket has a corresponding closing bracket.
-func indexNextAlt(s string, allowEscaping bool) int {
- alts := 1
- l := len(s)
- for i := 0; i < l; i++ {
- if allowEscaping && s[i] == '\\' {
- // skip next byte
- i++
- } else if s[i] == '{' {
- alts++
- } else if s[i] == '}' {
- alts--
- } else if s[i] == ',' && alts == 1 {
- return i
- }
- }
- return -1
-}
diff --git a/cli/internal/doublestar/validate.go b/cli/internal/doublestar/validate.go
deleted file mode 100644
index 225fc5e..0000000
--- a/cli/internal/doublestar/validate.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Package doublestar is adapted from https://github.com/bmatcuk/doublestar
-// Copyright Bob Matcuk. All Rights Reserved.
-// SPDX-License-Identifier: MIT
-package doublestar
-
-import "path/filepath"
-
-// ValidatePattern validates a pattern. Patterns are validated while they run in Match(),
-// PathMatch(), and Glob(), so, you normally wouldn't need to call this.
-// However, there are cases where this might be useful: for example, if your
-// program allows a user to enter a pattern that you'll run at a later time,
-// you might want to validate it.
-//
-// ValidatePattern assumes your pattern uses '/' as the path separator.
-func ValidatePattern(s string) bool {
- return doValidatePattern(s, '/')
-}
-
-// ValidatePathPattern only uses your OS path separator. In other words, use
-// ValidatePattern if you would normally use Match() or Glob(). Use
-// ValidatePathPattern if you would normally use PathMatch(). Keep in mind,
-// Glob() requires '/' separators, even if your OS uses something else.
-func ValidatePathPattern(s string) bool {
- return doValidatePattern(s, filepath.Separator)
-}
-
-func doValidatePattern(s string, separator rune) bool {
- altDepth := 0
- l := len(s)
-VALIDATE:
- for i := 0; i < l; i++ {
- switch s[i] {
- case '\\':
- if separator != '\\' {
- // skip the next byte - return false if there is no next byte
- if i++; i >= l {
- return false
- }
- }
- continue
-
- case '[':
- if i++; i >= l {
- // class didn't end
- return false
- }
- if s[i] == '^' || s[i] == '!' {
- i++
- }
- if i >= l || s[i] == ']' {
- // class didn't end or empty character class
- return false
- }
-
- for ; i < l; i++ {
- if separator != '\\' && s[i] == '\\' {
- i++
- } else if s[i] == ']' {
- // looks good
- continue VALIDATE
- }
- }
-
- // class didn't end
- return false
-
- case '{':
- altDepth++
- continue
-
- case '}':
- if altDepth == 0 {
- // alt end without a corresponding start
- return false
- }
- altDepth--
- continue
- }
- }
-
- // valid as long as all alts are closed
- return altDepth == 0
-}
diff --git a/cli/internal/encoding/gitoutput/gitoutput.go b/cli/internal/encoding/gitoutput/gitoutput.go
deleted file mode 100644
index 1c2ad4f..0000000
--- a/cli/internal/encoding/gitoutput/gitoutput.go
+++ /dev/null
@@ -1,345 +0,0 @@
-// Package gitoutput reads the output of calls to `git`.
-package gitoutput
-
-import (
- "bufio"
- "bytes"
- "errors"
- "fmt"
- "io"
-)
-
-// These describe the structure of fields in the output of `git` commands.
-var (
- LsTreeFields = []Field{ObjectMode, ObjectType, ObjectName, Path}
- LsFilesFields = []Field{ObjectMode, ObjectName, ObjectStage, Path}
- StatusFields = []Field{StatusX, StatusY, Path}
-)
-
-var _lsTreeFieldToIndex = map[Field]int{
- ObjectMode: 0,
- ObjectType: 1,
- ObjectName: 2,
- Path: 3,
-}
-
-var _lsFilesFieldToIndex = map[Field]int{
- ObjectMode: 0,
- ObjectName: 1,
- ObjectStage: 2,
- Path: 3,
-}
-
-var _statusFieldToIndex = map[Field]int{
- StatusX: 0,
- StatusY: 1,
- Path: 2,
-}
-
-// Field is the type for fields available in outputs to `git`.
-// Used for naming and sensible call sites.
-type Field int
-
-const (
- // ObjectMode is the mode field from `git` outputs. e.g. 100644
- ObjectMode Field = iota + 1
- // ObjectType is the set of allowed types from `git` outputs: blob, tree, commit
- ObjectType
- // ObjectName is the 40-character SHA hash
- ObjectName
- // ObjectStage is a value 0-3.
- ObjectStage
- // StatusX is the first character of the two-character output from `git status`.
- StatusX
- // StatusY is the second character of the two-character output from `git status`.
- StatusY
- // Path is the file path under version control in `git`.
- Path
-)
-
-// LsTreeEntry is the result from call `git ls-files`
-type LsTreeEntry []string
-
-// LsFilesEntry is the result from call `git ls-tree`
-type LsFilesEntry []string
-
-// StatusEntry is the result from call `git status`
-type StatusEntry []string
-
-// GetField returns the value of the specified field.
-func (e LsTreeEntry) GetField(field Field) string {
- value, exists := _lsTreeFieldToIndex[field]
- if !exists {
- panic("Received an invalid field for LsTreeEntry.")
- }
- return e[value]
-}
-
-// GetField returns the value of the specified field.
-func (e LsFilesEntry) GetField(field Field) string {
- value, exists := _lsFilesFieldToIndex[field]
- if !exists {
- panic("Received an invalid field for LsFilesEntry.")
- }
- return e[value]
-}
-
-// GetField returns the value of the specified field.
-func (e StatusEntry) GetField(field Field) string {
- value, exists := _statusFieldToIndex[field]
- if !exists {
- panic("Received an invalid field for StatusEntry.")
- }
- return e[value]
-}
-
-// Separators that appear in the output of `git` commands.
-const (
- _space = ' '
- _tab = '\t'
- _nul = '\000'
-)
-
-// A ParseError is returned for parsing errors.
-// Entries and columns are both 1-indexed.
-type ParseError struct {
- Entry int // Entry where the error occurred
- Column int // Column where the error occurred
- Err error // The actual error
-}
-
-// Error creates a string for a parse error.
-func (e *ParseError) Error() string {
- return fmt.Sprintf("parse error on entry %d, column %d: %v", e.Entry, e.Column, e.Err)
-}
-
-// Unwrap returns the raw error.
-func (e *ParseError) Unwrap() error { return e.Err }
-
-// These are the errors that can be returned in ParseError.Err.
-var (
- ErrInvalidObjectMode = errors.New("object mode is not valid")
- ErrInvalidObjectType = errors.New("object type is not valid")
- ErrInvalidObjectName = errors.New("object name is not valid")
- ErrInvalidObjectStage = errors.New("object stage is not valid")
- ErrInvalidObjectStatusX = errors.New("object status x is not valid")
- ErrInvalidObjectStatusY = errors.New("object status y is not valid")
- ErrInvalidPath = errors.New("path is not valid")
- ErrUnknownField = errors.New("unknown field")
-)
-
-// A Reader reads records from `git`'s output`.
-type Reader struct {
- // ReuseRecord controls whether calls to Read may return a slice sharing
- // the backing array of the previous call's returned slice for performance.
- // By default, each call to Read returns newly allocated memory owned by the caller.
- ReuseRecord bool
-
- // Fields specifies the type of each field.
- Fields []Field
-
- reader *bufio.Reader
-
- // numEntry is the current entry being read in the `git` output.
- numEntry int
-
- // rawBuffer is an entry buffer only used by the readEntry method.
- rawBuffer []byte
-
- // recordBuffer holds the unescaped fields, one after another.
- // The fields can be accessed by using the indexes in fieldIndexes.
- recordBuffer []byte
-
- // fieldIndexes is an index of fields inside recordBuffer.
- // The i'th field ends at offset fieldIndexes[i] in recordBuffer.
- fieldIndexes []int
-
- // fieldPositions is an index of field positions for the
- // last record returned by Read.
- fieldPositions []position
-
- // lastRecord is a record cache and only used when ReuseRecord == true.
- lastRecord []string
-}
-
-// NewLSTreeReader returns a new Reader that reads from reader.
-func NewLSTreeReader(reader io.Reader) *Reader {
- return &Reader{
- reader: bufio.NewReader(reader),
- Fields: LsTreeFields,
- }
-}
-
-// NewLSFilesReader returns a new Reader that reads from reader.
-func NewLSFilesReader(reader io.Reader) *Reader {
- return &Reader{
- reader: bufio.NewReader(reader),
- Fields: LsFilesFields,
- }
-}
-
-// NewStatusReader returns a new Reader that reads from reader.
-func NewStatusReader(reader io.Reader) *Reader {
- return &Reader{
- reader: bufio.NewReader(reader),
- Fields: StatusFields,
- }
-}
-
-// Read reads one record from `reader`.
-// Read always returns either a non-nil record or a non-nil error,
-// but not both.
-//
-// If there is no data left to be read, Read returns nil, io.EOF.
-//
-// If ReuseRecord is true, the returned slice may be shared
-// between multiple calls to Read.
-func (r *Reader) Read() (record []string, err error) {
- if r.ReuseRecord {
- record, err = r.readRecord(r.lastRecord)
- r.lastRecord = record
- } else {
- record, err = r.readRecord(nil)
- }
- return record, err
-}
-
-// FieldPos returns the entry and column corresponding to
-// the start of the field with the given index in the slice most recently
-// returned by Read. Numbering of entries and columns starts at 1;
-// columns are counted in bytes, not runes.
-//
-// If this is called with an out-of-bounds index, it panics.
-func (r *Reader) FieldPos(field int) (entry int, column int) {
- if field < 0 || field >= len(r.fieldPositions) {
- panic("out of range index passed to FieldPos")
- }
- p := &r.fieldPositions[field]
- return p.entry, p.col
-}
-
-// pos holds the position of a field in the current entry.
-type position struct {
- entry, col int
-}
-
-// ReadAll reads all the records from reader until EOF.
-//
-// A successful call returns err == nil, not err == io.EOF. Because ReadAll is
-// defined to read until EOF, it does not treat end of file as an error to be
-// reported.
-func (r *Reader) ReadAll() (records [][]string, err error) {
- for {
- record, err := r.readRecord(nil)
- if err == io.EOF {
- return records, nil
- }
- if err != nil {
- return nil, err
- }
- records = append(records, record)
- }
-}
-
-// readEntry reads the next entry (with the trailing NUL).
-// If EOF is hit without a trailing NUL, it will be omitted.
-// If some bytes were read then the error is never io.EOF.
-// The result is only valid until the next call to readEntry.
-func (r *Reader) readEntry() ([]byte, error) {
- entry, err := r.reader.ReadSlice('\000')
- if err == bufio.ErrBufferFull {
- r.rawBuffer = append(r.rawBuffer[:0], entry...)
- for err == bufio.ErrBufferFull {
- entry, err = r.reader.ReadSlice('\000')
- r.rawBuffer = append(r.rawBuffer, entry...)
- }
- entry = r.rawBuffer
- }
- if len(entry) > 0 && err == io.EOF {
- entry = append(entry, '\000')
- err = nil
- }
- r.numEntry++
-
- return entry, err
-}
-
-// getFieldLength returns the field length and the separator length for advancing.
-func getFieldLength(fieldType Field, fieldNumber int, fieldCount int, entry *[]byte) (int, int) {
- switch fieldType {
- case StatusX:
- return 1, 0
- case StatusY:
- return 1, 1
- default:
- return bytes.IndexRune(*entry, getSeparator(fieldNumber, fieldCount)), 1
- }
-}
-
-// getSeparator returns the separator between the current field and the next field.
-// Since fields separators are regular it doesn't hard code them.
-func getSeparator(fieldNumber int, fieldCount int) rune {
- remaining := fieldCount - fieldNumber
-
- switch remaining {
- default:
- return _space
- case 2:
- return _tab
- case 1:
- return _nul
- }
-}
-
-// readRecord reads a single record.
-func (r *Reader) readRecord(dst []string) ([]string, error) {
- entry, errRead := r.readEntry()
- if errRead == io.EOF {
- return nil, errRead
- }
-
- // Parse each field in the record.
- r.recordBuffer = r.recordBuffer[:0]
- r.fieldIndexes = r.fieldIndexes[:0]
- r.fieldPositions = r.fieldPositions[:0]
- pos := position{entry: r.numEntry, col: 1}
-
- fieldCount := len(r.Fields)
-
- for fieldNumber, fieldType := range r.Fields {
- length, advance := getFieldLength(fieldType, fieldNumber, fieldCount, &entry)
- field := entry[:length]
-
- fieldError := checkValid(fieldType, field)
- if fieldError != nil {
- return nil, &ParseError{
- Entry: pos.entry,
- Column: pos.col,
- Err: fieldError,
- }
- }
-
- offset := length + advance
- entry = entry[offset:]
- r.recordBuffer = append(r.recordBuffer, field...)
- r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer))
- r.fieldPositions = append(r.fieldPositions, pos)
- pos.col += offset
- }
-
- // Create a single string and create slices out of it.
- // This pins the memory of the fields together, but allocates once.
- str := string(r.recordBuffer) // Convert to string once to batch allocations
- dst = dst[:0]
- if cap(dst) < len(r.fieldIndexes) {
- dst = make([]string, len(r.fieldIndexes))
- }
- dst = dst[:len(r.fieldIndexes)]
- var preIdx int
- for i, idx := range r.fieldIndexes {
- dst[i] = str[preIdx:idx]
- preIdx = idx
- }
-
- return dst, nil
-}
diff --git a/cli/internal/encoding/gitoutput/gitoutput_test.go b/cli/internal/encoding/gitoutput/gitoutput_test.go
deleted file mode 100644
index 19ab056..0000000
--- a/cli/internal/encoding/gitoutput/gitoutput_test.go
+++ /dev/null
@@ -1,377 +0,0 @@
-package gitoutput
-
-import (
- "fmt"
- "io"
- "reflect"
- "strings"
- "testing"
- "unicode/utf8"
-)
-
-type readTest struct {
- Name string
- Input string
- Output [][]string
- Reader func(io.Reader) *Reader
- Positions [][][2]int
- Errors []error
-
- // These fields are copied into the Reader
- ReuseRecord bool
-}
-
-// In these tests, the § and ∑ characters in readTest.Input are used to denote
-// the start of a field and the position of an error respectively.
-// They are removed before parsing and are used to verify the position
-// information reported by FieldPos.
-
-var lsTreeTests = []readTest{
- {
- Name: "simple",
- Input: "§100644 §blob §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\t§package.json\000",
- Output: [][]string{{"100644", "blob", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "package.json"}},
- Reader: NewLSTreeReader,
- },
- {
- Name: "no trailing nul",
- Input: "§100644 §blob §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\t§package.json",
- Output: [][]string{{"100644", "blob", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "package.json"}},
- Reader: NewLSTreeReader,
- },
- {
- Name: "weird file names",
- Input: "§100644 §blob §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\t§\t\000§100644 §blob §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\t§\"\000§100644 §blob §5b999efa470b056e329b4c23a73904e0794bdc2f\t§\n\000§100644 §blob §f44f57fff95196c5f7139dfa0b96875f1e9650a9\t§.gitignore\000§100644 §blob §33dbaf21275ca2a5f460249d941cbc27d5da3121\t§README.md\000§040000 §tree §7360f2d292aec95907cebdcbb412a6bf2bd10f8a\t§apps\000§100644 §blob §9ec2879b24ce2c817296eebe2cb3846f8e4751ea\t§package.json\000§040000 §tree §5759aadaea2cde55468a61e7104eb0a9d86c1d30\t§packages\000§100644 §blob §33d0621ee2f4da4a2f6f6bdd51a42618d181e337\t§turbo.json\000",
- Output: [][]string{
- {"100644", "blob", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "\t"},
- {"100644", "blob", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "\""},
- {"100644", "blob", "5b999efa470b056e329b4c23a73904e0794bdc2f", "\n"},
- {"100644", "blob", "f44f57fff95196c5f7139dfa0b96875f1e9650a9", ".gitignore"},
- {"100644", "blob", "33dbaf21275ca2a5f460249d941cbc27d5da3121", "README.md"},
- {"040000", "tree", "7360f2d292aec95907cebdcbb412a6bf2bd10f8a", "apps"},
- {"100644", "blob", "9ec2879b24ce2c817296eebe2cb3846f8e4751ea", "package.json"},
- {"040000", "tree", "5759aadaea2cde55468a61e7104eb0a9d86c1d30", "packages"},
- {"100644", "blob", "33d0621ee2f4da4a2f6f6bdd51a42618d181e337", "turbo.json"},
- },
- Reader: NewLSTreeReader,
- },
- {
- Name: "invalid object mode",
- Input: "∑888888 §blob §5b999efa470b056e329b4c23a73904e0794bdc2f\t§.eslintrc.js\000",
- Output: [][]string{},
- Reader: NewLSTreeReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectMode}},
- },
- {
- Name: "invalid object type",
- Input: "§100644 ∑bush §5b999efa470b056e329b4c23a73904e0794bdc2f\t§.eslintrc.js\000",
- Output: [][]string{},
- Reader: NewLSTreeReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectType}},
- },
- {
- Name: "invalid object name",
- Input: "§100644 §blob ∑Zb999efa470b056e329b4c23a73904e0794bdc2f\t§.eslintrc.js\000",
- Output: [][]string{},
- Reader: NewLSTreeReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectName}},
- },
- {
- Name: "invalid path",
- Input: "§100644 §blob §5b999efa470b056e329b4c23a73904e0794bdc2f\t∑\000",
- Output: [][]string{},
- Reader: NewLSTreeReader,
- Errors: []error{&ParseError{Err: ErrInvalidPath}},
- },
-}
-
-var lsFilesTests = []readTest{
- {
- Name: "simple",
- Input: "§100644 §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 §0\t§package.json\000",
- Output: [][]string{{"100644", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "0", "package.json"}},
- Reader: NewLSFilesReader,
- },
- {
- Name: "no trailing nul",
- Input: "§100644 §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 §0\t§package.json",
- Output: [][]string{{"100644", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "0", "package.json"}},
- Reader: NewLSFilesReader,
- },
- {
- Name: "invalid object mode",
- Input: "∑888888 §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 §0\t§package.json",
- Output: [][]string{},
- Reader: NewLSFilesReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectMode}},
- },
- {
- Name: "invalid object name",
- Input: "§100644 ∑Z69de29bb2d1d6434b8b29ae775ad8c2e48c5391 §0\t§package.json",
- Output: [][]string{},
- Reader: NewLSFilesReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectName}},
- },
- {
- Name: "invalid object stage",
- Input: "§100644 §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 ∑4\t§package.json",
- Output: [][]string{},
- Reader: NewLSFilesReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectStage}},
- },
- {
- Name: "invalid path",
- Input: "§100644 §e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 §0\t∑",
- Output: [][]string{},
- Reader: NewLSFilesReader,
- Errors: []error{&ParseError{Err: ErrInvalidPath}},
- },
-}
-
-var statusTests = []readTest{
- {
- Name: "simple",
- Input: "§A§D §package.json\000",
- Output: [][]string{{"A", "D", "package.json"}},
- Reader: NewStatusReader,
- },
- {
- Name: "no trailing nul",
- Input: "§A§D §package.json",
- Output: [][]string{{"A", "D", "package.json"}},
- Reader: NewStatusReader,
- },
- {
- Name: "invalid status X",
- Input: "∑~§D §package.json\000",
- Output: [][]string{},
- Reader: NewStatusReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectStatusX}},
- },
- {
- Name: "invalid status Y",
- Input: "§D∑~ §package.json\000",
- Output: [][]string{},
- Reader: NewStatusReader,
- Errors: []error{&ParseError{Err: ErrInvalidObjectStatusY}},
- },
- {
- Name: "invalid path",
- Input: "§A§D ∑\000",
- Output: [][]string{},
- Reader: NewStatusReader,
- Errors: []error{&ParseError{Err: ErrInvalidPath}},
- },
-}
-
-func TestRead(t *testing.T) {
- newReader := func(tt readTest) (*Reader, [][][2]int, map[int][2]int) {
- positions, errPositions, input := makePositions(tt.Input)
- r := tt.Reader(strings.NewReader(input))
-
- r.ReuseRecord = tt.ReuseRecord
- return r, positions, errPositions
- }
-
- allTests := []readTest{}
- allTests = append(allTests, lsTreeTests...)
- allTests = append(allTests, lsFilesTests...)
- allTests = append(allTests, statusTests...)
-
- for _, tt := range allTests {
- t.Run(tt.Name, func(t *testing.T) {
- r, positions, errPositions := newReader(tt)
- out, err := r.ReadAll()
- if wantErr := firstError(tt.Errors, positions, errPositions); wantErr != nil {
- if !reflect.DeepEqual(err, wantErr) {
- t.Fatalf("ReadAll() error mismatch:\ngot %v (%#v)\nwant %v (%#v)", err, err, wantErr, wantErr)
- }
- if out != nil {
- t.Fatalf("ReadAll() output:\ngot %q\nwant nil", out)
- }
- } else {
- if err != nil {
- t.Fatalf("unexpected Readall() error: %v", err)
- }
- if !reflect.DeepEqual(out, tt.Output) {
- t.Fatalf("ReadAll() output:\ngot %q\nwant %q", out, tt.Output)
- }
- }
-
- // Check field and error positions.
- r, _, _ = newReader(tt)
- for recNum := 0; ; recNum++ {
- rec, err := r.Read()
- var wantErr error
- if recNum < len(tt.Errors) && tt.Errors[recNum] != nil {
- wantErr = errorWithPosition(tt.Errors[recNum], recNum, positions, errPositions)
- } else if recNum >= len(tt.Output) {
- wantErr = io.EOF
- }
- if !reflect.DeepEqual(err, wantErr) {
- t.Fatalf("Read() error at record %d:\ngot %v (%#v)\nwant %v (%#v)", recNum, err, err, wantErr, wantErr)
- }
- if err != nil {
- if recNum < len(tt.Output) {
- t.Fatalf("need more records; got %d want %d", recNum, len(tt.Output))
- }
- break
- }
- if got, want := rec, tt.Output[recNum]; !reflect.DeepEqual(got, want) {
- t.Errorf("Read vs ReadAll mismatch;\ngot %q\nwant %q", got, want)
- }
- pos := positions[recNum]
- if len(pos) != len(rec) {
- t.Fatalf("mismatched position length at record %d", recNum)
- }
- for i := range rec {
- entry, col := r.FieldPos(i)
- if got, want := [2]int{entry, col}, pos[i]; got != want {
- t.Errorf("position mismatch at record %d, field %d;\ngot %v\nwant %v", recNum, i, got, want)
- }
- }
- }
- })
- }
-}
-
-// firstError returns the first non-nil error in errs,
-// with the position adjusted according to the error's
-// index inside positions.
-func firstError(errs []error, positions [][][2]int, errPositions map[int][2]int) error {
- for i, err := range errs {
- if err != nil {
- return errorWithPosition(err, i, positions, errPositions)
- }
- }
- return nil
-}
-
-func errorWithPosition(err error, recNum int, positions [][][2]int, errPositions map[int][2]int) error {
- parseErr, ok := err.(*ParseError)
- if !ok {
- return err
- }
- if recNum >= len(positions) {
- panic(fmt.Errorf("no positions found for error at record %d", recNum))
- }
- errPos, ok := errPositions[recNum]
- if !ok {
- panic(fmt.Errorf("no error position found for error at record %d", recNum))
- }
- parseErr1 := *parseErr
- parseErr1.Entry = errPos[0]
- parseErr1.Column = errPos[1]
- return &parseErr1
-}
-
-// makePositions returns the expected field positions of all the fields in text,
-// the positions of any errors, and the text with the position markers removed.
-//
-// The start of each field is marked with a § symbol;
-// Error positions are marked with ∑ symbols.
-func makePositions(text string) ([][][2]int, map[int][2]int, string) {
- buf := make([]byte, 0, len(text))
- var positions [][][2]int
- errPositions := make(map[int][2]int)
- entry, col := 1, 1
- recNum := 0
-
- for len(text) > 0 {
- r, size := utf8.DecodeRuneInString(text)
- switch r {
- case '\000':
- col = 1
- buf = append(buf, '\000')
- positions = append(positions, [][2]int{})
- entry++
- recNum++
- case '§':
- if len(positions) == 0 {
- positions = append(positions, [][2]int{})
- }
- positions[len(positions)-1] = append(positions[len(positions)-1], [2]int{entry, col})
- case '∑':
- errPositions[recNum] = [2]int{entry, col}
- default:
- buf = append(buf, text[:size]...)
- col += size
- }
- text = text[size:]
- }
- return positions, errPositions, string(buf)
-}
-
-// nTimes is an io.Reader which yields the string s n times.
-type nTimes struct {
- s string
- n int
- off int
-}
-
-func (r *nTimes) Read(p []byte) (n int, err error) {
- for {
- if r.n <= 0 || r.s == "" {
- return n, io.EOF
- }
- n0 := copy(p, r.s[r.off:])
- p = p[n0:]
- n += n0
- r.off += n0
- if r.off == len(r.s) {
- r.off = 0
- r.n--
- }
- if len(p) == 0 {
- return
- }
- }
-}
-
-// TODO: track other types.
-// benchmarkRead measures reading the provided ls-tree data.
-// initReader, if non-nil, modifies the Reader before it's used.
-func benchmarkRead(b *testing.B, getReader func(reader io.Reader) *Reader, initReader func(*Reader), rows string) {
- b.ReportAllocs()
- r := getReader(&nTimes{s: rows, n: b.N})
- if initReader != nil {
- initReader(r)
- }
- for {
- _, err := r.Read()
- if err == io.EOF {
- break
- }
- if err != nil {
- b.Fatal(err)
- }
- }
-}
-
-const benchmarkLSTreeData = `100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 \000100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 "\000100644 blob 5b999efa470b056e329b4c23a73904e0794bdc2f .eslintrc.js\000100644 blob f44f57fff95196c5f7139dfa0b96875f1e9650a9 .gitignore\000100644 blob 33dbaf21275ca2a5f460249d941cbc27d5da3121 README.md\000040000 tree 7360f2d292aec95907cebdcbb412a6bf2bd10f8a apps\000100644 blob 9ec2879b24ce2c817296eebe2cb3846f8e4751ea package.json\000040000 tree 5759aadaea2cde55468a61e7104eb0a9d86c1d30 packages\000100644 blob 33d0621ee2f4da4a2f6f6bdd51a42618d181e337 turbo.json\000`
-const benchmarkLSFilesData = `100644 13e399637190f1edb7f034b4281ecfafb5dab9e2 0 Makefile\000100644 6c1c500409989499db51f1eff37b38b857547fdc 0 cmd/turbo/main.go\000100644 2d2b9a2c3ba82f6b806f58c7f7d5eb55fefa837e 0 cmd/turbo/main_utils.go\000100644 3329c8a7f6edee487caeeaf56c600f7c85fc69e7 0 cmd/turbo/signals.go\000100644 e81df7b6ed9a277c30dd35e3524d00e8b13cf584 0 cmd/turbo/version.go\000100644 8992ebf37df05fc5ff64c0f811a3259adff10d70 0 go.mod\000100644 3da872301c79986673d6a12914fbd48c924f5999 0 go.sum\000100644 d7b2d20a037aa9bf8b48eef451eb5f9ba5904237 0 internal/analytics/analytics.go\000`
-const benchmarkStatusData = ` M cli/internal/encoding/gitoutput/gitoutput.go\000 M cli/internal/encoding/gitoutput/gitoutput_test.go\000?? NOTICES.md\000 M cli/internal/encoding/gitoutput/gitoutput.go\000 M cli/internal/encoding/gitoutput/gitoutput_test.go\000?? NOTICES.md\000 M cli/internal/encoding/gitoutput/gitoutput.go\000 M cli/internal/encoding/gitoutput/gitoutput_test.go\000?? NOTICES.md\000 M cli/internal/encoding/gitoutput/gitoutput.go\000 M cli/internal/encoding/gitoutput/gitoutput_test.go\000?? NOTICES.md\000 M cli/internal/encoding/gitoutput/gitoutput.go\000 M cli/internal/encoding/gitoutput/gitoutput_test.go\000`
-
-func BenchmarkLSTreeRead(b *testing.B) {
- benchmarkRead(b, NewLSTreeReader, nil, benchmarkLSTreeData)
-}
-
-func BenchmarkLSTreeReadReuseRecord(b *testing.B) {
- benchmarkRead(b, NewLSTreeReader, func(r *Reader) { r.ReuseRecord = true }, benchmarkLSTreeData)
-}
-
-func BenchmarkLSFilesRead(b *testing.B) {
- benchmarkRead(b, NewLSFilesReader, nil, benchmarkLSFilesData)
-}
-
-func BenchmarkLSFilesReadReuseRecord(b *testing.B) {
- benchmarkRead(b, NewLSFilesReader, func(r *Reader) { r.ReuseRecord = true }, benchmarkLSFilesData)
-}
-
-func BenchmarkStatusRead(b *testing.B) {
- benchmarkRead(b, NewStatusReader, nil, benchmarkStatusData)
-}
-
-func BenchmarkStatusReadReuseRecord(b *testing.B) {
- benchmarkRead(b, NewStatusReader, func(r *Reader) { r.ReuseRecord = true }, benchmarkStatusData)
-}
diff --git a/cli/internal/encoding/gitoutput/validators.go b/cli/internal/encoding/gitoutput/validators.go
deleted file mode 100644
index e13c2d5..0000000
--- a/cli/internal/encoding/gitoutput/validators.go
+++ /dev/null
@@ -1,148 +0,0 @@
-package gitoutput
-
-import "bytes"
-
-var _allowedObjectType = []byte(" blob tree commit ")
-var _allowedStatusChars = []byte(" MTADRCU?!")
-
-// checkValid provides a uniform interface for calling `gitoutput` validators.
-func checkValid(fieldType Field, value []byte) error {
- switch fieldType {
- case ObjectMode:
- return checkObjectMode(value)
- case ObjectType:
- return checkObjectType(value)
- case ObjectName:
- return CheckObjectName(value)
- case ObjectStage:
- return checkObjectStage(value)
- case StatusX:
- return checkStatusX(value)
- case StatusY:
- return checkStatusY(value)
- case Path:
- return checkPath(value)
- default:
- return ErrUnknownField
- }
-}
-
-// checkObjectMode asserts that a byte slice is a six digit octal string (100644).
-// It does not attempt to ensure that the values in particular positions are reasonable.
-func checkObjectMode(value []byte) error {
- if len(value) != 6 {
- return ErrInvalidObjectMode
- }
-
- // 0-7 are 0x30 - 0x37
- for _, currentByte := range value {
- if (currentByte ^ 0x30) > 7 {
- return ErrInvalidObjectMode
- }
- }
-
- // length of 6, 0-7
- return nil
-}
-
-// checkObjectType asserts that a byte slice is a valid possibility (blob, tree, commit).
-func checkObjectType(value []byte) error {
- typeLength := len(value)
- // Based upon:
- // min(len("blob"), len("tree"), len("commit"))
- // max(len("blob"), len("tree"), len("commit"))
- if typeLength < 4 || typeLength > 6 {
- return ErrInvalidObjectType
- }
-
- // Because of the space separator there is no way to pass in a space.
- // We use that trick to enable fast lookups in _allowedObjectType.
- index := bytes.Index(_allowedObjectType, value)
-
- // Impossible to match at 0, not found is -1.
- if index < 1 {
- return ErrInvalidObjectType
- }
-
- // Followed by a space.
- if _allowedObjectType[index-1] != byte(_space) {
- return ErrInvalidObjectType
- }
-
- // Preceded by a space.
- if _allowedObjectType[index+typeLength] != byte(_space) {
- return ErrInvalidObjectType
- }
- return nil
-}
-
-// CheckObjectName asserts that a byte slice looks like a SHA hash.
-func CheckObjectName(value []byte) error {
- if len(value) != 40 {
- return ErrInvalidObjectName
- }
-
- // 0-9 are 0x30 - 0x39
- // a-f are 0x61 - 0x66
- for _, currentByte := range value {
- isNumber := (currentByte ^ 0x30) < 10
- numericAlpha := (currentByte ^ 0x60)
- isAlpha := (numericAlpha < 7) && (numericAlpha > 0)
- if !(isNumber || isAlpha) {
- return ErrInvalidObjectName
- }
- }
-
- // length of 40, hex
- return nil
-}
-
-// checkObjectStage asserts that a byte slice is a valid possibility (0-3).
-func checkObjectStage(value []byte) error {
- // 0-3 are 0x30 - 0x33
- if len(value) != 1 {
- return ErrInvalidObjectStage
- }
-
- currentByte := value[0]
- if (currentByte ^ 0x30) >= 4 {
- return ErrInvalidObjectStage
- }
-
- return nil
-}
-
-// checkStatusX asserts that a byte slice is a valid possibility (" MTADRCU?!").
-func checkStatusX(value []byte) error {
- if len(value) != 1 {
- return ErrInvalidObjectStatusX
- }
-
- index := bytes.Index(_allowedStatusChars, value)
- if index == -1 {
- return ErrInvalidObjectStatusX
- }
- return nil
-}
-
-// checkStatusY asserts that a byte slice is a valid possibility (" MTADRCU?!").
-func checkStatusY(value []byte) error {
- if len(value) != 1 {
- return ErrInvalidObjectStatusY
- }
-
- index := bytes.Index(_allowedStatusChars, value)
- if index == -1 {
- return ErrInvalidObjectStatusY
- }
- return nil
-}
-
-// checkPath asserts that a byte slice is non-empty.
-func checkPath(value []byte) error {
- // Exists at all. This is best effort as trying to be fully-compatible is silly.
- if len(value) == 0 {
- return ErrInvalidPath
- }
- return nil
-}
diff --git a/cli/internal/encoding/gitoutput/validators_test.go b/cli/internal/encoding/gitoutput/validators_test.go
deleted file mode 100644
index 29e1274..0000000
--- a/cli/internal/encoding/gitoutput/validators_test.go
+++ /dev/null
@@ -1,514 +0,0 @@
-package gitoutput
-
-import (
- "testing"
-)
-
-func Test_checkValid(t *testing.T) {
- type args struct {
- fieldType Field
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "ObjectMode",
- args: args{
- fieldType: ObjectMode,
- value: []byte("100644"),
- },
- wantErr: false,
- },
- {
- name: "ObjectType",
- args: args{
- fieldType: ObjectType,
- value: []byte("blob"),
- },
- wantErr: false,
- },
- {
- name: "ObjectName",
- args: args{
- fieldType: ObjectName,
- value: []byte("8992ebf37df05fc5ff64c0f811a3259adff10d70"),
- },
- wantErr: false,
- },
- {
- name: "ObjectStage",
- args: args{
- fieldType: ObjectStage,
- value: []byte("0"),
- },
- wantErr: false,
- },
- {
- name: "StatusX",
- args: args{
- fieldType: StatusX,
- value: []byte("!"),
- },
- wantErr: false,
- },
- {
- name: "StatusY",
- args: args{
- fieldType: StatusY,
- value: []byte("?"),
- },
- wantErr: false,
- },
- {
- name: "Path",
- args: args{
- fieldType: Path,
- value: []byte("/hello/world"),
- },
- wantErr: false,
- },
- {
- name: "Unknown",
- args: args{
- fieldType: Field(12),
- value: []byte("unused"),
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := checkValid(tt.args.fieldType, tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkValid() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func Test_checkObjectMode(t *testing.T) {
- type args struct {
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "Simple",
- args: args{
- value: []byte("100644"),
- },
- wantErr: false,
- },
- {
- name: "All sevens",
- args: args{
- value: []byte("777777"),
- },
- wantErr: false,
- },
- {
- name: "All zeroes",
- args: args{
- value: []byte("000000"),
- },
- wantErr: false,
- },
- {
- name: "Non-octal chars",
- args: args{
- value: []byte("sixsix"),
- },
- wantErr: true,
- },
- {
- name: "nul",
- args: args{
- value: []byte("\000\000\000\000\000\000"),
- },
- wantErr: true,
- },
- {
- name: "too long",
- args: args{
- value: []byte("1234567"),
- },
- wantErr: true,
- },
- {
- name: "off by plus one",
- args: args{
- value: []byte("888888"),
- },
- wantErr: true,
- },
- {
- name: "off by minus one",
- args: args{
- value: []byte("//////"),
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := checkObjectMode(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkObjectMode() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func Test_checkObjectType(t *testing.T) {
- type args struct {
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "Finds blob",
- args: args{
- value: []byte("blob"),
- },
- wantErr: false,
- },
- {
- name: "Finds tree",
- args: args{
- value: []byte("tree"),
- },
- wantErr: false,
- },
- {
- name: "Finds commit",
- args: args{
- value: []byte("commit"),
- },
- wantErr: false,
- },
- {
- name: "nonsense input",
- args: args{
- value: []byte("input"),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (all 3)",
- args: args{
- value: []byte("blob tree commit"),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (first two)",
- args: args{
- value: []byte("blob tree"),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (last two)",
- args: args{
- value: []byte("tree commit"),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (arbitrary substring)",
- args: args{
- value: []byte("tree c"),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (space)",
- args: args{
- value: []byte(" "),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (empty string)",
- args: args{
- value: []byte(""),
- },
- wantErr: true,
- },
- {
- name: "Knows too much about the implementation details (leading space)",
- args: args{
- value: []byte(" tree"),
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := checkObjectType(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkObjectType() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func TestCheckObjectName(t *testing.T) {
- type args struct {
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "Simple",
- args: args{
- value: []byte("8992ebf37df05fc5ff64c0f811a3259adff10d70"),
- },
- wantErr: false,
- },
- {
- name: "Too short",
- args: args{
- value: []byte("8992ebf37df05fc5ff64"),
- },
- wantErr: true,
- },
- {
- name: "Too long",
- args: args{
- value: []byte("8992ebf37df05fc5ff64c0f811a3259adff10d708992ebf37df05fc5ff64c0f811a3259adff10d70"),
- },
- wantErr: true,
- },
- {
- name: "Not hex",
- args: args{
- value: []byte("z992ebf37df05fc5ff64c0f811a3259adff10d70"),
- },
- wantErr: true,
- },
- {
- name: "Not lowercase",
- args: args{
- value: []byte("8992EBF37DF05FC5FF64C0F811A3259ADFF10D70"),
- },
- wantErr: true,
- },
- {
- name: "Off by plus one in the ASCII table (a-f).",
- args: args{
- value: []byte("gggggggggggggggggggggggggggggggggggggggg"),
- },
- wantErr: true,
- },
- {
- name: "Off by minus one in the ASCII table (a-f).",
- args: args{
- value: []byte("````````````````````````````````````````"),
- },
- wantErr: true,
- },
- {
- name: "Off by minus one in the ASCII table (0-9).",
- args: args{
- value: []byte("////////////////////////////////////////"),
- },
- wantErr: true,
- },
- {
- name: "Off by plus one in the ASCII table (0-9).",
- args: args{
- value: []byte("::::::::::::::::::::::::::::::::::::::::"),
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := CheckObjectName(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("CheckObjectName() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func Test_checkObjectStage(t *testing.T) {
- type args struct {
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "0",
- args: args{
- value: []byte("0"),
- },
- wantErr: false,
- },
- {
- name: "1",
- args: args{
- value: []byte("1"),
- },
- wantErr: false,
- },
- {
- name: "2",
- args: args{
- value: []byte("2"),
- },
- wantErr: false,
- },
- {
- name: "3",
- args: args{
- value: []byte("3"),
- },
- wantErr: false,
- },
- {
- name: "/",
- args: args{
- value: []byte("/"),
- },
- wantErr: true,
- },
- {
- name: "4",
- args: args{
- value: []byte("4"),
- },
- wantErr: true,
- },
- {
- name: "00",
- args: args{
- value: []byte("00"),
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := checkObjectStage(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkObjectStage() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func Test_checkStatus(t *testing.T) {
- type args struct {
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "Simple",
- args: args{
- value: []byte("D"),
- },
- wantErr: false,
- },
- {
- name: "Space",
- args: args{
- value: []byte(" "),
- },
- wantErr: false,
- },
- {
- name: "Empty",
- args: args{
- value: []byte(""),
- },
- wantErr: true,
- },
- {
- name: "Too long",
- args: args{
- value: []byte("?!"),
- },
- wantErr: true,
- },
- {
- name: "nul",
- args: args{
- value: []byte("\000"),
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := checkStatusX(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkStatusX() error = %v, wantErr %v", err, tt.wantErr)
- }
- if err := checkStatusY(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkStatusY() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func Test_checkPath(t *testing.T) {
- type args struct {
- value []byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "Simple",
- args: args{
- value: []byte("./"),
- },
- wantErr: false,
- },
- {
- name: "newline",
- args: args{
- value: []byte("has\nnewline"),
- },
- wantErr: false,
- },
- {
- name: "Empty",
- args: args{
- value: []byte(""),
- },
- wantErr: true,
- },
- {
- name: "newline",
- args: args{
- value: []byte("\n"),
- },
- wantErr: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if err := checkPath(tt.args.value); (err != nil) != tt.wantErr {
- t.Errorf("checkPath() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
diff --git a/cli/internal/ffi/bindings.h b/cli/internal/ffi/bindings.h
deleted file mode 100644
index c2bbcea..0000000
--- a/cli/internal/ffi/bindings.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-typedef struct Buffer {
- uint32_t len;
- uint8_t *data;
-} Buffer;
-
-void free_buffer(struct Buffer buffer);
-
-struct Buffer get_turbo_data_dir(void);
-
-struct Buffer changed_files(struct Buffer buffer);
-
-struct Buffer previous_content(struct Buffer buffer);
-
-struct Buffer npm_transitive_closure(struct Buffer buf);
-
-struct Buffer npm_subgraph(struct Buffer buf);
diff --git a/cli/internal/ffi/ffi.go b/cli/internal/ffi/ffi.go
deleted file mode 100644
index 7ac15e4..0000000
--- a/cli/internal/ffi/ffi.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package ffi
-
-// ffi
-//
-// Please read the notes about safety (marked with `SAFETY`) in both this file,
-// and in turborepo-ffi/lib.rs before modifying this file.
-
-// #include "bindings.h"
-//
-// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR} -lturborepo_ffi_darwin_arm64 -lz -liconv
-// #cgo darwin,amd64 LDFLAGS: -L${SRCDIR} -lturborepo_ffi_darwin_amd64 -lz -liconv
-// #cgo linux,arm64,staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_arm64 -lunwind
-// #cgo linux,amd64,staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_amd64 -lunwind
-// #cgo linux,arm64,!staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_arm64 -lz
-// #cgo linux,amd64,!staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_amd64 -lz
-// #cgo windows,amd64 LDFLAGS: -L${SRCDIR} -lturborepo_ffi_windows_amd64 -lole32 -lbcrypt -lws2_32 -luserenv
-import "C"
-
-import (
- "errors"
- "reflect"
- "unsafe"
-
- ffi_proto "github.com/vercel/turbo/cli/internal/ffi/proto"
- "google.golang.org/protobuf/proto"
-)
-
-// Unmarshal consumes a buffer and parses it into a proto.Message
-func Unmarshal[M proto.Message](b C.Buffer, c M) error {
- bytes := toBytes(b)
- if err := proto.Unmarshal(bytes, c); err != nil {
- return err
- }
-
- // free the buffer on the rust side
- //
- // SAFETY: do not use `C.free_buffer` to free a buffer that has been allocated
- // on the go side. If you happen to accidentally use the wrong one, you can
- // expect a segfault on some platforms. This is the only valid callsite.
- C.free_buffer(b)
-
- return nil
-}
-
-// Marshal consumes a proto.Message and returns a bufferfire
-//
-// NOTE: the buffer must be freed by calling `Free` on it
-func Marshal[M proto.Message](c M) C.Buffer {
- bytes, err := proto.Marshal(c)
- if err != nil {
- panic(err)
- }
-
- return toBuffer(bytes)
-}
-
-// Free frees a buffer that has been allocated *on the go side*.
-//
-// SAFETY: this is not the same as `C.free_buffer`, which frees a buffer that
-// has been allocated *on the rust side*. If you happen to accidentally use
-// the wrong one, you can expect a segfault on some platforms.
-//
-// EXAMPLE: it is recommended use this function via a `defer` statement, like so:
-//
-// reqBuf := Marshal(&req)
-// defer reqBuf.Free()
-func (c C.Buffer) Free() {
- C.free(unsafe.Pointer(c.data))
-}
-
-// rather than use C.GoBytes, we use this function to avoid copying the bytes,
-// since it is going to be immediately Unmarshalled into a proto.Message
-//
-// SAFETY: go slices contain a pointer to an underlying buffer with a length.
-// if the buffer is known to the garbage collector, dropping the last slice will
-// cause the memory to be freed. this memory is owned by the rust side (and is
-// not known the garbage collector), so dropping the slice will do nothing
-func toBytes(b C.Buffer) []byte {
- var out []byte
-
- len := (uint32)(b.len)
-
- sh := (*reflect.SliceHeader)(unsafe.Pointer(&out))
- sh.Data = uintptr(unsafe.Pointer(b.data))
- sh.Len = int(len)
- sh.Cap = int(len)
-
- return out
-}
-
-func toBuffer(bytes []byte) C.Buffer {
- b := C.Buffer{}
- b.len = C.uint(len(bytes))
- b.data = (*C.uchar)(C.CBytes(bytes))
- return b
-}
-
-// GetTurboDataDir returns the path to the Turbo data directory
-func GetTurboDataDir() string {
- buffer := C.get_turbo_data_dir()
- resp := ffi_proto.TurboDataDirResp{}
- if err := Unmarshal(buffer, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
- return resp.Dir
-}
-
-// Go convention is to use an empty string for an uninitialized or null-valued
-// string. Rust convention is to use an Option<String> for the same purpose, which
-// is encoded on the Go side as *string. This converts between the two.
-func stringToRef(s string) *string {
- if s == "" {
- return nil
- }
- return &s
-}
-
-// ChangedFiles returns the files changed in between two commits, the workdir and the index, and optionally untracked files
-func ChangedFiles(gitRoot string, turboRoot string, fromCommit string, toCommit string) ([]string, error) {
- fromCommitRef := stringToRef(fromCommit)
- toCommitRef := stringToRef(toCommit)
-
- req := ffi_proto.ChangedFilesReq{
- GitRoot: gitRoot,
- FromCommit: fromCommitRef,
- ToCommit: toCommitRef,
- TurboRoot: turboRoot,
- }
-
- reqBuf := Marshal(&req)
- defer reqBuf.Free()
-
- respBuf := C.changed_files(reqBuf)
-
- resp := ffi_proto.ChangedFilesResp{}
- if err := Unmarshal(respBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- return resp.GetFiles().GetFiles(), nil
-}
-
-// PreviousContent returns the content of a file at a previous commit
-func PreviousContent(gitRoot, fromCommit, filePath string) ([]byte, error) {
- req := ffi_proto.PreviousContentReq{
- GitRoot: gitRoot,
- FromCommit: fromCommit,
- FilePath: filePath,
- }
-
- reqBuf := Marshal(&req)
- defer reqBuf.Free()
-
- respBuf := C.previous_content(reqBuf)
-
- resp := ffi_proto.PreviousContentResp{}
- if err := Unmarshal(respBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
- content := resp.GetContent()
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- return []byte(content), nil
-}
-
-// NpmTransitiveDeps returns the transitive external deps of a given package based on the deps and specifiers given
-func NpmTransitiveDeps(content []byte, pkgDir string, unresolvedDeps map[string]string) ([]*ffi_proto.LockfilePackage, error) {
- return transitiveDeps(npmTransitiveDeps, content, pkgDir, unresolvedDeps)
-}
-
-func npmTransitiveDeps(buf C.Buffer) C.Buffer {
- return C.npm_transitive_closure(buf)
-}
-
-func transitiveDeps(cFunc func(C.Buffer) C.Buffer, content []byte, pkgDir string, unresolvedDeps map[string]string) ([]*ffi_proto.LockfilePackage, error) {
- req := ffi_proto.TransitiveDepsRequest{
- Contents: content,
- WorkspaceDir: pkgDir,
- UnresolvedDeps: unresolvedDeps,
- }
- reqBuf := Marshal(&req)
- resBuf := cFunc(reqBuf)
- reqBuf.Free()
-
- resp := ffi_proto.TransitiveDepsResponse{}
- if err := Unmarshal(resBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
-
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- list := resp.GetPackages()
- return list.GetList(), nil
-}
-
-// NpmSubgraph returns the contents of a npm lockfile subgraph
-func NpmSubgraph(content []byte, workspaces []string, packages []string) ([]byte, error) {
- req := ffi_proto.SubgraphRequest{
- Contents: content,
- Workspaces: workspaces,
- Packages: packages,
- }
- reqBuf := Marshal(&req)
- resBuf := C.npm_subgraph(reqBuf)
- reqBuf.Free()
-
- resp := ffi_proto.SubgraphResponse{}
- if err := Unmarshal(resBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
-
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- return resp.GetContents(), nil
-}
diff --git a/cli/internal/ffi/proto/messages.pb.go b/cli/internal/ffi/proto/messages.pb.go
deleted file mode 100644
index 22992d3..0000000
--- a/cli/internal/ffi/proto/messages.pb.go
+++ /dev/null
@@ -1,1380 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.28.1
-// protoc v3.21.12
-// source: turborepo-ffi/messages.proto
-
-package proto
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type TurboDataDirResp struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Dir string `protobuf:"bytes,1,opt,name=dir,proto3" json:"dir,omitempty"`
-}
-
-func (x *TurboDataDirResp) Reset() {
- *x = TurboDataDirResp{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *TurboDataDirResp) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TurboDataDirResp) ProtoMessage() {}
-
-func (x *TurboDataDirResp) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TurboDataDirResp.ProtoReflect.Descriptor instead.
-func (*TurboDataDirResp) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *TurboDataDirResp) GetDir() string {
- if x != nil {
- return x.Dir
- }
- return ""
-}
-
-type GlobReq struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- BasePath string `protobuf:"bytes,1,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"`
- IncludePatterns []string `protobuf:"bytes,2,rep,name=include_patterns,json=includePatterns,proto3" json:"include_patterns,omitempty"`
- ExcludePatterns []string `protobuf:"bytes,3,rep,name=exclude_patterns,json=excludePatterns,proto3" json:"exclude_patterns,omitempty"`
- FilesOnly bool `protobuf:"varint,4,opt,name=files_only,json=filesOnly,proto3" json:"files_only,omitempty"` // note that the default for a bool is false
-}
-
-func (x *GlobReq) Reset() {
- *x = GlobReq{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *GlobReq) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GlobReq) ProtoMessage() {}
-
-func (x *GlobReq) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GlobReq.ProtoReflect.Descriptor instead.
-func (*GlobReq) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *GlobReq) GetBasePath() string {
- if x != nil {
- return x.BasePath
- }
- return ""
-}
-
-func (x *GlobReq) GetIncludePatterns() []string {
- if x != nil {
- return x.IncludePatterns
- }
- return nil
-}
-
-func (x *GlobReq) GetExcludePatterns() []string {
- if x != nil {
- return x.ExcludePatterns
- }
- return nil
-}
-
-func (x *GlobReq) GetFilesOnly() bool {
- if x != nil {
- return x.FilesOnly
- }
- return false
-}
-
-type GlobResp struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // Types that are assignable to Response:
- // *GlobResp_Files
- // *GlobResp_Error
- Response isGlobResp_Response `protobuf_oneof:"response"`
-}
-
-func (x *GlobResp) Reset() {
- *x = GlobResp{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *GlobResp) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GlobResp) ProtoMessage() {}
-
-func (x *GlobResp) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[2]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GlobResp.ProtoReflect.Descriptor instead.
-func (*GlobResp) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{2}
-}
-
-func (m *GlobResp) GetResponse() isGlobResp_Response {
- if m != nil {
- return m.Response
- }
- return nil
-}
-
-func (x *GlobResp) GetFiles() *GlobRespList {
- if x, ok := x.GetResponse().(*GlobResp_Files); ok {
- return x.Files
- }
- return nil
-}
-
-func (x *GlobResp) GetError() string {
- if x, ok := x.GetResponse().(*GlobResp_Error); ok {
- return x.Error
- }
- return ""
-}
-
-type isGlobResp_Response interface {
- isGlobResp_Response()
-}
-
-type GlobResp_Files struct {
- Files *GlobRespList `protobuf:"bytes,1,opt,name=files,proto3,oneof"`
-}
-
-type GlobResp_Error struct {
- Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"`
-}
-
-func (*GlobResp_Files) isGlobResp_Response() {}
-
-func (*GlobResp_Error) isGlobResp_Response() {}
-
-type GlobRespList struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Files []string `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
-}
-
-func (x *GlobRespList) Reset() {
- *x = GlobRespList{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *GlobRespList) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GlobRespList) ProtoMessage() {}
-
-func (x *GlobRespList) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[3]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GlobRespList.ProtoReflect.Descriptor instead.
-func (*GlobRespList) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *GlobRespList) GetFiles() []string {
- if x != nil {
- return x.Files
- }
- return nil
-}
-
-type ChangedFilesReq struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- GitRoot string `protobuf:"bytes,1,opt,name=git_root,json=gitRoot,proto3" json:"git_root,omitempty"`
- TurboRoot string `protobuf:"bytes,2,opt,name=turbo_root,json=turboRoot,proto3" json:"turbo_root,omitempty"`
- FromCommit *string `protobuf:"bytes,3,opt,name=from_commit,json=fromCommit,proto3,oneof" json:"from_commit,omitempty"`
- ToCommit *string `protobuf:"bytes,4,opt,name=to_commit,json=toCommit,proto3,oneof" json:"to_commit,omitempty"`
-}
-
-func (x *ChangedFilesReq) Reset() {
- *x = ChangedFilesReq{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ChangedFilesReq) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ChangedFilesReq) ProtoMessage() {}
-
-func (x *ChangedFilesReq) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[4]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ChangedFilesReq.ProtoReflect.Descriptor instead.
-func (*ChangedFilesReq) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{4}
-}
-
-func (x *ChangedFilesReq) GetGitRoot() string {
- if x != nil {
- return x.GitRoot
- }
- return ""
-}
-
-func (x *ChangedFilesReq) GetTurboRoot() string {
- if x != nil {
- return x.TurboRoot
- }
- return ""
-}
-
-func (x *ChangedFilesReq) GetFromCommit() string {
- if x != nil && x.FromCommit != nil {
- return *x.FromCommit
- }
- return ""
-}
-
-func (x *ChangedFilesReq) GetToCommit() string {
- if x != nil && x.ToCommit != nil {
- return *x.ToCommit
- }
- return ""
-}
-
-type ChangedFilesResp struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // Types that are assignable to Response:
- // *ChangedFilesResp_Files
- // *ChangedFilesResp_Error
- Response isChangedFilesResp_Response `protobuf_oneof:"response"`
-}
-
-func (x *ChangedFilesResp) Reset() {
- *x = ChangedFilesResp{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ChangedFilesResp) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ChangedFilesResp) ProtoMessage() {}
-
-func (x *ChangedFilesResp) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[5]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ChangedFilesResp.ProtoReflect.Descriptor instead.
-func (*ChangedFilesResp) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{5}
-}
-
-func (m *ChangedFilesResp) GetResponse() isChangedFilesResp_Response {
- if m != nil {
- return m.Response
- }
- return nil
-}
-
-func (x *ChangedFilesResp) GetFiles() *ChangedFilesList {
- if x, ok := x.GetResponse().(*ChangedFilesResp_Files); ok {
- return x.Files
- }
- return nil
-}
-
-func (x *ChangedFilesResp) GetError() string {
- if x, ok := x.GetResponse().(*ChangedFilesResp_Error); ok {
- return x.Error
- }
- return ""
-}
-
-type isChangedFilesResp_Response interface {
- isChangedFilesResp_Response()
-}
-
-type ChangedFilesResp_Files struct {
- Files *ChangedFilesList `protobuf:"bytes,1,opt,name=files,proto3,oneof"`
-}
-
-type ChangedFilesResp_Error struct {
- Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"`
-}
-
-func (*ChangedFilesResp_Files) isChangedFilesResp_Response() {}
-
-func (*ChangedFilesResp_Error) isChangedFilesResp_Response() {}
-
-type ChangedFilesList struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Files []string `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
-}
-
-func (x *ChangedFilesList) Reset() {
- *x = ChangedFilesList{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ChangedFilesList) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ChangedFilesList) ProtoMessage() {}
-
-func (x *ChangedFilesList) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[6]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ChangedFilesList.ProtoReflect.Descriptor instead.
-func (*ChangedFilesList) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{6}
-}
-
-func (x *ChangedFilesList) GetFiles() []string {
- if x != nil {
- return x.Files
- }
- return nil
-}
-
-type PreviousContentReq struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- GitRoot string `protobuf:"bytes,1,opt,name=git_root,json=gitRoot,proto3" json:"git_root,omitempty"`
- FromCommit string `protobuf:"bytes,2,opt,name=from_commit,json=fromCommit,proto3" json:"from_commit,omitempty"`
- FilePath string `protobuf:"bytes,3,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
-}
-
-func (x *PreviousContentReq) Reset() {
- *x = PreviousContentReq{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *PreviousContentReq) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*PreviousContentReq) ProtoMessage() {}
-
-func (x *PreviousContentReq) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[7]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use PreviousContentReq.ProtoReflect.Descriptor instead.
-func (*PreviousContentReq) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{7}
-}
-
-func (x *PreviousContentReq) GetGitRoot() string {
- if x != nil {
- return x.GitRoot
- }
- return ""
-}
-
-func (x *PreviousContentReq) GetFromCommit() string {
- if x != nil {
- return x.FromCommit
- }
- return ""
-}
-
-func (x *PreviousContentReq) GetFilePath() string {
- if x != nil {
- return x.FilePath
- }
- return ""
-}
-
-type PreviousContentResp struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // Types that are assignable to Response:
- // *PreviousContentResp_Content
- // *PreviousContentResp_Error
- Response isPreviousContentResp_Response `protobuf_oneof:"response"`
-}
-
-func (x *PreviousContentResp) Reset() {
- *x = PreviousContentResp{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *PreviousContentResp) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*PreviousContentResp) ProtoMessage() {}
-
-func (x *PreviousContentResp) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[8]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use PreviousContentResp.ProtoReflect.Descriptor instead.
-func (*PreviousContentResp) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{8}
-}
-
-func (m *PreviousContentResp) GetResponse() isPreviousContentResp_Response {
- if m != nil {
- return m.Response
- }
- return nil
-}
-
-func (x *PreviousContentResp) GetContent() []byte {
- if x, ok := x.GetResponse().(*PreviousContentResp_Content); ok {
- return x.Content
- }
- return nil
-}
-
-func (x *PreviousContentResp) GetError() string {
- if x, ok := x.GetResponse().(*PreviousContentResp_Error); ok {
- return x.Error
- }
- return ""
-}
-
-type isPreviousContentResp_Response interface {
- isPreviousContentResp_Response()
-}
-
-type PreviousContentResp_Content struct {
- Content []byte `protobuf:"bytes,1,opt,name=content,proto3,oneof"`
-}
-
-type PreviousContentResp_Error struct {
- Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"`
-}
-
-func (*PreviousContentResp_Content) isPreviousContentResp_Response() {}
-
-func (*PreviousContentResp_Error) isPreviousContentResp_Response() {}
-
-type TransitiveDepsRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"`
- WorkspaceDir string `protobuf:"bytes,2,opt,name=workspace_dir,json=workspaceDir,proto3" json:"workspace_dir,omitempty"`
- UnresolvedDeps map[string]string `protobuf:"bytes,3,rep,name=unresolved_deps,json=unresolvedDeps,proto3" json:"unresolved_deps,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
-}
-
-func (x *TransitiveDepsRequest) Reset() {
- *x = TransitiveDepsRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[9]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *TransitiveDepsRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TransitiveDepsRequest) ProtoMessage() {}
-
-func (x *TransitiveDepsRequest) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[9]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TransitiveDepsRequest.ProtoReflect.Descriptor instead.
-func (*TransitiveDepsRequest) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{9}
-}
-
-func (x *TransitiveDepsRequest) GetContents() []byte {
- if x != nil {
- return x.Contents
- }
- return nil
-}
-
-func (x *TransitiveDepsRequest) GetWorkspaceDir() string {
- if x != nil {
- return x.WorkspaceDir
- }
- return ""
-}
-
-func (x *TransitiveDepsRequest) GetUnresolvedDeps() map[string]string {
- if x != nil {
- return x.UnresolvedDeps
- }
- return nil
-}
-
-type TransitiveDepsResponse struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // Types that are assignable to Response:
- // *TransitiveDepsResponse_Packages
- // *TransitiveDepsResponse_Error
- Response isTransitiveDepsResponse_Response `protobuf_oneof:"response"`
-}
-
-func (x *TransitiveDepsResponse) Reset() {
- *x = TransitiveDepsResponse{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[10]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *TransitiveDepsResponse) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TransitiveDepsResponse) ProtoMessage() {}
-
-func (x *TransitiveDepsResponse) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[10]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TransitiveDepsResponse.ProtoReflect.Descriptor instead.
-func (*TransitiveDepsResponse) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{10}
-}
-
-func (m *TransitiveDepsResponse) GetResponse() isTransitiveDepsResponse_Response {
- if m != nil {
- return m.Response
- }
- return nil
-}
-
-func (x *TransitiveDepsResponse) GetPackages() *LockfilePackageList {
- if x, ok := x.GetResponse().(*TransitiveDepsResponse_Packages); ok {
- return x.Packages
- }
- return nil
-}
-
-func (x *TransitiveDepsResponse) GetError() string {
- if x, ok := x.GetResponse().(*TransitiveDepsResponse_Error); ok {
- return x.Error
- }
- return ""
-}
-
-type isTransitiveDepsResponse_Response interface {
- isTransitiveDepsResponse_Response()
-}
-
-type TransitiveDepsResponse_Packages struct {
- Packages *LockfilePackageList `protobuf:"bytes,1,opt,name=packages,proto3,oneof"`
-}
-
-type TransitiveDepsResponse_Error struct {
- Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"`
-}
-
-func (*TransitiveDepsResponse_Packages) isTransitiveDepsResponse_Response() {}
-
-func (*TransitiveDepsResponse_Error) isTransitiveDepsResponse_Response() {}
-
-type LockfilePackage struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
- Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
- Found bool `protobuf:"varint,3,opt,name=found,proto3" json:"found,omitempty"`
-}
-
-func (x *LockfilePackage) Reset() {
- *x = LockfilePackage{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[11]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *LockfilePackage) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*LockfilePackage) ProtoMessage() {}
-
-func (x *LockfilePackage) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[11]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use LockfilePackage.ProtoReflect.Descriptor instead.
-func (*LockfilePackage) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{11}
-}
-
-func (x *LockfilePackage) GetKey() string {
- if x != nil {
- return x.Key
- }
- return ""
-}
-
-func (x *LockfilePackage) GetVersion() string {
- if x != nil {
- return x.Version
- }
- return ""
-}
-
-func (x *LockfilePackage) GetFound() bool {
- if x != nil {
- return x.Found
- }
- return false
-}
-
-type LockfilePackageList struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- List []*LockfilePackage `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
-}
-
-func (x *LockfilePackageList) Reset() {
- *x = LockfilePackageList{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[12]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *LockfilePackageList) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*LockfilePackageList) ProtoMessage() {}
-
-func (x *LockfilePackageList) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[12]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use LockfilePackageList.ProtoReflect.Descriptor instead.
-func (*LockfilePackageList) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{12}
-}
-
-func (x *LockfilePackageList) GetList() []*LockfilePackage {
- if x != nil {
- return x.List
- }
- return nil
-}
-
-type SubgraphRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"`
- Workspaces []string `protobuf:"bytes,2,rep,name=workspaces,proto3" json:"workspaces,omitempty"`
- Packages []string `protobuf:"bytes,3,rep,name=packages,proto3" json:"packages,omitempty"`
-}
-
-func (x *SubgraphRequest) Reset() {
- *x = SubgraphRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[13]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *SubgraphRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SubgraphRequest) ProtoMessage() {}
-
-func (x *SubgraphRequest) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[13]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SubgraphRequest.ProtoReflect.Descriptor instead.
-func (*SubgraphRequest) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{13}
-}
-
-func (x *SubgraphRequest) GetContents() []byte {
- if x != nil {
- return x.Contents
- }
- return nil
-}
-
-func (x *SubgraphRequest) GetWorkspaces() []string {
- if x != nil {
- return x.Workspaces
- }
- return nil
-}
-
-func (x *SubgraphRequest) GetPackages() []string {
- if x != nil {
- return x.Packages
- }
- return nil
-}
-
-type SubgraphResponse struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // Types that are assignable to Response:
- // *SubgraphResponse_Contents
- // *SubgraphResponse_Error
- Response isSubgraphResponse_Response `protobuf_oneof:"response"`
-}
-
-func (x *SubgraphResponse) Reset() {
- *x = SubgraphResponse{}
- if protoimpl.UnsafeEnabled {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[14]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *SubgraphResponse) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SubgraphResponse) ProtoMessage() {}
-
-func (x *SubgraphResponse) ProtoReflect() protoreflect.Message {
- mi := &file_turborepo_ffi_messages_proto_msgTypes[14]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SubgraphResponse.ProtoReflect.Descriptor instead.
-func (*SubgraphResponse) Descriptor() ([]byte, []int) {
- return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{14}
-}
-
-func (m *SubgraphResponse) GetResponse() isSubgraphResponse_Response {
- if m != nil {
- return m.Response
- }
- return nil
-}
-
-func (x *SubgraphResponse) GetContents() []byte {
- if x, ok := x.GetResponse().(*SubgraphResponse_Contents); ok {
- return x.Contents
- }
- return nil
-}
-
-func (x *SubgraphResponse) GetError() string {
- if x, ok := x.GetResponse().(*SubgraphResponse_Error); ok {
- return x.Error
- }
- return ""
-}
-
-type isSubgraphResponse_Response interface {
- isSubgraphResponse_Response()
-}
-
-type SubgraphResponse_Contents struct {
- Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3,oneof"`
-}
-
-type SubgraphResponse_Error struct {
- Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"`
-}
-
-func (*SubgraphResponse_Contents) isSubgraphResponse_Response() {}
-
-func (*SubgraphResponse_Error) isSubgraphResponse_Response() {}
-
-var File_turborepo_ffi_messages_proto protoreflect.FileDescriptor
-
-var file_turborepo_ffi_messages_proto_rawDesc = []byte{
- 0x0a, 0x1c, 0x74, 0x75, 0x72, 0x62, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2d, 0x66, 0x66, 0x69, 0x2f,
- 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x24,
- 0x0a, 0x10, 0x54, 0x75, 0x72, 0x62, 0x6f, 0x44, 0x61, 0x74, 0x61, 0x44, 0x69, 0x72, 0x52, 0x65,
- 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x03, 0x64, 0x69, 0x72, 0x22, 0x9b, 0x01, 0x0a, 0x07, 0x47, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71,
- 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x29, 0x0a,
- 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e,
- 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
- 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c,
- 0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x61, 0x74, 0x74, 0x65,
- 0x72, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x6f, 0x6e, 0x6c,
- 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4f, 0x6e,
- 0x6c, 0x79, 0x22, 0x55, 0x0a, 0x08, 0x47, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x12, 0x25,
- 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e,
- 0x47, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05,
- 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x0a, 0x0a,
- 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x0a, 0x0c, 0x47, 0x6c, 0x6f,
- 0x62, 0x52, 0x65, 0x73, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x6c,
- 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22,
- 0xb1, 0x01, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73,
- 0x52, 0x65, 0x71, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1d,
- 0x0a, 0x0a, 0x74, 0x75, 0x72, 0x62, 0x6f, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x09, 0x74, 0x75, 0x72, 0x62, 0x6f, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x24, 0x0a,
- 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01,
- 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
- 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x6d,
- 0x69, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63,
- 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6d,
- 0x6d, 0x69, 0x74, 0x22, 0x61, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x46, 0x69,
- 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x29, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
- 0x46, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x66, 0x69, 0x6c,
- 0x65, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
- 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69,
- 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
- 0x22, 0x6d, 0x0a, 0x12, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x43, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x69, 0x74, 0x5f, 0x72, 0x6f,
- 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x69, 0x74, 0x52, 0x6f, 0x6f,
- 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x43, 0x6f, 0x6d, 0x6d,
- 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22,
- 0x55, 0x0a, 0x13, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65,
- 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
- 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
- 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xf0, 0x01, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73,
- 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d,
- 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x69,
- 0x72, 0x12, 0x53, 0x0a, 0x0f, 0x75, 0x6e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x5f,
- 0x64, 0x65, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x54, 0x72, 0x61,
- 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x44, 0x65, 0x70,
- 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x75, 0x6e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76,
- 0x65, 0x64, 0x44, 0x65, 0x70, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x55, 0x6e, 0x72, 0x65, 0x73, 0x6f,
- 0x6c, 0x76, 0x65, 0x64, 0x44, 0x65, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
- 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
- 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x70, 0x0a, 0x16, 0x54, 0x72, 0x61,
- 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65,
- 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x08, 0x70,
- 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42,
- 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, 0x0f, 0x4c,
- 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x10,
- 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
- 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f,
- 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x75, 0x6e, 0x64,
- 0x22, 0x3b, 0x0a, 0x13, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b,
- 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18,
- 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65,
- 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x69, 0x0a,
- 0x0f, 0x53, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a,
- 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08,
- 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
- 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x22, 0x54, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x67,
- 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x08,
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
- 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72,
- 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72,
- 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0b,
- 0x5a, 0x09, 0x66, 0x66, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x33,
-}
-
-var (
- file_turborepo_ffi_messages_proto_rawDescOnce sync.Once
- file_turborepo_ffi_messages_proto_rawDescData = file_turborepo_ffi_messages_proto_rawDesc
-)
-
-func file_turborepo_ffi_messages_proto_rawDescGZIP() []byte {
- file_turborepo_ffi_messages_proto_rawDescOnce.Do(func() {
- file_turborepo_ffi_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_turborepo_ffi_messages_proto_rawDescData)
- })
- return file_turborepo_ffi_messages_proto_rawDescData
-}
-
-var file_turborepo_ffi_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
-var file_turborepo_ffi_messages_proto_goTypes = []interface{}{
- (*TurboDataDirResp)(nil), // 0: TurboDataDirResp
- (*GlobReq)(nil), // 1: GlobReq
- (*GlobResp)(nil), // 2: GlobResp
- (*GlobRespList)(nil), // 3: GlobRespList
- (*ChangedFilesReq)(nil), // 4: ChangedFilesReq
- (*ChangedFilesResp)(nil), // 5: ChangedFilesResp
- (*ChangedFilesList)(nil), // 6: ChangedFilesList
- (*PreviousContentReq)(nil), // 7: PreviousContentReq
- (*PreviousContentResp)(nil), // 8: PreviousContentResp
- (*TransitiveDepsRequest)(nil), // 9: TransitiveDepsRequest
- (*TransitiveDepsResponse)(nil), // 10: TransitiveDepsResponse
- (*LockfilePackage)(nil), // 11: LockfilePackage
- (*LockfilePackageList)(nil), // 12: LockfilePackageList
- (*SubgraphRequest)(nil), // 13: SubgraphRequest
- (*SubgraphResponse)(nil), // 14: SubgraphResponse
- nil, // 15: TransitiveDepsRequest.UnresolvedDepsEntry
-}
-var file_turborepo_ffi_messages_proto_depIdxs = []int32{
- 3, // 0: GlobResp.files:type_name -> GlobRespList
- 6, // 1: ChangedFilesResp.files:type_name -> ChangedFilesList
- 15, // 2: TransitiveDepsRequest.unresolved_deps:type_name -> TransitiveDepsRequest.UnresolvedDepsEntry
- 12, // 3: TransitiveDepsResponse.packages:type_name -> LockfilePackageList
- 11, // 4: LockfilePackageList.list:type_name -> LockfilePackage
- 5, // [5:5] is the sub-list for method output_type
- 5, // [5:5] is the sub-list for method input_type
- 5, // [5:5] is the sub-list for extension type_name
- 5, // [5:5] is the sub-list for extension extendee
- 0, // [0:5] is the sub-list for field type_name
-}
-
-func init() { file_turborepo_ffi_messages_proto_init() }
-func file_turborepo_ffi_messages_proto_init() {
- if File_turborepo_ffi_messages_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_turborepo_ffi_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*TurboDataDirResp); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*GlobReq); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*GlobResp); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*GlobRespList); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ChangedFilesReq); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ChangedFilesResp); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ChangedFilesList); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PreviousContentReq); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*PreviousContentResp); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*TransitiveDepsRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*TransitiveDepsResponse); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*LockfilePackage); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*LockfilePackageList); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SubgraphRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*SubgraphResponse); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- file_turborepo_ffi_messages_proto_msgTypes[2].OneofWrappers = []interface{}{
- (*GlobResp_Files)(nil),
- (*GlobResp_Error)(nil),
- }
- file_turborepo_ffi_messages_proto_msgTypes[4].OneofWrappers = []interface{}{}
- file_turborepo_ffi_messages_proto_msgTypes[5].OneofWrappers = []interface{}{
- (*ChangedFilesResp_Files)(nil),
- (*ChangedFilesResp_Error)(nil),
- }
- file_turborepo_ffi_messages_proto_msgTypes[8].OneofWrappers = []interface{}{
- (*PreviousContentResp_Content)(nil),
- (*PreviousContentResp_Error)(nil),
- }
- file_turborepo_ffi_messages_proto_msgTypes[10].OneofWrappers = []interface{}{
- (*TransitiveDepsResponse_Packages)(nil),
- (*TransitiveDepsResponse_Error)(nil),
- }
- file_turborepo_ffi_messages_proto_msgTypes[14].OneofWrappers = []interface{}{
- (*SubgraphResponse_Contents)(nil),
- (*SubgraphResponse_Error)(nil),
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_turborepo_ffi_messages_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 16,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_turborepo_ffi_messages_proto_goTypes,
- DependencyIndexes: file_turborepo_ffi_messages_proto_depIdxs,
- MessageInfos: file_turborepo_ffi_messages_proto_msgTypes,
- }.Build()
- File_turborepo_ffi_messages_proto = out.File
- file_turborepo_ffi_messages_proto_rawDesc = nil
- file_turborepo_ffi_messages_proto_goTypes = nil
- file_turborepo_ffi_messages_proto_depIdxs = nil
-}
diff --git a/cli/internal/filewatcher/backend.go b/cli/internal/filewatcher/backend.go
deleted file mode 100644
index b8b7fa8..0000000
--- a/cli/internal/filewatcher/backend.go
+++ /dev/null
@@ -1,209 +0,0 @@
-//go:build !darwin
-// +build !darwin
-
-package filewatcher
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "sync"
-
- "github.com/fsnotify/fsnotify"
- "github.com/hashicorp/go-hclog"
- "github.com/karrick/godirwalk"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// watchAddMode is used to indicate whether watchRecursively should synthesize events
-// for existing files.
-type watchAddMode int
-
-const (
- dontSynthesizeEvents watchAddMode = iota
- synthesizeEvents
-)
-
-type fsNotifyBackend struct {
- watcher *fsnotify.Watcher
- events chan Event
- errors chan error
- logger hclog.Logger
-
- mu sync.Mutex
- allExcludes []string
- closed bool
-}
-
-func (f *fsNotifyBackend) Events() <-chan Event {
- return f.events
-}
-
-func (f *fsNotifyBackend) Errors() <-chan error {
- return f.errors
-}
-
-func (f *fsNotifyBackend) Close() error {
- f.mu.Lock()
- defer f.mu.Unlock()
- if f.closed {
- return ErrFilewatchingClosed
- }
- f.closed = true
- close(f.events)
- close(f.errors)
- if err := f.watcher.Close(); err != nil {
- return err
- }
- return nil
-}
-
-// onFileAdded helps up paper over cross-platform inconsistencies in fsnotify.
-// Some fsnotify backends automatically add the contents of directories. Some do
-// not. Adding a watch is idempotent, so anytime any file we care about gets added,
-// watch it.
-func (f *fsNotifyBackend) onFileAdded(name turbopath.AbsoluteSystemPath) error {
- info, err := name.Lstat()
- if err != nil {
- if errors.Is(err, os.ErrNotExist) {
- // We can race with a file being added and removed. Ignore it
- return nil
- }
- return errors.Wrapf(err, "error checking lstat of new file %v", name)
- }
- if info.IsDir() {
- // If a directory has been added, we need to synthesize events for everything it contains
- if err := f.watchRecursively(name, []string{}, synthesizeEvents); err != nil {
- return errors.Wrapf(err, "failed recursive watch of %v", name)
- }
- } else {
- if err := f.watcher.Add(name.ToString()); err != nil {
- return errors.Wrapf(err, "failed adding watch to %v", name)
- }
- }
- return nil
-}
-
-func (f *fsNotifyBackend) watchRecursively(root turbopath.AbsoluteSystemPath, excludePatterns []string, addMode watchAddMode) error {
- f.mu.Lock()
- defer f.mu.Unlock()
- err := fs.WalkMode(root.ToString(), func(name string, isDir bool, info os.FileMode) error {
- for _, excludePattern := range excludePatterns {
- excluded, err := doublestar.Match(excludePattern, filepath.ToSlash(name))
- if err != nil {
- return err
- }
- if excluded {
- return godirwalk.SkipThis
- }
- }
- if info.IsDir() && (info&os.ModeSymlink == 0) {
- if err := f.watcher.Add(name); err != nil {
- return errors.Wrapf(err, "failed adding watch to %v", name)
- }
- f.logger.Debug(fmt.Sprintf("watching directory %v", name))
- }
- if addMode == synthesizeEvents {
- f.events <- Event{
- Path: fs.AbsoluteSystemPathFromUpstream(name),
- EventType: FileAdded,
- }
- }
- return nil
- })
- if err != nil {
- return err
- }
- f.allExcludes = append(f.allExcludes, excludePatterns...)
-
- return nil
-}
-
-func (f *fsNotifyBackend) watch() {
-outer:
- for {
- select {
- case ev, ok := <-f.watcher.Events:
- if !ok {
- break outer
- }
- eventType := toFileEvent(ev.Op)
- path := fs.AbsoluteSystemPathFromUpstream(ev.Name)
- if eventType == FileAdded {
- if err := f.onFileAdded(path); err != nil {
- f.errors <- err
- }
- }
- f.events <- Event{
- Path: path,
- EventType: eventType,
- }
- case err, ok := <-f.watcher.Errors:
- if !ok {
- break outer
- }
- f.errors <- err
- }
- }
-}
-
-var _modifiedMask = fsnotify.Chmod | fsnotify.Write
-
-func toFileEvent(op fsnotify.Op) FileEvent {
- if op&fsnotify.Create != 0 {
- return FileAdded
- } else if op&fsnotify.Remove != 0 {
- return FileDeleted
- } else if op&_modifiedMask != 0 {
- return FileModified
- } else if op&fsnotify.Rename != 0 {
- return FileRenamed
- }
- return FileOther
-}
-
-func (f *fsNotifyBackend) Start() error {
- f.mu.Lock()
- defer f.mu.Unlock()
- if f.closed {
- return ErrFilewatchingClosed
- }
- for _, dir := range f.watcher.WatchList() {
- for _, excludePattern := range f.allExcludes {
- excluded, err := doublestar.Match(excludePattern, filepath.ToSlash(dir))
- if err != nil {
- return err
- }
- if excluded {
- if err := f.watcher.Remove(dir); err != nil {
- return err
- }
- }
- }
- }
- go f.watch()
- return nil
-}
-
-func (f *fsNotifyBackend) AddRoot(root turbopath.AbsoluteSystemPath, excludePatterns ...string) error {
- // We don't synthesize events for the initial watch
- return f.watchRecursively(root, excludePatterns, dontSynthesizeEvents)
-}
-
-// GetPlatformSpecificBackend returns a filewatching backend appropriate for the OS we are
-// running on.
-func GetPlatformSpecificBackend(logger hclog.Logger) (Backend, error) {
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- return nil, err
- }
- return &fsNotifyBackend{
- watcher: watcher,
- events: make(chan Event),
- errors: make(chan error),
- logger: logger.Named("fsnotify"),
- }, nil
-}
diff --git a/cli/internal/filewatcher/backend_darwin.go b/cli/internal/filewatcher/backend_darwin.go
deleted file mode 100644
index 4c029c4..0000000
--- a/cli/internal/filewatcher/backend_darwin.go
+++ /dev/null
@@ -1,220 +0,0 @@
-//go:build darwin
-// +build darwin
-
-package filewatcher
-
-import (
- "fmt"
- "strings"
- "sync"
- "time"
-
- "github.com/pkg/errors"
- "github.com/yookoala/realpath"
-
- "github.com/fsnotify/fsevents"
- "github.com/hashicorp/go-hclog"
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-type fseventsBackend struct {
- events chan Event
- errors chan error
- logger hclog.Logger
- mu sync.Mutex
- streams []*fsevents.EventStream
- closed bool
-}
-
-func (f *fseventsBackend) Events() <-chan Event {
- return f.events
-}
-
-func (f *fseventsBackend) Errors() <-chan error {
- return f.errors
-}
-
-func (f *fseventsBackend) Close() error {
- f.mu.Lock()
- defer f.mu.Unlock()
- if f.closed {
- return ErrFilewatchingClosed
- }
- f.closed = true
- for _, stream := range f.streams {
- stream.Stop()
- }
- close(f.events)
- close(f.errors)
- return nil
-}
-
-func (f *fseventsBackend) Start() error {
- return nil
-}
-
-var (
- _eventLatency = 10 * time.Millisecond
- _cookieTimeout = 500 * time.Millisecond
-)
-
-// AddRoot starts watching a new directory hierarchy. Events matching the provided excludePatterns
-// will not be forwarded.
-func (f *fseventsBackend) AddRoot(someRoot turbopath.AbsoluteSystemPath, excludePatterns ...string) error {
- // We need to resolve the real path to the hierarchy that we are going to watch
- realRoot, err := realpath.Realpath(someRoot.ToString())
- if err != nil {
- return err
- }
- root := fs.AbsoluteSystemPathFromUpstream(realRoot)
- dev, err := fsevents.DeviceForPath(root.ToString())
- if err != nil {
- return err
- }
-
- // Optimistically set up and start a stream, assuming the watch is still valid.
- s := &fsevents.EventStream{
- Paths: []string{root.ToString()},
- Latency: _eventLatency,
- Device: dev,
- Flags: fsevents.FileEvents | fsevents.WatchRoot,
- }
- s.Start()
- events := s.Events
-
- // fsevents delivers events for all existing files first, so use a cookie to detect when we're ready for new events
- if err := waitForCookie(root, events, _cookieTimeout); err != nil {
- s.Stop()
- return err
- }
-
- // Now try to persist the stream.
- f.mu.Lock()
- defer f.mu.Unlock()
- if f.closed {
- s.Stop()
- return ErrFilewatchingClosed
- }
- f.streams = append(f.streams, s)
- f.logger.Debug(fmt.Sprintf("watching root %v, excluding %v", root, excludePatterns))
-
- go func() {
- for evs := range events {
- for _, ev := range evs {
- isExcluded := false
-
- // 1. Ensure that we have a `/`-prefixed path from the event.
- var eventPath string
- if !strings.HasPrefix("/", ev.Path) {
- eventPath = "/" + ev.Path
- } else {
- eventPath = ev.Path
- }
-
- // 2. We're getting events from the real path, but we need to translate
- // back to the path we were provided since that's what the caller will
- // expect in terms of event paths.
- watchRootRelativePath := eventPath[len(realRoot):]
- processedEventPath := someRoot.UntypedJoin(watchRootRelativePath)
-
- // 3. Compare the event to all exclude patterns, short-circuit if we know
- // we are not watching this file.
- processedPathString := processedEventPath.ToString() // loop invariant
- for _, pattern := range excludePatterns {
- matches, err := doublestar.Match(pattern, processedPathString)
- if err != nil {
- f.errors <- err
- } else if matches {
- isExcluded = true
- break
- }
- }
-
- // 4. Report the file events we care about.
- if !isExcluded {
- f.events <- Event{
- Path: processedEventPath,
- EventType: toFileEvent(ev.Flags),
- }
- }
- }
- }
- }()
-
- return nil
-}
-
-func waitForCookie(root turbopath.AbsoluteSystemPath, events <-chan []fsevents.Event, timeout time.Duration) error {
- // This cookie needs to be in a location that we're watching, and at this point we can't guarantee
- // what the root is, or if something like "node_modules/.cache/turbo" would make sense. As a compromise, ensure
- // that we clean it up even in the event of a failure.
- cookiePath := root.UntypedJoin(".turbo-cookie")
- if err := cookiePath.WriteFile([]byte("cookie"), 0755); err != nil {
- return err
- }
- expected := cookiePath.ToString()[1:] // trim leading slash
- if err := waitForEvent(events, expected, fsevents.ItemCreated, timeout); err != nil {
- // Attempt to not leave the cookie file lying around.
- // Ignore the error, since there's not much we can do with it.
- _ = cookiePath.Remove()
- return err
- }
- if err := cookiePath.Remove(); err != nil {
- return err
- }
- if err := waitForEvent(events, expected, fsevents.ItemRemoved, timeout); err != nil {
- return err
- }
- return nil
-}
-
-func waitForEvent(events <-chan []fsevents.Event, path string, flag fsevents.EventFlags, timeout time.Duration) error {
- ch := make(chan struct{})
- go func() {
- for evs := range events {
- for _, ev := range evs {
- if ev.Path == path && ev.Flags&flag != 0 {
- close(ch)
- return
- }
- }
- }
- }()
- select {
- case <-time.After(timeout):
- return errors.Wrap(ErrFailedToStart, "timed out waiting for initial fsevents cookie")
- case <-ch:
- return nil
- }
-}
-
-var _modifiedMask = fsevents.ItemModified | fsevents.ItemInodeMetaMod | fsevents.ItemFinderInfoMod | fsevents.ItemChangeOwner | fsevents.ItemXattrMod
-
-func toFileEvent(flags fsevents.EventFlags) FileEvent {
- if flags&fsevents.ItemCreated != 0 {
- return FileAdded
- } else if flags&fsevents.ItemRemoved != 0 {
- return FileDeleted
- } else if flags&_modifiedMask != 0 {
- return FileModified
- } else if flags&fsevents.ItemRenamed != 0 {
- return FileRenamed
- } else if flags&fsevents.RootChanged != 0 {
- // count this as a delete, something affected the path to the root
- // of the stream
- return FileDeleted
- }
- return FileOther
-}
-
-// GetPlatformSpecificBackend returns a filewatching backend appropriate for the OS we are
-// running on.
-func GetPlatformSpecificBackend(logger hclog.Logger) (Backend, error) {
- return &fseventsBackend{
- events: make(chan Event),
- errors: make(chan error),
- logger: logger.Named("fsevents"),
- }, nil
-}
diff --git a/cli/internal/filewatcher/cookie.go b/cli/internal/filewatcher/cookie.go
deleted file mode 100644
index 7a4931e..0000000
--- a/cli/internal/filewatcher/cookie.go
+++ /dev/null
@@ -1,160 +0,0 @@
-package filewatcher
-
-import (
- "fmt"
- "os"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// CookieWaiter is the interface used by clients that need to wait
-// for a roundtrip through the filewatching API.
-type CookieWaiter interface {
- WaitForCookie() error
-}
-
-var (
- // ErrCookieTimeout is returned when we did not see our cookie file within the given time constraints
- ErrCookieTimeout = errors.New("timed out waiting for cookie")
- // ErrCookieWatchingClosed is returned when the underlying filewatching has been closed.
- ErrCookieWatchingClosed = errors.New("filewatching has closed, cannot watch cookies")
-)
-
-// CookieJar is used for tracking roundtrips through the filesystem watching API
-type CookieJar struct {
- timeout time.Duration
- dir turbopath.AbsoluteSystemPath
- serial uint64
- mu sync.Mutex
- cookies map[turbopath.AbsoluteSystemPath]chan error
- closed bool
-}
-
-// NewCookieJar returns a new instance of a CookieJar. There should only ever be a single
-// instance live per cookieDir, since they expect to have full control over that directory.
-func NewCookieJar(cookieDir turbopath.AbsoluteSystemPath, timeout time.Duration) (*CookieJar, error) {
- if err := cookieDir.RemoveAll(); err != nil {
- return nil, err
- }
- if err := cookieDir.MkdirAll(0775); err != nil {
- return nil, err
- }
- return &CookieJar{
- timeout: timeout,
- dir: cookieDir,
- cookies: make(map[turbopath.AbsoluteSystemPath]chan error),
- }, nil
-}
-
-// removeAllCookiesWithError sends the error to every channel, closes every channel,
-// and attempts to remove every cookie file. Must be called while the cj.mu is held.
-// If the cookie jar is going to be reused afterwards, the cookies map must be reinitialized.
-func (cj *CookieJar) removeAllCookiesWithError(err error) {
- for p, ch := range cj.cookies {
- _ = p.Remove()
- ch <- err
- close(ch)
- }
- // Drop all of the references so they can be cleaned up
- cj.cookies = nil
-}
-
-// OnFileWatchClosed handles the case where filewatching had to close for some reason
-// We send an error to all of our cookies and stop accepting new ones.
-func (cj *CookieJar) OnFileWatchClosed() {
- cj.mu.Lock()
- defer cj.mu.Unlock()
- cj.closed = true
- cj.removeAllCookiesWithError(ErrCookieWatchingClosed)
-
-}
-
-// OnFileWatchError handles when filewatching has encountered an error.
-// In the error case, we remove all cookies and send them errors. We remain
-// available for later cookies.
-func (cj *CookieJar) OnFileWatchError(err error) {
- // We are now in an inconsistent state. Drop all of our cookies,
- // but we still allow new ones to be created
- cj.mu.Lock()
- defer cj.mu.Unlock()
- cj.removeAllCookiesWithError(err)
- cj.cookies = make(map[turbopath.AbsoluteSystemPath]chan error)
-}
-
-// OnFileWatchEvent determines if the specified event is relevant
-// for cookie watching and notifies the appropriate cookie if so.
-func (cj *CookieJar) OnFileWatchEvent(ev Event) {
- if ev.EventType == FileAdded {
- isCookie, err := fs.DirContainsPath(cj.dir.ToStringDuringMigration(), ev.Path.ToStringDuringMigration())
- if err != nil {
- cj.OnFileWatchError(errors.Wrapf(err, "failed to determine if path is a cookie: %v", ev.Path))
- } else if isCookie {
- cj.notifyCookie(ev.Path, nil)
- }
- }
-}
-
-// WaitForCookie touches a unique file, then waits for it to show up in filesystem notifications.
-// This provides a theoretical bound on filesystem operations, although it's possible
-// that underlying filewatch mechanisms don't respect this ordering.
-func (cj *CookieJar) WaitForCookie() error {
- // we're only ever going to send a single error on the channel, add a buffer so that we never
- // block sending it.
- ch := make(chan error, 1)
- serial := atomic.AddUint64(&cj.serial, 1)
- cookiePath := cj.dir.UntypedJoin(fmt.Sprintf("%v.cookie", serial))
- cj.mu.Lock()
- if cj.closed {
- cj.mu.Unlock()
- return ErrCookieWatchingClosed
- }
- cj.cookies[cookiePath] = ch
- cj.mu.Unlock()
- if err := touchCookieFile(cookiePath); err != nil {
- cj.notifyCookie(cookiePath, err)
- return err
- }
- select {
- case <-time.After(cj.timeout):
- return ErrCookieTimeout
- case err, ok := <-ch:
- if !ok {
- // the channel closed without an error, we're all set
- return nil
- }
- // the channel didn't close, meaning we got some error.
- // We don't need to wait on channel close, it's going to be closed
- // immediately by whoever sent the error. Return the error directly
- return err
- }
-}
-
-func (cj *CookieJar) notifyCookie(cookie turbopath.AbsoluteSystemPath, err error) {
- cj.mu.Lock()
- ch, ok := cj.cookies[cookie]
- // delete is a no-op if the key doesn't exist
- delete(cj.cookies, cookie)
- cj.mu.Unlock()
- if ok {
- if err != nil {
- ch <- err
- }
- close(ch)
- }
-}
-
-func touchCookieFile(cookie turbopath.AbsoluteSystemPath) error {
- f, err := cookie.OpenFile(os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0700)
- if err != nil {
- return err
- }
- if err := f.Close(); err != nil {
- return err
- }
- return nil
-}
diff --git a/cli/internal/filewatcher/cookie_test.go b/cli/internal/filewatcher/cookie_test.go
deleted file mode 100644
index 96241b4..0000000
--- a/cli/internal/filewatcher/cookie_test.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package filewatcher
-
-import (
- "testing"
- "time"
-
- "github.com/hashicorp/go-hclog"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/fs"
- "gotest.tools/v3/assert"
-)
-
-func TestWaitForCookie(t *testing.T) {
- logger := hclog.Default()
- cookieDir := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- jar, err := NewCookieJar(cookieDir, 5*time.Second)
- assert.NilError(t, err, "NewCookieJar")
-
- watcher, err := GetPlatformSpecificBackend(logger)
- assert.NilError(t, err, "NewWatcher")
- fw := New(logger, repoRoot, watcher)
- err = fw.Start()
- assert.NilError(t, err, "Start")
- fw.AddClient(jar)
- err = fw.AddRoot(cookieDir)
- assert.NilError(t, err, "Add")
-
- err = jar.WaitForCookie()
- assert.NilError(t, err, "failed to roundtrip cookie")
-}
-
-func TestWaitForCookieAfterClose(t *testing.T) {
- logger := hclog.Default()
- cookieDir := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- jar, err := NewCookieJar(cookieDir, 5*time.Second)
- assert.NilError(t, err, "NewCookieJar")
-
- watcher, err := GetPlatformSpecificBackend(logger)
- assert.NilError(t, err, "NewWatcher")
- fw := New(logger, repoRoot, watcher)
- err = fw.Start()
- assert.NilError(t, err, "Start")
- fw.AddClient(jar)
- err = fw.AddRoot(cookieDir)
- assert.NilError(t, err, "Add")
-
- err = fw.Close()
- assert.NilError(t, err, "Close")
- err = jar.WaitForCookie()
- assert.ErrorIs(t, err, ErrCookieWatchingClosed)
-}
-
-func TestWaitForCookieTimeout(t *testing.T) {
- logger := hclog.Default()
- cookieDir := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- jar, err := NewCookieJar(cookieDir, 10*time.Millisecond)
- assert.NilError(t, err, "NewCookieJar")
-
- watcher, err := GetPlatformSpecificBackend(logger)
- assert.NilError(t, err, "NewWatcher")
- fw := New(logger, repoRoot, watcher)
- err = fw.Start()
- assert.NilError(t, err, "Start")
- fw.AddClient(jar)
-
- // NOTE: don't call fw.Add here so that no file event gets delivered
-
- err = jar.WaitForCookie()
- assert.ErrorIs(t, err, ErrCookieTimeout)
-}
-
-func TestWaitForCookieWithError(t *testing.T) {
- logger := hclog.Default()
- cookieDir := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- jar, err := NewCookieJar(cookieDir, 10*time.Second)
- assert.NilError(t, err, "NewCookieJar")
-
- watcher, err := GetPlatformSpecificBackend(logger)
- assert.NilError(t, err, "NewWatcher")
- fw := New(logger, repoRoot, watcher)
- err = fw.Start()
- assert.NilError(t, err, "Start")
- fw.AddClient(jar)
-
- // NOTE: don't call fw.Add here so that no file event gets delivered
- myErr := errors.New("an error")
- ch := make(chan error)
- go func() {
- if err := jar.WaitForCookie(); err != nil {
- ch <- err
- }
- close(ch)
- }()
- // wait for the cookie to be registered in the jar
- for {
- found := false
- jar.mu.Lock()
- if len(jar.cookies) == 1 {
- found = true
- }
- jar.mu.Unlock()
- if found {
- break
- }
- <-time.After(10 * time.Millisecond)
- }
- jar.OnFileWatchError(myErr)
-
- err, ok := <-ch
- if !ok {
- t.Error("expected to get an error from cookie watching")
- }
- assert.ErrorIs(t, err, myErr)
-
- // ensure waiting for a new cookie still works.
- // Add the filewatch to allow cookies work normally
- err = fw.AddRoot(cookieDir)
- assert.NilError(t, err, "Add")
-
- err = jar.WaitForCookie()
- assert.NilError(t, err, "WaitForCookie")
-}
diff --git a/cli/internal/filewatcher/filewatcher.go b/cli/internal/filewatcher/filewatcher.go
deleted file mode 100644
index 4f79495..0000000
--- a/cli/internal/filewatcher/filewatcher.go
+++ /dev/null
@@ -1,167 +0,0 @@
-// Package filewatcher is used to handle watching for file changes inside the monorepo
-package filewatcher
-
-import (
- "path/filepath"
- "strings"
- "sync"
-
- "github.com/hashicorp/go-hclog"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// _ignores is the set of paths we exempt from file-watching
-var _ignores = []string{".git", "node_modules"}
-
-// FileWatchClient defines the callbacks used by the file watching loop.
-// All methods are called from the same goroutine so they:
-// 1) do not need synchronization
-// 2) should minimize the work they are doing when called, if possible
-type FileWatchClient interface {
- OnFileWatchEvent(ev Event)
- OnFileWatchError(err error)
- OnFileWatchClosed()
-}
-
-// FileEvent is an enum covering the kinds of things that can happen
-// to files that we might be interested in
-type FileEvent int
-
-const (
- // FileAdded - this is a new file
- FileAdded FileEvent = iota + 1
- // FileDeleted - this file has been removed
- FileDeleted
- // FileModified - this file has been changed in some way
- FileModified
- // FileRenamed - a file's name has changed
- FileRenamed
- // FileOther - some other backend-specific event has happened
- FileOther
-)
-
-var (
- // ErrFilewatchingClosed is returned when filewatching has been closed
- ErrFilewatchingClosed = errors.New("Close() has already been called for filewatching")
- // ErrFailedToStart is returned when filewatching fails to start up
- ErrFailedToStart = errors.New("filewatching failed to start")
-)
-
-// Event is the backend-independent information about a file change
-type Event struct {
- Path turbopath.AbsoluteSystemPath
- EventType FileEvent
-}
-
-// Backend is the interface that describes what an underlying filesystem watching backend
-// must provide.
-type Backend interface {
- AddRoot(root turbopath.AbsoluteSystemPath, excludePatterns ...string) error
- Events() <-chan Event
- Errors() <-chan error
- Close() error
- Start() error
-}
-
-// FileWatcher handles watching all of the files in the monorepo.
-// We currently ignore .git and top-level node_modules. We can revisit
-// if necessary.
-type FileWatcher struct {
- backend Backend
-
- logger hclog.Logger
- repoRoot turbopath.AbsoluteSystemPath
- excludePattern string
-
- clientsMu sync.RWMutex
- clients []FileWatchClient
- closed bool
-}
-
-// New returns a new FileWatcher instance
-func New(logger hclog.Logger, repoRoot turbopath.AbsoluteSystemPath, backend Backend) *FileWatcher {
- excludes := make([]string, len(_ignores))
- for i, ignore := range _ignores {
- excludes[i] = filepath.ToSlash(repoRoot.UntypedJoin(ignore).ToString() + "/**")
- }
- excludePattern := "{" + strings.Join(excludes, ",") + "}"
- return &FileWatcher{
- backend: backend,
- logger: logger,
- repoRoot: repoRoot,
- excludePattern: excludePattern,
- }
-}
-
-// Close shuts down filewatching
-func (fw *FileWatcher) Close() error {
- return fw.backend.Close()
-}
-
-// Start recursively adds all directories from the repo root, redacts the excluded ones,
-// then fires off a goroutine to respond to filesystem events
-func (fw *FileWatcher) Start() error {
- if err := fw.backend.AddRoot(fw.repoRoot, fw.excludePattern); err != nil {
- return err
- }
- if err := fw.backend.Start(); err != nil {
- return err
- }
- go fw.watch()
- return nil
-}
-
-// AddRoot registers the root a filesystem hierarchy to be watched for changes. Events are *not*
-// fired for existing files when AddRoot is called, only for subsequent changes.
-// NOTE: if it appears helpful, we could change this behavior so that we provide a stream of initial
-// events.
-func (fw *FileWatcher) AddRoot(root turbopath.AbsoluteSystemPath, excludePatterns ...string) error {
- return fw.backend.AddRoot(root, excludePatterns...)
-}
-
-// watch is the main file-watching loop. Watching is not recursive,
-// so when new directories are added, they are manually recursively watched.
-func (fw *FileWatcher) watch() {
-outer:
- for {
- select {
- case ev, ok := <-fw.backend.Events():
- if !ok {
- fw.logger.Info("Events channel closed. Exiting watch loop")
- break outer
- }
- fw.clientsMu.RLock()
- for _, client := range fw.clients {
- client.OnFileWatchEvent(ev)
- }
- fw.clientsMu.RUnlock()
- case err, ok := <-fw.backend.Errors():
- if !ok {
- fw.logger.Info("Errors channel closed. Exiting watch loop")
- break outer
- }
- fw.clientsMu.RLock()
- for _, client := range fw.clients {
- client.OnFileWatchError(err)
- }
- fw.clientsMu.RUnlock()
- }
- }
- fw.clientsMu.Lock()
- fw.closed = true
- for _, client := range fw.clients {
- client.OnFileWatchClosed()
- }
- fw.clientsMu.Unlock()
-}
-
-// AddClient registers a client for filesystem events
-func (fw *FileWatcher) AddClient(client FileWatchClient) {
- fw.clientsMu.Lock()
- defer fw.clientsMu.Unlock()
- fw.clients = append(fw.clients, client)
- if fw.closed {
- client.OnFileWatchClosed()
- }
-}
diff --git a/cli/internal/filewatcher/filewatcher_test.go b/cli/internal/filewatcher/filewatcher_test.go
deleted file mode 100644
index 72b48ba..0000000
--- a/cli/internal/filewatcher/filewatcher_test.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package filewatcher
-
-import (
- "fmt"
- "sync"
- "testing"
- "time"
-
- "github.com/hashicorp/go-hclog"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-type testClient struct {
- mu sync.Mutex
- createEvents []Event
- notify chan Event
-}
-
-func (c *testClient) OnFileWatchEvent(ev Event) {
- if ev.EventType == FileAdded {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.createEvents = append(c.createEvents, ev)
- c.notify <- ev
- }
-}
-
-func (c *testClient) OnFileWatchError(err error) {}
-
-func (c *testClient) OnFileWatchClosed() {}
-
-func expectFilesystemEvent(t *testing.T, ch <-chan Event, expected Event) {
- // mark this method as a helper
- t.Helper()
- timeout := time.After(1 * time.Second)
- for {
- select {
- case ev := <-ch:
- t.Logf("got event %v", ev)
- if ev.Path == expected.Path && ev.EventType == expected.EventType {
- return
- }
- case <-timeout:
- t.Errorf("Timed out waiting for filesystem event at %v", expected.Path)
- return
- }
- }
-}
-
-func expectNoFilesystemEvent(t *testing.T, ch <-chan Event) {
- // mark this method as a helper
- t.Helper()
- select {
- case ev, ok := <-ch:
- if ok {
- t.Errorf("got unexpected filesystem event %v", ev)
- } else {
- t.Error("filewatching closed unexpectedly")
- }
- case <-time.After(500 * time.Millisecond):
- return
- }
-}
-
-func expectWatching(t *testing.T, c *testClient, dirs []turbopath.AbsoluteSystemPath) {
- t.Helper()
- now := time.Now()
- filename := fmt.Sprintf("test-%v", now.UnixMilli())
- for _, dir := range dirs {
- file := dir.UntypedJoin(filename)
- err := file.WriteFile([]byte("hello"), 0755)
- assert.NilError(t, err, "WriteFile")
- expectFilesystemEvent(t, c.notify, Event{
- Path: file,
- EventType: FileAdded,
- })
- }
-}
-
-func TestFileWatching(t *testing.T) {
- logger := hclog.Default()
- logger.SetLevel(hclog.Debug)
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- err := repoRoot.UntypedJoin(".git").MkdirAll(0775)
- assert.NilError(t, err, "MkdirAll")
- err = repoRoot.UntypedJoin("node_modules", "some-dep").MkdirAll(0775)
- assert.NilError(t, err, "MkdirAll")
- err = repoRoot.UntypedJoin("parent", "child").MkdirAll(0775)
- assert.NilError(t, err, "MkdirAll")
- err = repoRoot.UntypedJoin("parent", "sibling").MkdirAll(0775)
- assert.NilError(t, err, "MkdirAll")
-
- // Directory layout:
- // <repoRoot>/
- // .git/
- // node_modules/
- // some-dep/
- // parent/
- // child/
- // sibling/
-
- watcher, err := GetPlatformSpecificBackend(logger)
- assert.NilError(t, err, "GetPlatformSpecificBackend")
- fw := New(logger, repoRoot, watcher)
- err = fw.Start()
- assert.NilError(t, err, "fw.Start")
-
- // Add a client
- ch := make(chan Event, 1)
- c := &testClient{
- notify: ch,
- }
- fw.AddClient(c)
- expectedWatching := []turbopath.AbsoluteSystemPath{
- repoRoot,
- repoRoot.UntypedJoin("parent"),
- repoRoot.UntypedJoin("parent", "child"),
- repoRoot.UntypedJoin("parent", "sibling"),
- }
- expectWatching(t, c, expectedWatching)
-
- fooPath := repoRoot.UntypedJoin("parent", "child", "foo")
- err = fooPath.WriteFile([]byte("hello"), 0644)
- assert.NilError(t, err, "WriteFile")
- expectFilesystemEvent(t, ch, Event{
- EventType: FileAdded,
- Path: fooPath,
- })
-
- deepPath := repoRoot.UntypedJoin("parent", "sibling", "deep", "path")
- err = deepPath.MkdirAll(0775)
- assert.NilError(t, err, "MkdirAll")
- // We'll catch an event for "deep", but not "deep/path" since
- // we don't have a recursive watch
- expectFilesystemEvent(t, ch, Event{
- Path: repoRoot.UntypedJoin("parent", "sibling", "deep"),
- EventType: FileAdded,
- })
- expectFilesystemEvent(t, ch, Event{
- Path: repoRoot.UntypedJoin("parent", "sibling", "deep", "path"),
- EventType: FileAdded,
- })
- expectedWatching = append(expectedWatching, deepPath, repoRoot.UntypedJoin("parent", "sibling", "deep"))
- expectWatching(t, c, expectedWatching)
-
- gitFilePath := repoRoot.UntypedJoin(".git", "git-file")
- err = gitFilePath.WriteFile([]byte("nope"), 0644)
- assert.NilError(t, err, "WriteFile")
- expectNoFilesystemEvent(t, ch)
-}
diff --git a/cli/internal/fs/copy_file.go b/cli/internal/fs/copy_file.go
deleted file mode 100644
index e7619de..0000000
--- a/cli/internal/fs/copy_file.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Adapted from https://github.com/thought-machine/please
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package fs
-
-import (
- "errors"
- "os"
- "path/filepath"
-
- "github.com/karrick/godirwalk"
-)
-
-// RecursiveCopy copies either a single file or a directory.
-// 'mode' is the mode of the destination file.
-func RecursiveCopy(from string, to string) error {
- // Verified all callers are passing in absolute paths for from (and to)
- statedFrom := LstatCachedFile{Path: UnsafeToAbsoluteSystemPath(from)}
- fromType, err := statedFrom.GetType()
- if err != nil {
- return err
- }
-
- if fromType.IsDir() {
- return WalkMode(statedFrom.Path.ToStringDuringMigration(), func(name string, isDir bool, fileType os.FileMode) error {
- dest := filepath.Join(to, name[len(statedFrom.Path.ToString()):])
- // name is absolute, (originates from godirwalk)
- src := LstatCachedFile{Path: UnsafeToAbsoluteSystemPath(name), fileType: &fileType}
- if isDir {
- mode, err := src.GetMode()
- if err != nil {
- return err
- }
- return os.MkdirAll(dest, mode)
- }
- return CopyFile(&src, dest)
- })
- }
- return CopyFile(&statedFrom, to)
-}
-
-// Walk implements an equivalent to filepath.Walk.
-// It's implemented over github.com/karrick/godirwalk but the provided interface doesn't use that
-// to make it a little easier to handle.
-func Walk(rootPath string, callback func(name string, isDir bool) error) error {
- return WalkMode(rootPath, func(name string, isDir bool, mode os.FileMode) error {
- return callback(name, isDir)
- })
-}
-
-// WalkMode is like Walk but the callback receives an additional type specifying the file mode type.
-// N.B. This only includes the bits of the mode that determine the mode type, not the permissions.
-func WalkMode(rootPath string, callback func(name string, isDir bool, mode os.FileMode) error) error {
- return godirwalk.Walk(rootPath, &godirwalk.Options{
- Callback: func(name string, info *godirwalk.Dirent) error {
- // currently we support symlinked files, but not symlinked directories:
- // For copying, we Mkdir and bail if we encounter a symlink to a directoy
- // For finding packages, we enumerate the symlink, but don't follow inside
- isDir, err := info.IsDirOrSymlinkToDir()
- if err != nil {
- pathErr := &os.PathError{}
- if errors.As(err, &pathErr) {
- // If we have a broken link, skip this entry
- return godirwalk.SkipThis
- }
- return err
- }
- return callback(name, isDir, info.ModeType())
- },
- ErrorCallback: func(pathname string, err error) godirwalk.ErrorAction {
- pathErr := &os.PathError{}
- if errors.As(err, &pathErr) {
- return godirwalk.SkipNode
- }
- return godirwalk.Halt
- },
- Unsorted: true,
- AllowNonDirectory: true,
- FollowSymbolicLinks: false,
- })
-}
diff --git a/cli/internal/fs/copy_file_test.go b/cli/internal/fs/copy_file_test.go
deleted file mode 100644
index 6a61576..0000000
--- a/cli/internal/fs/copy_file_test.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package fs
-
-import (
- "errors"
- "io/ioutil"
- "os"
- "path/filepath"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
- "gotest.tools/v3/fs"
-)
-
-func TestCopyFile(t *testing.T) {
- srcTmpDir := turbopath.AbsoluteSystemPath(t.TempDir())
- destTmpDir := turbopath.AbsoluteSystemPath(t.TempDir())
- srcFilePath := srcTmpDir.UntypedJoin("src")
- destFilePath := destTmpDir.UntypedJoin("dest")
- from := &LstatCachedFile{Path: srcFilePath}
-
- // The src file doesn't exist, will error.
- err := CopyFile(from, destFilePath.ToString())
- pathErr := &os.PathError{}
- if !errors.As(err, &pathErr) {
- t.Errorf("got %v, want PathError", err)
- }
-
- // Create the src file.
- srcFile, err := srcFilePath.Create()
- assert.NilError(t, err, "Create")
- _, err = srcFile.WriteString("src")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, srcFile.Close(), "Close")
-
- // Copy the src to the dest.
- err = CopyFile(from, destFilePath.ToString())
- assert.NilError(t, err, "src exists dest does not, should not error.")
-
- // Now test for symlinks.
- symlinkSrcDir := turbopath.AbsoluteSystemPath(t.TempDir())
- symlinkTargetDir := turbopath.AbsoluteSystemPath(t.TempDir())
- symlinkDestDir := turbopath.AbsoluteSystemPath(t.TempDir())
- symlinkSrcPath := symlinkSrcDir.UntypedJoin("symlink")
- symlinkTargetPath := symlinkTargetDir.UntypedJoin("target")
- symlinkDestPath := symlinkDestDir.UntypedJoin("dest")
- fromSymlink := &LstatCachedFile{Path: symlinkSrcPath}
-
- // Create the symlink target.
- symlinkTargetFile, err := symlinkTargetPath.Create()
- assert.NilError(t, err, "Create")
- _, err = symlinkTargetFile.WriteString("Target")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, symlinkTargetFile.Close(), "Close")
-
- // Link things up.
- err = symlinkSrcPath.Symlink(symlinkTargetPath.ToString())
- assert.NilError(t, err, "Symlink")
-
- // Run the test.
- err = CopyFile(fromSymlink, symlinkDestPath.ToString())
- assert.NilError(t, err, "Copying a valid symlink does not error.")
-
- // Break the symlink.
- err = symlinkTargetPath.Remove()
- assert.NilError(t, err, "breaking the symlink")
-
- // Remove the existing copy.
- err = symlinkDestPath.Remove()
- assert.NilError(t, err, "existing copy is removed")
-
- // Try copying the now-broken symlink.
- err = CopyFile(fromSymlink, symlinkDestPath.ToString())
- assert.NilError(t, err, "CopyFile")
-
- // Confirm that it copied
- target, err := symlinkDestPath.Readlink()
- assert.NilError(t, err, "Readlink")
- assert.Equal(t, target, symlinkTargetPath.ToString())
-}
-
-func TestCopyOrLinkFileWithPerms(t *testing.T) {
- // Directory layout:
- //
- // <src>/
- // foo
- readonlyMode := os.FileMode(0444)
- srcDir := turbopath.AbsoluteSystemPath(t.TempDir())
- dstDir := turbopath.AbsoluteSystemPath(t.TempDir())
- srcFilePath := srcDir.UntypedJoin("src")
- dstFilePath := dstDir.UntypedJoin("dst")
- srcFile, err := srcFilePath.Create()
- defer func() { _ = srcFile.Close() }()
- assert.NilError(t, err, "Create")
- err = srcFile.Chmod(readonlyMode)
- assert.NilError(t, err, "Chmod")
- err = CopyFile(&LstatCachedFile{Path: srcFilePath}, dstFilePath.ToStringDuringMigration())
- assert.NilError(t, err, "CopyOrLinkFile")
- info, err := dstFilePath.Lstat()
- assert.NilError(t, err, "Lstat")
- assert.Equal(t, info.Mode(), readonlyMode, "expected dest to have matching permissions")
-}
-
-func TestRecursiveCopy(t *testing.T) {
- // Directory layout:
- //
- // <src>/
- // b
- // child/
- // a
- // link -> ../b
- // broken -> missing
- // circle -> ../child
- src := fs.NewDir(t, "recursive-copy-or-link")
- dst := fs.NewDir(t, "recursive-copy-or-link-dist")
- childDir := filepath.Join(src.Path(), "child")
- err := os.Mkdir(childDir, os.ModeDir|0777)
- assert.NilError(t, err, "Mkdir")
- aPath := filepath.Join(childDir, "a")
- aFile, err := os.Create(aPath)
- assert.NilError(t, err, "Create")
- _, err = aFile.WriteString("hello")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, aFile.Close(), "Close")
-
- bPath := filepath.Join(src.Path(), "b")
- bFile, err := os.Create(bPath)
- assert.NilError(t, err, "Create")
- _, err = bFile.WriteString("bFile")
- assert.NilError(t, err, "WriteString")
- assert.NilError(t, bFile.Close(), "Close")
-
- srcLinkPath := filepath.Join(childDir, "link")
- assert.NilError(t, os.Symlink(filepath.FromSlash("../b"), srcLinkPath), "Symlink")
-
- srcBrokenLinkPath := filepath.Join(childDir, "broken")
- assert.NilError(t, os.Symlink("missing", srcBrokenLinkPath), "Symlink")
- circlePath := filepath.Join(childDir, "circle")
- assert.NilError(t, os.Symlink(filepath.FromSlash("../child"), circlePath), "Symlink")
-
- err = RecursiveCopy(src.Path(), dst.Path())
- assert.NilError(t, err, "RecursiveCopy")
- // For ensure multiple times copy will not broken
- err = RecursiveCopy(src.Path(), dst.Path())
- assert.NilError(t, err, "RecursiveCopy")
-
- dstChildDir := filepath.Join(dst.Path(), "child")
- assertDirMatches(t, childDir, dstChildDir)
- dstAPath := filepath.Join(dst.Path(), "child", "a")
- assertFileMatches(t, aPath, dstAPath)
- dstBPath := filepath.Join(dst.Path(), "b")
- assertFileMatches(t, bPath, dstBPath)
- dstLinkPath := filepath.Join(dst.Path(), "child", "link")
- dstLinkDest, err := os.Readlink(dstLinkPath)
- assert.NilError(t, err, "Readlink")
- expectedLinkDest := filepath.FromSlash("../b")
- if dstLinkDest != expectedLinkDest {
- t.Errorf("Readlink got %v, want %v", dstLinkDest, expectedLinkDest)
- }
- dstBrokenLinkPath := filepath.Join(dst.Path(), "child", "broken")
- brokenLinkExists := PathExists(dstBrokenLinkPath)
- if brokenLinkExists {
- t.Errorf("We cached a broken link at %v", dstBrokenLinkPath)
- }
- // Currently, we convert symlink-to-directory to empty-directory
- // This is very likely not ideal behavior, but leaving this test here to verify
- // that it is what we expect at this point in time.
- dstCirclePath := filepath.Join(dst.Path(), "child", "circle")
- circleStat, err := os.Lstat(dstCirclePath)
- assert.NilError(t, err, "Lstat")
- assert.Equal(t, circleStat.IsDir(), true)
- entries, err := os.ReadDir(dstCirclePath)
- assert.NilError(t, err, "ReadDir")
- assert.Equal(t, len(entries), 0)
-}
-
-func assertFileMatches(t *testing.T, orig string, copy string) {
- t.Helper()
- origBytes, err := ioutil.ReadFile(orig)
- assert.NilError(t, err, "ReadFile")
- copyBytes, err := ioutil.ReadFile(copy)
- assert.NilError(t, err, "ReadFile")
- assert.DeepEqual(t, origBytes, copyBytes)
- origStat, err := os.Lstat(orig)
- assert.NilError(t, err, "Lstat")
- copyStat, err := os.Lstat(copy)
- assert.NilError(t, err, "Lstat")
- assert.Equal(t, origStat.Mode(), copyStat.Mode())
-}
-
-func assertDirMatches(t *testing.T, orig string, copy string) {
- t.Helper()
- origStat, err := os.Lstat(orig)
- assert.NilError(t, err, "Lstat")
- copyStat, err := os.Lstat(copy)
- assert.NilError(t, err, "Lstat")
- assert.Equal(t, origStat.Mode(), copyStat.Mode())
-}
diff --git a/cli/internal/fs/fs.go b/cli/internal/fs/fs.go
deleted file mode 100644
index 77804c0..0000000
--- a/cli/internal/fs/fs.go
+++ /dev/null
@@ -1,191 +0,0 @@
-package fs
-
-import (
- "io"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "runtime"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// https://github.com/thought-machine/please/blob/master/src/fs/fs.go
-
-// DirPermissions are the default permission bits we apply to directories.
-const DirPermissions = os.ModeDir | 0775
-
-// EnsureDir ensures that the directory of the given file has been created.
-func EnsureDir(filename string) error {
- dir := filepath.Dir(filename)
- err := os.MkdirAll(dir, DirPermissions)
- if err != nil && FileExists(dir) {
- // It looks like this is a file and not a directory. Attempt to remove it; this can
- // happen in some cases if you change a rule from outputting a file to a directory.
- log.Printf("Attempting to remove file %s; a subdirectory is required", dir)
- if err2 := os.Remove(dir); err2 == nil {
- err = os.MkdirAll(dir, DirPermissions)
- } else {
- return err
- }
- }
- return err
-}
-
-var nonRelativeSentinel string = ".." + string(filepath.Separator)
-
-// DirContainsPath returns true if the path 'target' is contained within 'dir'
-// Expects both paths to be absolute and does not verify that either path exists.
-func DirContainsPath(dir string, target string) (bool, error) {
- // On windows, trying to get a relative path between files on different volumes
- // is an error. We don't care about the error, it's good enough for us to say
- // that one path doesn't contain the other if they're on different volumes.
- if runtime.GOOS == "windows" && filepath.VolumeName(dir) != filepath.VolumeName(target) {
- return false, nil
- }
- // In Go, filepath.Rel can return a path that starts with "../" or equivalent.
- // Checking filesystem-level contains can get extremely complicated
- // (see https://github.com/golang/dep/blob/f13583b555deaa6742f141a9c1185af947720d60/internal/fs/fs.go#L33)
- // As a compromise, rely on the stdlib to generate a relative path and then check
- // if the first step is "../".
- rel, err := filepath.Rel(dir, target)
- if err != nil {
- return false, err
- }
- return !strings.HasPrefix(rel, nonRelativeSentinel), nil
-}
-
-// PathExists returns true if the given path exists, as a file or a directory.
-func PathExists(filename string) bool {
- _, err := os.Lstat(filename)
- return err == nil
-}
-
-// FileExists returns true if the given path exists and is a file.
-func FileExists(filename string) bool {
- info, err := os.Lstat(filename)
- return err == nil && !info.IsDir()
-}
-
-// CopyFile copies a file from 'from' to 'to', with an attempt to perform a copy & rename
-// to avoid chaos if anything goes wrong partway.
-func CopyFile(from *LstatCachedFile, to string) error {
- fromMode, err := from.GetMode()
- if err != nil {
- return errors.Wrapf(err, "getting mode for %v", from.Path)
- }
- if fromMode&os.ModeSymlink != 0 {
- target, err := from.Path.Readlink()
- if err != nil {
- return errors.Wrapf(err, "reading link target for %v", from.Path)
- }
- if err := EnsureDir(to); err != nil {
- return err
- }
- if _, err := os.Lstat(to); err == nil {
- // target link file exist, should remove it first
- err := os.Remove(to)
- if err != nil {
- return err
- }
- }
- return os.Symlink(target, to)
- }
- fromFile, err := from.Path.Open()
- if err != nil {
- return err
- }
- defer util.CloseAndIgnoreError(fromFile)
- return writeFileFromStream(fromFile, to, fromMode)
-}
-
-// writeFileFromStream writes data from a reader to the file named 'to', with an attempt to perform
-// a copy & rename to avoid chaos if anything goes wrong partway.
-func writeFileFromStream(fromFile io.Reader, to string, mode os.FileMode) error {
- dir, file := filepath.Split(to)
- if dir != "" {
- if err := os.MkdirAll(dir, DirPermissions); err != nil {
- return err
- }
- }
- tempFile, err := ioutil.TempFile(dir, file)
- if err != nil {
- return err
- }
- if _, err := io.Copy(tempFile, fromFile); err != nil {
- return err
- }
- if err := tempFile.Close(); err != nil {
- return err
- }
- // OK, now file is written; adjust permissions appropriately.
- if mode == 0 {
- mode = 0664
- }
- if err := os.Chmod(tempFile.Name(), mode); err != nil {
- return err
- }
- // And move it to its final destination.
- return renameFile(tempFile.Name(), to)
-}
-
-// IsDirectory checks if a given path is a directory
-func IsDirectory(path string) bool {
- info, err := os.Stat(path)
- return err == nil && info.IsDir()
-}
-
-// Try to gracefully rename the file as the os.Rename does not work across
-// filesystems and on most Linux systems /tmp is mounted as tmpfs
-func renameFile(from, to string) (err error) {
- err = os.Rename(from, to)
- if err == nil {
- return nil
- }
- err = copyFile(from, to)
- if err != nil {
- return err
- }
- err = os.RemoveAll(from)
- if err != nil {
- return err
- }
- return nil
-}
-
-func copyFile(from, to string) (err error) {
- in, err := os.Open(from)
- if err != nil {
- return err
- }
- defer in.Close()
-
- out, err := os.Create(to)
- if err != nil {
- return err
- }
- defer func() {
- if e := out.Close(); e != nil {
- err = e
- }
- }()
-
- _, err = io.Copy(out, in)
- if err != nil {
- return err
- }
-
- si, err := os.Stat(from)
- if err != nil {
- return err
- }
- err = os.Chmod(to, si.Mode())
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/cli/internal/fs/fs_test.go b/cli/internal/fs/fs_test.go
deleted file mode 100644
index 0598d43..0000000
--- a/cli/internal/fs/fs_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package fs
-
-import (
- "path/filepath"
- "testing"
-)
-
-func Test_DirContainsPath(t *testing.T) {
- parent, err := filepath.Abs(filepath.Join("some", "path"))
- if err != nil {
- t.Fatalf("failed to construct parent path %v", err)
- }
- testcases := []struct {
- target []string
- want bool
- }{
- {
- []string{"..", "elsewhere"},
- false,
- },
- {
- []string{"sibling"},
- false,
- },
- {
- // The same path as parent
- []string{"some", "path"},
- true,
- },
- {
- []string{"some", "path", "..", "path", "inside", "parent"},
- true,
- },
- {
- []string{"some", "path", "inside", "..", "inside", "parent"},
- true,
- },
- {
- []string{"some", "path", "inside", "..", "..", "outside", "parent"},
- false,
- },
- {
- []string{"some", "pathprefix"},
- false,
- },
- }
- for _, tc := range testcases {
- target, err := filepath.Abs(filepath.Join(tc.target...))
- if err != nil {
- t.Fatalf("failed to construct path for %v: %v", tc.target, err)
- }
- got, err := DirContainsPath(parent, target)
- if err != nil {
- t.Fatalf("failed to check ")
- }
- if got != tc.want {
- t.Errorf("DirContainsPath(%v, %v) got %v, want %v", parent, target, got, tc.want)
- }
- }
-}
diff --git a/cli/internal/fs/fs_windows_test.go b/cli/internal/fs/fs_windows_test.go
deleted file mode 100644
index 4e71e2c..0000000
--- a/cli/internal/fs/fs_windows_test.go
+++ /dev/null
@@ -1,18 +0,0 @@
-//go:build windows
-// +build windows
-
-package fs
-
-import "testing"
-
-func TestDifferentVolumes(t *testing.T) {
- p1 := "C:\\some\\path"
- p2 := "D:\\other\\path"
- contains, err := DirContainsPath(p1, p2)
- if err != nil {
- t.Errorf("DirContainsPath got error %v, want <nil>", err)
- }
- if contains {
- t.Errorf("DirContainsPath got true, want false")
- }
-}
diff --git a/cli/internal/fs/get_turbo_data_dir_go.go b/cli/internal/fs/get_turbo_data_dir_go.go
deleted file mode 100644
index 2cf459a..0000000
--- a/cli/internal/fs/get_turbo_data_dir_go.go
+++ /dev/null
@@ -1,16 +0,0 @@
-//go:build go || !rust
-// +build go !rust
-
-package fs
-
-import (
- "github.com/adrg/xdg"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// GetTurboDataDir returns a directory outside of the repo
-// where turbo can store data files related to turbo.
-func GetTurboDataDir() turbopath.AbsoluteSystemPath {
- dataHome := AbsoluteSystemPathFromUpstream(xdg.DataHome)
- return dataHome.UntypedJoin("turborepo")
-}
diff --git a/cli/internal/fs/get_turbo_data_dir_rust.go b/cli/internal/fs/get_turbo_data_dir_rust.go
deleted file mode 100644
index dbc80f3..0000000
--- a/cli/internal/fs/get_turbo_data_dir_rust.go
+++ /dev/null
@@ -1,16 +0,0 @@
-//go:build rust
-// +build rust
-
-package fs
-
-import (
- "github.com/vercel/turbo/cli/internal/ffi"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// GetTurboDataDir returns a directory outside of the repo
-// where turbo can store data files related to turbo.
-func GetTurboDataDir() turbopath.AbsoluteSystemPath {
- dir := ffi.GetTurboDataDir()
- return turbopath.AbsoluteSystemPathFromUpstream(dir)
-}
diff --git a/cli/internal/fs/hash.go b/cli/internal/fs/hash.go
deleted file mode 100644
index fed7d87..0000000
--- a/cli/internal/fs/hash.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package fs
-
-import (
- "crypto/sha1"
- "encoding/hex"
- "fmt"
- "io"
- "os"
- "strconv"
-
- "github.com/vercel/turbo/cli/internal/xxhash"
-)
-
-func HashObject(i interface{}) (string, error) {
- hash := xxhash.New()
-
- _, err := hash.Write([]byte(fmt.Sprintf("%v", i)))
-
- return hex.EncodeToString(hash.Sum(nil)), err
-}
-
-func HashFile(filePath string) (string, error) {
- file, err := os.Open(filePath)
- if err != nil {
- return "", err
- }
- defer file.Close()
-
- hash := xxhash.New()
- if _, err := io.Copy(hash, file); err != nil {
- return "", err
- }
-
- return hex.EncodeToString(hash.Sum(nil)), nil
-}
-
-// GitLikeHashFile is a function that mimics how Git
-// calculates the SHA1 for a file (or, in Git terms, a "blob") (without git)
-func GitLikeHashFile(filePath string) (string, error) {
- file, err := os.Open(filePath)
- if err != nil {
- return "", err
- }
- defer file.Close()
-
- stat, err := file.Stat()
- if err != nil {
- return "", err
- }
- hash := sha1.New()
- hash.Write([]byte("blob"))
- hash.Write([]byte(" "))
- hash.Write([]byte(strconv.FormatInt(stat.Size(), 10)))
- hash.Write([]byte{0})
-
- if _, err := io.Copy(hash, file); err != nil {
- return "", err
- }
-
- return hex.EncodeToString(hash.Sum(nil)), nil
-}
diff --git a/cli/internal/fs/hash_test.go b/cli/internal/fs/hash_test.go
deleted file mode 100644
index dd2fa84..0000000
--- a/cli/internal/fs/hash_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package fs
-
-import (
- "testing"
-
- "gotest.tools/v3/assert"
-)
-
-const _numOfRuns = 20
-
-func Test_HashObjectStability(t *testing.T) {
- type TestCase struct {
- name string
- obj interface{}
- }
- type complexStruct struct {
- nested TaskOutputs
- foo string
- bar []string
- }
-
- testCases := []TestCase{
- {
- name: "task object",
- obj: TaskOutputs{
- Inclusions: []string{"foo", "bar"},
- Exclusions: []string{"baz"},
- },
- },
- {
- name: "complex struct",
- obj: complexStruct{
- nested: TaskOutputs{
- Exclusions: []string{"bar", "baz"},
- Inclusions: []string{"foo"},
- },
- foo: "a",
- bar: []string{"b", "c"},
- },
- },
- }
-
- for _, tc := range testCases {
- expectedHash, err := HashObject(tc.obj)
- assert.NilError(t, err, tc.name)
-
- for n := 0; n < _numOfRuns; n++ {
- hash, err := HashObject(tc.obj)
- assert.NilError(t, err, tc.name)
- assert.Equal(t, expectedHash, hash, tc.name)
- }
- }
-}
diff --git a/cli/internal/fs/lstat.go b/cli/internal/fs/lstat.go
deleted file mode 100644
index eff0810..0000000
--- a/cli/internal/fs/lstat.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package fs
-
-import (
- "io/fs"
- "os"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// LstatCachedFile maintains a cache of file info, mode and type for the given Path
-type LstatCachedFile struct {
- Path turbopath.AbsoluteSystemPath
- fileInfo fs.FileInfo
- fileMode *fs.FileMode
- fileType *fs.FileMode
-}
-
-// GetInfo returns, and caches the file info for the LstatCachedFile.Path
-func (file *LstatCachedFile) GetInfo() (fs.FileInfo, error) {
- if file.fileInfo != nil {
- return file.fileInfo, nil
- }
-
- err := file.lstat()
- if err != nil {
- return nil, err
- }
-
- return file.fileInfo, nil
-}
-
-// GetMode returns, and caches the file mode for the LstatCachedFile.Path
-func (file *LstatCachedFile) GetMode() (fs.FileMode, error) {
- if file.fileMode != nil {
- return *file.fileMode, nil
- }
-
- err := file.lstat()
- if err != nil {
- return 0, err
- }
-
- return *file.fileMode, nil
-}
-
-// GetType returns, and caches the type bits of (FileMode & os.ModeType) for the LstatCachedFile.Path
-func (file *LstatCachedFile) GetType() (fs.FileMode, error) {
- if file.fileType != nil {
- return *file.fileType, nil
- }
-
- err := file.lstat()
- if err != nil {
- return 0, err
- }
-
- return *file.fileType, nil
-}
-
-func (file *LstatCachedFile) lstat() error {
- fileInfo, err := file.Path.Lstat()
- if err != nil {
- return err
- }
-
- fileMode := fileInfo.Mode()
- fileModeType := fileMode & os.ModeType
-
- file.fileInfo = fileInfo
- file.fileMode = &fileMode
- file.fileType = &fileModeType
-
- return nil
-}
diff --git a/cli/internal/fs/package_json.go b/cli/internal/fs/package_json.go
deleted file mode 100644
index 883f7a4..0000000
--- a/cli/internal/fs/package_json.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package fs
-
-import (
- "bytes"
- "encoding/json"
- "sync"
-
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// PackageJSON represents NodeJS package.json
-type PackageJSON struct {
- Name string `json:"name"`
- Version string `json:"version"`
- Scripts map[string]string `json:"scripts"`
- Dependencies map[string]string `json:"dependencies"`
- DevDependencies map[string]string `json:"devDependencies"`
- OptionalDependencies map[string]string `json:"optionalDependencies"`
- PeerDependencies map[string]string `json:"peerDependencies"`
- PackageManager string `json:"packageManager"`
- Os []string `json:"os"`
- Workspaces Workspaces `json:"workspaces"`
- Private bool `json:"private"`
- // Exact JSON object stored in package.json including unknown fields
- // During marshalling struct fields will take priority over raw fields
- RawJSON map[string]interface{} `json:"-"`
-
- // relative path from repo root to the package.json file
- PackageJSONPath turbopath.AnchoredSystemPath `json:"-"`
- // relative path from repo root to the package
- Dir turbopath.AnchoredSystemPath `json:"-"`
- InternalDeps []string `json:"-"`
- UnresolvedExternalDeps map[string]string `json:"-"`
- TransitiveDeps []lockfile.Package `json:"-"`
- LegacyTurboConfig *TurboJSON `json:"turbo"`
- Mu sync.Mutex `json:"-"`
- ExternalDepsHash string `json:"-"`
-}
-
-type Workspaces []string
-
-type WorkspacesAlt struct {
- Packages []string `json:"packages,omitempty"`
-}
-
-func (r *Workspaces) UnmarshalJSON(data []byte) error {
- var tmp = &WorkspacesAlt{}
- if err := json.Unmarshal(data, tmp); err == nil {
- *r = Workspaces(tmp.Packages)
- return nil
- }
- var tempstr = []string{}
- if err := json.Unmarshal(data, &tempstr); err != nil {
- return err
- }
- *r = tempstr
- return nil
-}
-
-// ReadPackageJSON returns a struct of package.json
-func ReadPackageJSON(path turbopath.AbsoluteSystemPath) (*PackageJSON, error) {
- b, err := path.ReadFile()
- if err != nil {
- return nil, err
- }
- return UnmarshalPackageJSON(b)
-}
-
-// UnmarshalPackageJSON decodes a byte slice into a PackageJSON struct
-func UnmarshalPackageJSON(data []byte) (*PackageJSON, error) {
- var rawJSON map[string]interface{}
- if err := json.Unmarshal(data, &rawJSON); err != nil {
- return nil, err
- }
-
- pkgJSON := &PackageJSON{}
- if err := json.Unmarshal(data, &pkgJSON); err != nil {
- return nil, err
- }
- pkgJSON.RawJSON = rawJSON
-
- return pkgJSON, nil
-}
-
-// MarshalPackageJSON Serialize PackageJSON to a slice of bytes
-func MarshalPackageJSON(pkgJSON *PackageJSON) ([]byte, error) {
- structuredContent, err := json.Marshal(pkgJSON)
- if err != nil {
- return nil, err
- }
- var structuredFields map[string]interface{}
- if err := json.Unmarshal(structuredContent, &structuredFields); err != nil {
- return nil, err
- }
-
- fieldsToSerialize := make(map[string]interface{}, len(pkgJSON.RawJSON))
-
- // copy pkgJSON.RawJSON
- for key, value := range pkgJSON.RawJSON {
- fieldsToSerialize[key] = value
- }
-
- for key, value := range structuredFields {
- if isEmpty(value) {
- delete(fieldsToSerialize, key)
- } else {
- fieldsToSerialize[key] = value
- }
- }
-
- var b bytes.Buffer
- encoder := json.NewEncoder(&b)
- encoder.SetEscapeHTML(false)
- encoder.SetIndent("", " ")
- if err := encoder.Encode(fieldsToSerialize); err != nil {
- return nil, err
- }
-
- return b.Bytes(), nil
-}
-
-func isEmpty(value interface{}) bool {
- if value == nil {
- return true
- }
- switch s := value.(type) {
- case string:
- return s == ""
- case bool:
- return !s
- case []string:
- return len(s) == 0
- case map[string]interface{}:
- return len(s) == 0
- case Workspaces:
- return len(s) == 0
- default:
- // Assume any unknown types aren't empty
- return false
- }
-}
diff --git a/cli/internal/fs/package_json_test.go b/cli/internal/fs/package_json_test.go
deleted file mode 100644
index 3c16620..0000000
--- a/cli/internal/fs/package_json_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package fs
-
-import (
- "testing"
-
- "gotest.tools/v3/assert"
-)
-
-func Test_UnmarshalPackageJSON(t *testing.T) {
- type Case struct {
- name string
- json string
- expectedFields *PackageJSON
- }
-
- testCases := []Case{
- {
- name: "basic types are in raw and processed",
- json: `{"name":"foo","version":"1.2.3"}`,
- expectedFields: &PackageJSON{
- Name: "foo",
- Version: "1.2.3",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "version": "1.2.3",
- },
- },
- },
- {
- name: "map types get copied",
- json: `{"dependencies":{"foo":"1.2.3"},"devDependencies":{"bar": "^1.0.0"}}`,
- expectedFields: &PackageJSON{
- Dependencies: map[string]string{"foo": "1.2.3"},
- DevDependencies: map[string]string{"bar": "^1.0.0"},
- RawJSON: map[string]interface{}{
- "dependencies": map[string]interface{}{"foo": "1.2.3"},
- "devDependencies": map[string]interface{}{"bar": "^1.0.0"},
- },
- },
- },
- {
- name: "array types get copied",
- json: `{"os":["linux", "windows"]}`,
- expectedFields: &PackageJSON{
- Os: []string{"linux", "windows"},
- RawJSON: map[string]interface{}{
- "os": []interface{}{"linux", "windows"},
- },
- },
- },
- }
-
- for _, testCase := range testCases {
- actual, err := UnmarshalPackageJSON([]byte(testCase.json))
- assert.NilError(t, err, testCase.name)
- assertPackageJSONEqual(t, actual, testCase.expectedFields)
- }
-}
-
-func Test_MarshalPackageJSON(t *testing.T) {
- type TestCase struct {
- name string
- input *PackageJSON
- expected *PackageJSON
- }
-
- testCases := []TestCase{
- {
- name: "roundtrip should have no effect",
- input: &PackageJSON{
- Name: "foo",
- Version: "1.2.3",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "version": "1.2.3",
- },
- },
- expected: &PackageJSON{
- Name: "foo",
- Version: "1.2.3",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "version": "1.2.3",
- },
- },
- },
- {
- name: "structured fields should take priority over raw values",
- input: &PackageJSON{
- Name: "foo",
- Version: "2.3.4",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "version": "1.2.3",
- },
- },
- expected: &PackageJSON{
- Name: "foo",
- Version: "2.3.4",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "version": "2.3.4",
- },
- },
- },
- {
- name: "empty structured fields don't get serialized",
- input: &PackageJSON{
- Name: "foo",
- Version: "",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "version": "1.2.3",
- },
- },
- expected: &PackageJSON{
- Name: "foo",
- Version: "",
- RawJSON: map[string]interface{}{
- "name": "foo",
- },
- },
- },
- {
- name: "unstructured fields survive the round trip",
- input: &PackageJSON{
- Name: "foo",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "special-field": "special-value",
- "special-config": map[string]interface{}{
- "flag": true,
- "value": "toggled",
- },
- },
- },
- expected: &PackageJSON{
- Name: "foo",
- RawJSON: map[string]interface{}{
- "name": "foo",
- "special-field": "special-value",
- "special-config": map[string]interface{}{
- "flag": true,
- "value": "toggled",
- },
- },
- },
- },
- }
-
- for _, testCase := range testCases {
- serializedInput, err := MarshalPackageJSON(testCase.input)
- assert.NilError(t, err, testCase.name)
- actual, err := UnmarshalPackageJSON(serializedInput)
- assert.NilError(t, err, testCase.name)
- assertPackageJSONEqual(t, actual, testCase.expected)
- }
-}
-
-// Asserts that the data section of two PackageJSON structs are equal
-func assertPackageJSONEqual(t *testing.T, x *PackageJSON, y *PackageJSON) {
- t.Helper()
- assert.Equal(t, x.Name, y.Name)
- assert.Equal(t, x.Version, y.Version)
- assert.DeepEqual(t, x.Scripts, y.Scripts)
- assert.DeepEqual(t, x.Dependencies, y.Dependencies)
- assert.DeepEqual(t, x.DevDependencies, y.DevDependencies)
- assert.DeepEqual(t, x.OptionalDependencies, y.OptionalDependencies)
- assert.DeepEqual(t, x.PeerDependencies, y.PeerDependencies)
- assert.Equal(t, x.PackageManager, y.PackageManager)
- assert.DeepEqual(t, x.Workspaces, y.Workspaces)
- assert.DeepEqual(t, x.Private, y.Private)
- assert.DeepEqual(t, x.RawJSON, y.RawJSON)
-}
diff --git a/cli/internal/fs/path.go b/cli/internal/fs/path.go
deleted file mode 100644
index 2023d69..0000000
--- a/cli/internal/fs/path.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package fs
-
-import (
- "fmt"
- iofs "io/fs"
- "os"
- "path/filepath"
- "reflect"
-
- "github.com/adrg/xdg"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// CheckedToAbsoluteSystemPath inspects a string and determines if it is an absolute path.
-func CheckedToAbsoluteSystemPath(s string) (turbopath.AbsoluteSystemPath, error) {
- if filepath.IsAbs(s) {
- return turbopath.AbsoluteSystemPath(s), nil
- }
- return "", fmt.Errorf("%v is not an absolute path", s)
-}
-
-// ResolveUnknownPath returns unknown if it is an absolute path, otherwise, it
-// assumes unknown is a path relative to the given root.
-func ResolveUnknownPath(root turbopath.AbsoluteSystemPath, unknown string) turbopath.AbsoluteSystemPath {
- if filepath.IsAbs(unknown) {
- return turbopath.AbsoluteSystemPath(unknown)
- }
- return root.UntypedJoin(unknown)
-}
-
-// UnsafeToAbsoluteSystemPath directly converts a string to an AbsoluteSystemPath
-func UnsafeToAbsoluteSystemPath(s string) turbopath.AbsoluteSystemPath {
- return turbopath.AbsoluteSystemPath(s)
-}
-
-// UnsafeToAnchoredSystemPath directly converts a string to an AbsoluteSystemPath
-func UnsafeToAnchoredSystemPath(s string) turbopath.AnchoredSystemPath {
- return turbopath.AnchoredSystemPath(s)
-}
-
-// AbsoluteSystemPathFromUpstream is used to mark return values from APIs that we
-// expect to give us absolute paths. No checking is performed.
-// Prefer to use this over a cast to maintain the search-ability of interfaces
-// into and out of the turbopath.AbsoluteSystemPath type.
-func AbsoluteSystemPathFromUpstream(s string) turbopath.AbsoluteSystemPath {
- return turbopath.AbsoluteSystemPath(s)
-}
-
-// GetCwd returns the calculated working directory after traversing symlinks.
-func GetCwd(cwdRaw string) (turbopath.AbsoluteSystemPath, error) {
- if cwdRaw == "" {
- var err error
- cwdRaw, err = os.Getwd()
- if err != nil {
- return "", err
- }
- }
- // We evaluate symlinks here because the package managers
- // we support do the same.
- cwdRaw, err := filepath.EvalSymlinks(cwdRaw)
- if err != nil {
- return "", fmt.Errorf("evaluating symlinks in cwd: %w", err)
- }
- cwd, err := CheckedToAbsoluteSystemPath(cwdRaw)
- if err != nil {
- return "", fmt.Errorf("cwd is not an absolute path %v: %v", cwdRaw, err)
- }
- return cwd, nil
-}
-
-// GetVolumeRoot returns the root directory given an absolute path.
-func GetVolumeRoot(absolutePath string) string {
- return filepath.VolumeName(absolutePath) + string(os.PathSeparator)
-}
-
-// CreateDirFSAtRoot creates an `os.dirFS` instance at the root of the
-// volume containing the specified path.
-func CreateDirFSAtRoot(absolutePath string) iofs.FS {
- return os.DirFS(GetVolumeRoot(absolutePath))
-}
-
-// GetDirFSRootPath returns the root path of a os.dirFS.
-func GetDirFSRootPath(fsys iofs.FS) string {
- // We can't typecheck fsys to enforce using an `os.dirFS` because the
- // type isn't exported from `os`. So instead, reflection. 🤷‍♂️
-
- fsysType := reflect.TypeOf(fsys).Name()
- if fsysType != "dirFS" {
- // This is not a user error, fail fast
- panic("GetDirFSRootPath must receive an os.dirFS")
- }
-
- // The underlying type is a string; this is the original path passed in.
- return reflect.ValueOf(fsys).String()
-}
-
-// IofsRelativePath calculates a `os.dirFS`-friendly path from an absolute system path.
-func IofsRelativePath(fsysRoot string, absolutePath string) (string, error) {
- return filepath.Rel(fsysRoot, absolutePath)
-}
-
-// TempDir returns the absolute path of a directory with the given name
-// under the system's default temp directory location
-func TempDir(subDir string) turbopath.AbsoluteSystemPath {
- return turbopath.AbsoluteSystemPath(os.TempDir()).UntypedJoin(subDir)
-}
-
-// GetUserConfigDir returns the platform-specific common location
-// for configuration files that belong to a user.
-func GetUserConfigDir() turbopath.AbsoluteSystemPath {
- configHome := AbsoluteSystemPathFromUpstream(xdg.ConfigHome)
- return configHome.UntypedJoin("turborepo")
-}
diff --git a/cli/internal/fs/testdata/both/package.json b/cli/internal/fs/testdata/both/package.json
deleted file mode 100644
index 03534b7..0000000
--- a/cli/internal/fs/testdata/both/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "turbo": {
- "pipeline": {
- "build": {}
- }
- }
-}
diff --git a/cli/internal/fs/testdata/both/turbo.json b/cli/internal/fs/testdata/both/turbo.json
deleted file mode 100644
index 721e897..0000000
--- a/cli/internal/fs/testdata/both/turbo.json
+++ /dev/null
@@ -1,18 +0,0 @@
-// mocked test comment
-{
- "pipeline": {
- "build": {
- // mocked test comment
- "dependsOn": [
- // mocked test comment
- "^build"
- ],
- "outputs": ["dist/**", ".next/**", "!dist/assets/**"],
- "outputMode": "new-only"
- } // mocked test comment
- },
- "remoteCache": {
- "teamId": "team_id",
- "signature": true
- }
-}
diff --git a/cli/internal/fs/testdata/correct/turbo.json b/cli/internal/fs/testdata/correct/turbo.json
deleted file mode 100644
index e22cde2..0000000
--- a/cli/internal/fs/testdata/correct/turbo.json
+++ /dev/null
@@ -1,49 +0,0 @@
-// mocked test comment
-{
- "pipeline": {
- "build": {
- "experimentalPassthroughEnv": ["GITHUB_TOKEN"],
- // mocked test comment
- "dependsOn": [
- // mocked test comment
- "^build"
- ],
- "outputs": ["dist/**", "!dist/assets/**", ".next/**"],
- "outputMode": "new-only"
- }, // mocked test comment
- "lint": {
- "outputs": [],
- "dependsOn": ["$MY_VAR"],
- "cache": true,
- "outputMode": "new-only"
- },
- "dev": {
- "cache": false,
- "outputMode": "full"
- },
- /* mocked test comment */
- "publish": {
- "outputs": ["dist/**"],
- "inputs": [
- /*
- mocked test comment
- */
- "build/**/*"
- ],
- "dependsOn": [
- /* mocked test comment */ "^publish",
- "^build",
- "build",
- "admin#lint"
- ],
- "cache": false
- }
- },
- "globalDependencies": ["some-file", "../another-dir/**", "$GLOBAL_ENV_VAR"],
- "globlaEnv": ["SOME_VAR", "ANOTHER_VAR"],
- "experimentalGlobalPassThroughEnv": ["AWS_SECRET_KEY"],
- "remoteCache": {
- "teamId": "team_id",
- "signature": true
- }
-}
diff --git a/cli/internal/fs/testdata/invalid-env-1/turbo.json b/cli/internal/fs/testdata/invalid-env-1/turbo.json
deleted file mode 100644
index e4a6517..0000000
--- a/cli/internal/fs/testdata/invalid-env-1/turbo.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "pipeline": {
- "task1": {
- // all invalid value
- "env": ["$A", "$B"]
- }
- }
-}
diff --git a/cli/internal/fs/testdata/invalid-env-2/turbo.json b/cli/internal/fs/testdata/invalid-env-2/turbo.json
deleted file mode 100644
index 92eec96..0000000
--- a/cli/internal/fs/testdata/invalid-env-2/turbo.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "pipeline": {
- "task1": {
- // Mixed values
- "env": ["$A", "B"]
- }
- }
-}
diff --git a/cli/internal/fs/testdata/invalid-global-env/turbo.json b/cli/internal/fs/testdata/invalid-global-env/turbo.json
deleted file mode 100644
index 2ae9ff9..0000000
--- a/cli/internal/fs/testdata/invalid-global-env/turbo.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- // Both global declarations with duplicates
- "globalDependencies": ["$FOO", "$BAR", "somefile.txt", "somefile.txt"],
- // some invalid values
- "globalEnv": ["FOO", "BAZ", "$QUX"],
- "pipeline": {
- "task1": {
- "dependsOn": ["$A"]
- }
- }
-}
diff --git a/cli/internal/fs/testdata/legacy-env/turbo.json b/cli/internal/fs/testdata/legacy-env/turbo.json
deleted file mode 100644
index 6b082c4..0000000
--- a/cli/internal/fs/testdata/legacy-env/turbo.json
+++ /dev/null
@@ -1,34 +0,0 @@
-// mocked test comment
-{
- // Both global declarations with duplicates and with
- "globalDependencies": ["$FOO", "$BAR", "somefile.txt", "somefile.txt"],
- "globalEnv": ["FOO", "BAZ", "QUX"],
- "pipeline": {
- // Only legacy declaration
- "task1": {
- "dependsOn": ["$A"]
- },
- // Only new declaration
- "task2": {
- "env": ["A"]
- },
- // Same var declared in both
- "task3": {
- "dependsOn": ["$A"],
- "env": ["A"]
- },
- // Different vars declared in both
- "task4": {
- "dependsOn": ["$A"],
- "env": ["B"]
- },
-
- // some edge cases
- "task6": { "env": ["A", "B", "C"], "dependsOn": ["$D", "$E", "$F"] },
- "task7": { "env": ["A", "B", "C"], "dependsOn": ["$A", "$B", "$C"] },
- "task8": { "env": ["A", "B", "C"], "dependsOn": ["A", "B", "C"] },
- "task9": { "env": [], "dependsOn": ["$A"] },
- "task10": { "env": ["A", "A"], "dependsOn": ["$A", "$A"] },
- "task11": { "env": ["A", "A"], "dependsOn": ["$B", "$B"] }
- }
-}
diff --git a/cli/internal/fs/testdata/legacy-only/package.json b/cli/internal/fs/testdata/legacy-only/package.json
deleted file mode 100644
index 03534b7..0000000
--- a/cli/internal/fs/testdata/legacy-only/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "turbo": {
- "pipeline": {
- "build": {}
- }
- }
-}
diff --git a/cli/internal/fs/turbo_json.go b/cli/internal/fs/turbo_json.go
deleted file mode 100644
index 71ef29d..0000000
--- a/cli/internal/fs/turbo_json.go
+++ /dev/null
@@ -1,741 +0,0 @@
-package fs
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "sort"
- "strings"
-
- "github.com/muhammadmuzzammil1998/jsonc"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-const (
- configFile = "turbo.json"
- envPipelineDelimiter = "$"
- topologicalPipelineDelimiter = "^"
-)
-
-type rawTurboJSON struct {
- // Global root filesystem dependencies
- GlobalDependencies []string `json:"globalDependencies,omitempty"`
- // Global env
- GlobalEnv []string `json:"globalEnv,omitempty"`
-
- // Global passthrough env
- GlobalPassthroughEnv []string `json:"experimentalGlobalPassThroughEnv,omitempty"`
-
- // Pipeline is a map of Turbo pipeline entries which define the task graph
- // and cache behavior on a per task or per package-task basis.
- Pipeline Pipeline `json:"pipeline"`
- // Configuration options when interfacing with the remote cache
- RemoteCacheOptions RemoteCacheOptions `json:"remoteCache,omitempty"`
-
- // Extends can be the name of another workspace
- Extends []string `json:"extends,omitempty"`
-}
-
-// pristineTurboJSON is used when marshaling a TurboJSON object into a turbo.json string
-// Notably, it includes a PristinePipeline instead of the regular Pipeline. (i.e. TaskDefinition
-// instead of BookkeepingTaskDefinition.)
-type pristineTurboJSON struct {
- GlobalDependencies []string `json:"globalDependencies,omitempty"`
- GlobalEnv []string `json:"globalEnv,omitempty"`
- GlobalPassthroughEnv []string `json:"experimentalGlobalPassThroughEnv,omitempty"`
- Pipeline PristinePipeline `json:"pipeline"`
- RemoteCacheOptions RemoteCacheOptions `json:"remoteCache,omitempty"`
- Extends []string `json:"extends,omitempty"`
-}
-
-// TurboJSON represents a turbo.json configuration file
-type TurboJSON struct {
- GlobalDeps []string
- GlobalEnv []string
- GlobalPassthroughEnv []string
- Pipeline Pipeline
- RemoteCacheOptions RemoteCacheOptions
-
- // A list of Workspace names
- Extends []string
-}
-
-// RemoteCacheOptions is a struct for deserializing .remoteCache of configFile
-type RemoteCacheOptions struct {
- TeamID string `json:"teamId,omitempty"`
- Signature bool `json:"signature,omitempty"`
-}
-
-// rawTaskWithDefaults exists to Marshal (i.e. turn a TaskDefinition into json).
-// We use this for printing ResolvedTaskConfiguration, because we _want_ to show
-// the user the default values for key they have not configured.
-type rawTaskWithDefaults struct {
- Outputs []string `json:"outputs"`
- Cache *bool `json:"cache"`
- DependsOn []string `json:"dependsOn"`
- Inputs []string `json:"inputs"`
- OutputMode util.TaskOutputMode `json:"outputMode"`
- PassthroughEnv []string `json:"experimentalPassThroughEnv,omitempty"`
- Env []string `json:"env"`
- Persistent bool `json:"persistent"`
-}
-
-// rawTask exists to Unmarshal from json. When fields are omitted, we _want_
-// them to be missing, so that we can distinguish missing from empty value.
-type rawTask struct {
- Outputs []string `json:"outputs,omitempty"`
- Cache *bool `json:"cache,omitempty"`
- DependsOn []string `json:"dependsOn,omitempty"`
- Inputs []string `json:"inputs,omitempty"`
- OutputMode *util.TaskOutputMode `json:"outputMode,omitempty"`
- Env []string `json:"env,omitempty"`
- PassthroughEnv []string `json:"experimentalPassthroughEnv,omitempty"`
- Persistent *bool `json:"persistent,omitempty"`
-}
-
-// taskDefinitionHashable exists as a definition for PristinePipeline, which is used down
-// stream for calculating the global hash. We want to exclude experimental fields here
-// because we don't want experimental fields to be part of the global hash.
-type taskDefinitionHashable struct {
- Outputs TaskOutputs
- ShouldCache bool
- EnvVarDependencies []string
- TopologicalDependencies []string
- TaskDependencies []string
- Inputs []string
- OutputMode util.TaskOutputMode
- Persistent bool
-}
-
-// taskDefinitionExperiments is a list of config fields in a task definition that are considered
-// experimental. We keep these separated so we can compute a global hash without these.
-type taskDefinitionExperiments struct {
- PassthroughEnv []string
-}
-
-// PristinePipeline is a map of task names to TaskDefinition or taskDefinitionHashable.
-// Depending on whether any experimental fields are defined, we will use either struct.
-// The purpose is to omit experimental fields when making a pristine version, so that
-// it doesn't show up in --dry/--summarize output or affect the global hash.
-type PristinePipeline map[string]interface{}
-
-// Pipeline is a struct for deserializing .pipeline in configFile
-type Pipeline map[string]BookkeepingTaskDefinition
-
-// BookkeepingTaskDefinition holds the underlying TaskDefinition and some bookkeeping data
-// about the TaskDefinition. This wrapper struct allows us to leave TaskDefinition untouched.
-type BookkeepingTaskDefinition struct {
- definedFields util.Set
- experimentalFields util.Set
- experimental taskDefinitionExperiments
- TaskDefinition taskDefinitionHashable
-}
-
-// TaskDefinition is a representation of the configFile pipeline for further computation.
-type TaskDefinition struct {
- Outputs TaskOutputs
- ShouldCache bool
-
- // This field is custom-marshalled from rawTask.Env and rawTask.DependsOn
- EnvVarDependencies []string
-
- // rawTask.PassthroughEnv
- PassthroughEnv []string
-
- // TopologicalDependencies are tasks from package dependencies.
- // E.g. "build" is a topological dependency in:
- // dependsOn: ['^build'].
- // This field is custom-marshalled from rawTask.DependsOn
- TopologicalDependencies []string
-
- // TaskDependencies are anything that is not a topological dependency
- // E.g. both something and //whatever are TaskDependencies in:
- // dependsOn: ['something', '//whatever']
- // This field is custom-marshalled from rawTask.DependsOn
- TaskDependencies []string
-
- // Inputs indicate the list of files this Task depends on. If any of those files change
- // we can conclude that any cached outputs or logs for this Task should be invalidated.
- Inputs []string
-
- // OutputMode determins how we should log the output.
- OutputMode util.TaskOutputMode
-
- // Persistent indicates whether the Task is expected to exit or not
- // Tasks marked Persistent do not exit (e.g. --watch mode or dev servers)
- Persistent bool
-}
-
-// GetTask returns a TaskDefinition based on the ID (package#task format) or name (e.g. "build")
-func (pc Pipeline) GetTask(taskID string, taskName string) (*BookkeepingTaskDefinition, error) {
- // first check for package-tasks
- taskDefinition, ok := pc[taskID]
- if !ok {
- // then check for regular tasks
- fallbackTaskDefinition, notcool := pc[taskName]
- // if neither, then bail
- if !notcool {
- // Return an empty TaskDefinition
- return nil, fmt.Errorf("Could not find task \"%s\" in pipeline", taskID)
- }
-
- // override if we need to...
- taskDefinition = fallbackTaskDefinition
- }
-
- return &taskDefinition, nil
-}
-
-// LoadTurboConfig loads, or optionally, synthesizes a TurboJSON instance
-func LoadTurboConfig(dir turbopath.AbsoluteSystemPath, rootPackageJSON *PackageJSON, includeSynthesizedFromRootPackageJSON bool) (*TurboJSON, error) {
- // If the root package.json stil has a `turbo` key, log a warning and remove it.
- if rootPackageJSON.LegacyTurboConfig != nil {
- log.Printf("[WARNING] \"turbo\" in package.json is no longer supported. Migrate to %s by running \"npx @turbo/codemod create-turbo-config\"\n", configFile)
- rootPackageJSON.LegacyTurboConfig = nil
- }
-
- var turboJSON *TurboJSON
- turboFromFiles, err := readTurboConfig(dir.UntypedJoin(configFile))
-
- if !includeSynthesizedFromRootPackageJSON && err != nil {
- // If the file didn't exist, throw a custom error here instead of propagating
- if errors.Is(err, os.ErrNotExist) {
- return nil, errors.Wrap(err, fmt.Sprintf("Could not find %s. Follow directions at https://turbo.build/repo/docs to create one", configFile))
-
- }
-
- // There was an error, and we don't have any chance of recovering
- // because we aren't synthesizing anything
- return nil, err
- } else if !includeSynthesizedFromRootPackageJSON {
- // We're not synthesizing anything and there was no error, we're done
- return turboFromFiles, nil
- } else if errors.Is(err, os.ErrNotExist) {
- // turbo.json doesn't exist, but we're going try to synthesize something
- turboJSON = &TurboJSON{
- Pipeline: make(Pipeline),
- }
- } else if err != nil {
- // some other happened, we can't recover
- return nil, err
- } else {
- // we're synthesizing, but we have a starting point
- // Note: this will have to change to support task inference in a monorepo
- // for now, we're going to error on any "root" tasks and turn non-root tasks into root tasks
- pipeline := make(Pipeline)
- for taskID, taskDefinition := range turboFromFiles.Pipeline {
- if util.IsPackageTask(taskID) {
- return nil, fmt.Errorf("Package tasks (<package>#<task>) are not allowed in single-package repositories: found %v", taskID)
- }
- pipeline[util.RootTaskID(taskID)] = taskDefinition
- }
- turboJSON = turboFromFiles
- turboJSON.Pipeline = pipeline
- }
-
- for scriptName := range rootPackageJSON.Scripts {
- if !turboJSON.Pipeline.HasTask(scriptName) {
- taskName := util.RootTaskID(scriptName)
- // Explicitly set ShouldCache to false in this definition and add the bookkeeping fields
- // so downstream we can pretend that it was set on purpose (as if read from a config file)
- // rather than defaulting to the 0-value of a boolean field.
- turboJSON.Pipeline[taskName] = BookkeepingTaskDefinition{
- definedFields: util.SetFromStrings([]string{"ShouldCache"}),
- TaskDefinition: taskDefinitionHashable{
- ShouldCache: false,
- },
- }
- }
- }
- return turboJSON, nil
-}
-
-// TurboJSONValidation is the signature for a validation function passed to Validate()
-type TurboJSONValidation func(*TurboJSON) []error
-
-// Validate calls an array of validation functions on the TurboJSON struct.
-// The validations can be customized by the caller.
-func (tj *TurboJSON) Validate(validations []TurboJSONValidation) []error {
- allErrors := []error{}
- for _, validation := range validations {
- errors := validation(tj)
- allErrors = append(allErrors, errors...)
- }
-
- return allErrors
-}
-
-// TaskOutputs represents the patterns for including and excluding files from outputs
-type TaskOutputs struct {
- Inclusions []string
- Exclusions []string
-}
-
-// Sort contents of task outputs
-func (to TaskOutputs) Sort() TaskOutputs {
- var inclusions []string
- var exclusions []string
- copy(inclusions, to.Inclusions)
- copy(exclusions, to.Exclusions)
- sort.Strings(inclusions)
- sort.Strings(exclusions)
- return TaskOutputs{Inclusions: inclusions, Exclusions: exclusions}
-}
-
-// readTurboConfig reads turbo.json from a provided path
-func readTurboConfig(turboJSONPath turbopath.AbsoluteSystemPath) (*TurboJSON, error) {
- // If the configFile exists, use that
- if turboJSONPath.FileExists() {
- turboJSON, err := readTurboJSON(turboJSONPath)
- if err != nil {
- return nil, fmt.Errorf("%s: %w", configFile, err)
- }
-
- return turboJSON, nil
- }
-
- // If there's no turbo.json, return an error.
- return nil, os.ErrNotExist
-}
-
-// readTurboJSON reads the configFile in to a struct
-func readTurboJSON(path turbopath.AbsoluteSystemPath) (*TurboJSON, error) {
- file, err := path.Open()
- if err != nil {
- return nil, err
- }
- var turboJSON *TurboJSON
- data, err := ioutil.ReadAll(file)
- if err != nil {
- return nil, err
- }
-
- err = jsonc.Unmarshal(data, &turboJSON)
-
- if err != nil {
- return nil, err
- }
-
- return turboJSON, nil
-}
-
-// GetTaskDefinition returns a TaskDefinition from a serialized definition in configFile
-func (pc Pipeline) GetTaskDefinition(taskID string) (TaskDefinition, bool) {
- if entry, ok := pc[taskID]; ok {
- return entry.GetTaskDefinition(), true
- }
- _, task := util.GetPackageTaskFromId(taskID)
- entry, ok := pc[task]
- return entry.GetTaskDefinition(), ok
-}
-
-// HasTask returns true if the given task is defined in the pipeline, either directly or
-// via a package task (`pkg#task`)
-func (pc Pipeline) HasTask(task string) bool {
- for key := range pc {
- if key == task {
- return true
- }
- if util.IsPackageTask(key) {
- _, taskName := util.GetPackageTaskFromId(key)
- if taskName == task {
- return true
- }
- }
- }
- return false
-}
-
-// Pristine returns a PristinePipeline, this is used for printing to console and pruning
-func (pc Pipeline) Pristine() PristinePipeline {
- pristine := PristinePipeline{}
- for taskName, taskDef := range pc {
- // If there are any experimental fields, we will include them with 0-values
- // if there aren't, we will omit them entirely
- if taskDef.hasExperimentalFields() {
- pristine[taskName] = taskDef.GetTaskDefinition() // merges experimental fields in
- } else {
- pristine[taskName] = taskDef.TaskDefinition // has no experimental fields
- }
- }
- return pristine
-}
-
-// hasField checks the internal bookkeeping definedFields field to
-// see whether a field was actually in the underlying turbo.json
-// or whether it was initialized with its 0-value.
-func (btd BookkeepingTaskDefinition) hasField(fieldName string) bool {
- return btd.definedFields.Includes(fieldName) || btd.experimentalFields.Includes(fieldName)
-}
-
-// hasExperimentalFields keeps track of whether any experimental fields were found
-func (btd BookkeepingTaskDefinition) hasExperimentalFields() bool {
- return len(btd.experimentalFields) > 0
-}
-
-// GetTaskDefinition gets a TaskDefinition by merging the experimental and non-experimental fields
-// into a single representation to use downstream.
-func (btd BookkeepingTaskDefinition) GetTaskDefinition() TaskDefinition {
- return TaskDefinition{
- Outputs: btd.TaskDefinition.Outputs,
- ShouldCache: btd.TaskDefinition.ShouldCache,
- EnvVarDependencies: btd.TaskDefinition.EnvVarDependencies,
- TopologicalDependencies: btd.TaskDefinition.TopologicalDependencies,
- TaskDependencies: btd.TaskDefinition.TaskDependencies,
- Inputs: btd.TaskDefinition.Inputs,
- OutputMode: btd.TaskDefinition.OutputMode,
- Persistent: btd.TaskDefinition.Persistent,
- // From experimental fields
- PassthroughEnv: btd.experimental.PassthroughEnv,
- }
-}
-
-// MergeTaskDefinitions accepts an array of BookkeepingTaskDefinitions and merges them into
-// a single TaskDefinition. It uses the bookkeeping definedFields to determine which fields should
-// be overwritten and when 0-values should be respected.
-func MergeTaskDefinitions(taskDefinitions []BookkeepingTaskDefinition) (*TaskDefinition, error) {
- // Start with an empty definition
- mergedTaskDefinition := &TaskDefinition{}
-
- // Set the default, because the 0-value will be false, and if no turbo.jsons had
- // this field set for this task, we want it to be true.
- mergedTaskDefinition.ShouldCache = true
-
- // For each of the TaskDefinitions we know of, merge them in
- for _, bookkeepingTaskDef := range taskDefinitions {
- taskDef := bookkeepingTaskDef.GetTaskDefinition()
-
- if bookkeepingTaskDef.hasField("Outputs") {
- mergedTaskDefinition.Outputs = taskDef.Outputs
- }
-
- if bookkeepingTaskDef.hasField("ShouldCache") {
- mergedTaskDefinition.ShouldCache = taskDef.ShouldCache
- }
-
- if bookkeepingTaskDef.hasField("EnvVarDependencies") {
- mergedTaskDefinition.EnvVarDependencies = taskDef.EnvVarDependencies
- }
-
- if bookkeepingTaskDef.hasField("PassthroughEnv") {
- mergedTaskDefinition.PassthroughEnv = taskDef.PassthroughEnv
- }
-
- if bookkeepingTaskDef.hasField("DependsOn") {
- mergedTaskDefinition.TopologicalDependencies = taskDef.TopologicalDependencies
- }
-
- if bookkeepingTaskDef.hasField("DependsOn") {
- mergedTaskDefinition.TaskDependencies = taskDef.TaskDependencies
- }
-
- if bookkeepingTaskDef.hasField("Inputs") {
- mergedTaskDefinition.Inputs = taskDef.Inputs
- }
-
- if bookkeepingTaskDef.hasField("OutputMode") {
- mergedTaskDefinition.OutputMode = taskDef.OutputMode
- }
- if bookkeepingTaskDef.hasField("Persistent") {
- mergedTaskDefinition.Persistent = taskDef.Persistent
- }
- }
-
- return mergedTaskDefinition, nil
-}
-
-// UnmarshalJSON deserializes a single task definition from
-// turbo.json into a TaskDefinition struct
-func (btd *BookkeepingTaskDefinition) UnmarshalJSON(data []byte) error {
- task := rawTask{}
- if err := json.Unmarshal(data, &task); err != nil {
- return err
- }
-
- btd.definedFields = util.Set{}
- btd.experimentalFields = util.Set{}
-
- if task.Outputs != nil {
- var inclusions []string
- var exclusions []string
- // Assign a bookkeeping field so we know that there really were
- // outputs configured in the underlying config file.
- btd.definedFields.Add("Outputs")
-
- for _, glob := range task.Outputs {
- if strings.HasPrefix(glob, "!") {
- if filepath.IsAbs(glob[1:]) {
- log.Printf("[WARNING] Using an absolute path in \"outputs\" (%v) will not work and will be an error in a future version", glob)
- }
- exclusions = append(exclusions, glob[1:])
- } else {
- if filepath.IsAbs(glob) {
- log.Printf("[WARNING] Using an absolute path in \"outputs\" (%v) will not work and will be an error in a future version", glob)
- }
- inclusions = append(inclusions, glob)
- }
- }
-
- btd.TaskDefinition.Outputs = TaskOutputs{
- Inclusions: inclusions,
- Exclusions: exclusions,
- }
-
- sort.Strings(btd.TaskDefinition.Outputs.Inclusions)
- sort.Strings(btd.TaskDefinition.Outputs.Exclusions)
- }
-
- if task.Cache == nil {
- btd.TaskDefinition.ShouldCache = true
- } else {
- btd.definedFields.Add("ShouldCache")
- btd.TaskDefinition.ShouldCache = *task.Cache
- }
-
- envVarDependencies := make(util.Set)
- envVarPassthroughs := make(util.Set)
-
- btd.TaskDefinition.TopologicalDependencies = []string{} // TODO @mehulkar: this should be a set
- btd.TaskDefinition.TaskDependencies = []string{} // TODO @mehulkar: this should be a set
-
- // If there was a dependsOn field, add the bookkeeping
- // we don't care what's in the field, just that it was there
- // We'll use this marker to overwrite while merging TaskDefinitions.
- if task.DependsOn != nil {
- btd.definedFields.Add("DependsOn")
- }
-
- for _, dependency := range task.DependsOn {
- if strings.HasPrefix(dependency, envPipelineDelimiter) {
- log.Printf("[DEPRECATED] Declaring an environment variable in \"dependsOn\" is deprecated, found %s. Use the \"env\" key or use `npx @turbo/codemod migrate-env-var-dependencies`.\n", dependency)
- envVarDependencies.Add(strings.TrimPrefix(dependency, envPipelineDelimiter))
- } else if strings.HasPrefix(dependency, topologicalPipelineDelimiter) {
- // Note: This will get assigned multiple times in the loop, but we only care that it's true
- btd.TaskDefinition.TopologicalDependencies = append(btd.TaskDefinition.TopologicalDependencies, strings.TrimPrefix(dependency, topologicalPipelineDelimiter))
- } else {
- btd.TaskDefinition.TaskDependencies = append(btd.TaskDefinition.TaskDependencies, dependency)
- }
- }
-
- sort.Strings(btd.TaskDefinition.TaskDependencies)
- sort.Strings(btd.TaskDefinition.TopologicalDependencies)
-
- // Append env key into EnvVarDependencies
- if task.Env != nil {
- btd.definedFields.Add("EnvVarDependencies")
- if err := gatherEnvVars(task.Env, "env", &envVarDependencies); err != nil {
- return err
- }
- }
-
- btd.TaskDefinition.EnvVarDependencies = envVarDependencies.UnsafeListOfStrings()
-
- sort.Strings(btd.TaskDefinition.EnvVarDependencies)
-
- if task.PassthroughEnv != nil {
- btd.experimentalFields.Add("PassthroughEnv")
- if err := gatherEnvVars(task.PassthroughEnv, "passthrougEnv", &envVarPassthroughs); err != nil {
- return err
- }
- }
-
- btd.experimental.PassthroughEnv = envVarPassthroughs.UnsafeListOfStrings()
- sort.Strings(btd.experimental.PassthroughEnv)
-
- if task.Inputs != nil {
- // Note that we don't require Inputs to be sorted, we're going to
- // hash the resulting files and sort that instead
- btd.definedFields.Add("Inputs")
- // TODO: during rust port, this should be moved to a post-parse validation step
- for _, input := range task.Inputs {
- if filepath.IsAbs(input) {
- log.Printf("[WARNING] Using an absolute path in \"inputs\" (%v) will not work and will be an error in a future version", input)
- }
- }
- btd.TaskDefinition.Inputs = task.Inputs
- }
-
- if task.OutputMode != nil {
- btd.definedFields.Add("OutputMode")
- btd.TaskDefinition.OutputMode = *task.OutputMode
- }
-
- if task.Persistent != nil {
- btd.definedFields.Add("Persistent")
- btd.TaskDefinition.Persistent = *task.Persistent
- } else {
- btd.TaskDefinition.Persistent = false
- }
- return nil
-}
-
-// MarshalJSON serializes taskDefinitionHashable struct into json
-func (c taskDefinitionHashable) MarshalJSON() ([]byte, error) {
- task := makeRawTask(
- c.Persistent,
- c.ShouldCache,
- c.OutputMode,
- c.Inputs,
- c.Outputs,
- c.EnvVarDependencies,
- c.TaskDependencies,
- c.TopologicalDependencies,
- )
- return json.Marshal(task)
-}
-
-// MarshalJSON serializes TaskDefinition struct into json
-func (c TaskDefinition) MarshalJSON() ([]byte, error) {
- task := makeRawTask(
- c.Persistent,
- c.ShouldCache,
- c.OutputMode,
- c.Inputs,
- c.Outputs,
- c.EnvVarDependencies,
- c.TaskDependencies,
- c.TopologicalDependencies,
- )
-
- if len(c.PassthroughEnv) > 0 {
- task.PassthroughEnv = append(task.PassthroughEnv, c.PassthroughEnv...)
- }
- sort.Strings(task.PassthroughEnv)
-
- return json.Marshal(task)
-}
-
-// UnmarshalJSON deserializes the contents of turbo.json into a TurboJSON struct
-func (c *TurboJSON) UnmarshalJSON(data []byte) error {
- raw := &rawTurboJSON{}
- if err := json.Unmarshal(data, &raw); err != nil {
- return err
- }
-
- envVarDependencies := make(util.Set)
- envVarPassthroughs := make(util.Set)
- globalFileDependencies := make(util.Set)
-
- if err := gatherEnvVars(raw.GlobalEnv, "globalEnv", &envVarDependencies); err != nil {
- return err
- }
- if err := gatherEnvVars(raw.GlobalPassthroughEnv, "experimentalGlobalPassThroughEnv", &envVarPassthroughs); err != nil {
- return err
- }
-
- // TODO: In the rust port, warnings should be refactored to a post-parse validation step
- for _, value := range raw.GlobalDependencies {
- if strings.HasPrefix(value, envPipelineDelimiter) {
- log.Printf("[DEPRECATED] Declaring an environment variable in \"globalDependencies\" is deprecated, found %s. Use the \"globalEnv\" key or use `npx @turbo/codemod migrate-env-var-dependencies`.\n", value)
- envVarDependencies.Add(strings.TrimPrefix(value, envPipelineDelimiter))
- } else {
- if filepath.IsAbs(value) {
- log.Printf("[WARNING] Using an absolute path in \"globalDependencies\" (%v) will not work and will be an error in a future version", value)
- }
- globalFileDependencies.Add(value)
- }
- }
-
- // turn the set into an array and assign to the TurboJSON struct fields.
- c.GlobalEnv = envVarDependencies.UnsafeListOfStrings()
- sort.Strings(c.GlobalEnv)
-
- if raw.GlobalPassthroughEnv != nil {
- c.GlobalPassthroughEnv = envVarPassthroughs.UnsafeListOfStrings()
- sort.Strings(c.GlobalPassthroughEnv)
- }
-
- c.GlobalDeps = globalFileDependencies.UnsafeListOfStrings()
- sort.Strings(c.GlobalDeps)
-
- // copy these over, we don't need any changes here.
- c.Pipeline = raw.Pipeline
- c.RemoteCacheOptions = raw.RemoteCacheOptions
- c.Extends = raw.Extends
-
- return nil
-}
-
-// MarshalJSON converts a TurboJSON into the equivalent json object in bytes
-// note: we go via rawTurboJSON so that the output format is correct.
-// This is used by `turbo prune` to generate a pruned turbo.json
-// and also by --summarize & --dry=json to serialize the known config
-// into something we can print to screen
-func (c *TurboJSON) MarshalJSON() ([]byte, error) {
- raw := pristineTurboJSON{}
- raw.GlobalDependencies = c.GlobalDeps
- raw.GlobalEnv = c.GlobalEnv
- raw.GlobalPassthroughEnv = c.GlobalPassthroughEnv
- raw.Pipeline = c.Pipeline.Pristine()
- raw.RemoteCacheOptions = c.RemoteCacheOptions
-
- return json.Marshal(&raw)
-}
-
-func makeRawTask(persistent bool, shouldCache bool, outputMode util.TaskOutputMode, inputs []string, outputs TaskOutputs, envVarDependencies []string, taskDependencies []string, topologicalDependencies []string) *rawTaskWithDefaults {
- // Initialize with empty arrays, so we get empty arrays serialized into JSON
- task := &rawTaskWithDefaults{
- Outputs: []string{},
- Inputs: []string{},
- Env: []string{},
- PassthroughEnv: []string{},
- DependsOn: []string{},
- }
-
- task.Persistent = persistent
- task.Cache = &shouldCache
- task.OutputMode = outputMode
-
- if len(inputs) > 0 {
- task.Inputs = inputs
- }
-
- if len(envVarDependencies) > 0 {
- task.Env = append(task.Env, envVarDependencies...)
- }
-
- if len(outputs.Inclusions) > 0 {
- task.Outputs = append(task.Outputs, outputs.Inclusions...)
- }
-
- for _, i := range outputs.Exclusions {
- task.Outputs = append(task.Outputs, "!"+i)
- }
-
- if len(taskDependencies) > 0 {
- task.DependsOn = append(task.DependsOn, taskDependencies...)
- }
-
- for _, i := range topologicalDependencies {
- task.DependsOn = append(task.DependsOn, "^"+i)
- }
-
- // These _should_ already be sorted when the TaskDefinition struct was unmarshaled,
- // but we want to ensure they're sorted on the way out also, just in case something
- // in the middle mutates the items.
- sort.Strings(task.DependsOn)
- sort.Strings(task.Outputs)
- sort.Strings(task.Env)
- sort.Strings(task.Inputs)
- return task
-}
-
-// gatherEnvVars puts env vars into the provided set as long as they don't have an invalid value.
-func gatherEnvVars(vars []string, key string, into *util.Set) error {
- for _, value := range vars {
- if strings.HasPrefix(value, envPipelineDelimiter) {
- // Hard error to help people specify this correctly during migration.
- // TODO: Remove this error after we have run summary.
- return fmt.Errorf("You specified \"%s\" in the \"%s\" key. You should not prefix your environment variables with \"%s\"", value, key, envPipelineDelimiter)
- }
-
- into.Add(value)
- }
-
- return nil
-}
diff --git a/cli/internal/fs/turbo_json_test.go b/cli/internal/fs/turbo_json_test.go
deleted file mode 100644
index 1d384d5..0000000
--- a/cli/internal/fs/turbo_json_test.go
+++ /dev/null
@@ -1,277 +0,0 @@
-package fs
-
-import (
- "os"
- "reflect"
- "sort"
- "strings"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "gotest.tools/v3/assert/cmp"
-)
-
-func assertIsSorted(t *testing.T, arr []string, msg string) {
- t.Helper()
- if arr == nil {
- return
- }
-
- copied := make([]string, len(arr))
- copy(copied, arr)
- sort.Strings(copied)
- if !reflect.DeepEqual(arr, copied) {
- t.Errorf("Expected sorted, got %v: %v", arr, msg)
- }
-}
-
-func Test_ReadTurboConfig(t *testing.T) {
- testDir := getTestDir(t, "correct")
- turboJSON, turboJSONReadErr := readTurboConfig(testDir.UntypedJoin("turbo.json"))
-
- if turboJSONReadErr != nil {
- t.Fatalf("invalid parse: %#v", turboJSONReadErr)
- }
-
- assert.EqualValues(t, []string{"AWS_SECRET_KEY"}, turboJSON.GlobalPassthroughEnv)
-
- pipelineExpected := map[string]BookkeepingTaskDefinition{
- "build": {
- definedFields: util.SetFromStrings([]string{"Outputs", "OutputMode", "DependsOn"}),
- experimentalFields: util.SetFromStrings([]string{"PassthroughEnv"}),
- experimental: taskDefinitionExperiments{
- PassthroughEnv: []string{"GITHUB_TOKEN"},
- },
- TaskDefinition: taskDefinitionHashable{
- Outputs: TaskOutputs{Inclusions: []string{".next/**", "dist/**"}, Exclusions: []string{"dist/assets/**"}},
- TopologicalDependencies: []string{"build"},
- EnvVarDependencies: []string{},
- TaskDependencies: []string{},
- ShouldCache: true,
- OutputMode: util.NewTaskOutput,
- },
- },
- "lint": {
- definedFields: util.SetFromStrings([]string{"Outputs", "OutputMode", "ShouldCache", "DependsOn"}),
- experimentalFields: util.SetFromStrings([]string{}),
- experimental: taskDefinitionExperiments{
- PassthroughEnv: []string{},
- },
- TaskDefinition: taskDefinitionHashable{
- Outputs: TaskOutputs{},
- TopologicalDependencies: []string{},
- EnvVarDependencies: []string{"MY_VAR"},
- TaskDependencies: []string{},
- ShouldCache: true,
- OutputMode: util.NewTaskOutput,
- },
- },
- "dev": {
- definedFields: util.SetFromStrings([]string{"OutputMode", "ShouldCache"}),
- experimentalFields: util.SetFromStrings([]string{}),
- experimental: taskDefinitionExperiments{
- PassthroughEnv: []string{},
- },
- TaskDefinition: taskDefinitionHashable{
- Outputs: TaskOutputs{},
- TopologicalDependencies: []string{},
- EnvVarDependencies: []string{},
- TaskDependencies: []string{},
- ShouldCache: false,
- OutputMode: util.FullTaskOutput,
- },
- },
- "publish": {
- definedFields: util.SetFromStrings([]string{"Inputs", "Outputs", "DependsOn", "ShouldCache"}),
- experimentalFields: util.SetFromStrings([]string{}),
- experimental: taskDefinitionExperiments{
- PassthroughEnv: []string{},
- },
- TaskDefinition: taskDefinitionHashable{
- Outputs: TaskOutputs{Inclusions: []string{"dist/**"}},
- TopologicalDependencies: []string{"build", "publish"},
- EnvVarDependencies: []string{},
- TaskDependencies: []string{"admin#lint", "build"},
- ShouldCache: false,
- Inputs: []string{"build/**/*"},
- OutputMode: util.FullTaskOutput,
- },
- },
- }
-
- validateOutput(t, turboJSON, pipelineExpected)
- remoteCacheOptionsExpected := RemoteCacheOptions{"team_id", true}
- assert.EqualValues(t, remoteCacheOptionsExpected, turboJSON.RemoteCacheOptions)
-}
-
-func Test_LoadTurboConfig_Legacy(t *testing.T) {
- testDir := getTestDir(t, "legacy-only")
- packageJSONPath := testDir.UntypedJoin("package.json")
- rootPackageJSON, pkgJSONReadErr := ReadPackageJSON(packageJSONPath)
-
- if pkgJSONReadErr != nil {
- t.Fatalf("invalid parse: %#v", pkgJSONReadErr)
- }
-
- _, turboJSONReadErr := LoadTurboConfig(testDir, rootPackageJSON, false)
- expectedErrorMsg := "Could not find turbo.json. Follow directions at https://turbo.build/repo/docs to create one: file does not exist"
- assert.EqualErrorf(t, turboJSONReadErr, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, turboJSONReadErr)
-}
-
-func Test_LoadTurboConfig_BothCorrectAndLegacy(t *testing.T) {
- testDir := getTestDir(t, "both")
-
- packageJSONPath := testDir.UntypedJoin("package.json")
- rootPackageJSON, pkgJSONReadErr := ReadPackageJSON(packageJSONPath)
-
- if pkgJSONReadErr != nil {
- t.Fatalf("invalid parse: %#v", pkgJSONReadErr)
- }
-
- turboJSON, turboJSONReadErr := LoadTurboConfig(testDir, rootPackageJSON, false)
-
- if turboJSONReadErr != nil {
- t.Fatalf("invalid parse: %#v", turboJSONReadErr)
- }
-
- pipelineExpected := map[string]BookkeepingTaskDefinition{
- "build": {
- definedFields: util.SetFromStrings([]string{"Outputs", "OutputMode", "DependsOn"}),
- experimentalFields: util.SetFromStrings([]string{}),
- experimental: taskDefinitionExperiments{
- PassthroughEnv: []string{},
- },
- TaskDefinition: taskDefinitionHashable{
- Outputs: TaskOutputs{Inclusions: []string{".next/**", "dist/**"}, Exclusions: []string{"dist/assets/**"}},
- TopologicalDependencies: []string{"build"},
- EnvVarDependencies: []string{},
- TaskDependencies: []string{},
- ShouldCache: true,
- OutputMode: util.NewTaskOutput,
- },
- },
- }
-
- validateOutput(t, turboJSON, pipelineExpected)
-
- remoteCacheOptionsExpected := RemoteCacheOptions{"team_id", true}
- assert.EqualValues(t, remoteCacheOptionsExpected, turboJSON.RemoteCacheOptions)
- assert.Equal(t, rootPackageJSON.LegacyTurboConfig == nil, true)
-}
-
-func Test_ReadTurboConfig_InvalidEnvDeclarations1(t *testing.T) {
- testDir := getTestDir(t, "invalid-env-1")
- _, turboJSONReadErr := readTurboConfig(testDir.UntypedJoin("turbo.json"))
-
- expectedErrorMsg := "turbo.json: You specified \"$A\" in the \"env\" key. You should not prefix your environment variables with \"$\""
- assert.EqualErrorf(t, turboJSONReadErr, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, turboJSONReadErr)
-}
-
-func Test_ReadTurboConfig_InvalidEnvDeclarations2(t *testing.T) {
- testDir := getTestDir(t, "invalid-env-2")
- _, turboJSONReadErr := readTurboConfig(testDir.UntypedJoin("turbo.json"))
- expectedErrorMsg := "turbo.json: You specified \"$A\" in the \"env\" key. You should not prefix your environment variables with \"$\""
- assert.EqualErrorf(t, turboJSONReadErr, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, turboJSONReadErr)
-}
-
-func Test_ReadTurboConfig_InvalidGlobalEnvDeclarations(t *testing.T) {
- testDir := getTestDir(t, "invalid-global-env")
- _, turboJSONReadErr := readTurboConfig(testDir.UntypedJoin("turbo.json"))
- expectedErrorMsg := "turbo.json: You specified \"$QUX\" in the \"globalEnv\" key. You should not prefix your environment variables with \"$\""
- assert.EqualErrorf(t, turboJSONReadErr, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, turboJSONReadErr)
-}
-
-func Test_ReadTurboConfig_EnvDeclarations(t *testing.T) {
- testDir := getTestDir(t, "legacy-env")
- turboJSON, turboJSONReadErr := readTurboConfig(testDir.UntypedJoin("turbo.json"))
-
- if turboJSONReadErr != nil {
- t.Fatalf("invalid parse: %#v", turboJSONReadErr)
- }
-
- pipeline := turboJSON.Pipeline
- assert.EqualValues(t, pipeline["task1"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A"}))
- assert.EqualValues(t, pipeline["task2"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A"}))
- assert.EqualValues(t, pipeline["task3"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A"}))
- assert.EqualValues(t, pipeline["task4"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A", "B"}))
- assert.EqualValues(t, pipeline["task6"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A", "B", "C", "D", "E", "F"}))
- assert.EqualValues(t, pipeline["task7"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A", "B", "C"}))
- assert.EqualValues(t, pipeline["task8"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A", "B", "C"}))
- assert.EqualValues(t, pipeline["task9"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A"}))
- assert.EqualValues(t, pipeline["task10"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A"}))
- assert.EqualValues(t, pipeline["task11"].TaskDefinition.EnvVarDependencies, sortedArray([]string{"A", "B"}))
-
- // check global env vars also
- assert.EqualValues(t, sortedArray([]string{"FOO", "BAR", "BAZ", "QUX"}), sortedArray(turboJSON.GlobalEnv))
- assert.EqualValues(t, sortedArray([]string{"somefile.txt"}), sortedArray(turboJSON.GlobalDeps))
-}
-
-func Test_TaskOutputsSort(t *testing.T) {
- inclusions := []string{"foo/**", "bar"}
- exclusions := []string{"special-file", ".hidden/**"}
- taskOutputs := TaskOutputs{Inclusions: inclusions, Exclusions: exclusions}
- sortedOutputs := taskOutputs.Sort()
- assertIsSorted(t, sortedOutputs.Inclusions, "Inclusions")
- assertIsSorted(t, sortedOutputs.Exclusions, "Exclusions")
- assert.False(t, cmp.DeepEqual(taskOutputs, sortedOutputs)().Success())
-}
-
-// Helpers
-func validateOutput(t *testing.T, turboJSON *TurboJSON, expectedPipeline Pipeline) {
- t.Helper()
- assertIsSorted(t, turboJSON.GlobalDeps, "Global Deps")
- assertIsSorted(t, turboJSON.GlobalEnv, "Global Env")
- validatePipeline(t, turboJSON.Pipeline, expectedPipeline)
-}
-
-func validatePipeline(t *testing.T, actual Pipeline, expected Pipeline) {
- t.Helper()
- // check top level keys
- if len(actual) != len(expected) {
- expectedKeys := []string{}
- for k := range expected {
- expectedKeys = append(expectedKeys, k)
- }
- actualKeys := []string{}
- for k := range actual {
- actualKeys = append(actualKeys, k)
- }
- t.Errorf("pipeline tasks mismatch. got %v, want %v", strings.Join(actualKeys, ","), strings.Join(expectedKeys, ","))
- }
-
- // check individual task definitions
- for taskName, expectedTaskDefinition := range expected {
- bookkeepingTaskDef, ok := actual[taskName]
- if !ok {
- t.Errorf("missing expected task: %v", taskName)
- }
- actualTaskDefinition := bookkeepingTaskDef.GetTaskDefinition()
- assertIsSorted(t, actualTaskDefinition.Outputs.Inclusions, "Task output inclusions")
- assertIsSorted(t, actualTaskDefinition.Outputs.Exclusions, "Task output exclusions")
- assertIsSorted(t, actualTaskDefinition.EnvVarDependencies, "Task env vars")
- assertIsSorted(t, actualTaskDefinition.PassthroughEnv, "Task env vars")
- assertIsSorted(t, actualTaskDefinition.TopologicalDependencies, "Topo deps")
- assertIsSorted(t, actualTaskDefinition.TaskDependencies, "Task deps")
- assert.EqualValuesf(t, expectedTaskDefinition, bookkeepingTaskDef, "task definition mismatch for %v", taskName)
- }
-}
-
-func getTestDir(t *testing.T, testName string) turbopath.AbsoluteSystemPath {
- defaultCwd, err := os.Getwd()
- if err != nil {
- t.Errorf("failed to get cwd: %v", err)
- }
- cwd, err := CheckedToAbsoluteSystemPath(defaultCwd)
- if err != nil {
- t.Fatalf("cwd is not an absolute directory %v: %v", defaultCwd, err)
- }
-
- return cwd.UntypedJoin("testdata", testName)
-}
-
-func sortedArray(arr []string) []string {
- sort.Strings(arr)
- return arr
-}
diff --git a/cli/internal/globby/globby.go b/cli/internal/globby/globby.go
deleted file mode 100644
index 14c40d9..0000000
--- a/cli/internal/globby/globby.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package globby
-
-import (
- "fmt"
- "path/filepath"
- "sort"
- "strings"
-
- iofs "io/fs"
-
- "github.com/vercel/turbo/cli/internal/fs"
-
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// GlobAll returns an array of files and folders that match the specified set of glob patterns.
-// The returned files and folders are absolute paths, assuming that basePath is an absolute path.
-func GlobAll(basePath string, includePatterns []string, excludePatterns []string) ([]string, error) {
- fsys := fs.CreateDirFSAtRoot(basePath)
- fsysRoot := fs.GetDirFSRootPath(fsys)
- output, err := globAllFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns)
-
- // Because this is coming out of a map output is in no way ordered.
- // Sorting will put the files in a depth-first order.
- sort.Strings(output)
- return output, err
-}
-
-// GlobFiles returns an array of files that match the specified set of glob patterns.
-// The return files are absolute paths, assuming that basePath is an absolute path.
-func GlobFiles(basePath string, includePatterns []string, excludePatterns []string) ([]string, error) {
- fsys := fs.CreateDirFSAtRoot(basePath)
- fsysRoot := fs.GetDirFSRootPath(fsys)
- output, err := globFilesFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns)
-
- // Because this is coming out of a map output is in no way ordered.
- // Sorting will put the files in a depth-first order.
- sort.Strings(output)
- return output, err
-}
-
-// checkRelativePath ensures that the the requested file path is a child of `from`.
-func checkRelativePath(from string, to string) error {
- relativePath, err := filepath.Rel(from, to)
-
- if err != nil {
- return err
- }
-
- if strings.HasPrefix(relativePath, "..") {
- return fmt.Errorf("the path you are attempting to specify (%s) is outside of the root", to)
- }
-
- return nil
-}
-
-// globFilesFs searches the specified file system to enumerate all files to include.
-func globFilesFs(fsys iofs.FS, fsysRoot string, basePath string, includePatterns []string, excludePatterns []string) ([]string, error) {
- return globWalkFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns, false)
-}
-
-// globAllFs searches the specified file system to enumerate all files to include.
-func globAllFs(fsys iofs.FS, fsysRoot string, basePath string, includePatterns []string, excludePatterns []string) ([]string, error) {
- return globWalkFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns, true)
-}
-
-// globWalkFs searches the specified file system to enumerate all files and folders to include.
-func globWalkFs(fsys iofs.FS, fsysRoot string, basePath string, includePatterns []string, excludePatterns []string, includeDirs bool) ([]string, error) {
- var processedIncludes []string
- var processedExcludes []string
- result := make(util.Set)
-
- for _, includePattern := range includePatterns {
- includePath := filepath.Join(basePath, includePattern)
- err := checkRelativePath(basePath, includePath)
-
- if err != nil {
- return nil, err
- }
-
- // fs.FS paths may not include leading separators. Calculate the
- // correct path for this relative to the filesystem root.
- // This will not error as it follows the call to checkRelativePath.
- iofsRelativePath, _ := fs.IofsRelativePath(fsysRoot, includePath)
-
- // Includes only operate on files.
- processedIncludes = append(processedIncludes, iofsRelativePath)
- }
-
- for _, excludePattern := range excludePatterns {
- excludePath := filepath.Join(basePath, excludePattern)
- err := checkRelativePath(basePath, excludePath)
-
- if err != nil {
- return nil, err
- }
-
- // fs.FS paths may not include leading separators. Calculate the
- // correct path for this relative to the filesystem root.
- // This will not error as it follows the call to checkRelativePath.
- iofsRelativePath, _ := fs.IofsRelativePath(fsysRoot, excludePath)
-
- // In case this is a file pattern and not a directory, add the exact pattern.
- // In the event that the user has already specified /**,
- if !strings.HasSuffix(iofsRelativePath, string(filepath.Separator)+"**") {
- processedExcludes = append(processedExcludes, iofsRelativePath)
- }
- // TODO: we need to either document or change this behavior
- // Excludes operate on entire folders, so we also exclude everything under this in case it represents a directory
- processedExcludes = append(processedExcludes, filepath.Join(iofsRelativePath, "**"))
- }
-
- // We start from a naive includePattern
- includePattern := ""
- includeCount := len(processedIncludes)
-
- // Do not use alternation if unnecessary.
- if includeCount == 1 {
- includePattern = processedIncludes[0]
- } else if includeCount > 1 {
- // We use alternation from the very root of the path. This avoids fs.Stat of the basePath.
- includePattern = "{" + strings.Join(processedIncludes, ",") + "}"
- }
-
- // We start with an empty string excludePattern which we only use if excludeCount > 0.
- excludePattern := ""
- excludeCount := len(processedExcludes)
-
- // Do not use alternation if unnecessary.
- if excludeCount == 1 {
- excludePattern = processedExcludes[0]
- } else if excludeCount > 1 {
- // We use alternation from the very root of the path. This avoids fs.Stat of the basePath.
- excludePattern = "{" + strings.Join(processedExcludes, ",") + "}"
- }
-
- // GlobWalk expects that everything uses Unix path conventions.
- includePattern = filepath.ToSlash(includePattern)
- excludePattern = filepath.ToSlash(excludePattern)
-
- err := doublestar.GlobWalk(fsys, includePattern, func(path string, dirEntry iofs.DirEntry) error {
- if !includeDirs && dirEntry.IsDir() {
- return nil
- }
-
- // All files that are returned by doublestar.GlobWalk are relative to
- // the fsys root. Go, however, has decided that `fs.FS` filesystems do
- // not address the root of the file system using `/` and instead use
- // paths without leading separators.
- //
- // We need to track where the `fsys` root is so that when we hand paths back
- // we hand them back as the path addressable in the actual OS filesystem.
- //
- // As a consequence, when processing, we need to *restore* the original
- // root to the file path after returning. This works because when we create
- // the `os.dirFS` filesystem we do so at the root of the current volume.
- if excludeCount == 0 {
- // Reconstruct via string concatenation since the root is already pre-composed.
- result.Add(fsysRoot + path)
- return nil
- }
-
- isExcluded, err := doublestar.Match(excludePattern, filepath.ToSlash(path))
- if err != nil {
- return err
- }
-
- if !isExcluded {
- // Reconstruct via string concatenation since the root is already pre-composed.
- result.Add(fsysRoot + path)
- }
-
- return nil
- })
-
- // GlobWalk threw an error.
- if err != nil {
- return nil, err
- }
-
- // Never actually capture the root folder.
- // This is a risk because of how we rework the globs.
- result.Delete(strings.TrimSuffix(basePath, "/"))
-
- return result.UnsafeListOfStrings(), nil
-}
diff --git a/cli/internal/globby/globby_test.go b/cli/internal/globby/globby_test.go
deleted file mode 100644
index 2fdd613..0000000
--- a/cli/internal/globby/globby_test.go
+++ /dev/null
@@ -1,832 +0,0 @@
-package globby
-
-import (
- "io/fs"
- "path/filepath"
- "reflect"
- "sort"
- "testing"
-
- "testing/fstest"
-)
-
-// setup prepares the test file system contents and returns the file system.
-func setup(fsysRoot string, files []string) fs.FS {
- fsys := fstest.MapFS{}
- for _, file := range files {
- // We're populating a `fs.FS` filesytem which requires paths to have no
- // leading slash. As a consequence we strip it during creation.
- iofsRelativePath := file[1:]
-
- fsys[iofsRelativePath] = &fstest.MapFile{Mode: 0666}
- }
-
- return fsys
-}
-
-func TestGlobFilesFs(t *testing.T) {
- type args struct {
- basePath string
- includePatterns []string
- excludePatterns []string
- }
- tests := []struct {
- name string
- files []string
- args args
- wantAll []string
- wantFiles []string
- wantErr bool
- }{
- {
- name: "hello world",
- files: []string{"/test.txt"},
- args: args{
- basePath: "/",
- includePatterns: []string{"*.txt"},
- excludePatterns: []string{},
- },
- wantAll: []string{"/test.txt"},
- wantFiles: []string{"/test.txt"},
- },
- {
- name: "bullet files",
- files: []string{
- "/test.txt",
- "/subdir/test.txt",
- "/other/test.txt",
- },
- args: args{
- basePath: "/",
- includePatterns: []string{"subdir/test.txt", "test.txt"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/subdir/test.txt",
- "/test.txt",
- },
- wantFiles: []string{
- "/subdir/test.txt",
- "/test.txt",
- },
- },
- {
- name: "finding workspace package.json files",
- files: []string{
- "/external/file.txt",
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/bower_components/readline/package.json",
- "/repos/some-app/examples/package.json",
- "/repos/some-app/node_modules/gulp/bower_components/readline/package.json",
- "/repos/some-app/node_modules/react/package.json",
- "/repos/some-app/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/test/mocks/kitchen-sink/package.json",
- "/repos/some-app/tests/mocks/kitchen-sink/package.json",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"packages/*/package.json", "apps/*/package.json"},
- excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"},
- },
- wantAll: []string{
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- },
- wantFiles: []string{
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- },
- },
- {
- name: "excludes unexpected workspace package.json files",
- files: []string{
- "/external/file.txt",
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/bower_components/readline/package.json",
- "/repos/some-app/examples/package.json",
- "/repos/some-app/node_modules/gulp/bower_components/readline/package.json",
- "/repos/some-app/node_modules/react/package.json",
- "/repos/some-app/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/test/mocks/spanish-inquisition/package.json",
- "/repos/some-app/tests/mocks/spanish-inquisition/package.json",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**/package.json"},
- excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"},
- },
- wantAll: []string{
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/examples/package.json",
- "/repos/some-app/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- },
- wantFiles: []string{
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/examples/package.json",
- "/repos/some-app/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- },
- },
- {
- name: "nested packages work",
- files: []string{
- "/external/file.txt",
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/bower_components/readline/package.json",
- "/repos/some-app/examples/package.json",
- "/repos/some-app/node_modules/gulp/bower_components/readline/package.json",
- "/repos/some-app/node_modules/react/package.json",
- "/repos/some-app/package.json",
- "/repos/some-app/packages/xzibit/package.json",
- "/repos/some-app/packages/xzibit/node_modules/street-legal/package.json",
- "/repos/some-app/packages/xzibit/node_modules/paint-colors/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/meme/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/yo-dawg/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/test/mocks/spanish-inquisition/package.json",
- "/repos/some-app/tests/mocks/spanish-inquisition/package.json",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"packages/**/package.json"},
- excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"},
- },
- wantAll: []string{
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/packages/xzibit/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json",
- },
- wantFiles: []string{
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/packages/xzibit/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json",
- },
- },
- {
- name: "includes do not override excludes",
- files: []string{
- "/external/file.txt",
- "/repos/some-app/apps/docs/package.json",
- "/repos/some-app/apps/web/package.json",
- "/repos/some-app/bower_components/readline/package.json",
- "/repos/some-app/examples/package.json",
- "/repos/some-app/node_modules/gulp/bower_components/readline/package.json",
- "/repos/some-app/node_modules/react/package.json",
- "/repos/some-app/package.json",
- "/repos/some-app/packages/xzibit/package.json",
- "/repos/some-app/packages/xzibit/node_modules/street-legal/package.json",
- "/repos/some-app/packages/xzibit/node_modules/paint-colors/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/meme/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/yo-dawg/package.json",
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/test/mocks/spanish-inquisition/package.json",
- "/repos/some-app/tests/mocks/spanish-inquisition/package.json",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"packages/**/package.json", "tests/mocks/*/package.json"},
- excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"},
- },
- wantAll: []string{
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/packages/xzibit/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json",
- },
- wantFiles: []string{
- "/repos/some-app/packages/colors/package.json",
- "/repos/some-app/packages/faker/package.json",
- "/repos/some-app/packages/left-pad/package.json",
- "/repos/some-app/packages/xzibit/package.json",
- "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json",
- },
- },
- {
- name: "output globbing grabs the desired content",
- files: []string{
- "/external/file.txt",
- "/repos/some-app/src/index.js",
- "/repos/some-app/public/src/css/index.css",
- "/repos/some-app/.turbo/turbo-build.log",
- "/repos/some-app/.turbo/somebody-touched-this-file-into-existence.txt",
- "/repos/some-app/.next/log.txt",
- "/repos/some-app/.next/cache/db6a76a62043520e7aaadd0bb2104e78.txt",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- "/repos/some-app/public/dist/css/index.css",
- "/repos/some-app/public/dist/images/rick_astley.jpg",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{".turbo/turbo-build.log", "dist/**", ".next/**", "public/dist/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/.next",
- "/repos/some-app/.next/cache",
- "/repos/some-app/.next/cache/db6a76a62043520e7aaadd0bb2104e78.txt",
- "/repos/some-app/.next/log.txt",
- "/repos/some-app/.turbo/turbo-build.log",
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- "/repos/some-app/public/dist",
- "/repos/some-app/public/dist/css",
- "/repos/some-app/public/dist/css/index.css",
- "/repos/some-app/public/dist/images",
- "/repos/some-app/public/dist/images/rick_astley.jpg",
- },
- wantFiles: []string{
- "/repos/some-app/.next/cache/db6a76a62043520e7aaadd0bb2104e78.txt",
- "/repos/some-app/.next/log.txt",
- "/repos/some-app/.turbo/turbo-build.log",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- "/repos/some-app/public/dist/css/index.css",
- "/repos/some-app/public/dist/images/rick_astley.jpg",
- },
- },
- {
- name: "passing ** captures all children",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"dist/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- },
- {
- name: "passing just a directory captures no children",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"dist"},
- excludePatterns: []string{},
- },
- wantAll: []string{"/repos/some-app/dist"},
- wantFiles: []string{},
- },
- {
- name: "redundant includes do not duplicate",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**/*", "dist/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- },
- {
- name: "exclude everything, include everything",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**"},
- excludePatterns: []string{"**"},
- },
- wantAll: []string{},
- wantFiles: []string{},
- },
- {
- name: "passing just a directory to exclude prevents capture of children",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"dist/**"},
- excludePatterns: []string{"dist/js"},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- },
- },
- {
- name: "passing ** to exclude prevents capture of children",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"dist/**"},
- excludePatterns: []string{"dist/js/**"},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- },
- },
- {
- name: "exclude everything with folder . applies at base path",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**"},
- excludePatterns: []string{"./"},
- },
- wantAll: []string{},
- wantFiles: []string{},
- },
- {
- name: "exclude everything with traversal applies at a non-base path",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**"},
- excludePatterns: []string{"./dist"},
- },
- wantAll: []string{},
- wantFiles: []string{},
- },
- {
- name: "exclude everything with folder traversal (..) applies at base path",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**"},
- excludePatterns: []string{"dist/../"},
- },
- wantAll: []string{},
- wantFiles: []string{},
- },
- {
- name: "how do globs even work bad glob microformat",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**/**/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- },
- {
- name: "directory traversal stops at base path",
- files: []string{
- "/repos/spanish-inquisition/index.html",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"../spanish-inquisition/**", "dist/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{},
- wantFiles: []string{},
- wantErr: true,
- },
- {
- name: "globs and traversal and globs do not cross base path",
- files: []string{
- "/repos/spanish-inquisition/index.html",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**/../../spanish-inquisition/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{},
- wantFiles: []string{},
- wantErr: true,
- },
- {
- name: "traversal works within base path",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"dist/js/../**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- },
- {
- name: "self-references (.) work",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"dist/./././**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- },
- {
- name: "depth of 1 includes handles folders properly",
- files: []string{
- "/repos/some-app/package.json",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"*"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/package.json",
- },
- wantFiles: []string{"/repos/some-app/package.json"},
- },
- {
- name: "depth of 1 excludes prevents capturing folders",
- files: []string{
- "/repos/some-app/package.json",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app/",
- includePatterns: []string{"**"},
- excludePatterns: []string{"dist/*"},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/package.json",
- },
- wantFiles: []string{"/repos/some-app/package.json"},
- },
- {
- name: "No-trailing slash basePath works",
- files: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"dist/**"},
- excludePatterns: []string{},
- },
- wantAll: []string{
- "/repos/some-app/dist",
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- wantFiles: []string{
- "/repos/some-app/dist/index.html",
- "/repos/some-app/dist/js/index.js",
- "/repos/some-app/dist/js/lib.js",
- "/repos/some-app/dist/js/node_modules/browserify.js",
- },
- },
- {
- name: "exclude single file",
- files: []string{
- "/repos/some-app/included.txt",
- "/repos/some-app/excluded.txt",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"*.txt"},
- excludePatterns: []string{"excluded.txt"},
- },
- wantAll: []string{
- "/repos/some-app/included.txt",
- },
- wantFiles: []string{
- "/repos/some-app/included.txt",
- },
- },
- {
- name: "exclude nested single file",
- files: []string{
- "/repos/some-app/one/included.txt",
- "/repos/some-app/one/two/included.txt",
- "/repos/some-app/one/two/three/included.txt",
- "/repos/some-app/one/excluded.txt",
- "/repos/some-app/one/two/excluded.txt",
- "/repos/some-app/one/two/three/excluded.txt",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"**"},
- excludePatterns: []string{"**/excluded.txt"},
- },
- wantAll: []string{
- "/repos/some-app/one/included.txt",
- "/repos/some-app/one/two/included.txt",
- "/repos/some-app/one/two/three/included.txt",
- "/repos/some-app/one",
- "/repos/some-app/one/two",
- "/repos/some-app/one/two/three",
- },
- wantFiles: []string{
- "/repos/some-app/one/included.txt",
- "/repos/some-app/one/two/included.txt",
- "/repos/some-app/one/two/three/included.txt",
- },
- },
- {
- name: "exclude everything",
- files: []string{
- "/repos/some-app/one/included.txt",
- "/repos/some-app/one/two/included.txt",
- "/repos/some-app/one/two/three/included.txt",
- "/repos/some-app/one/excluded.txt",
- "/repos/some-app/one/two/excluded.txt",
- "/repos/some-app/one/two/three/excluded.txt",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"**"},
- excludePatterns: []string{"**"},
- },
- wantAll: []string{},
- wantFiles: []string{},
- },
- {
- name: "exclude everything with slash",
- files: []string{
- "/repos/some-app/one/included.txt",
- "/repos/some-app/one/two/included.txt",
- "/repos/some-app/one/two/three/included.txt",
- "/repos/some-app/one/excluded.txt",
- "/repos/some-app/one/two/excluded.txt",
- "/repos/some-app/one/two/three/excluded.txt",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"**"},
- excludePatterns: []string{"**/"},
- },
- wantAll: []string{},
- wantFiles: []string{},
- },
- {
- name: "exclude everything with leading **",
- files: []string{
- "/repos/some-app/foo/bar",
- "/repos/some-app/some-foo",
- "/repos/some-app/some-foo/bar",
- "/repos/some-app/included",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"**"},
- excludePatterns: []string{"**foo"},
- },
- wantAll: []string{
- "/repos/some-app/included",
- },
- wantFiles: []string{
- "/repos/some-app/included",
- },
- },
- {
- name: "exclude everything with trailing **",
- files: []string{
- "/repos/some-app/foo/bar",
- "/repos/some-app/foo-file",
- "/repos/some-app/foo-dir/bar",
- "/repos/some-app/included",
- },
- args: args{
- basePath: "/repos/some-app",
- includePatterns: []string{"**"},
- excludePatterns: []string{"foo**"},
- },
- wantAll: []string{
- "/repos/some-app/included",
- },
- wantFiles: []string{
- "/repos/some-app/included",
- },
- },
- }
- for _, tt := range tests {
- fsysRoot := "/"
- fsys := setup(fsysRoot, tt.files)
-
- t.Run(tt.name, func(t *testing.T) {
- got, err := globFilesFs(fsys, fsysRoot, tt.args.basePath, tt.args.includePatterns, tt.args.excludePatterns)
-
- if (err != nil) != tt.wantErr {
- t.Errorf("globFilesFs() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
-
- gotToSlash := make([]string, len(got))
- for index, path := range got {
- gotToSlash[index] = filepath.ToSlash(path)
- }
-
- sort.Strings(gotToSlash)
-
- if !reflect.DeepEqual(gotToSlash, tt.wantFiles) {
- t.Errorf("globFilesFs() = %v, want %v", gotToSlash, tt.wantFiles)
- }
- })
-
- t.Run(tt.name, func(t *testing.T) {
- got, err := globAllFs(fsys, fsysRoot, tt.args.basePath, tt.args.includePatterns, tt.args.excludePatterns)
-
- if (err != nil) != tt.wantErr {
- t.Errorf("globAllFs() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
-
- gotToSlash := make([]string, len(got))
- for index, path := range got {
- gotToSlash[index] = filepath.ToSlash(path)
- }
-
- sort.Strings(gotToSlash)
- sort.Strings(tt.wantAll)
-
- if !reflect.DeepEqual(gotToSlash, tt.wantAll) {
- t.Errorf("globAllFs() = %v, want %v", gotToSlash, tt.wantAll)
- }
- })
- }
-}
diff --git a/cli/internal/globwatcher/globwatcher.go b/cli/internal/globwatcher/globwatcher.go
deleted file mode 100644
index 9226cfa..0000000
--- a/cli/internal/globwatcher/globwatcher.go
+++ /dev/null
@@ -1,210 +0,0 @@
-package globwatcher
-
-import (
- "errors"
- "fmt"
- "path/filepath"
- "sync"
-
- "github.com/hashicorp/go-hclog"
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/filewatcher"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// ErrClosed is returned when attempting to get changed globs after glob watching has closed
-var ErrClosed = errors.New("glob watching is closed")
-
-type globs struct {
- Inclusions util.Set
- Exclusions util.Set
-}
-
-// GlobWatcher is used to track unchanged globs by hash. Once a glob registers a file change
-// it is no longer tracked until a new hash requests it. Once all globs for a particular hash
-// have changed, that hash is no longer tracked.
-type GlobWatcher struct {
- logger hclog.Logger
- repoRoot turbopath.AbsoluteSystemPath
- cookieWaiter filewatcher.CookieWaiter
-
- mu sync.RWMutex // protects field below
- hashGlobs map[string]globs
- globStatus map[string]util.Set // glob -> hashes where this glob hasn't changed
-
- closed bool
-}
-
-// New returns a new GlobWatcher instance
-func New(logger hclog.Logger, repoRoot turbopath.AbsoluteSystemPath, cookieWaiter filewatcher.CookieWaiter) *GlobWatcher {
- return &GlobWatcher{
- logger: logger,
- repoRoot: repoRoot,
- cookieWaiter: cookieWaiter,
- hashGlobs: make(map[string]globs),
- globStatus: make(map[string]util.Set),
- }
-}
-
-func (g *GlobWatcher) setClosed() {
- g.mu.Lock()
- g.closed = true
- g.mu.Unlock()
-}
-
-func (g *GlobWatcher) isClosed() bool {
- g.mu.RLock()
- defer g.mu.RUnlock()
- return g.closed
-}
-
-// WatchGlobs registers the given set of globs to be watched for changes and grouped
-// under the given hash. This method pairs with GetChangedGlobs to determine which globs
-// out of a set of candidates have changed since WatchGlobs was called for the same hash.
-func (g *GlobWatcher) WatchGlobs(hash string, globsToWatch fs.TaskOutputs) error {
- if g.isClosed() {
- return ErrClosed
- }
- // Wait for a cookie here
- // that will ensure that we have seen all filesystem writes
- // *by the calling client*. Other tasks _could_ write to the
- // same output directories, however we are relying on task
- // execution dependencies to prevent that.
- if err := g.cookieWaiter.WaitForCookie(); err != nil {
- return err
- }
- g.mu.Lock()
- defer g.mu.Unlock()
- g.hashGlobs[hash] = globs{
- Inclusions: util.SetFromStrings(globsToWatch.Inclusions),
- Exclusions: util.SetFromStrings(globsToWatch.Exclusions),
- }
-
- for _, glob := range globsToWatch.Inclusions {
- existing, ok := g.globStatus[glob]
- if !ok {
- existing = make(util.Set)
- }
- existing.Add(hash)
- g.globStatus[glob] = existing
- }
- return nil
-}
-
-// GetChangedGlobs returns the subset of the given candidates that we are not currently
-// tracking as "unchanged".
-func (g *GlobWatcher) GetChangedGlobs(hash string, candidates []string) ([]string, error) {
- if g.isClosed() {
- // If filewatching has crashed, return all candidates as changed.
- return candidates, nil
- }
- // Wait for a cookie here
- // that will ensure that we have seen all filesystem writes
- // *by the calling client*. Other tasks _could_ write to the
- // same output directories, however we are relying on task
- // execution dependencies to prevent that.
- if err := g.cookieWaiter.WaitForCookie(); err != nil {
- return nil, err
- }
- // hashGlobs tracks all of the unchanged globs for a given hash
- // If hashGlobs doesn't have our hash, either everything has changed,
- // or we were never tracking it. Either way, consider all the candidates
- // to be changed globs.
- g.mu.RLock()
- defer g.mu.RUnlock()
- globsToCheck, ok := g.hashGlobs[hash]
- if !ok {
- return candidates, nil
- }
- allGlobs := util.SetFromStrings(candidates)
- diff := allGlobs.Difference(globsToCheck.Inclusions)
-
- return diff.UnsafeListOfStrings(), nil
-}
-
-// OnFileWatchEvent implements FileWatchClient.OnFileWatchEvent
-// On a file change, check if we have a glob that matches this file. Invalidate
-// any matching globs, and remove them from the set of unchanged globs for the corresponding
-// hashes. If this is the last glob for a hash, remove the hash from being tracked.
-func (g *GlobWatcher) OnFileWatchEvent(ev filewatcher.Event) {
- // At this point, we don't care what the Op is, any Op represents a change
- // that should invalidate matching globs
- g.logger.Trace(fmt.Sprintf("Got fsnotify event %v", ev))
- absolutePath := ev.Path
- repoRelativePath, err := g.repoRoot.RelativePathString(absolutePath.ToStringDuringMigration())
- if err != nil {
- g.logger.Debug(fmt.Sprintf("could not get relative path from %v to %v: %v", g.repoRoot, absolutePath, err))
- return
- }
- g.mu.Lock()
- defer g.mu.Unlock()
- for glob, hashStatus := range g.globStatus {
- matches, err := doublestar.Match(glob, filepath.ToSlash(repoRelativePath))
- if err != nil {
- g.logger.Error(fmt.Sprintf("failed to check path %v against glob %v: %v", repoRelativePath, glob, err))
- continue
- }
- // If this glob matches, we know that it has changed for every hash that included this glob
- // and is not excluded by a hash's exclusion globs.
- // So, we can delete this glob from every hash tracking it as well as stop watching this glob.
- // To stop watching, we unref each of the directories corresponding to this glob.
- if matches {
- for hashUntyped := range hashStatus {
- hash := hashUntyped.(string)
- hashGlobs, ok := g.hashGlobs[hash]
-
- if !ok {
- g.logger.Warn(fmt.Sprintf("failed to find hash %v referenced from glob %v", hash, glob))
- continue
- }
-
- isExcluded := false
- // Check if we've excluded this path by going through exclusion globs
- for exclusionGlob := range hashGlobs.Exclusions {
- matches, err := doublestar.Match(exclusionGlob.(string), filepath.ToSlash(repoRelativePath))
- if err != nil {
- g.logger.Error(fmt.Sprintf("failed to check path %v against glob %v: %v", repoRelativePath, glob, err))
- continue
- }
-
- if matches {
- isExcluded = true
- break
- }
- }
-
- // If we have excluded this path, then we skip it
- if isExcluded {
- continue
- }
-
- // We delete hash from the globStatus entry
- g.globStatus[glob].Delete(hash)
-
- // If we've deleted the last hash for a glob in globStatus, delete the whole glob entry
- if len(g.globStatus[glob]) == 0 {
- delete(g.globStatus, glob)
- }
-
- hashGlobs.Inclusions.Delete(glob)
- // If we've deleted the last glob for a hash, delete the whole hash entry
- if hashGlobs.Inclusions.Len() == 0 {
- delete(g.hashGlobs, hash)
- }
- }
- }
- }
-}
-
-// OnFileWatchError implements FileWatchClient.OnFileWatchError
-func (g *GlobWatcher) OnFileWatchError(err error) {
- g.logger.Error(fmt.Sprintf("file watching received an error: %v", err))
-}
-
-// OnFileWatchClosed implements FileWatchClient.OnFileWatchClosed
-func (g *GlobWatcher) OnFileWatchClosed() {
- g.setClosed()
- g.logger.Warn("GlobWatching is closing due to file watching closing")
-}
diff --git a/cli/internal/globwatcher/globwatcher_test.go b/cli/internal/globwatcher/globwatcher_test.go
deleted file mode 100644
index 6fb89a7..0000000
--- a/cli/internal/globwatcher/globwatcher_test.go
+++ /dev/null
@@ -1,232 +0,0 @@
-package globwatcher
-
-import (
- "testing"
-
- "github.com/hashicorp/go-hclog"
- "github.com/vercel/turbo/cli/internal/filewatcher"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func setup(t *testing.T, repoRoot turbopath.AbsoluteSystemPath) {
- // Directory layout:
- // <repoRoot>/
- // my-pkg/
- // irrelevant
- // dist/
- // dist-file
- // distChild/
- // child-file
- // .next/
- // next-file
- distPath := repoRoot.UntypedJoin("my-pkg", "dist")
- childFilePath := distPath.UntypedJoin("distChild", "child-file")
- err := childFilePath.EnsureDir()
- assert.NilError(t, err, "EnsureDir")
- f, err := childFilePath.Create()
- assert.NilError(t, err, "Create")
- err = f.Close()
- assert.NilError(t, err, "Close")
- distFilePath := repoRoot.UntypedJoin("my-pkg", "dist", "dist-file")
- f, err = distFilePath.Create()
- assert.NilError(t, err, "Create")
- err = f.Close()
- assert.NilError(t, err, "Close")
- nextFilePath := repoRoot.UntypedJoin("my-pkg", ".next", "next-file")
- err = nextFilePath.EnsureDir()
- assert.NilError(t, err, "EnsureDir")
- f, err = nextFilePath.Create()
- assert.NilError(t, err, "Create")
- err = f.Close()
- assert.NilError(t, err, "Close")
- irrelevantPath := repoRoot.UntypedJoin("my-pkg", "irrelevant")
- f, err = irrelevantPath.Create()
- assert.NilError(t, err, "Create")
- err = f.Close()
- assert.NilError(t, err, "Close")
-}
-
-type noopCookieWaiter struct{}
-
-func (*noopCookieWaiter) WaitForCookie() error {
- return nil
-}
-
-var _noopCookieWaiter = &noopCookieWaiter{}
-
-func TestTrackOutputs(t *testing.T) {
- logger := hclog.Default()
-
- repoRootRaw := t.TempDir()
- repoRoot := fs.AbsoluteSystemPathFromUpstream(repoRootRaw)
-
- setup(t, repoRoot)
-
- globWatcher := New(logger, repoRoot, _noopCookieWaiter)
-
- globs := fs.TaskOutputs{
- Inclusions: []string{
- "my-pkg/dist/**",
- "my-pkg/.next/**",
- },
- Exclusions: []string{"my-pkg/.next/cache/**"},
- }
-
- hash := "the-hash"
- err := globWatcher.WatchGlobs(hash, globs)
- assert.NilError(t, err, "WatchGlobs")
-
- changed, err := globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 0, len(changed), "Expected no changed paths")
-
- // Make an irrelevant change
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", "irrelevant"),
- })
-
- changed, err = globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 0, len(changed), "Expected no changed paths")
-
- // Make an excluded change
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.Join("my-pkg", ".next", "cache", "foo"),
- })
-
- changed, err = globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 0, len(changed), "Expected no changed paths")
-
- // Make a relevant change
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", "dist", "foo"),
- })
-
- changed, err = globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 1, len(changed), "Expected one changed path remaining")
- expected := "my-pkg/dist/**"
- assert.Equal(t, expected, changed[0], "Expected dist glob to have changed")
-
- // Change a file matching the other glob
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", ".next", "foo"),
- })
- // We should no longer be watching anything, since both globs have
- // registered changes
- if len(globWatcher.hashGlobs) != 0 {
- t.Errorf("expected to not track any hashes, found %v", globWatcher.hashGlobs)
- }
-
- // Both globs have changed, we should have stopped tracking
- // this hash
- changed, err = globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.DeepEqual(t, globs.Inclusions, changed)
-}
-
-func TestTrackMultipleHashes(t *testing.T) {
- logger := hclog.Default()
-
- repoRootRaw := t.TempDir()
- repoRoot := fs.AbsoluteSystemPathFromUpstream(repoRootRaw)
-
- setup(t, repoRoot)
-
- globWatcher := New(logger, repoRoot, _noopCookieWaiter)
-
- globs := fs.TaskOutputs{
- Inclusions: []string{
- "my-pkg/dist/**",
- "my-pkg/.next/**",
- },
- }
-
- hash := "the-hash"
- err := globWatcher.WatchGlobs(hash, globs)
- assert.NilError(t, err, "WatchGlobs")
-
- secondGlobs := fs.TaskOutputs{
- Inclusions: []string{
- "my-pkg/.next/**",
- },
- Exclusions: []string{"my-pkg/.next/cache/**"},
- }
-
- secondHash := "the-second-hash"
- err = globWatcher.WatchGlobs(secondHash, secondGlobs)
- assert.NilError(t, err, "WatchGlobs")
-
- changed, err := globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 0, len(changed), "Expected no changed paths")
-
- changed, err = globWatcher.GetChangedGlobs(secondHash, secondGlobs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 0, len(changed), "Expected no changed paths")
-
- // Make a change that is excluded in one of the hashes but not in the other
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", ".next", "cache", "foo"),
- })
-
- changed, err = globWatcher.GetChangedGlobs(hash, globs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 1, len(changed), "Expected one changed path remaining")
-
- changed, err = globWatcher.GetChangedGlobs(secondHash, secondGlobs.Inclusions)
- assert.NilError(t, err, "GetChangedGlobs")
- assert.Equal(t, 0, len(changed), "Expected no changed paths")
-
- assert.Equal(t, 1, len(globWatcher.globStatus["my-pkg/.next/**"]), "Expected to be still watching `my-pkg/.next/**`")
-
- // Make a change for secondHash
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", ".next", "bar"),
- })
-
- assert.Equal(t, 0, len(globWatcher.globStatus["my-pkg/.next/**"]), "Expected to be no longer watching `my-pkg/.next/**`")
-}
-
-func TestWatchSingleFile(t *testing.T) {
- logger := hclog.Default()
-
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
-
- setup(t, repoRoot)
-
- //watcher := newTestWatcher()
- globWatcher := New(logger, repoRoot, _noopCookieWaiter)
- globs := fs.TaskOutputs{
- Inclusions: []string{"my-pkg/.next/next-file"},
- Exclusions: []string{},
- }
- hash := "the-hash"
- err := globWatcher.WatchGlobs(hash, globs)
- assert.NilError(t, err, "WatchGlobs")
-
- assert.Equal(t, 1, len(globWatcher.hashGlobs))
-
- // A change to an irrelevant file
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", ".next", "foo"),
- })
- assert.Equal(t, 1, len(globWatcher.hashGlobs))
-
- // Change the watched file
- globWatcher.OnFileWatchEvent(filewatcher.Event{
- EventType: filewatcher.FileAdded,
- Path: repoRoot.UntypedJoin("my-pkg", ".next", "next-file"),
- })
- assert.Equal(t, 0, len(globWatcher.hashGlobs))
-}
diff --git a/cli/internal/graph/graph.go b/cli/internal/graph/graph.go
deleted file mode 100644
index 480dec9..0000000
--- a/cli/internal/graph/graph.go
+++ /dev/null
@@ -1,274 +0,0 @@
-// Package graph contains the CompleteGraph struct and some methods around it
-package graph
-
-import (
- gocontext "context"
- "fmt"
- "path/filepath"
- "regexp"
- "sort"
- "strings"
-
- "github.com/hashicorp/go-hclog"
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/env"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/nodes"
- "github.com/vercel/turbo/cli/internal/runsummary"
- "github.com/vercel/turbo/cli/internal/taskhash"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-// CompleteGraph represents the common state inferred from the filesystem and pipeline.
-// It is not intended to include information specific to a particular run.
-type CompleteGraph struct {
- // WorkspaceGraph expresses the dependencies between packages
- WorkspaceGraph dag.AcyclicGraph
-
- // Pipeline is config from turbo.json
- Pipeline fs.Pipeline
-
- // WorkspaceInfos stores the package.json contents by package name
- WorkspaceInfos workspace.Catalog
-
- // GlobalHash is the hash of all global dependencies
- GlobalHash string
-
- RootNode string
-
- // Map of TaskDefinitions by taskID
- TaskDefinitions map[string]*fs.TaskDefinition
- RepoRoot turbopath.AbsoluteSystemPath
-
- TaskHashTracker *taskhash.Tracker
-}
-
-// GetPackageTaskVisitor wraps a `visitor` function that is used for walking the TaskGraph
-// during execution (or dry-runs). The function returned here does not execute any tasks itself,
-// but it helps curry some data from the Complete Graph and pass it into the visitor function.
-func (g *CompleteGraph) GetPackageTaskVisitor(
- ctx gocontext.Context,
- taskGraph *dag.AcyclicGraph,
- globalEnvMode util.EnvMode,
- getArgs func(taskID string) []string,
- logger hclog.Logger,
- execFunc func(ctx gocontext.Context, packageTask *nodes.PackageTask, taskSummary *runsummary.TaskSummary) error,
-) func(taskID string) error {
- return func(taskID string) error {
- packageName, taskName := util.GetPackageTaskFromId(taskID)
- pkg, ok := g.WorkspaceInfos.PackageJSONs[packageName]
- if !ok {
- return fmt.Errorf("cannot find package %v for task %v", packageName, taskID)
- }
-
- // Check for root task
- var command string
- if cmd, ok := pkg.Scripts[taskName]; ok {
- command = cmd
- }
-
- if packageName == util.RootPkgName && commandLooksLikeTurbo(command) {
- return fmt.Errorf("root task %v (%v) looks like it invokes turbo and might cause a loop", taskName, command)
- }
-
- taskDefinition, ok := g.TaskDefinitions[taskID]
- if !ok {
- return fmt.Errorf("Could not find definition for task")
- }
-
- // Task env mode is only independent when global env mode is `infer`.
- taskEnvMode := globalEnvMode
- useOldTaskHashable := false
- if taskEnvMode == util.Infer {
- if taskDefinition.PassthroughEnv != nil {
- taskEnvMode = util.Strict
- } else {
- // If we're in infer mode we have just detected non-usage of strict env vars.
- // Since we haven't stabilized this we don't want to break their cache.
- useOldTaskHashable = true
-
- // But our old behavior's actual meaning of this state is `loose`.
- taskEnvMode = util.Loose
- }
- }
-
- // TODO: maybe we can remove this PackageTask struct at some point
- packageTask := &nodes.PackageTask{
- TaskID: taskID,
- Task: taskName,
- PackageName: packageName,
- Pkg: pkg,
- EnvMode: taskEnvMode,
- Dir: pkg.Dir.ToString(),
- TaskDefinition: taskDefinition,
- Outputs: taskDefinition.Outputs.Inclusions,
- ExcludedOutputs: taskDefinition.Outputs.Exclusions,
- }
-
- passThruArgs := getArgs(taskName)
- hash, err := g.TaskHashTracker.CalculateTaskHash(
- packageTask,
- taskGraph.DownEdges(taskID),
- logger,
- passThruArgs,
- useOldTaskHashable,
- )
-
- // Not being able to construct the task hash is a hard error
- if err != nil {
- return fmt.Errorf("Hashing error: %v", err)
- }
-
- pkgDir := pkg.Dir
- packageTask.Hash = hash
- envVars := g.TaskHashTracker.GetEnvVars(taskID)
- expandedInputs := g.TaskHashTracker.GetExpandedInputs(packageTask)
- framework := g.TaskHashTracker.GetFramework(taskID)
-
- logFile := repoRelativeLogFile(pkgDir, taskName)
- packageTask.LogFile = logFile
- packageTask.Command = command
-
- var envVarPassthroughMap env.EnvironmentVariableMap
- if taskDefinition.PassthroughEnv != nil {
- if envVarPassthroughDetailedMap, err := env.GetHashableEnvVars(taskDefinition.PassthroughEnv, nil, ""); err == nil {
- envVarPassthroughMap = envVarPassthroughDetailedMap.BySource.Explicit
- }
- }
-
- summary := &runsummary.TaskSummary{
- TaskID: taskID,
- Task: taskName,
- Hash: hash,
- Package: packageName,
- Dir: pkgDir.ToString(),
- Outputs: taskDefinition.Outputs.Inclusions,
- ExcludedOutputs: taskDefinition.Outputs.Exclusions,
- LogFile: logFile,
- ResolvedTaskDefinition: taskDefinition,
- ExpandedInputs: expandedInputs,
- ExpandedOutputs: []turbopath.AnchoredSystemPath{},
- Command: command,
- CommandArguments: passThruArgs,
- Framework: framework,
- EnvMode: taskEnvMode,
- EnvVars: runsummary.TaskEnvVarSummary{
- Configured: envVars.BySource.Explicit.ToSecretHashable(),
- Inferred: envVars.BySource.Matching.ToSecretHashable(),
- Passthrough: envVarPassthroughMap.ToSecretHashable(),
- },
- ExternalDepsHash: pkg.ExternalDepsHash,
- }
-
- if ancestors, err := g.getTaskGraphAncestors(taskGraph, packageTask.TaskID); err == nil {
- summary.Dependencies = ancestors
- }
- if descendents, err := g.getTaskGraphDescendants(taskGraph, packageTask.TaskID); err == nil {
- summary.Dependents = descendents
- }
-
- return execFunc(ctx, packageTask, summary)
- }
-}
-
-// GetPipelineFromWorkspace returns the Unmarshaled fs.Pipeline struct from turbo.json in the given workspace.
-func (g *CompleteGraph) GetPipelineFromWorkspace(workspaceName string, isSinglePackage bool) (fs.Pipeline, error) {
- turboConfig, err := g.GetTurboConfigFromWorkspace(workspaceName, isSinglePackage)
-
- if err != nil {
- return nil, err
- }
-
- return turboConfig.Pipeline, nil
-}
-
-// GetTurboConfigFromWorkspace returns the Unmarshaled fs.TurboJSON from turbo.json in the given workspace.
-func (g *CompleteGraph) GetTurboConfigFromWorkspace(workspaceName string, isSinglePackage bool) (*fs.TurboJSON, error) {
- cachedTurboConfig, ok := g.WorkspaceInfos.TurboConfigs[workspaceName]
-
- if ok {
- return cachedTurboConfig, nil
- }
-
- var workspacePackageJSON *fs.PackageJSON
- if pkgJSON, err := g.GetPackageJSONFromWorkspace(workspaceName); err == nil {
- workspacePackageJSON = pkgJSON
- } else {
- return nil, err
- }
-
- // Note: pkgJSON.Dir for the root workspace will be an empty string, and for
- // other workspaces, it will be a relative path.
- workspaceAbsolutePath := workspacePackageJSON.Dir.RestoreAnchor(g.RepoRoot)
- turboConfig, err := fs.LoadTurboConfig(workspaceAbsolutePath, workspacePackageJSON, isSinglePackage)
-
- // If we failed to load a TurboConfig, bubble up the error
- if err != nil {
- return nil, err
- }
-
- // add to cache
- g.WorkspaceInfos.TurboConfigs[workspaceName] = turboConfig
-
- return g.WorkspaceInfos.TurboConfigs[workspaceName], nil
-}
-
-// GetPackageJSONFromWorkspace returns an Unmarshaled struct of the package.json in the given workspace
-func (g *CompleteGraph) GetPackageJSONFromWorkspace(workspaceName string) (*fs.PackageJSON, error) {
- if pkgJSON, ok := g.WorkspaceInfos.PackageJSONs[workspaceName]; ok {
- return pkgJSON, nil
- }
-
- return nil, fmt.Errorf("No package.json for %s", workspaceName)
-}
-
-// repoRelativeLogFile returns the path to the log file for this task execution as a
-// relative path from the root of the monorepo.
-func repoRelativeLogFile(dir turbopath.AnchoredSystemPath, taskName string) string {
- return filepath.Join(dir.ToStringDuringMigration(), ".turbo", fmt.Sprintf("turbo-%v.log", taskName))
-}
-
-// getTaskGraphAncestors gets all the ancestors for a given task in the graph.
-// "ancestors" are all tasks that the given task depends on.
-func (g *CompleteGraph) getTaskGraphAncestors(taskGraph *dag.AcyclicGraph, taskID string) ([]string, error) {
- ancestors, err := taskGraph.Ancestors(taskID)
- if err != nil {
- return nil, err
- }
- stringAncestors := []string{}
- for _, dep := range ancestors {
- // Don't leak out internal root node name, which are just placeholders
- if !strings.Contains(dep.(string), g.RootNode) {
- stringAncestors = append(stringAncestors, dep.(string))
- }
- }
-
- sort.Strings(stringAncestors)
- return stringAncestors, nil
-}
-
-// getTaskGraphDescendants gets all the descendants for a given task in the graph.
-// "descendants" are all tasks that depend on the given taskID.
-func (g *CompleteGraph) getTaskGraphDescendants(taskGraph *dag.AcyclicGraph, taskID string) ([]string, error) {
- descendents, err := taskGraph.Descendents(taskID)
- if err != nil {
- return nil, err
- }
- stringDescendents := []string{}
- for _, dep := range descendents {
- // Don't leak out internal root node name, which are just placeholders
- if !strings.Contains(dep.(string), g.RootNode) {
- stringDescendents = append(stringDescendents, dep.(string))
- }
- }
- sort.Strings(stringDescendents)
- return stringDescendents, nil
-}
-
-var _isTurbo = regexp.MustCompile(`(?:^|\s)turbo(?:$|\s)`)
-
-func commandLooksLikeTurbo(command string) bool {
- return _isTurbo.MatchString(command)
-}
diff --git a/cli/internal/graph/graph_test.go b/cli/internal/graph/graph_test.go
deleted file mode 100644
index 9323e19..0000000
--- a/cli/internal/graph/graph_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package graph
-
-import (
- "testing"
-
- "gotest.tools/v3/assert"
-)
-
-func Test_CommandsInvokingTurbo(t *testing.T) {
- type testCase struct {
- command string
- match bool
- }
- testCases := []testCase{
- {
- "turbo run foo",
- true,
- },
- {
- "rm -rf ~/Library/Caches/pnpm && turbo run foo && rm -rf ~/.npm",
- true,
- },
- {
- "FLAG=true turbo run foo",
- true,
- },
- {
- "npx turbo run foo",
- true,
- },
- {
- "echo starting; turbo foo; echo done",
- true,
- },
- // We don't catch this as if people are going to try to invoke the turbo
- // binary directly, they'll always be able to work around us.
- {
- "./node_modules/.bin/turbo foo",
- false,
- },
- {
- "rm -rf ~/Library/Caches/pnpm && rm -rf ~/Library/Caches/turbo && rm -rf ~/.npm && rm -rf ~/.pnpm-store && rm -rf ~/.turbo",
- false,
- },
- }
-
- for _, tc := range testCases {
- assert.Equal(t, commandLooksLikeTurbo(tc.command), tc.match, tc.command)
- }
-}
diff --git a/cli/internal/graphvisualizer/graphvisualizer.go b/cli/internal/graphvisualizer/graphvisualizer.go
deleted file mode 100644
index 4e134b2..0000000
--- a/cli/internal/graphvisualizer/graphvisualizer.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package graphvisualizer
-
-import (
- "fmt"
- "io"
- "math/rand"
- "os/exec"
- "path/filepath"
- "sort"
- "strings"
-
- "github.com/fatih/color"
- "github.com/mitchellh/cli"
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/util/browser"
-)
-
-// GraphVisualizer requirements
-type GraphVisualizer struct {
- repoRoot turbopath.AbsoluteSystemPath
- ui cli.Ui
- TaskGraph *dag.AcyclicGraph
-}
-
-// hasGraphViz checks for the presence of https://graphviz.org/
-func hasGraphViz() bool {
- err := exec.Command("dot", "-V").Run()
- return err == nil
-}
-
-func getRandChar() string {
- i := rand.Intn(25) + 65
- return string(rune(i))
-}
-
-func getRandID() string {
- return getRandChar() + getRandChar() + getRandChar() + getRandChar()
-}
-
-// New creates an instance of ColorCache with helpers for adding colors to task outputs
-func New(repoRoot turbopath.AbsoluteSystemPath, ui cli.Ui, TaskGraph *dag.AcyclicGraph) *GraphVisualizer {
- return &GraphVisualizer{
- repoRoot: repoRoot,
- ui: ui,
- TaskGraph: TaskGraph,
- }
-}
-
-// Converts the TaskGraph dag into a string
-func (g *GraphVisualizer) generateDotString() string {
- return string(g.TaskGraph.Dot(&dag.DotOpts{
- Verbose: true,
- DrawCycles: true,
- }))
-}
-
-// Outputs a warning when a file was requested, but graphviz is not available
-func (g *GraphVisualizer) graphVizWarnUI() {
- g.ui.Warn(color.New(color.FgYellow, color.Bold, color.ReverseVideo).Sprint(" WARNING ") + color.YellowString(" `turbo` uses Graphviz to generate an image of your\ngraph, but Graphviz isn't installed on this machine.\n\nYou can download Graphviz from https://graphviz.org/download.\n\nIn the meantime, you can use this string output with an\nonline Dot graph viewer."))
-}
-
-// RenderDotGraph renders a dot graph string for the current TaskGraph
-func (g *GraphVisualizer) RenderDotGraph() {
- g.ui.Output("")
- g.ui.Output(g.generateDotString())
-}
-
-type nameCache map[string]string
-
-func (nc nameCache) getName(in string) string {
- if existing, ok := nc[in]; ok {
- return existing
- }
- newName := getRandID()
- nc[in] = newName
- return newName
-}
-
-type sortableEdge dag.Edge
-type sortableEdges []sortableEdge
-
-// methods mostly copied from marshalEdges in the dag library
-func (e sortableEdges) Less(i, j int) bool {
- iSrc := dag.VertexName(e[i].Source())
- jSrc := dag.VertexName(e[j].Source())
- if iSrc < jSrc {
- return true
- } else if iSrc > jSrc {
- return false
- }
- return dag.VertexName(e[i].Target()) < dag.VertexName(e[j].Target())
-}
-func (e sortableEdges) Len() int { return len(e) }
-func (e sortableEdges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
-
-func (g *GraphVisualizer) generateMermaid(out io.StringWriter) error {
- if _, err := out.WriteString("graph TD\n"); err != nil {
- return err
- }
- cache := make(nameCache)
- // cast edges to our custom type so we can sort them
- // this allows us to generate the same graph every time
- var edges sortableEdges
- for _, edge := range g.TaskGraph.Edges() {
- edges = append(edges, sortableEdge(edge))
- }
- sort.Sort(edges)
- for _, edge := range edges {
- left := dag.VertexName(edge.Source())
- right := dag.VertexName(edge.Target())
- leftName := cache.getName(left)
- rightName := cache.getName(right)
- if _, err := out.WriteString(fmt.Sprintf("\t%v(\"%v\") --> %v(\"%v\")\n", leftName, left, rightName, right)); err != nil {
- return err
- }
- }
- return nil
-}
-
-// GenerateGraphFile saves a visualization of the TaskGraph to a file (or renders a DotGraph as a fallback))
-func (g *GraphVisualizer) GenerateGraphFile(outputName string) error {
- outputFilename := g.repoRoot.UntypedJoin(outputName)
- ext := outputFilename.Ext()
- // use .jpg as default extension if none is provided
- if ext == "" {
- ext = ".jpg"
- outputFilename = g.repoRoot.UntypedJoin(outputName + ext)
- }
- if ext == ".mermaid" {
- f, err := outputFilename.Create()
- if err != nil {
- return fmt.Errorf("error creating file: %w", err)
- }
- defer util.CloseAndIgnoreError(f)
- if err := g.generateMermaid(f); err != nil {
- return err
- }
- g.ui.Output(fmt.Sprintf("✔ Generated task graph in %s", ui.Bold(outputFilename.ToString())))
- return nil
- }
- graphString := g.generateDotString()
- if ext == ".html" {
- f, err := outputFilename.Create()
- if err != nil {
- return fmt.Errorf("error creating file: %w", err)
- }
- defer f.Close() //nolint errcheck
- _, writeErr1 := f.WriteString(`<!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>Graph</title>
- </head>
- <body>
- <script src="https://cdn.jsdelivr.net/npm/viz.js@2.1.2-pre.1/viz.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/viz.js@2.1.2-pre.1/full.render.js"></script>
- <script>`)
- if writeErr1 != nil {
- return fmt.Errorf("error writing graph contents: %w", writeErr1)
- }
-
- _, writeErr2 := f.WriteString("const s = `" + graphString + "`.replace(/\\_\\_\\_ROOT\\_\\_\\_/g, \"Root\").replace(/\\[root\\]/g, \"\");new Viz().renderSVGElement(s).then(el => document.body.appendChild(el)).catch(e => console.error(e));")
- if writeErr2 != nil {
- return fmt.Errorf("error creating file: %w", writeErr2)
- }
-
- _, writeErr3 := f.WriteString(`
- </script>
- </body>
- </html>`)
- if writeErr3 != nil {
- return fmt.Errorf("error creating file: %w", writeErr3)
- }
-
- g.ui.Output("")
- g.ui.Output(fmt.Sprintf("✔ Generated task graph in %s", ui.Bold(outputFilename.ToString())))
- if ui.IsTTY {
- if err := browser.OpenBrowser(outputFilename.ToString()); err != nil {
- g.ui.Warn(color.New(color.FgYellow, color.Bold, color.ReverseVideo).Sprintf("failed to open browser. Please navigate to file://%v", filepath.ToSlash(outputFilename.ToString())))
- }
- }
- return nil
- }
- hasDot := hasGraphViz()
- if hasDot {
- dotArgs := []string{"-T" + ext[1:], "-o", outputFilename.ToString()}
- cmd := exec.Command("dot", dotArgs...)
- cmd.Stdin = strings.NewReader(graphString)
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("could not generate task graphfile %v: %w", outputFilename, err)
- }
- g.ui.Output("")
- g.ui.Output(fmt.Sprintf("✔ Generated task graph in %s", ui.Bold(outputFilename.ToString())))
-
- } else {
- g.ui.Output("")
- // User requested a file, but we're falling back to console here so warn about installing graphViz correctly
- g.graphVizWarnUI()
- g.RenderDotGraph()
- }
- return nil
-}
diff --git a/cli/internal/hashing/package_deps_hash.go b/cli/internal/hashing/package_deps_hash.go
deleted file mode 100644
index 517cddd..0000000
--- a/cli/internal/hashing/package_deps_hash.go
+++ /dev/null
@@ -1,461 +0,0 @@
-package hashing
-
-import (
- "bufio"
- "fmt"
- "io"
- "os/exec"
- "path/filepath"
- "strings"
- "sync"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/encoding/gitoutput"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/globby"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// PackageDepsOptions are parameters for getting git hashes for a filesystem
-type PackageDepsOptions struct {
- // PackagePath is the folder path to derive the package dependencies from. This is typically the folder
- // containing package.json. If omitted, the default value is the current working directory.
- PackagePath turbopath.AnchoredSystemPath
-
- InputPatterns []string
-}
-
-// GetPackageDeps Builds an object containing git hashes for the files under the specified `packagePath` folder.
-func GetPackageDeps(rootPath turbopath.AbsoluteSystemPath, p *PackageDepsOptions) (map[turbopath.AnchoredUnixPath]string, error) {
- pkgPath := rootPath.UntypedJoin(p.PackagePath.ToStringDuringMigration())
- // Add all the checked in hashes.
- var result map[turbopath.AnchoredUnixPath]string
-
- // make a copy of the inputPatterns array, because we may be appending to it later.
- calculatedInputs := make([]string, len(p.InputPatterns))
- copy(calculatedInputs, p.InputPatterns)
-
- if len(calculatedInputs) == 0 {
- gitLsTreeOutput, err := gitLsTree(pkgPath)
- if err != nil {
- return nil, fmt.Errorf("could not get git hashes for files in package %s: %w", p.PackagePath, err)
- }
- result = gitLsTreeOutput
-
- // Update the checked in hashes with the current repo status
- // The paths returned from this call are anchored at the package directory
- gitStatusOutput, err := gitStatus(pkgPath, calculatedInputs)
- if err != nil {
- return nil, fmt.Errorf("Could not get git hashes from git status: %v", err)
- }
-
- var filesToHash []turbopath.AnchoredSystemPath
- for filePath, status := range gitStatusOutput {
- if status.isDelete() {
- delete(result, filePath)
- } else {
- filesToHash = append(filesToHash, filePath.ToSystemPath())
- }
- }
-
- hashes, err := gitHashObject(turbopath.AbsoluteSystemPathFromUpstream(pkgPath.ToString()), filesToHash)
- if err != nil {
- return nil, err
- }
-
- // Zip up file paths and hashes together
- for filePath, hash := range hashes {
- result[filePath] = hash
- }
- } else {
- // Add in package.json and turbo.json to input patterns. Both file paths are relative to pkgPath
- //
- // - package.json is an input because if the `scripts` in
- // the package.json change (i.e. the tasks that turbo executes), we want
- // a cache miss, since any existing cache could be invalid.
- // - turbo.json because it's the definition of the tasks themselves. The root turbo.json
- // is similarly included in the global hash. This file may not exist in the workspace, but
- // that is ok, because it will get ignored downstream.
- calculatedInputs = append(calculatedInputs, "package.json")
- calculatedInputs = append(calculatedInputs, "turbo.json")
-
- // The input patterns are relative to the package.
- // However, we need to change the globbing to be relative to the repo root.
- // Prepend the package path to each of the input patterns.
- prefixedInputPatterns := []string{}
- prefixedExcludePatterns := []string{}
- for _, pattern := range calculatedInputs {
- if len(pattern) > 0 && pattern[0] == '!' {
- rerooted, err := rootPath.PathTo(pkgPath.UntypedJoin(pattern[1:]))
- if err != nil {
- return nil, err
- }
- prefixedExcludePatterns = append(prefixedExcludePatterns, rerooted)
- } else {
- rerooted, err := rootPath.PathTo(pkgPath.UntypedJoin(pattern))
- if err != nil {
- return nil, err
- }
- prefixedInputPatterns = append(prefixedInputPatterns, rerooted)
- }
- }
- absoluteFilesToHash, err := globby.GlobFiles(rootPath.ToStringDuringMigration(), prefixedInputPatterns, prefixedExcludePatterns)
-
- if err != nil {
- return nil, errors.Wrapf(err, "failed to resolve input globs %v", calculatedInputs)
- }
-
- filesToHash := make([]turbopath.AnchoredSystemPath, len(absoluteFilesToHash))
- for i, rawPath := range absoluteFilesToHash {
- relativePathString, err := pkgPath.RelativePathString(rawPath)
-
- if err != nil {
- return nil, errors.Wrapf(err, "not relative to package: %v", rawPath)
- }
-
- filesToHash[i] = turbopath.AnchoredSystemPathFromUpstream(relativePathString)
- }
-
- hashes, err := gitHashObject(turbopath.AbsoluteSystemPathFromUpstream(pkgPath.ToStringDuringMigration()), filesToHash)
- if err != nil {
- return nil, errors.Wrap(err, "failed hashing resolved inputs globs")
- }
- result = hashes
- // Note that in this scenario, we don't need to check git status, we're using hash-object directly which
- // hashes the current state, not state at a commit
- }
-
- return result, nil
-}
-
-func manuallyHashFiles(rootPath turbopath.AbsoluteSystemPath, files []turbopath.AnchoredSystemPath) (map[turbopath.AnchoredUnixPath]string, error) {
- hashObject := make(map[turbopath.AnchoredUnixPath]string)
- for _, file := range files {
- hash, err := fs.GitLikeHashFile(file.ToString())
- if err != nil {
- return nil, fmt.Errorf("could not hash file %v. \n%w", file.ToString(), err)
- }
-
- hashObject[file.ToUnixPath()] = hash
- }
- return hashObject, nil
-}
-
-// GetHashableDeps hashes the list of given files, then returns a map of normalized path to hash
-// this map is suitable for cross-platform caching.
-func GetHashableDeps(rootPath turbopath.AbsoluteSystemPath, files []turbopath.AbsoluteSystemPath) (map[turbopath.AnchoredUnixPath]string, error) {
- output := make([]turbopath.AnchoredSystemPath, len(files))
- convertedRootPath := turbopath.AbsoluteSystemPathFromUpstream(rootPath.ToString())
-
- for index, file := range files {
- anchoredSystemPath, err := file.RelativeTo(convertedRootPath)
- if err != nil {
- return nil, err
- }
- output[index] = anchoredSystemPath
- }
- hashObject, err := gitHashObject(convertedRootPath, output)
- if err != nil {
- manuallyHashedObject, err := manuallyHashFiles(convertedRootPath, output)
- if err != nil {
- return nil, err
- }
- hashObject = manuallyHashedObject
- }
-
- return hashObject, nil
-}
-
-// gitHashObject returns a map of paths to their SHA hashes calculated by passing the paths to `git hash-object`.
-// `git hash-object` expects paths to use Unix separators, even on Windows.
-//
-// Note: paths of files to hash passed to `git hash-object` are processed as relative to the given anchor.
-// For that reason we convert all input paths and make them relative to the anchor prior to passing them
-// to `git hash-object`.
-func gitHashObject(anchor turbopath.AbsoluteSystemPath, filesToHash []turbopath.AnchoredSystemPath) (map[turbopath.AnchoredUnixPath]string, error) {
- fileCount := len(filesToHash)
- output := make(map[turbopath.AnchoredUnixPath]string, fileCount)
-
- if fileCount > 0 {
- cmd := exec.Command(
- "git", // Using `git` from $PATH,
- "hash-object", // hash a file,
- "--stdin-paths", // using a list of newline-separated paths from stdin.
- )
- cmd.Dir = anchor.ToString() // Start at this directory.
-
- // The functionality for gitHashObject is different enough that it isn't reasonable to
- // generalize the behavior for `runGitCmd`. In fact, it doesn't even use the `gitoutput`
- // encoding library, instead relying on its own separate `bufio.Scanner`.
-
- // We're going to send the list of files in via `stdin`, so we grab that pipe.
- // This prevents a huge number of encoding issues and shell compatibility issues
- // before they even start.
- stdinPipe, stdinPipeError := cmd.StdinPipe()
- if stdinPipeError != nil {
- return nil, stdinPipeError
- }
-
- // Kick the processing off in a goroutine so while that is doing its thing we can go ahead
- // and wire up the consumer of `stdout`.
- go func() {
- defer util.CloseAndIgnoreError(stdinPipe)
-
- // `git hash-object` understands all relative paths to be relative to the repository.
- // This function's result needs to be relative to `rootPath`.
- // We convert all files to absolute paths and assume that they will be inside of the repository.
- for _, file := range filesToHash {
- converted := file.RestoreAnchor(anchor)
-
- // `git hash-object` expects paths to use Unix separators, even on Windows.
- // `git hash-object` expects paths to be one per line so we must escape newlines.
- // In order to understand the escapes, the path must be quoted.
- // In order to quote the path, the quotes in the path must be escaped.
- // Other than that, we just write everything with full Unicode.
- stringPath := converted.ToString()
- toSlashed := filepath.ToSlash(stringPath)
- escapedNewLines := strings.ReplaceAll(toSlashed, "\n", "\\n")
- escapedQuotes := strings.ReplaceAll(escapedNewLines, "\"", "\\\"")
- prepared := fmt.Sprintf("\"%s\"\n", escapedQuotes)
- _, err := io.WriteString(stdinPipe, prepared)
- if err != nil {
- return
- }
- }
- }()
-
- // This gives us an io.ReadCloser so that we never have to read the entire input in
- // at a single time. It is doing stream processing instead of string processing.
- stdoutPipe, stdoutPipeError := cmd.StdoutPipe()
- if stdoutPipeError != nil {
- return nil, fmt.Errorf("failed to read `git hash-object`: %w", stdoutPipeError)
- }
-
- startError := cmd.Start()
- if startError != nil {
- return nil, fmt.Errorf("failed to read `git hash-object`: %w", startError)
- }
-
- // The output of `git hash-object` is a 40-character SHA per input, then a newline.
- // We need to track the SHA that corresponds to the input file path.
- index := 0
- hashes := make([]string, len(filesToHash))
- scanner := bufio.NewScanner(stdoutPipe)
-
- // Read the output line-by-line (which is our separator) until exhausted.
- for scanner.Scan() {
- bytes := scanner.Bytes()
-
- scanError := scanner.Err()
- if scanError != nil {
- return nil, fmt.Errorf("failed to read `git hash-object`: %w", scanError)
- }
-
- hashError := gitoutput.CheckObjectName(bytes)
- if hashError != nil {
- return nil, fmt.Errorf("failed to read `git hash-object`: %s", "invalid hash received")
- }
-
- // Worked, save it off.
- hashes[index] = string(bytes)
- index++
- }
-
- // Waits until stdout is closed before proceeding.
- waitErr := cmd.Wait()
- if waitErr != nil {
- return nil, fmt.Errorf("failed to read `git hash-object`: %w", waitErr)
- }
-
- // Make sure we end up with a matching number of files and hashes.
- hashCount := len(hashes)
- if fileCount != hashCount {
- return nil, fmt.Errorf("failed to read `git hash-object`: %d files %d hashes", fileCount, hashCount)
- }
-
- // The API of this method specifies that we return a `map[turbopath.AnchoredUnixPath]string`.
- for i, hash := range hashes {
- filePath := filesToHash[i]
- output[filePath.ToUnixPath()] = hash
- }
- }
-
- return output, nil
-}
-
-// runGitCommand provides boilerplate command handling for `ls-tree`, `ls-files`, and `status`
-// Rather than doing string processing, it does stream processing of `stdout`.
-func runGitCommand(cmd *exec.Cmd, commandName string, handler func(io.Reader) *gitoutput.Reader) ([][]string, error) {
- stdoutPipe, pipeError := cmd.StdoutPipe()
- if pipeError != nil {
- return nil, fmt.Errorf("failed to read `git %s`: %w", commandName, pipeError)
- }
-
- startError := cmd.Start()
- if startError != nil {
- return nil, fmt.Errorf("failed to read `git %s`: %w", commandName, startError)
- }
-
- reader := handler(stdoutPipe)
- entries, readErr := reader.ReadAll()
- if readErr != nil {
- return nil, fmt.Errorf("failed to read `git %s`: %w", commandName, readErr)
- }
-
- waitErr := cmd.Wait()
- if waitErr != nil {
- return nil, fmt.Errorf("failed to read `git %s`: %w", commandName, waitErr)
- }
-
- return entries, nil
-}
-
-// gitLsTree returns a map of paths to their SHA hashes starting at a particular directory
-// that are present in the `git` index at a particular revision.
-func gitLsTree(rootPath turbopath.AbsoluteSystemPath) (map[turbopath.AnchoredUnixPath]string, error) {
- cmd := exec.Command(
- "git", // Using `git` from $PATH,
- "ls-tree", // list the contents of the git index,
- "-r", // recursively,
- "-z", // with each file path relative to the invocation directory and \000-terminated,
- "HEAD", // at this specified version.
- )
- cmd.Dir = rootPath.ToString() // Include files only from this directory.
-
- entries, err := runGitCommand(cmd, "ls-tree", gitoutput.NewLSTreeReader)
- if err != nil {
- return nil, err
- }
-
- output := make(map[turbopath.AnchoredUnixPath]string, len(entries))
-
- for _, entry := range entries {
- lsTreeEntry := gitoutput.LsTreeEntry(entry)
- output[turbopath.AnchoredUnixPathFromUpstream(lsTreeEntry.GetField(gitoutput.Path))] = lsTreeEntry[2]
- }
-
- return output, nil
-}
-
-// getTraversePath gets the distance of the current working directory to the repository root.
-// This is used to convert repo-relative paths to cwd-relative paths.
-//
-// `git rev-parse --show-cdup` always returns Unix paths, even on Windows.
-func getTraversePath(rootPath turbopath.AbsoluteSystemPath) (turbopath.RelativeUnixPath, error) {
- cmd := exec.Command("git", "rev-parse", "--show-cdup")
- cmd.Dir = rootPath.ToString()
-
- traversePath, err := cmd.Output()
- if err != nil {
- return "", err
- }
-
- trimmedTraversePath := strings.TrimSuffix(string(traversePath), "\n")
-
- return turbopath.RelativeUnixPathFromUpstream(trimmedTraversePath), nil
-}
-
-// Don't shell out if we already know where you are in the repository.
-// `memoize` is a good candidate for generics.
-func memoizeGetTraversePath() func(turbopath.AbsoluteSystemPath) (turbopath.RelativeUnixPath, error) {
- cacheMutex := &sync.RWMutex{}
- cachedResult := map[turbopath.AbsoluteSystemPath]turbopath.RelativeUnixPath{}
- cachedError := map[turbopath.AbsoluteSystemPath]error{}
-
- return func(rootPath turbopath.AbsoluteSystemPath) (turbopath.RelativeUnixPath, error) {
- cacheMutex.RLock()
- result, resultExists := cachedResult[rootPath]
- err, errExists := cachedError[rootPath]
- cacheMutex.RUnlock()
-
- if resultExists && errExists {
- return result, err
- }
-
- invokedResult, invokedErr := getTraversePath(rootPath)
- cacheMutex.Lock()
- cachedResult[rootPath] = invokedResult
- cachedError[rootPath] = invokedErr
- cacheMutex.Unlock()
-
- return invokedResult, invokedErr
- }
-}
-
-var memoizedGetTraversePath = memoizeGetTraversePath()
-
-// statusCode represents the two-letter status code from `git status` with two "named" fields, x & y.
-// They have different meanings based upon the actual state of the working tree. Using x & y maps
-// to upstream behavior.
-type statusCode struct {
- x string
- y string
-}
-
-func (s statusCode) isDelete() bool {
- return s.x == "D" || s.y == "D"
-}
-
-// gitStatus returns a map of paths to their `git` status code. This can be used to identify what should
-// be done with files that do not currently match what is in the index.
-//
-// Note: `git status -z`'s relative path results are relative to the repository's location.
-// We need to calculate where the repository's location is in order to determine what the full path is
-// before we can return those paths relative to the calling directory, normalizing to the behavior of
-// `ls-files` and `ls-tree`.
-func gitStatus(rootPath turbopath.AbsoluteSystemPath, patterns []string) (map[turbopath.AnchoredUnixPath]statusCode, error) {
- cmd := exec.Command(
- "git", // Using `git` from $PATH,
- "status", // tell me about the status of the working tree,
- "--untracked-files", // including information about untracked files,
- "--no-renames", // do not detect renames,
- "-z", // with each file path relative to the repository root and \000-terminated,
- "--", // and any additional argument you see is a path, promise.
- )
- if len(patterns) == 0 {
- cmd.Args = append(cmd.Args, ".") // Operate in the current directory instead of the root of the working tree.
- } else {
- // FIXME: Globbing is using `git`'s globbing rules which are not consistent with `doublestar``.
- cmd.Args = append(cmd.Args, patterns...) // Pass in input patterns as arguments.
- }
- cmd.Dir = rootPath.ToString() // Include files only from this directory.
-
- entries, err := runGitCommand(cmd, "status", gitoutput.NewStatusReader)
- if err != nil {
- return nil, err
- }
-
- output := make(map[turbopath.AnchoredUnixPath]statusCode, len(entries))
- convertedRootPath := turbopath.AbsoluteSystemPathFromUpstream(rootPath.ToString())
-
- traversePath, err := memoizedGetTraversePath(convertedRootPath)
- if err != nil {
- return nil, err
- }
-
- for _, entry := range entries {
- statusEntry := gitoutput.StatusEntry(entry)
- // Anchored at repository.
- pathFromStatus := turbopath.AnchoredUnixPathFromUpstream(statusEntry.GetField(gitoutput.Path))
- var outputPath turbopath.AnchoredUnixPath
-
- if len(traversePath) > 0 {
- repositoryPath := convertedRootPath.Join(traversePath.ToSystemPath())
- fileFullPath := pathFromStatus.ToSystemPath().RestoreAnchor(repositoryPath)
-
- relativePath, err := fileFullPath.RelativeTo(convertedRootPath)
- if err != nil {
- return nil, err
- }
-
- outputPath = relativePath.ToUnixPath()
- } else {
- outputPath = pathFromStatus
- }
-
- output[outputPath] = statusCode{x: statusEntry.GetField(gitoutput.StatusX), y: statusEntry.GetField(gitoutput.StatusY)}
- }
-
- return output, nil
-}
diff --git a/cli/internal/hashing/package_deps_hash_test.go b/cli/internal/hashing/package_deps_hash_test.go
deleted file mode 100644
index 8f68d38..0000000
--- a/cli/internal/hashing/package_deps_hash_test.go
+++ /dev/null
@@ -1,386 +0,0 @@
-package hashing
-
-import (
- "errors"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "reflect"
- "runtime"
- "strings"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func getFixture(id int) turbopath.AbsoluteSystemPath {
- cwd, _ := os.Getwd()
- root := turbopath.AbsoluteSystemPath(filepath.VolumeName(cwd) + string(os.PathSeparator))
- checking := turbopath.AbsoluteSystemPath(cwd)
-
- for checking != root {
- fixtureDirectory := checking.Join("fixtures")
- _, err := os.Stat(fixtureDirectory.ToString())
- if !errors.Is(err, os.ErrNotExist) {
- // Found the fixture directory!
- files, _ := os.ReadDir(fixtureDirectory.ToString())
-
- // Grab the specified fixture.
- for _, file := range files {
- fileName := turbopath.RelativeSystemPath(file.Name())
- if strings.Index(fileName.ToString(), fmt.Sprintf("%02d-", id)) == 0 {
- return turbopath.AbsoluteSystemPath(fixtureDirectory.Join(fileName))
- }
- }
- }
- checking = checking.Join("..")
- }
-
- panic("fixtures not found!")
-}
-
-func TestSpecialCharacters(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
-
- fixturePath := getFixture(1)
- newlinePath := turbopath.AnchoredUnixPath("new\nline").ToSystemPath()
- quotePath := turbopath.AnchoredUnixPath("\"quote\"").ToSystemPath()
- newline := newlinePath.RestoreAnchor(fixturePath)
- quote := quotePath.RestoreAnchor(fixturePath)
-
- // Setup
- one := os.WriteFile(newline.ToString(), []byte{}, 0644)
- two := os.WriteFile(quote.ToString(), []byte{}, 0644)
-
- // Cleanup
- defer func() {
- one := os.Remove(newline.ToString())
- two := os.Remove(quote.ToString())
-
- if one != nil || two != nil {
- return
- }
- }()
-
- // Setup error check
- if one != nil || two != nil {
- return
- }
-
- tests := []struct {
- name string
- rootPath turbopath.AbsoluteSystemPath
- filesToHash []turbopath.AnchoredSystemPath
- want map[turbopath.AnchoredUnixPath]string
- wantErr bool
- }{
- {
- name: "Quotes",
- rootPath: fixturePath,
- filesToHash: []turbopath.AnchoredSystemPath{
- quotePath,
- },
- want: map[turbopath.AnchoredUnixPath]string{
- quotePath.ToUnixPath(): "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
- },
- },
- {
- name: "Newlines",
- rootPath: fixturePath,
- filesToHash: []turbopath.AnchoredSystemPath{
- newlinePath,
- },
- want: map[turbopath.AnchoredUnixPath]string{
- newlinePath.ToUnixPath(): "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got, err := gitHashObject(tt.rootPath, tt.filesToHash)
- if (err != nil) != tt.wantErr {
- t.Errorf("gitHashObject() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("gitHashObject() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func Test_gitHashObject(t *testing.T) {
- fixturePath := getFixture(1)
- traversePath, err := getTraversePath(fixturePath)
- if err != nil {
- return
- }
-
- tests := []struct {
- name string
- rootPath turbopath.AbsoluteSystemPath
- filesToHash []turbopath.AnchoredSystemPath
- want map[turbopath.AnchoredUnixPath]string
- wantErr bool
- }{
- {
- name: "No paths",
- rootPath: fixturePath,
- filesToHash: []turbopath.AnchoredSystemPath{},
- want: map[turbopath.AnchoredUnixPath]string{},
- },
- {
- name: "Absolute paths come back relative to rootPath",
- rootPath: fixturePath.Join("child"),
- filesToHash: []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("../root.json").ToSystemPath(),
- turbopath.AnchoredUnixPath("child.json").ToSystemPath(),
- turbopath.AnchoredUnixPath("grandchild/grandchild.json").ToSystemPath(),
- },
- want: map[turbopath.AnchoredUnixPath]string{
- "../root.json": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
- "child.json": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
- "grandchild/grandchild.json": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
- },
- },
- {
- name: "Traverse outside of the repo",
- rootPath: fixturePath.Join(traversePath.ToSystemPath(), ".."),
- filesToHash: []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("null.json").ToSystemPath(),
- },
- want: nil,
- wantErr: true,
- },
- {
- name: "Nonexistent file",
- rootPath: fixturePath,
- filesToHash: []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("nonexistent.json").ToSystemPath(),
- },
- want: nil,
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got, err := gitHashObject(tt.rootPath, tt.filesToHash)
- if (err != nil) != tt.wantErr {
- t.Errorf("gitHashObject() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("gitHashObject() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func Test_getTraversePath(t *testing.T) {
- fixturePath := getFixture(1)
-
- tests := []struct {
- name string
- rootPath turbopath.AbsoluteSystemPath
- want turbopath.RelativeUnixPath
- wantErr bool
- }{
- {
- name: "From fixture location",
- rootPath: fixturePath,
- want: turbopath.RelativeUnixPath("../../../"),
- wantErr: false,
- },
- {
- name: "Traverse out of git repo",
- rootPath: fixturePath.UntypedJoin("..", "..", "..", ".."),
- want: "",
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got, err := getTraversePath(tt.rootPath)
- if (err != nil) != tt.wantErr {
- t.Errorf("getTraversePath() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("getTraversePath() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func requireGitCmd(t *testing.T, repoRoot turbopath.AbsoluteSystemPath, args ...string) {
- t.Helper()
- cmd := exec.Command("git", args...)
- cmd.Dir = repoRoot.ToString()
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("git commit failed: %v %v", err, string(out))
- }
-}
-
-func TestGetPackageDeps(t *testing.T) {
- // Directory structure:
- // <root>/
- // new-root-file <- new file not added to git
- // my-pkg/
- // committed-file
- // deleted-file
- // uncommitted-file <- new file not added to git
- // dir/
- // nested-file
-
- repoRoot := fs.AbsoluteSystemPathFromUpstream(t.TempDir())
- myPkgDir := repoRoot.UntypedJoin("my-pkg")
-
- // create the dir first
- err := myPkgDir.MkdirAll(0775)
- assert.NilError(t, err, "CreateDir")
-
- // create file 1
- committedFilePath := myPkgDir.UntypedJoin("committed-file")
- err = committedFilePath.WriteFile([]byte("committed bytes"), 0644)
- assert.NilError(t, err, "WriteFile")
-
- // create file 2
- deletedFilePath := myPkgDir.UntypedJoin("deleted-file")
- err = deletedFilePath.WriteFile([]byte("delete-me"), 0644)
- assert.NilError(t, err, "WriteFile")
-
- // create file 3
- nestedPath := myPkgDir.UntypedJoin("dir", "nested-file")
- assert.NilError(t, nestedPath.EnsureDir(), "EnsureDir")
- assert.NilError(t, nestedPath.WriteFile([]byte("nested"), 0644), "WriteFile")
-
- // create a package.json
- packageJSONPath := myPkgDir.UntypedJoin("package.json")
- err = packageJSONPath.WriteFile([]byte("{}"), 0644)
- assert.NilError(t, err, "WriteFile")
-
- // set up git repo and commit all
- requireGitCmd(t, repoRoot, "init", ".")
- requireGitCmd(t, repoRoot, "config", "--local", "user.name", "test")
- requireGitCmd(t, repoRoot, "config", "--local", "user.email", "test@example.com")
- requireGitCmd(t, repoRoot, "add", ".")
- requireGitCmd(t, repoRoot, "commit", "-m", "foo")
-
- // remove a file
- err = deletedFilePath.Remove()
- assert.NilError(t, err, "Remove")
-
- // create another untracked file in git
- uncommittedFilePath := myPkgDir.UntypedJoin("uncommitted-file")
- err = uncommittedFilePath.WriteFile([]byte("uncommitted bytes"), 0644)
- assert.NilError(t, err, "WriteFile")
-
- // create an untracked file in git up a level
- rootFilePath := repoRoot.UntypedJoin("new-root-file")
- err = rootFilePath.WriteFile([]byte("new-root bytes"), 0644)
- assert.NilError(t, err, "WriteFile")
-
- tests := []struct {
- opts *PackageDepsOptions
- expected map[turbopath.AnchoredUnixPath]string
- }{
- // base case. when inputs aren't specified, all files hashes are computed
- {
- opts: &PackageDepsOptions{
- PackagePath: "my-pkg",
- },
- expected: map[turbopath.AnchoredUnixPath]string{
- "committed-file": "3a29e62ea9ba15c4a4009d1f605d391cdd262033",
- "uncommitted-file": "4e56ad89387e6379e4e91ddfe9872cf6a72c9976",
- "package.json": "9e26dfeeb6e641a33dae4961196235bdb965b21b",
- "dir/nested-file": "bfe53d766e64d78f80050b73cd1c88095bc70abb",
- },
- },
- // with inputs, only the specified inputs are hashed
- {
- opts: &PackageDepsOptions{
- PackagePath: "my-pkg",
- InputPatterns: []string{"uncommitted-file"},
- },
- expected: map[turbopath.AnchoredUnixPath]string{
- "package.json": "9e26dfeeb6e641a33dae4961196235bdb965b21b",
- "uncommitted-file": "4e56ad89387e6379e4e91ddfe9872cf6a72c9976",
- },
- },
- // inputs with glob pattern also works
- {
- opts: &PackageDepsOptions{
- PackagePath: "my-pkg",
- InputPatterns: []string{"**/*-file"},
- },
- expected: map[turbopath.AnchoredUnixPath]string{
- "committed-file": "3a29e62ea9ba15c4a4009d1f605d391cdd262033",
- "uncommitted-file": "4e56ad89387e6379e4e91ddfe9872cf6a72c9976",
- "package.json": "9e26dfeeb6e641a33dae4961196235bdb965b21b",
- "dir/nested-file": "bfe53d766e64d78f80050b73cd1c88095bc70abb",
- },
- },
- // inputs with traversal work
- {
- opts: &PackageDepsOptions{
- PackagePath: "my-pkg",
- InputPatterns: []string{"../**/*-file"},
- },
- expected: map[turbopath.AnchoredUnixPath]string{
- "../new-root-file": "8906ddcdd634706188bd8ef1c98ac07b9be3425e",
- "committed-file": "3a29e62ea9ba15c4a4009d1f605d391cdd262033",
- "uncommitted-file": "4e56ad89387e6379e4e91ddfe9872cf6a72c9976",
- "package.json": "9e26dfeeb6e641a33dae4961196235bdb965b21b",
- "dir/nested-file": "bfe53d766e64d78f80050b73cd1c88095bc70abb",
- },
- },
- // inputs with another glob pattern works
- {
- opts: &PackageDepsOptions{
- PackagePath: "my-pkg",
- InputPatterns: []string{"**/{uncommitted,committed}-file"},
- },
- expected: map[turbopath.AnchoredUnixPath]string{
- "committed-file": "3a29e62ea9ba15c4a4009d1f605d391cdd262033",
- "package.json": "9e26dfeeb6e641a33dae4961196235bdb965b21b",
- "uncommitted-file": "4e56ad89387e6379e4e91ddfe9872cf6a72c9976",
- },
- },
- // inputs with another glob pattern + traversal work
- {
- opts: &PackageDepsOptions{
- PackagePath: "my-pkg",
- InputPatterns: []string{"../**/{new-root,uncommitted,committed}-file"},
- },
- expected: map[turbopath.AnchoredUnixPath]string{
- "../new-root-file": "8906ddcdd634706188bd8ef1c98ac07b9be3425e",
- "committed-file": "3a29e62ea9ba15c4a4009d1f605d391cdd262033",
- "package.json": "9e26dfeeb6e641a33dae4961196235bdb965b21b",
- "uncommitted-file": "4e56ad89387e6379e4e91ddfe9872cf6a72c9976",
- },
- },
- }
- for _, tt := range tests {
- got, err := GetPackageDeps(repoRoot, tt.opts)
- if err != nil {
- t.Errorf("GetPackageDeps got error %v", err)
- continue
- }
- assert.DeepEqual(t, got, tt.expected)
- }
-}
-
-func Test_memoizedGetTraversePath(t *testing.T) {
- fixturePath := getFixture(1)
-
- gotOne, _ := memoizedGetTraversePath(fixturePath)
- gotTwo, _ := memoizedGetTraversePath(fixturePath)
-
- assert.Check(t, gotOne == gotTwo, "The strings are identical.")
-}
diff --git a/cli/internal/inference/inference.go b/cli/internal/inference/inference.go
deleted file mode 100644
index 5d6d34f..0000000
--- a/cli/internal/inference/inference.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package inference
-
-import "github.com/vercel/turbo/cli/internal/fs"
-
-// Framework is an identifier for something that we wish to inference against.
-type Framework struct {
- Slug string
- EnvMatcher string
- DependencyMatch matcher
-}
-
-type matcher struct {
- strategy matchStrategy
- dependencies []string
-}
-
-type matchStrategy int
-
-const (
- all matchStrategy = iota + 1
- some
-)
-
-var _frameworks = []Framework{
- {
- Slug: "blitzjs",
- EnvMatcher: "^NEXT_PUBLIC_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"blitz"},
- },
- },
- {
- Slug: "nextjs",
- EnvMatcher: "^NEXT_PUBLIC_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"next"},
- },
- },
- {
- Slug: "gatsby",
- EnvMatcher: "^GATSBY_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"gatsby"},
- },
- },
- {
- Slug: "astro",
- EnvMatcher: "^PUBLIC_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"astro"},
- },
- },
- {
- Slug: "solidstart",
- EnvMatcher: "^VITE_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"solid-js", "solid-start"},
- },
- },
- {
- Slug: "vue",
- EnvMatcher: "^VUE_APP_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"@vue/cli-service"},
- },
- },
- {
- Slug: "sveltekit",
- EnvMatcher: "^VITE_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"@sveltejs/kit"},
- },
- },
- {
- Slug: "create-react-app",
- EnvMatcher: "^REACT_APP_",
- DependencyMatch: matcher{
- strategy: some,
- dependencies: []string{"react-scripts", "react-dev-utils"},
- },
- },
- {
- Slug: "nuxtjs",
- EnvMatcher: "^NUXT_ENV_",
- DependencyMatch: matcher{
- strategy: some,
- dependencies: []string{"nuxt", "nuxt-edge", "nuxt3", "nuxt3-edge"},
- },
- },
- {
- Slug: "redwoodjs",
- EnvMatcher: "^REDWOOD_ENV_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"@redwoodjs/core"},
- },
- },
- {
- Slug: "vite",
- EnvMatcher: "^VITE_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"vite"},
- },
- },
- {
- Slug: "sanity",
- EnvMatcher: "^SANITY_STUDIO_",
- DependencyMatch: matcher{
- strategy: all,
- dependencies: []string{"@sanity/cli"},
- },
- },
-}
-
-func (m matcher) match(pkg *fs.PackageJSON) bool {
- deps := pkg.UnresolvedExternalDeps
- // only check dependencies if we're in a non-monorepo
- if pkg.Workspaces != nil && len(pkg.Workspaces) == 0 {
- deps = pkg.Dependencies
- }
-
- if m.strategy == all {
- for _, dependency := range m.dependencies {
- _, exists := deps[dependency]
- if !exists {
- return false
- }
- }
- return true
- }
-
- // m.strategy == some
- for _, dependency := range m.dependencies {
- _, exists := deps[dependency]
- if exists {
- return true
- }
- }
- return false
-}
-
-func (f Framework) match(pkg *fs.PackageJSON) bool {
- return f.DependencyMatch.match(pkg)
-}
-
-// InferFramework returns a reference to a matched framework
-func InferFramework(pkg *fs.PackageJSON) *Framework {
- if pkg == nil {
- return nil
- }
-
- for _, candidateFramework := range _frameworks {
- if candidateFramework.match(pkg) {
- return &candidateFramework
- }
- }
-
- return nil
-}
diff --git a/cli/internal/inference/inference_test.go b/cli/internal/inference/inference_test.go
deleted file mode 100644
index ed82ecc..0000000
--- a/cli/internal/inference/inference_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package inference
-
-import (
- "reflect"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
-)
-
-func getFrameworkBySlug(slug string) *Framework {
- for _, framework := range _frameworks {
- if framework.Slug == slug {
- return &framework
- }
- }
- panic("that framework doesn't exist")
-}
-
-func TestInferFramework(t *testing.T) {
- tests := []struct {
- name string
- pkg *fs.PackageJSON
- want *Framework
- }{
- {
- name: "Hello world",
- pkg: nil,
- want: nil,
- },
- {
- name: "Empty dependencies",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{}},
- want: nil,
- },
- {
- name: "Finds Blitz",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{
- "blitz": "*",
- }},
- want: getFrameworkBySlug("blitzjs"),
- },
- {
- name: "Order is preserved (returns blitz, not next)",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{
- "blitz": "*",
- "next": "*",
- }},
- want: getFrameworkBySlug("blitzjs"),
- },
- {
- name: "Finds next without blitz",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{
- "next": "*",
- }},
- want: getFrameworkBySlug("nextjs"),
- },
- {
- name: "match strategy of all works (solid)",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{
- "solid-js": "*",
- "solid-start": "*",
- }},
- want: getFrameworkBySlug("solidstart"),
- },
- {
- name: "match strategy of some works (nuxt)",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{
- "nuxt3": "*",
- }},
- want: getFrameworkBySlug("nuxtjs"),
- },
- {
- name: "match strategy of some works (c-r-a)",
- pkg: &fs.PackageJSON{UnresolvedExternalDeps: map[string]string{
- "react-scripts": "*",
- }},
- want: getFrameworkBySlug("create-react-app"),
- },
- {
- name: "Finds next in non monorepo",
- pkg: &fs.PackageJSON{
- Dependencies: map[string]string{
- "next": "*",
- },
- Workspaces: []string{},
- },
- want: getFrameworkBySlug("nextjs"),
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := InferFramework(tt.pkg); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("InferFramework() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/cli/internal/lockfile/berry_lockfile.go b/cli/internal/lockfile/berry_lockfile.go
deleted file mode 100644
index e76f230..0000000
--- a/cli/internal/lockfile/berry_lockfile.go
+++ /dev/null
@@ -1,709 +0,0 @@
-package lockfile
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
-
- "github.com/Masterminds/semver"
- "github.com/andybalholm/crlf"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/yaml"
-)
-
-var _multipleKeyRegex = regexp.MustCompile(" *, *")
-
-// A tag cannot start with a "v"
-var _tagRegex = regexp.MustCompile("^[a-zA-Z0-9.-_-[v]][a-zA-Z0-9._-]*$")
-
-var _metadataKey = "__metadata"
-
-type _void struct{}
-
-// BerryLockfileEntry package information from yarn lockfile
-// Full Definition at https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-core/sources/Manifest.ts
-// Only a subset of full definition are written to the lockfile
-type BerryLockfileEntry struct {
- Version string `yaml:"version"`
- LanguageName string `yaml:"languageName,omitempty"`
-
- Dependencies map[string]string `yaml:"dependencies,omitempty"`
- PeerDependencies map[string]string `yaml:"peerDependencies,omitempty"`
-
- DependenciesMeta map[string]BerryDependencyMetaEntry `yaml:"dependenciesMeta,omitempty"`
- PeerDependenciesMeta map[string]BerryDependencyMetaEntry `yaml:"peerDependenciesMeta,omitempty"`
-
- Bin map[string]string `yaml:"bin,omitempty"`
-
- LinkType string `yaml:"linkType,omitempty"`
- Resolution string `yaml:"resolution,omitempty"`
- Checksum string `yaml:"checksum,omitempty"`
- Conditions string `yaml:"conditions,omitempty"`
-
- // Only used for metadata entry
- CacheKey string `yaml:"cacheKey,omitempty"`
-}
-
-// Return a list of descriptors that this entry possibly uses
-func (b *BerryLockfileEntry) possibleDescriptors() []_Descriptor {
- descriptors := []_Descriptor{}
- addDescriptor := func(name, version string) {
- descriptors = append(descriptors, berryPossibleKeys(name, version)...)
- }
-
- for dep, version := range b.Dependencies {
- addDescriptor(dep, version)
- }
-
- return descriptors
-}
-
-// BerryLockfile representation of berry lockfile
-type BerryLockfile struct {
- packages map[_Locator]*BerryLockfileEntry
- version int
- cacheKey string
- // Mapping descriptors (lodash@npm:^4.17.21) to their resolutions (lodash@npm:4.17.21)
- descriptors map[_Descriptor]_Locator
- // Mapping regular package locators to patched package locators
- patches map[_Locator]_Locator
- // Descriptors that are only used by package extensions
- packageExtensions map[_Descriptor]_void
- hasCRLF bool
-}
-
-// BerryDependencyMetaEntry Structure for holding if a package is optional or not
-type BerryDependencyMetaEntry struct {
- Optional bool `yaml:"optional,omitempty"`
- Unplugged bool `yaml:"unplugged,omitempty"`
-}
-
-var _ Lockfile = (*BerryLockfile)(nil)
-
-// ResolvePackage Given a package and version returns the key, resolved version, and if it was found
-func (l *BerryLockfile) ResolvePackage(_workspace turbopath.AnchoredUnixPath, name string, version string) (Package, error) {
- for _, key := range berryPossibleKeys(name, version) {
- if locator, ok := l.descriptors[key]; ok {
- entry := l.packages[locator]
- return Package{
- Found: true,
- Key: locator.String(),
- Version: entry.Version,
- }, nil
- }
- }
-
- return Package{}, nil
-}
-
-// AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package
-func (l *BerryLockfile) AllDependencies(key string) (map[string]string, bool) {
- deps := map[string]string{}
- var locator _Locator
- if err := locator.parseLocator(key); err != nil {
- // We should never hit this as we have already vetted all entries in the lockfile
- // during the creation of the lockfile struct
- panic(fmt.Sprintf("invalid locator string: %s", key))
- }
- entry, ok := l.packages[locator]
- if !ok {
- return deps, false
- }
-
- for name, version := range entry.Dependencies {
- deps[name] = version
- }
-
- return deps, true
-}
-
-// Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given
-func (l *BerryLockfile) Subgraph(workspacePackages []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) {
- prunedPackages := make(map[_Locator]*BerryLockfileEntry, len(packages))
- prunedDescriptors := make(map[_Descriptor]_Locator, len(prunedPackages))
- patches := make(map[_Locator]_Locator, len(l.patches))
- reverseLookup := l.locatorToDescriptors()
-
- // add workspace package entries
- for locator, pkg := range l.packages {
- if locator.reference == "workspace:." {
- prunedPackages[locator] = pkg
- descriptor := _Descriptor{locator._Ident, locator.reference}
- prunedDescriptors[descriptor] = locator
- for desc := range reverseLookup[locator] {
- prunedDescriptors[desc] = locator
- }
- }
- }
- for _, workspacePackage := range workspacePackages {
- expectedReference := fmt.Sprintf("workspace:%s", workspacePackage.ToUnixPath().ToString())
- for locator, pkg := range l.packages {
- if locator.reference == expectedReference {
- prunedPackages[locator] = pkg
- descriptor := _Descriptor{locator._Ident, locator.reference}
- prunedDescriptors[descriptor] = locator
- }
- }
- }
-
- for _, key := range packages {
- var locator _Locator
- if err := locator.parseLocator(key); err != nil {
- // We should never hit this as we have already vetted all entries in the lockfile
- // during the creation of the lockfile struct
- panic(fmt.Sprintf("invalid locator string: %s", key))
- }
- entry, ok := l.packages[locator]
- if ok {
- prunedPackages[locator] = entry
- }
- // If a package has a patch it should be included in the subgraph
- patchLocator, ok := l.patches[locator]
- if ok {
- patches[locator] = patchLocator
- prunedPackages[patchLocator] = l.packages[patchLocator]
- }
- }
-
- for _, entry := range prunedPackages {
- for _, desc := range entry.possibleDescriptors() {
- locator, ok := l.descriptors[desc]
- if ok {
- prunedDescriptors[desc] = locator
- }
- }
- }
-
- // For each patch we find all descriptors for the primary package and patched package
- for primaryLocator, patchLocator := range patches {
- primaryDescriptors := reverseLookup[primaryLocator]
- patchDescriptors := reverseLookup[patchLocator]
-
- // For each patch descriptor we extract the primary descriptor that each patch descriptor targets
- // and check if that descriptor is present in the pruned map and add it if it is present
- for patch := range patchDescriptors {
- primaryVersion, _ := patch.primaryVersion()
- primaryDescriptor := _Descriptor{patch._Ident, primaryVersion}
- _, isPresent := primaryDescriptors[primaryDescriptor]
- if !isPresent {
- panic(fmt.Sprintf("Unable to find primary descriptor %s", &primaryDescriptor))
- }
-
- _, ok := prunedDescriptors[primaryDescriptor]
- if ok {
- if !ok {
- panic(fmt.Sprintf("Unable to find patch for %s", &patchLocator))
- }
- prunedDescriptors[patch] = patchLocator
- }
- }
- }
-
- // Add any descriptors used by package extensions
- for descriptor := range l.packageExtensions {
- locator := l.descriptors[descriptor]
- _, ok := prunedPackages[locator]
- if ok {
- prunedDescriptors[descriptor] = locator
- }
- }
-
- // berry only includes a cache key in the lockfile if there are entries with a checksum
- cacheKey := ""
- for _, entry := range prunedPackages {
- if entry.Checksum != "" {
- cacheKey = l.cacheKey
- break
- }
- }
-
- return &BerryLockfile{
- packages: prunedPackages,
- version: l.version,
- cacheKey: cacheKey,
- descriptors: prunedDescriptors,
- patches: patches,
- packageExtensions: l.packageExtensions,
- hasCRLF: l.hasCRLF,
- }, nil
-}
-
-// Encode encode the lockfile representation and write it to the given writer
-func (l *BerryLockfile) Encode(w io.Writer) error {
- // Map all resolved packages to the descriptors that match them
- reverseLookup := l.locatorToDescriptors()
-
- lockfile := make(map[string]*BerryLockfileEntry, len(l.packages))
-
- lockfile[_metadataKey] = &BerryLockfileEntry{
- Version: fmt.Sprintf("%d", l.version),
- CacheKey: l.cacheKey,
- }
-
- for locator, descriptors := range reverseLookup {
- sortedDescriptors := make([]string, len(descriptors))
- i := 0
- for descriptor := range descriptors {
- sortedDescriptors[i] = descriptor.String()
- i++
- }
- sort.Strings(sortedDescriptors)
-
- key := strings.Join(sortedDescriptors, ", ")
-
- entry, ok := l.packages[locator]
- if !ok {
- return fmt.Errorf("Unable to find entry for %s", &locator)
- }
-
- lockfile[key] = entry
- }
-
- if l.hasCRLF {
- w = crlf.NewWriter(w)
- }
-
- _, err := io.WriteString(w, `# This file is generated by running "yarn install" inside your project.
-# Manual changes might be lost - proceed with caution!
-`)
- if err != nil {
- return errors.Wrap(err, "unable to write header to lockfile")
- }
-
- return _writeBerryLockfile(w, lockfile)
-}
-
-// Invert the descriptor to locator map
-func (l *BerryLockfile) locatorToDescriptors() map[_Locator]map[_Descriptor]_void {
- reverseLookup := make(map[_Locator]map[_Descriptor]_void, len(l.packages))
- for descriptor, locator := range l.descriptors {
- descriptors, ok := reverseLookup[locator]
- if !ok {
- reverseLookup[locator] = map[_Descriptor]_void{descriptor: {}}
- } else {
- descriptors[descriptor] = _void{}
- }
- }
-
- return reverseLookup
-}
-
-// Patches return a list of patches used in the lockfile
-func (l *BerryLockfile) Patches() []turbopath.AnchoredUnixPath {
- patches := []turbopath.AnchoredUnixPath{}
-
- for _, patchLocator := range l.patches {
- patchPath, isPatch := patchLocator.patchPath()
-
- if isPatch && !strings.HasPrefix(patchPath, "~") && !_builtinRegexp.MatchString(patchPath) {
- patches = append(patches, turbopath.AnchoredUnixPath(patchPath))
- }
- }
-
- if len(patches) == 0 {
- return nil
- }
-
- return patches
-}
-
-// DecodeBerryLockfile Takes the contents of a berry lockfile and returns a struct representation
-func DecodeBerryLockfile(contents []byte) (*BerryLockfile, error) {
- var packages map[string]*BerryLockfileEntry
-
- hasCRLF := bytes.HasSuffix(contents, _crlfLiteral)
- err := yaml.Unmarshal(contents, &packages)
- if err != nil {
- return &BerryLockfile{}, fmt.Errorf("could not unmarshal lockfile: %w", err)
- }
-
- metadata, ok := packages[_metadataKey]
- if !ok {
- return nil, errors.New("No __metadata entry found when decoding yarn.lock")
- }
- version, err := strconv.Atoi(metadata.Version)
- if err != nil {
- return nil, errors.Wrap(err, "yarn lockfile version isn't valid integer")
- }
- delete(packages, _metadataKey)
-
- locatorToPackage := map[_Locator]*BerryLockfileEntry{}
- descriptorToLocator := map[_Descriptor]_Locator{}
- // A map from packages to their patch entries
- patches := map[_Locator]_Locator{}
-
- for key, data := range packages {
- var locator _Locator
- if err := locator.parseLocator(data.Resolution); err != nil {
- return nil, errors.Wrap(err, "unable to parse entry")
- }
-
- if _, isPatch := locator.patchPath(); isPatch {
- // A patch will have the same identifier and version allowing us to construct the non-patch entry
- originalLocator := _Locator{locator._Ident, fmt.Sprintf("npm:%s", data.Version)}
- patches[originalLocator] = locator
- }
-
- // Before storing cacheKey set it to "" so we know it's invalid
- data.CacheKey = ""
-
- locatorToPackage[locator] = data
-
- // All descriptors that resolve to a single locator are grouped into a single key
- for _, entry := range _multipleKeyRegex.Split(key, -1) {
- descriptor := _Descriptor{}
- if err := descriptor.parseDescriptor(entry); err != nil {
- return nil, errors.Wrap(err, "Bad entry key found")
- }
-
- // Before lockfile version 6 descriptors could be missing the npm protocol
- if version <= 6 && descriptor.versionRange != "*" {
- _, err := semver.NewConstraint(descriptor.versionRange)
- if err == nil || _tagRegex.MatchString(descriptor.versionRange) {
- descriptor.versionRange = fmt.Sprintf("npm:%s", descriptor.versionRange)
- }
- }
-
- descriptorToLocator[descriptor] = locator
- }
- }
-
- // Build up list of all descriptors in the file
- packageExtensions := make(map[_Descriptor]_void, len(descriptorToLocator))
- for descriptor := range descriptorToLocator {
- if descriptor.protocol() == "npm" {
- packageExtensions[descriptor] = _void{}
- }
- }
- // Remove any that are found in the lockfile entries
- for _, entry := range packages {
- for _, descriptor := range entry.possibleDescriptors() {
- delete(packageExtensions, descriptor)
- }
- }
-
- lockfile := BerryLockfile{
- packages: locatorToPackage,
- version: version,
- cacheKey: metadata.CacheKey,
- descriptors: descriptorToLocator,
- patches: patches,
- packageExtensions: packageExtensions,
- hasCRLF: hasCRLF,
- }
- return &lockfile, nil
-}
-
-// GlobalChange checks if there are any differences between lockfiles that would completely invalidate
-// the cache.
-func (l *BerryLockfile) GlobalChange(other Lockfile) bool {
- otherBerry, ok := other.(*BerryLockfile)
- return !ok ||
- l.cacheKey != otherBerry.cacheKey ||
- l.version != otherBerry.version ||
- // This is probably overly cautious, but getting it correct will be hard
- !reflect.DeepEqual(l.patches, otherBerry.patches)
-}
-
-// Fields shared between _Locator and _Descriptor
-type _Ident struct {
- // Scope of package without leading @
- scope string
- // Name of package
- name string
-}
-
-type _Locator struct {
- _Ident
- // Resolved version e.g. 1.2.3
- reference string
-}
-
-type _Descriptor struct {
- _Ident
- // Version range e.g. ^1.0.0
- // Can be prefixed with the protocol e.g. npm, workspace, patch,
- versionRange string
-}
-
-func (i _Ident) String() string {
- if i.scope == "" {
- return i.name
- }
- return fmt.Sprintf("@%s/%s", i.scope, i.name)
-}
-
-var _locatorRegexp = regexp.MustCompile("^(?:@([^/]+?)/)?([^/]+?)(?:@(.+))$")
-
-func (l *_Locator) parseLocator(data string) error {
- matches := _locatorRegexp.FindStringSubmatch(data)
- if len(matches) != 4 {
- return fmt.Errorf("%s is not a valid locator string", data)
- }
- l.scope = matches[1]
- l.name = matches[2]
- l.reference = matches[3]
-
- return nil
-}
-
-func (l *_Locator) String() string {
- if l.scope == "" {
- return fmt.Sprintf("%s@%s", l.name, l.reference)
- }
- return fmt.Sprintf("@%s/%s@%s", l.scope, l.name, l.reference)
-}
-
-var _builtinRegexp = regexp.MustCompile("^builtin<([^>]+)>$")
-
-func (l *_Locator) patchPath() (string, bool) {
- if strings.HasPrefix(l.reference, "patch:") {
- patchFileIndex := strings.Index(l.reference, "#")
- paramIndex := strings.LastIndex(l.reference, "::")
- if patchFileIndex == -1 || paramIndex == -1 {
- // Better error handling
- panic("Unable to extract patch file path from lockfile entry")
- }
- patchPath := strings.TrimPrefix(l.reference[patchFileIndex+1:paramIndex], "./")
-
- return patchPath, true
- }
-
- return "", false
-}
-
-var _descriptorRegexp = regexp.MustCompile("^(?:@([^/]+?)/)?([^/]+?)(?:@(.+))?$")
-
-func (d *_Descriptor) parseDescriptor(data string) error {
- matches := _descriptorRegexp.FindStringSubmatch(data)
- if len(matches) != 4 {
- return fmt.Errorf("%s is not a valid descriptor string", data)
- }
-
- d.scope = matches[1]
- d.name = matches[2]
- d.versionRange = matches[3]
-
- return nil
-}
-
-// If the descriptor is for a patch it will return the primary descriptor that it patches
-func (d *_Descriptor) primaryVersion() (string, bool) {
- if !strings.HasPrefix(d.versionRange, "patch:") {
- return "", false
- }
- patchFileIndex := strings.Index(d.versionRange, "#")
- versionRangeIndex := strings.Index(d.versionRange, "@")
- if patchFileIndex < 0 || versionRangeIndex < 0 {
- panic("Patch reference is missing required markers")
- }
- // The ':' following npm protocol gets encoded as '%3A' in the patch string
- version := strings.Replace(d.versionRange[versionRangeIndex+1:patchFileIndex], "%3A", ":", 1)
- if !strings.HasPrefix(version, "npm:") {
- version = fmt.Sprintf("npm:%s", version)
- }
-
- return version, true
-}
-
-// Returns the protocol of the descriptor
-func (d *_Descriptor) protocol() string {
- if index := strings.Index(d.versionRange, ":"); index > 0 {
- return d.versionRange[:index]
- }
- return ""
-}
-
-func (d *_Descriptor) String() string {
- if d.scope == "" {
- return fmt.Sprintf("%s@%s", d.name, d.versionRange)
- }
- return fmt.Sprintf("@%s/%s@%s", d.scope, d.name, d.versionRange)
-}
-
-func berryPossibleKeys(name string, version string) []_Descriptor {
- makeDescriptor := func(protocol string) _Descriptor {
- descriptorString := fmt.Sprintf("%s@%s%s", name, protocol, version)
- var descriptor _Descriptor
- if err := descriptor.parseDescriptor(descriptorString); err != nil {
- panic("Generated invalid descriptor")
- }
- return descriptor
- }
- return []_Descriptor{
- makeDescriptor(""),
- makeDescriptor("npm:"),
- makeDescriptor("file:"),
- makeDescriptor("workspace:"),
- makeDescriptor("yarn:"),
- }
-}
-
-func _writeBerryLockfile(w io.Writer, lockfile map[string]*BerryLockfileEntry) error {
- keys := make([]string, len(lockfile))
- i := 0
- for key := range lockfile {
- keys[i] = key
- i++
- }
-
- // The __metadata key gets hoisted to the top
- sort.Slice(keys, func(i, j int) bool {
- if keys[i] == _metadataKey {
- return true
- } else if keys[j] == _metadataKey {
- return false
- }
- return keys[i] < keys[j]
- })
-
- for _, key := range keys {
- value, ok := lockfile[key]
- if !ok {
- panic(fmt.Sprintf("Unable to find entry for %s", key))
- }
-
- wrappedKey := _wrapString(key)
- wrappedValue := _stringifyEntry(*value, 1)
-
- var keyPart string
- if len(wrappedKey) > 1024 {
- keyPart = fmt.Sprintf("? %s\n:", keyPart)
- } else {
- keyPart = fmt.Sprintf("%s:", wrappedKey)
- }
-
- _, err := io.WriteString(w, fmt.Sprintf("\n%s\n%s\n", keyPart, wrappedValue))
- if err != nil {
- return errors.Wrap(err, "unable to write to lockfile")
- }
- }
-
- return nil
-}
-
-var _simpleStringPattern = regexp.MustCompile("^[^-?:,\\][{}#&*!|>'\"%@` \t\r\n]([ \t]*[^,\\][{}:# \t\r\n])*$")
-
-func _wrapString(str string) string {
- if !_simpleStringPattern.MatchString(str) {
- var b bytes.Buffer
- encoder := json.NewEncoder(&b)
- encoder.SetEscapeHTML(false)
- err := encoder.Encode(str)
- if err != nil {
- panic("Unexpected error wrapping key")
- }
-
- return strings.TrimRight(b.String(), "\n")
- }
- return str
-}
-
-func _stringifyEntry(entry BerryLockfileEntry, indentLevel int) string {
- lines := []string{}
- addLine := func(field, value string, inline bool) {
- var line string
- if inline {
- line = fmt.Sprintf(" %s: %s", field, value)
- } else {
- line = fmt.Sprintf(" %s:\n%s", field, value)
- }
- lines = append(lines, line)
- }
-
- if entry.Version != "" {
- addLine("version", _wrapString(entry.Version), true)
- }
- if entry.Resolution != "" {
- addLine("resolution", _wrapString(entry.Resolution), true)
- }
- if len(entry.Dependencies) > 0 {
- addLine("dependencies", _stringifyDeps(entry.Dependencies), false)
- }
- if len(entry.PeerDependencies) > 0 {
- addLine("peerDependencies", _stringifyDeps(entry.PeerDependencies), false)
- }
- if len(entry.DependenciesMeta) > 0 {
- addLine("dependenciesMeta", _stringifyDepsMeta(entry.DependenciesMeta), false)
- }
- if len(entry.PeerDependenciesMeta) > 0 {
- addLine("peerDependenciesMeta", _stringifyDepsMeta(entry.PeerDependenciesMeta), false)
- }
-
- if len(entry.Bin) > 0 {
- addLine("bin", _stringifyDeps(entry.Bin), false)
- }
- if entry.Checksum != "" {
- addLine("checksum", _wrapString(entry.Checksum), true)
- }
- if entry.Conditions != "" {
- addLine("conditions", _wrapString(entry.Conditions), true)
- }
- if entry.LanguageName != "" {
- addLine("languageName", _wrapString(entry.LanguageName), true)
- }
- if entry.LinkType != "" {
- addLine("linkType", _wrapString(entry.LinkType), true)
- }
- if entry.CacheKey != "" {
- addLine("cacheKey", _wrapString(entry.CacheKey), true)
- }
-
- return strings.Join(lines, "\n")
-}
-
-func _stringifyDeps(deps map[string]string) string {
- keys := make([]string, len(deps))
- i := 0
- for key := range deps {
- keys[i] = key
- i++
- }
- sort.Strings(keys)
-
- lines := make([]string, 0, len(deps))
- addLine := func(name, version string) {
- lines = append(lines, fmt.Sprintf(" %s: %s", _wrapString(name), _wrapString(version)))
- }
-
- for _, name := range keys {
- version := deps[name]
- addLine(name, version)
- }
-
- return strings.Join(lines, "\n")
-}
-
-func _stringifyDepsMeta(meta map[string]BerryDependencyMetaEntry) string {
- keys := make([]string, len(meta))
- i := 0
- for key := range meta {
- keys[i] = key
- i++
- }
- sort.Strings(keys)
-
- lines := make([]string, 0, len(meta))
- addLine := func(name string, key string) {
- lines = append(lines, fmt.Sprintf(" %s:\n %s: true", _wrapString(name), key))
- }
-
- for _, name := range keys {
- optional := meta[name]
- if optional.Optional {
- addLine(name, "optional")
- }
- if optional.Unplugged {
- addLine(name, "unplugged")
- }
- }
-
- return strings.Join(lines, "\n")
-}
diff --git a/cli/internal/lockfile/berry_lockfile_test.go b/cli/internal/lockfile/berry_lockfile_test.go
deleted file mode 100644
index afcbe46..0000000
--- a/cli/internal/lockfile/berry_lockfile_test.go
+++ /dev/null
@@ -1,273 +0,0 @@
-package lockfile
-
-import (
- "bytes"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func getBerryLockfile(t *testing.T, filename string) *BerryLockfile {
- content, err := getFixture(t, filename)
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodeBerryLockfile(content)
- if err != nil {
- t.Error(err)
- }
- return lockfile
-}
-
-func Test_DecodingBerryLockfile(t *testing.T) {
- lockfile := getBerryLockfile(t, "berry.lock")
- assert.Equal(t, lockfile.version, 6)
- assert.Equal(t, lockfile.cacheKey, "8c0")
-}
-
-func Test_ResolvePackage(t *testing.T) {
- lockfile := getBerryLockfile(t, "berry.lock")
-
- type Case struct {
- name string
- semver string
- key string
- version string
- found bool
- }
-
- cases := map[string]Case{
- "can resolve '||' semver syntax": {
- name: "js-tokens",
- semver: "^3.0.0 || ^4.0.0",
- key: "js-tokens@npm:4.0.0",
- version: "4.0.0",
- found: true,
- },
- "handles packages with multiple descriptors": {
- name: "js-tokens",
- semver: "^4.0.0",
- key: "js-tokens@npm:4.0.0",
- version: "4.0.0",
- found: true,
- },
- "doesn't find nonexistent descriptors": {
- name: "@babel/code-frame",
- semver: "^7.12.11",
- found: false,
- },
- "handles workspace packages": {
- name: "eslint-config-custom",
- semver: "*",
- key: "eslint-config-custom@workspace:packages/eslint-config-custom",
- version: "0.0.0-use.local",
- found: true,
- },
- }
-
- for testName, testCase := range cases {
- pkg, err := lockfile.ResolvePackage("some-pkg", testCase.name, testCase.semver)
- assert.NilError(t, err)
- if testCase.found {
- assert.Equal(t, pkg.Key, testCase.key, testName)
- assert.Equal(t, pkg.Version, testCase.version, testName)
- }
- assert.Equal(t, pkg.Found, testCase.found, testName)
- }
-}
-
-func Test_AllDependencies(t *testing.T) {
- lockfile := getBerryLockfile(t, "berry.lock")
-
- pkg, err := lockfile.ResolvePackage("some-pkg", "react-dom", "18.2.0")
- assert.NilError(t, err)
- assert.Assert(t, pkg.Found, "expected to find react-dom")
- deps, found := lockfile.AllDependencies(pkg.Key)
- assert.Assert(t, found, "expected lockfile key for react-dom to be present")
- assert.Equal(t, len(deps), 2, "expected to find all react-dom direct dependencies")
- for pkgName, version := range deps {
- pkg, err := lockfile.ResolvePackage("some-pkg", pkgName, version)
- assert.NilError(t, err, "error finding %s@%s", pkgName, version)
- assert.Assert(t, pkg.Found, "expected to find lockfile entry for %s@%s", pkgName, version)
- }
-}
-
-func Test_BerryPatchList(t *testing.T) {
- lockfile := getBerryLockfile(t, "berry.lock")
-
- var locator _Locator
- if err := locator.parseLocator("resolve@npm:2.0.0-next.4"); err != nil {
- t.Error(err)
- }
-
- patchLocator, ok := lockfile.patches[locator]
- assert.Assert(t, ok, "Expected to find patch locator")
- patch, ok := lockfile.packages[patchLocator]
- assert.Assert(t, ok, "Expected to find patch")
- assert.Equal(t, patch.Version, "2.0.0-next.4")
-}
-
-func Test_PackageExtensions(t *testing.T) {
- lockfile := getBerryLockfile(t, "berry.lock")
-
- expectedExtensions := map[_Descriptor]_void{}
- for _, extension := range []string{"@babel/types@npm:^7.8.3", "lodash@npm:4.17.21"} {
- var extensionDescriptor _Descriptor
- if err := extensionDescriptor.parseDescriptor(extension); err != nil {
- t.Error(err)
- }
- expectedExtensions[extensionDescriptor] = _void{}
- }
-
- assert.DeepEqual(t, lockfile.packageExtensions, expectedExtensions)
-}
-
-func Test_StringifyMetadata(t *testing.T) {
- metadata := BerryLockfileEntry{
- Version: "6",
- CacheKey: "8c0",
- }
- lockfile := map[string]*BerryLockfileEntry{"__metadata": &metadata}
-
- var b bytes.Buffer
- err := _writeBerryLockfile(&b, lockfile)
- assert.Assert(t, err == nil)
- assert.Equal(t, b.String(), `
-__metadata:
- version: 6
- cacheKey: 8c0
-`)
-}
-
-func Test_BerryRoundtrip(t *testing.T) {
- content, err := getFixture(t, "berry.lock")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodeBerryLockfile(content)
- if err != nil {
- t.Error(err)
- }
-
- var b bytes.Buffer
- if err := lockfile.Encode(&b); err != nil {
- t.Error(err)
- }
-
- assert.Equal(t, b.String(), string(content))
-}
-
-func Test_PatchPathExtraction(t *testing.T) {
- type Case struct {
- locator string
- patchPath string
- isPatch bool
- }
- cases := []Case{
- {
- locator: "lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch::version=4.17.21&hash=2c6e9e&locator=berry-patch%40workspace%3A.",
- patchPath: ".yarn/patches/lodash-npm-4.17.21-6382451519.patch",
- isPatch: true,
- },
- {
- locator: "lodash@npm:4.17.21",
- isPatch: false,
- },
- {
- locator: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin<compat/resolve>::version=2.0.0-next.4&hash=07638b",
- patchPath: "~builtin<compat/resolve>",
- isPatch: true,
- },
- }
-
- for _, testCase := range cases {
- var locator _Locator
- err := locator.parseLocator(testCase.locator)
- if err != nil {
- t.Error(err)
- }
- patchPath, isPatch := locator.patchPath()
- assert.Equal(t, isPatch, testCase.isPatch, locator)
- assert.Equal(t, patchPath, testCase.patchPath, locator)
- }
-}
-
-func Test_PatchPrimaryVersion(t *testing.T) {
- // todo write tests to make sure extraction actually works
- type TestCase struct {
- descriptor string
- version string
- isPatch bool
- }
- testCases := []TestCase{
- {
- descriptor: "lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch::locator=berry-patch%40workspace%3A.",
- version: "npm:4.17.21",
- isPatch: true,
- },
- {
- descriptor: "typescript@patch:typescript@^4.5.2#~builtin<compat/typescript>",
- version: "npm:^4.5.2",
- isPatch: true,
- },
- {
- descriptor: "react@npm:18.2.0",
- isPatch: false,
- },
- }
-
- for _, testCase := range testCases {
- var d _Descriptor
- err := d.parseDescriptor(testCase.descriptor)
- assert.NilError(t, err, testCase.descriptor)
- actual, isPatch := d.primaryVersion()
- assert.Equal(t, isPatch, testCase.isPatch, testCase)
- if testCase.isPatch {
- assert.Equal(t, actual, testCase.version, testCase.descriptor)
- }
- }
-}
-
-func Test_BerryPruneDescriptors(t *testing.T) {
- lockfile := getBerryLockfile(t, "minimal-berry.lock")
- prunedLockfile, err := lockfile.Subgraph(
- []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("packages/a").ToSystemPath(),
- turbopath.AnchoredUnixPath("packages/c").ToSystemPath(),
- },
- []string{"lodash@npm:4.17.21"},
- )
- if err != nil {
- t.Error(err)
- }
- lockfileA := prunedLockfile.(*BerryLockfile)
-
- prunedLockfile, err = lockfile.Subgraph(
- []turbopath.AnchoredSystemPath{
- turbopath.AnchoredUnixPath("packages/b").ToSystemPath(),
- turbopath.AnchoredUnixPath("packages/c").ToSystemPath(),
- },
- []string{"lodash@npm:4.17.21"},
- )
- if err != nil {
- t.Error(err)
- }
- lockfileB := prunedLockfile.(*BerryLockfile)
-
- lodashIdent := _Ident{name: "lodash"}
- lodashA := _Descriptor{lodashIdent, "npm:^4.17.0"}
- lodashB := _Descriptor{lodashIdent, "npm:^3.0.0 || ^4.0.0"}
-
- lodashEntryA, hasLodashA := lockfileA.descriptors[lodashA]
- lodashEntryB, hasLodashB := lockfileB.descriptors[lodashB]
-
- assert.Assert(t, hasLodashA, "Expected lockfile a to have descriptor used by a")
- assert.Assert(t, hasLodashB, "Expected lockfile b to have descriptor used by b")
- assert.DeepEqual(t, lodashEntryA.reference, lodashEntryB.reference)
-
- _, lockfileAHasB := lockfileA.descriptors[lodashB]
- _, lockfileBHasA := lockfileB.descriptors[lodashA]
- assert.Assert(t, !lockfileAHasB, "Expected lockfile a not to have descriptor used by b")
- assert.Assert(t, !lockfileBHasA, "Expected lockfile b not to have descriptor used by a")
-}
diff --git a/cli/internal/lockfile/lockfile.go b/cli/internal/lockfile/lockfile.go
deleted file mode 100644
index bb36eda..0000000
--- a/cli/internal/lockfile/lockfile.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Package lockfile provides the lockfile interface and implementations for the various package managers
-package lockfile
-
-import (
- "fmt"
- "io"
- "reflect"
- "sort"
-
- mapset "github.com/deckarep/golang-set"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "golang.org/x/sync/errgroup"
-)
-
-// Lockfile Interface for general operations that work across all lockfiles
-type Lockfile interface {
- // ResolvePackage Given a workspace, a package it imports and version returns the key, resolved version, and if it was found
- ResolvePackage(workspacePath turbopath.AnchoredUnixPath, name string, version string) (Package, error)
- // AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package
- AllDependencies(key string) (map[string]string, bool)
- // Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given
- Subgraph(workspacePackages []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error)
- // Encode encode the lockfile representation and write it to the given writer
- Encode(w io.Writer) error
- // Patches return a list of patches used in the lockfile
- Patches() []turbopath.AnchoredUnixPath
- // GlobalChange checks if there are any differences between lockfiles that would completely invalidate
- // the cache.
- GlobalChange(other Lockfile) bool
-}
-
-// IsNil checks if lockfile is nil
-func IsNil(l Lockfile) bool {
- return l == nil || reflect.ValueOf(l).IsNil()
-}
-
-// Package Structure representing a possible Pack
-type Package struct {
- // Key used to lookup a package in the lockfile
- Key string
- // The resolved version of a package as it appears in the lockfile
- Version string
- // Set to true iff Key and Version are set
- Found bool
-}
-
-// ByKey sort package structures by key
-type ByKey []Package
-
-func (p ByKey) Len() int {
- return len(p)
-}
-
-func (p ByKey) Swap(i, j int) {
- p[i], p[j] = p[j], p[i]
-}
-
-func (p ByKey) Less(i, j int) bool {
- return p[i].Key+p[i].Version < p[j].Key+p[j].Version
-}
-
-var _ (sort.Interface) = (*ByKey)(nil)
-
-// TransitiveClosure the set of all lockfile keys that pkg depends on
-func TransitiveClosure(
- workspaceDir turbopath.AnchoredUnixPath,
- unresolvedDeps map[string]string,
- lockFile Lockfile,
-) (mapset.Set, error) {
- if lf, ok := lockFile.(*NpmLockfile); ok {
- // We special case as Rust implementations have their own dep crawl
- return npmTransitiveDeps(lf, workspaceDir, unresolvedDeps)
- }
- return transitiveClosure(workspaceDir, unresolvedDeps, lockFile)
-}
-
-func transitiveClosure(
- workspaceDir turbopath.AnchoredUnixPath,
- unresolvedDeps map[string]string,
- lockFile Lockfile,
-) (mapset.Set, error) {
- if IsNil(lockFile) {
- return nil, fmt.Errorf("No lockfile available to do analysis on")
- }
-
- resolvedPkgs := mapset.NewSet()
- lockfileEg := &errgroup.Group{}
-
- transitiveClosureHelper(lockfileEg, workspaceDir, lockFile, unresolvedDeps, resolvedPkgs)
-
- if err := lockfileEg.Wait(); err != nil {
- return nil, err
- }
-
- return resolvedPkgs, nil
-}
-
-func transitiveClosureHelper(
- wg *errgroup.Group,
- workspacePath turbopath.AnchoredUnixPath,
- lockfile Lockfile,
- unresolvedDirectDeps map[string]string,
- resolvedDeps mapset.Set,
-) {
- for directDepName, unresolvedVersion := range unresolvedDirectDeps {
- directDepName := directDepName
- unresolvedVersion := unresolvedVersion
- wg.Go(func() error {
-
- lockfilePkg, err := lockfile.ResolvePackage(workspacePath, directDepName, unresolvedVersion)
-
- if err != nil {
- return err
- }
-
- if !lockfilePkg.Found || resolvedDeps.Contains(lockfilePkg) {
- return nil
- }
-
- resolvedDeps.Add(lockfilePkg)
-
- allDeps, ok := lockfile.AllDependencies(lockfilePkg.Key)
-
- if !ok {
- panic(fmt.Sprintf("Unable to find entry for %s", lockfilePkg.Key))
- }
-
- if len(allDeps) > 0 {
- transitiveClosureHelper(wg, workspacePath, lockfile, allDeps, resolvedDeps)
- }
-
- return nil
- })
- }
-}
diff --git a/cli/internal/lockfile/lockfile_test.go b/cli/internal/lockfile/lockfile_test.go
deleted file mode 100644
index 7c666cc..0000000
--- a/cli/internal/lockfile/lockfile_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package lockfile
-
-import (
- "sort"
- "testing"
-
- "gotest.tools/v3/assert"
-)
-
-func Test_ByKeySortIsStable(t *testing.T) {
- packagesA := []Package{
- {"/foo/1.2.3", "1.2.3", true},
- {"/baz/1.0.9", "/baz/1.0.9", true},
- {"/bar/1.2.3", "1.2.3", true},
- {"/foo/1.2.3", "/foo/1.2.3", true},
- {"/baz/1.0.9", "1.0.9", true},
- }
- packagesB := make([]Package, len(packagesA))
- copy(packagesB, packagesA)
-
- sort.Sort(ByKey(packagesA))
- sort.Sort(ByKey(packagesB))
-
- assert.DeepEqual(t, packagesA, packagesB)
-}
diff --git a/cli/internal/lockfile/npm_lockfile.go b/cli/internal/lockfile/npm_lockfile.go
deleted file mode 100644
index 67cd32a..0000000
--- a/cli/internal/lockfile/npm_lockfile.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package lockfile
-
-import (
- "encoding/json"
- "io"
-
- mapset "github.com/deckarep/golang-set"
- "github.com/vercel/turbo/cli/internal/ffi"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// NpmLockfile representation of package-lock.json
-type NpmLockfile struct {
- // We just story the entire lockfile in memory and pass it for every call
- contents []byte
-}
-
-// ResolvePackage Given a workspace, a package it imports and version returns the key, resolved version, and if it was found
-func (l *NpmLockfile) ResolvePackage(workspacePath turbopath.AnchoredUnixPath, name string, version string) (Package, error) {
- // This is only used when doing calculating the transitive deps, but Rust
- // implementations do this calculation on the Rust side.
- panic("Unreachable")
-}
-
-// AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package
-func (l *NpmLockfile) AllDependencies(key string) (map[string]string, bool) {
- // This is only used when doing calculating the transitive deps, but Rust
- // implementations do this calculation on the Rust side.
- panic("Unreachable")
-}
-
-// Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given
-func (l *NpmLockfile) Subgraph(workspacePackages []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) {
- workspaces := make([]string, len(workspacePackages))
- for i, workspace := range workspacePackages {
- workspaces[i] = workspace.ToUnixPath().ToString()
- }
- contents, err := ffi.NpmSubgraph(l.contents, workspaces, packages)
- if err != nil {
- return nil, err
- }
- return &NpmLockfile{contents: contents}, nil
-}
-
-// Encode the lockfile representation and write it to the given writer
-func (l *NpmLockfile) Encode(w io.Writer) error {
- _, err := w.Write(l.contents)
- return err
-}
-
-// Patches return a list of patches used in the lockfile
-func (l *NpmLockfile) Patches() []turbopath.AnchoredUnixPath {
- return nil
-}
-
-// GlobalChange checks if there are any differences between lockfiles that would completely invalidate
-// the cache.
-func (l *NpmLockfile) GlobalChange(other Lockfile) bool {
- o, ok := other.(*NpmLockfile)
- if !ok {
- return true
- }
-
- // We just grab the few global fields and check if they've changed
- type minimalJSON struct {
- LockfileVersion string `json:"version"`
- Requires bool `json:"requires"`
- }
- var self minimalJSON
- var otherJSON minimalJSON
- if err := json.Unmarshal(o.contents, &otherJSON); err != nil {
- return true
- }
- if err := json.Unmarshal(l.contents, &self); err != nil {
- return true
- }
-
- return self.LockfileVersion != otherJSON.LockfileVersion ||
- self.Requires != otherJSON.Requires
-}
-
-var _ (Lockfile) = (*NpmLockfile)(nil)
-
-// DecodeNpmLockfile Parse contents of package-lock.json into NpmLockfile
-func DecodeNpmLockfile(contents []byte) (Lockfile, error) {
- return &NpmLockfile{contents: contents}, nil
-}
-
-func npmTransitiveDeps(lockfile *NpmLockfile, workspacePath turbopath.AnchoredUnixPath, unresolvedDeps map[string]string) (mapset.Set, error) {
- pkgDir := workspacePath.ToString()
-
- packages, err := ffi.NpmTransitiveDeps(lockfile.contents, pkgDir, unresolvedDeps)
- if err != nil {
- return nil, err
- }
-
- deps := make([]interface{}, len(packages))
- for i, pkg := range packages {
- deps[i] = Package{
- Found: pkg.Found,
- Key: pkg.Key,
- Version: pkg.Version,
- }
- }
-
- return mapset.NewSetFromSlice(deps), nil
-}
diff --git a/cli/internal/lockfile/pnpm_lockfile.go b/cli/internal/lockfile/pnpm_lockfile.go
deleted file mode 100644
index a51b36e..0000000
--- a/cli/internal/lockfile/pnpm_lockfile.go
+++ /dev/null
@@ -1,579 +0,0 @@
-package lockfile
-
-import (
- "fmt"
- "io"
- "reflect"
- "sort"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/yaml"
-)
-
-// PnpmLockfile Go representation of the contents of 'pnpm-lock.yaml'
-// Reference https://github.com/pnpm/pnpm/blob/main/packages/lockfile-types/src/index.ts
-type PnpmLockfile struct {
- isV6 bool
- // Before 6.0 version was stored as a float, but as of 6.0+ it's a string
- Version interface{} `yaml:"lockfileVersion"`
- NeverBuiltDependencies []string `yaml:"neverBuiltDependencies,omitempty"`
- OnlyBuiltDependencies []string `yaml:"onlyBuiltDependencies,omitempty"`
- Overrides map[string]string `yaml:"overrides,omitempty"`
- PackageExtensionsChecksum string `yaml:"packageExtensionsChecksum,omitempty"`
- PatchedDependencies map[string]PatchFile `yaml:"patchedDependencies,omitempty"`
- Importers map[string]ProjectSnapshot `yaml:"importers"`
- Packages map[string]PackageSnapshot `yaml:"packages,omitempty"`
- Time map[string]string `yaml:"time,omitempty"`
-}
-
-var _ Lockfile = (*PnpmLockfile)(nil)
-
-// ProjectSnapshot Snapshot used to represent projects in the importers section
-type ProjectSnapshot struct {
- // for v6 we omitempty
- // for pre v6 we *need* to omit the empty map
- Specifiers SpecifierMap `yaml:"specifiers,omitempty"`
-
- // The values of these maps will be string if lockfileVersion <6 or DependencyV6 if 6+
- Dependencies map[string]yaml.Node `yaml:"dependencies,omitempty"`
- OptionalDependencies map[string]yaml.Node `yaml:"optionalDependencies,omitempty"`
- DevDependencies map[string]yaml.Node `yaml:"devDependencies,omitempty"`
-
- DependenciesMeta map[string]DependenciesMeta `yaml:"dependenciesMeta,omitempty"`
- PublishDirectory string `yaml:"publishDirectory,omitempty"`
-}
-
-// SpecifierMap is a type wrapper that overrides IsZero for Golang's map
-// to match the behavior that pnpm expects
-type SpecifierMap map[string]string
-
-// IsZero is used to check whether an object is zero to
-// determine whether it should be omitted when marshaling
-// with the omitempty flag.
-func (m SpecifierMap) IsZero() bool {
- return m == nil
-}
-
-var _ (yaml.IsZeroer) = (*SpecifierMap)(nil)
-
-// DependencyV6 are dependency entries for lockfileVersion 6.0+
-type DependencyV6 struct {
- Specifier string `yaml:"specifier"`
- Version string `yaml:"version"`
-}
-
-// Will try to find a resolution in any of the dependency fields
-func (p *ProjectSnapshot) findResolution(dependency string) (DependencyV6, bool, error) {
- var getResolution func(yaml.Node) (DependencyV6, bool, error)
- if len(p.Specifiers) > 0 {
- getResolution = func(node yaml.Node) (DependencyV6, bool, error) {
- specifier, ok := p.Specifiers[dependency]
- if !ok {
- return DependencyV6{}, false, nil
- }
- var version string
- if err := node.Decode(&version); err != nil {
- return DependencyV6{}, false, err
- }
- return DependencyV6{Version: version, Specifier: specifier}, true, nil
- }
- } else {
- getResolution = func(node yaml.Node) (DependencyV6, bool, error) {
- var resolution DependencyV6
- if err := node.Decode(&resolution); err != nil {
- return DependencyV6{}, false, err
- }
- return resolution, true, nil
- }
- }
- if resolution, ok := p.Dependencies[dependency]; ok {
- return getResolution(resolution)
- }
- if resolution, ok := p.DevDependencies[dependency]; ok {
- return getResolution(resolution)
- }
- if resolution, ok := p.OptionalDependencies[dependency]; ok {
- return getResolution(resolution)
- }
- return DependencyV6{}, false, nil
-}
-
-// PackageSnapshot Snapshot used to represent a package in the packages setion
-type PackageSnapshot struct {
- Resolution PackageResolution `yaml:"resolution,flow"`
- ID string `yaml:"id,omitempty"`
-
- // only needed for packages that aren't in npm
- Name string `yaml:"name,omitempty"`
- Version string `yaml:"version,omitempty"`
-
- Engines struct {
- Node string `yaml:"node"`
- NPM string `yaml:"npm,omitempty"`
- } `yaml:"engines,omitempty,flow"`
- CPU []string `yaml:"cpu,omitempty,flow"`
- Os []string `yaml:"os,omitempty,flow"`
- LibC []string `yaml:"libc,omitempty"`
-
- Deprecated string `yaml:"deprecated,omitempty"`
- HasBin bool `yaml:"hasBin,omitempty"`
- Prepare bool `yaml:"prepare,omitempty"`
- RequiresBuild bool `yaml:"requiresBuild,omitempty"`
-
- BundledDependencies []string `yaml:"bundledDependencies,omitempty"`
- PeerDependencies map[string]string `yaml:"peerDependencies,omitempty"`
- PeerDependenciesMeta map[string]struct {
- Optional bool `yaml:"optional"`
- } `yaml:"peerDependenciesMeta,omitempty"`
-
- Dependencies map[string]string `yaml:"dependencies,omitempty"`
- OptionalDependencies map[string]string `yaml:"optionalDependencies,omitempty"`
-
- TransitivePeerDependencies []string `yaml:"transitivePeerDependencies,omitempty"`
- Dev bool `yaml:"dev"`
- Optional bool `yaml:"optional,omitempty"`
- Patched bool `yaml:"patched,omitempty"`
-}
-
-// PackageResolution Various resolution strategies for packages
-type PackageResolution struct {
- Type string `yaml:"type,omitempty"`
- // For npm or tarball
- Integrity string `yaml:"integrity,omitempty"`
-
- // For tarball
- Tarball string `yaml:"tarball,omitempty"`
-
- // For local directory
- Dir string `yaml:"directory,omitempty"`
-
- // For git repo
- Repo string `yaml:"repo,omitempty"`
- Commit string `yaml:"commit,omitempty"`
-}
-
-// PatchFile represent a patch applied to a package
-type PatchFile struct {
- Path string `yaml:"path"`
- Hash string `yaml:"hash"`
-}
-
-func isSupportedVersion(version interface{}) error {
- switch version.(type) {
- case string:
- if version == "6.0" {
- return nil
- }
- case float64:
- if version == 5.3 || version == 5.4 {
- return nil
- }
- default:
- return fmt.Errorf("lockfileVersion of type %T is invalid", version)
- }
- supportedVersions := []string{"5.3", "5.4", "6.0"}
- return errors.Errorf("Unable to generate pnpm-lock.yaml with lockfileVersion: %s. Supported lockfile versions are %v", version, supportedVersions)
-}
-
-// DependenciesMeta metadata for dependencies
-type DependenciesMeta struct {
- Injected bool `yaml:"injected,omitempty"`
- Node string `yaml:"node,omitempty"`
- Patch string `yaml:"patch,omitempty"`
-}
-
-// DecodePnpmLockfile parse a pnpm lockfile
-func DecodePnpmLockfile(contents []byte) (*PnpmLockfile, error) {
- var lockfile PnpmLockfile
- err := yaml.Unmarshal(contents, &lockfile)
- if err != nil {
- return nil, errors.Wrap(err, "could not unmarshal lockfile: ")
- }
-
- switch lockfile.Version.(type) {
- case float64:
- lockfile.isV6 = false
- case string:
- lockfile.isV6 = true
- default:
- return nil, fmt.Errorf("Unexpected type of lockfileVersion: '%T', expected float64 or string", lockfile.Version)
- }
- return &lockfile, nil
-}
-
-// ResolvePackage Given a package and version returns the key, resolved version, and if it was found
-func (p *PnpmLockfile) ResolvePackage(workspacePath turbopath.AnchoredUnixPath, name string, version string) (Package, error) {
- // Check if version is a key
- if _, ok := p.Packages[version]; ok {
- return Package{Key: version, Version: p.extractVersion(version), Found: true}, nil
- }
-
- resolvedVersion, ok, err := p.resolveSpecifier(workspacePath, name, version)
- if !ok || err != nil {
- return Package{}, err
- }
- key := p.formatKey(name, resolvedVersion)
- if entry, ok := (p.Packages)[key]; ok {
- var version string
- if entry.Version != "" {
- version = entry.Version
- } else {
- version = resolvedVersion
- }
- return Package{Key: key, Version: version, Found: true}, nil
- }
-
- if entry, ok := p.Packages[resolvedVersion]; ok {
- var version string
- if entry.Version != "" {
- version = entry.Version
- } else {
- // If there isn't a version field in the entry then the version is
- // encoded in the key and we can omit the name from the version.
- version = p.extractVersion(resolvedVersion)
- }
- return Package{Key: resolvedVersion, Version: version, Found: true}, nil
- }
-
- return Package{}, nil
-}
-
-// AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package
-func (p *PnpmLockfile) AllDependencies(key string) (map[string]string, bool) {
- deps := map[string]string{}
- entry, ok := p.Packages[key]
- if !ok {
- return deps, false
- }
-
- for name, version := range entry.Dependencies {
- deps[name] = version
- }
-
- for name, version := range entry.OptionalDependencies {
- deps[name] = version
- }
-
- // Peer dependencies appear in the Dependencies map resolved
-
- return deps, true
-}
-
-// Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given
-func (p *PnpmLockfile) Subgraph(workspacePackages []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) {
- lockfilePackages := make(map[string]PackageSnapshot, len(packages))
- for _, key := range packages {
- entry, ok := p.Packages[key]
- if ok {
- lockfilePackages[key] = entry
- } else {
- return nil, fmt.Errorf("Unable to find lockfile entry for %s", key)
- }
- }
-
- importers, err := pruneImporters(p.Importers, workspacePackages)
- if err != nil {
- return nil, err
- }
-
- for _, importer := range importers {
- for dependency, meta := range importer.DependenciesMeta {
- if meta.Injected {
- resolution, ok, err := importer.findResolution(dependency)
- if err != nil {
- return nil, errors.Wrapf(err, "Unable to decode reference to %s", dependency)
- }
- if !ok {
- return nil, fmt.Errorf("Unable to find %s other than reference in dependenciesMeta", dependency)
- }
- entry, ok := p.Packages[resolution.Version]
- if !ok {
- return nil, fmt.Errorf("Unable to find package entry for %s", resolution)
- }
-
- lockfilePackages[resolution.Version] = entry
- }
- }
- }
-
- lockfile := PnpmLockfile{
- Version: p.Version,
- Packages: lockfilePackages,
- NeverBuiltDependencies: p.NeverBuiltDependencies,
- OnlyBuiltDependencies: p.OnlyBuiltDependencies,
- Overrides: p.Overrides,
- PackageExtensionsChecksum: p.PackageExtensionsChecksum,
- PatchedDependencies: p.prunePatches(p.PatchedDependencies, lockfilePackages),
- Importers: importers,
- }
-
- return &lockfile, nil
-}
-
-// Prune imports to only those have all of their dependencies in the packages list
-func pruneImporters(importers map[string]ProjectSnapshot, workspacePackages []turbopath.AnchoredSystemPath) (map[string]ProjectSnapshot, error) {
- prunedImporters := map[string]ProjectSnapshot{}
-
- // Copy over root level importer
- if root, ok := importers["."]; ok {
- prunedImporters["."] = root
- }
-
- for _, workspacePath := range workspacePackages {
- workspace := workspacePath.ToUnixPath().ToString()
- importer, ok := importers[workspace]
-
- // If a workspace has no dependencies *and* it is only depended on by the
- // workspace root it will not show up as an importer.
- if ok {
- prunedImporters[workspace] = importer
- }
-
- }
-
- return prunedImporters, nil
-}
-
-func (p *PnpmLockfile) prunePatches(patches map[string]PatchFile, packages map[string]PackageSnapshot) map[string]PatchFile {
- if len(patches) == 0 {
- return nil
- }
-
- patchPackages := make(map[string]PatchFile, len(patches))
- for dependency := range packages {
- if p.isV6 {
- // Internally pnpm partially converts the new path format to the old
- // format in order for existing parsing logic to work.
- dependency = convertNewToOldDepPath(dependency)
- }
- dp := parseDepPath(dependency)
- patchKey := fmt.Sprintf("%s@%s", dp.name, dp.version)
-
- if patch, ok := patches[patchKey]; ok && patch.Hash == dp.patchHash() {
- patchPackages[patchKey] = patch
- }
- }
-
- return patchPackages
-}
-
-// Encode encode the lockfile representation and write it to the given writer
-func (p *PnpmLockfile) Encode(w io.Writer) error {
- if err := isSupportedVersion(p.Version); err != nil {
- return err
- }
-
- encoder := yaml.NewEncoder(w)
- encoder.SetIndent(2)
-
- if err := encoder.Encode(p); err != nil {
- return errors.Wrap(err, "unable to encode pnpm lockfile")
- }
- return nil
-}
-
-// Patches return a list of patches used in the lockfile
-func (p *PnpmLockfile) Patches() []turbopath.AnchoredUnixPath {
- if len(p.PatchedDependencies) == 0 {
- return nil
- }
- patches := make([]string, len(p.PatchedDependencies))
- i := 0
- for _, patch := range p.PatchedDependencies {
- patches[i] = patch.Path
- i++
- }
- sort.Strings(patches)
-
- patchPaths := make([]turbopath.AnchoredUnixPath, len(p.PatchedDependencies))
- for i, patch := range patches {
- patchPaths[i] = turbopath.AnchoredUnixPath(patch)
- }
- return patchPaths
-}
-
-// GlobalChange checks if there are any differences between lockfiles that would completely invalidate
-// the cache.
-func (p *PnpmLockfile) GlobalChange(other Lockfile) bool {
- o, ok := other.(*PnpmLockfile)
- return !ok ||
- p.Version != o.Version ||
- p.PackageExtensionsChecksum != o.PackageExtensionsChecksum ||
- !reflect.DeepEqual(p.Overrides, o.Overrides) ||
- !reflect.DeepEqual(p.PatchedDependencies, o.PatchedDependencies)
-}
-
-func (p *PnpmLockfile) resolveSpecifier(workspacePath turbopath.AnchoredUnixPath, name string, specifier string) (string, bool, error) {
- pnpmWorkspacePath := workspacePath.ToString()
- if pnpmWorkspacePath == "" {
- // For pnpm, the root is named "."
- pnpmWorkspacePath = "."
- }
- importer, ok := p.Importers[pnpmWorkspacePath]
- if !ok {
- return "", false, fmt.Errorf("no workspace '%v' found in lockfile", workspacePath)
- }
- resolution, ok, err := importer.findResolution(name)
- if err != nil {
- return "", false, err
- }
- // Verify that the specifier in the importer matches the one given
- if !ok {
- // Check if the specifier is already a resolved version
- if _, ok := p.Packages[p.formatKey(name, specifier)]; ok {
- return specifier, true, nil
- }
- return "", false, fmt.Errorf("Unable to find resolved version for %s@%s in %s", name, specifier, workspacePath)
- }
- overrideSpecifier := p.applyOverrides(name, specifier)
- if resolution.Specifier != overrideSpecifier {
- if _, ok := p.Packages[p.formatKey(name, overrideSpecifier)]; ok {
- return overrideSpecifier, true, nil
- }
- return "", false, nil
- }
- return resolution.Version, true, nil
-}
-
-// Apply pnpm overrides to specifier, see https://pnpm.io/package_json#pnpmoverrides
-// Note this is barebones support and will only supports global overrides
-// future work will support semver ranges and selector filtering.
-func (p *PnpmLockfile) applyOverrides(name string, specifier string) string {
- if len(p.Overrides) > 0 {
- if new, ok := p.Overrides[name]; ok {
- return new
- }
- }
- return specifier
-}
-
-// Formatter of the lockfile key given a package name and version
-func (p *PnpmLockfile) formatKey(name string, version string) string {
- if p.isV6 {
- return fmt.Sprintf("/%s@%s", name, version)
- }
- return fmt.Sprintf("/%s/%s", name, version)
-}
-
-// Extracts version from lockfile key
-func (p *PnpmLockfile) extractVersion(key string) string {
- if p.isV6 {
- key = convertNewToOldDepPath(key)
- }
- dp := parseDepPath(key)
- if dp.peerSuffix != "" {
- sep := ""
- if !p.isV6 {
- sep = "_"
- }
- return fmt.Sprintf("%s%s%s", dp.version, sep, dp.peerSuffix)
- }
- return dp.version
-}
-
-// Parsed representation of a pnpm lockfile key
-type depPath struct {
- host string
- name string
- version string
- peerSuffix string
-}
-
-func parseDepPath(dependency string) depPath {
- // See https://github.com/pnpm/pnpm/blob/185ab01adfc927ea23d2db08a14723bf51d0025f/packages/dependency-path/src/index.ts#L96
- var dp depPath
- parts := strings.Split(dependency, "/")
- shift := func() string {
- if len(parts) == 0 {
- return ""
- }
- val := parts[0]
- parts = parts[1:]
- return val
- }
-
- isAbsolute := dependency[0] != '/'
- // Skip leading '/'
- if !isAbsolute {
- shift()
- }
-
- if isAbsolute {
- dp.host = shift()
- }
-
- if len(parts) == 0 {
- return dp
- }
-
- if strings.HasPrefix(parts[0], "@") {
- dp.name = fmt.Sprintf("%s/%s", shift(), shift())
- } else {
- dp.name = shift()
- }
-
- version := strings.Join(parts, "/")
- if len(version) > 0 {
- var peerSuffixIndex int
- if strings.Contains(version, "(") && strings.HasSuffix(version, ")") {
- // v6 encodes peers deps using (peer=version)
- // also used to encode patches using (path_hash=hash)
- peerSuffixIndex = strings.Index(version, "(")
- dp.peerSuffix = version[peerSuffixIndex:]
- dp.version = version[0:peerSuffixIndex]
- } else {
- // pre v6 uses _ to separate version from peer dependencies
- // if a dependency is patched and has peer dependencies its version will
- // be encoded as version_patchHash_peerDepsHash
- peerSuffixIndex = strings.Index(version, "_")
- if peerSuffixIndex != -1 {
- dp.peerSuffix = version[peerSuffixIndex+1:]
- dp.version = version[0:peerSuffixIndex]
- }
- }
- if peerSuffixIndex == -1 {
- dp.version = version
- }
- }
-
- return dp
-}
-
-var _patchHashKey = "patch_hash="
-
-func (d depPath) patchHash() string {
- if strings.HasPrefix(d.peerSuffix, "(") && strings.HasSuffix(d.peerSuffix, ")") {
- for _, part := range strings.Split(d.peerSuffix, "(") {
- if strings.HasPrefix(part, _patchHashKey) {
- // drop the enclosing ')'
- return part[len(_patchHashKey) : len(part)-1]
- }
- }
- // no patch entry found
- return ""
- }
-
- sepIndex := strings.Index(d.peerSuffix, "_")
- if sepIndex != -1 {
- return d.peerSuffix[:sepIndex]
- }
- // if a dependency just has a single suffix we can't tell if it's a patch or peer hash
- // return it in case it's a patch hash
- return d.peerSuffix
-}
-
-// Used to convert v6's dep path of /name@version to v5's /name/version
-// See https://github.com/pnpm/pnpm/blob/185ab01adfc927ea23d2db08a14723bf51d0025f/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L162
-func convertNewToOldDepPath(newPath string) string {
- if len(newPath) > 2 && !strings.Contains(newPath[2:], "@") {
- return newPath
- }
- searchStartIndex := strings.Index(newPath, "/@") + 2
- index := strings.Index(newPath[searchStartIndex:], "@") + searchStartIndex
- if strings.Contains(newPath, "(") && index > strings.Index(newPath, "(") {
- return newPath
- }
- return fmt.Sprintf("%s/%s", newPath[0:index], newPath[index+1:])
-}
diff --git a/cli/internal/lockfile/pnpm_lockfile_test.go b/cli/internal/lockfile/pnpm_lockfile_test.go
deleted file mode 100644
index b4c8475..0000000
--- a/cli/internal/lockfile/pnpm_lockfile_test.go
+++ /dev/null
@@ -1,405 +0,0 @@
-package lockfile
-
-import (
- "bytes"
- "os"
- "sort"
- "testing"
-
- "github.com/google/go-cmp/cmp/cmpopts"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/yaml"
- "gotest.tools/v3/assert"
-)
-
-func getFixture(t *testing.T, name string) ([]byte, error) {
- defaultCwd, err := os.Getwd()
- if err != nil {
- t.Errorf("failed to get cwd: %v", err)
- }
- cwd := turbopath.AbsoluteSystemPath(defaultCwd)
- lockfilePath := cwd.UntypedJoin("testdata", name)
- if !lockfilePath.FileExists() {
- return nil, errors.Errorf("unable to find 'testdata/%s'", name)
- }
- return os.ReadFile(lockfilePath.ToString())
-}
-
-func Test_Roundtrip(t *testing.T) {
- lockfiles := []string{"pnpm6-workspace.yaml", "pnpm7-workspace.yaml", "pnpm8.yaml"}
-
- for _, lockfilePath := range lockfiles {
- lockfileContent, err := getFixture(t, lockfilePath)
- if err != nil {
- t.Errorf("failure getting fixture: %s", err)
- }
- lockfile, err := DecodePnpmLockfile(lockfileContent)
- if err != nil {
- t.Errorf("decoding failed %s", err)
- }
- var b bytes.Buffer
- if err := lockfile.Encode(&b); err != nil {
- t.Errorf("encoding failed %s", err)
- }
- newLockfile, err := DecodePnpmLockfile(b.Bytes())
- if err != nil {
- t.Errorf("decoding failed %s", err)
- }
-
- assert.DeepEqual(
- t,
- lockfile,
- newLockfile,
- // Skip over fields that don't get serialized
- cmpopts.IgnoreUnexported(PnpmLockfile{}),
- cmpopts.IgnoreTypes(yaml.Node{}),
- )
- }
-}
-
-func Test_SpecifierResolution(t *testing.T) {
- contents, err := getFixture(t, "pnpm7-workspace.yaml")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodePnpmLockfile(contents)
- if err != nil {
- t.Errorf("failure decoding lockfile: %v", err)
- }
-
- type Case struct {
- workspacePath turbopath.AnchoredUnixPath
- pkg string
- specifier string
- version string
- found bool
- err string
- }
-
- cases := []Case{
- {workspacePath: "apps/docs", pkg: "next", specifier: "12.2.5", version: "12.2.5_ir3quccc6i62x6qn6jjhyjjiey", found: true},
- {workspacePath: "apps/web", pkg: "next", specifier: "12.2.5", version: "12.2.5_ir3quccc6i62x6qn6jjhyjjiey", found: true},
- {workspacePath: "apps/web", pkg: "typescript", specifier: "^4.5.3", version: "4.8.3", found: true},
- {workspacePath: "apps/web", pkg: "lodash", specifier: "bad-tag", version: "", found: false},
- {workspacePath: "apps/web", pkg: "lodash", specifier: "^4.17.21", version: "4.17.21_ehchni3mpmovsvjxesffg2i5a4", found: true},
- {workspacePath: "apps/docs", pkg: "dashboard-icons", specifier: "github:peerigon/dashboard-icons", version: "github.com/peerigon/dashboard-icons/ce27ef933144e09cef3911025f3649040a8571b6", found: true},
- {workspacePath: "", pkg: "turbo", specifier: "latest", version: "1.4.6", found: true},
- {workspacePath: "apps/bad_workspace", pkg: "turbo", specifier: "latest", version: "1.4.6", err: "no workspace 'apps/bad_workspace' found in lockfile"},
- }
-
- for _, testCase := range cases {
- actualVersion, actualFound, err := lockfile.resolveSpecifier(testCase.workspacePath, testCase.pkg, testCase.specifier)
- if testCase.err != "" {
- assert.Error(t, err, testCase.err)
- } else {
- assert.Equal(t, actualFound, testCase.found, "%s@%s", testCase.pkg, testCase.version)
- assert.Equal(t, actualVersion, testCase.version, "%s@%s", testCase.pkg, testCase.version)
- }
- }
-}
-
-func Test_SpecifierResolutionV6(t *testing.T) {
- contents, err := getFixture(t, "pnpm8.yaml")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodePnpmLockfile(contents)
- if err != nil {
- t.Errorf("failure decoding lockfile: %v", err)
- }
-
- type Case struct {
- workspacePath turbopath.AnchoredUnixPath
- pkg string
- specifier string
- version string
- found bool
- err string
- }
-
- cases := []Case{
- {workspacePath: "packages/a", pkg: "c", specifier: "workspace:*", version: "link:../c", found: true},
- {workspacePath: "packages/a", pkg: "is-odd", specifier: "^3.0.1", version: "3.0.1", found: true},
- {workspacePath: "packages/b", pkg: "is-odd", specifier: "^3.0.1", version: "3.0.1", err: "Unable to find resolved version for is-odd@^3.0.1 in packages/b"},
- {workspacePath: "apps/bad_workspace", pkg: "turbo", specifier: "latest", version: "1.4.6", err: "no workspace 'apps/bad_workspace' found in lockfile"},
- }
-
- for _, testCase := range cases {
- actualVersion, actualFound, err := lockfile.resolveSpecifier(testCase.workspacePath, testCase.pkg, testCase.specifier)
- if testCase.err != "" {
- assert.Error(t, err, testCase.err)
- } else {
- assert.Equal(t, actualFound, testCase.found, "%s@%s", testCase.pkg, testCase.version)
- assert.Equal(t, actualVersion, testCase.version, "%s@%s", testCase.pkg, testCase.version)
- }
- }
-}
-
-func Test_SubgraphInjectedPackages(t *testing.T) {
- contents, err := getFixture(t, "pnpm7-workspace.yaml")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err, "decode lockfile")
-
- packageWithInjectedPackage := turbopath.AnchoredUnixPath("apps/docs").ToSystemPath()
-
- prunedLockfile, err := lockfile.Subgraph([]turbopath.AnchoredSystemPath{packageWithInjectedPackage}, []string{})
- assert.NilError(t, err, "prune lockfile")
-
- pnpmLockfile, ok := prunedLockfile.(*PnpmLockfile)
- assert.Assert(t, ok, "got different lockfile impl")
-
- _, hasInjectedPackage := pnpmLockfile.Packages["file:packages/ui"]
-
- assert.Assert(t, hasInjectedPackage, "pruned lockfile is missing injected package")
-
-}
-
-func Test_GitPackages(t *testing.T) {
- contents, err := getFixture(t, "pnpm7-workspace.yaml")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err, "decode lockfile")
-
- pkg, err := lockfile.ResolvePackage(turbopath.AnchoredUnixPath("apps/docs"), "dashboard-icons", "github:peerigon/dashboard-icons")
- assert.NilError(t, err, "failure to find package")
- assert.Assert(t, pkg.Found)
- assert.DeepEqual(t, pkg.Key, "github.com/peerigon/dashboard-icons/ce27ef933144e09cef3911025f3649040a8571b6")
- assert.DeepEqual(t, pkg.Version, "1.0.0")
- // make sure subgraph produces git dep
-}
-
-func Test_DecodePnpmUnquotedURL(t *testing.T) {
- resolutionWithQuestionMark := `{integrity: sha512-deadbeef, tarball: path/to/tarball?foo=bar}`
- var resolution map[string]interface{}
- err := yaml.Unmarshal([]byte(resolutionWithQuestionMark), &resolution)
- assert.NilError(t, err, "valid package entry should be able to be decoded")
- assert.Equal(t, resolution["tarball"], "path/to/tarball?foo=bar")
-}
-
-func Test_PnpmLockfilePatches(t *testing.T) {
- contents, err := getFixture(t, "pnpm-patch.yaml")
- assert.NilError(t, err)
-
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err)
-
- patches := lockfile.Patches()
- assert.Equal(t, len(patches), 3)
- assert.Equal(t, patches[0], turbopath.AnchoredUnixPath("patches/@babel__core@7.20.12.patch"))
- assert.Equal(t, patches[1], turbopath.AnchoredUnixPath("patches/is-odd@3.0.1.patch"))
-}
-
-func Test_PnpmPrunePatches(t *testing.T) {
- contents, err := getFixture(t, "pnpm-patch.yaml")
- assert.NilError(t, err)
-
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err)
-
- prunedLockfile, err := lockfile.Subgraph(
- []turbopath.AnchoredSystemPath{turbopath.AnchoredSystemPath("packages/dependency")},
- []string{"/is-odd/3.0.1_nrrwwz7lemethtlvvm75r5bmhq", "/is-number/6.0.0", "/@babel/core/7.20.12_3hyn7hbvzkemudbydlwjmrb65y", "/moleculer/0.14.28_5pk7ojv7qbqha75ozglk4y4f74_kumip57h7zlinbhp4gz3jrbqry"},
- )
- assert.NilError(t, err)
-
- assert.Equal(t, len(prunedLockfile.Patches()), 3)
-}
-
-func Test_PnpmPrunePatchesV6(t *testing.T) {
- contents, err := getFixture(t, "pnpm-patch-v6.yaml")
- assert.NilError(t, err)
-
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err)
-
- prunedLockfile, err := lockfile.Subgraph(
- []turbopath.AnchoredSystemPath{turbopath.AnchoredSystemPath("packages/a")},
- []string{"/lodash@4.17.21(patch_hash=lgum37zgng4nfkynzh3cs7wdeq)"},
- )
- assert.NilError(t, err)
-
- assert.Equal(t, len(prunedLockfile.Patches()), 1)
-
- prunedLockfile, err = lockfile.Subgraph(
- []turbopath.AnchoredSystemPath{turbopath.AnchoredSystemPath("packages/b")},
- []string{"/@babel/helper-string-parser@7.19.4(patch_hash=wjhgmpzh47qmycrzgpeyoyh3ce)(@babel/core@7.21.0)"},
- )
- assert.NilError(t, err)
-
- assert.Equal(t, len(prunedLockfile.Patches()), 1)
-}
-
-func Test_PnpmAbsoluteDependency(t *testing.T) {
- type testCase struct {
- fixture string
- key string
- }
- testcases := []testCase{
- {"pnpm-absolute.yaml", "/@scope/child/1.0.0"},
- {"pnpm-absolute-v6.yaml", "/@scope/child@1.0.0"},
- }
- for _, tc := range testcases {
- contents, err := getFixture(t, tc.fixture)
- assert.NilError(t, err, tc.fixture)
-
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err, tc.fixture)
-
- pkg, err := lockfile.ResolvePackage(turbopath.AnchoredUnixPath("packages/a"), "child", tc.key)
- assert.NilError(t, err, "resolve")
- assert.Assert(t, pkg.Found, tc.fixture)
- assert.DeepEqual(t, pkg.Key, tc.key)
- assert.DeepEqual(t, pkg.Version, "1.0.0")
- }
-}
-
-func Test_LockfilePeer(t *testing.T) {
- contents, err := getFixture(t, "pnpm-peer-v6.yaml")
- if err != nil {
- t.Error(err)
- }
- assert.NilError(t, err, "read fixture")
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err, "parse lockfile")
-
- pkg, err := lockfile.ResolvePackage(turbopath.AnchoredUnixPath("apps/web"), "next", "13.0.4")
- assert.NilError(t, err, "read lockfile")
- assert.Assert(t, pkg.Found)
- assert.DeepEqual(t, pkg.Version, "13.0.4(react-dom@18.2.0)(react@18.2.0)")
- assert.DeepEqual(t, pkg.Key, "/next@13.0.4(react-dom@18.2.0)(react@18.2.0)")
-}
-
-func Test_LockfileTopLevelOverride(t *testing.T) {
- contents, err := getFixture(t, "pnpm-top-level-dupe.yaml")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err, "decode lockfile")
-
- pkg, err := lockfile.ResolvePackage(turbopath.AnchoredUnixPath("packages/a"), "ci-info", "3.7.1")
- assert.NilError(t, err, "resolve package")
-
- assert.Assert(t, pkg.Found)
- assert.DeepEqual(t, pkg.Key, "/ci-info/3.7.1")
- assert.DeepEqual(t, pkg.Version, "3.7.1")
-}
-
-func Test_PnpmOverride(t *testing.T) {
- contents, err := getFixture(t, "pnpm_override.yaml")
- if err != nil {
- t.Error(err)
- }
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err, "decode lockfile")
-
- pkg, err := lockfile.ResolvePackage(
- turbopath.AnchoredUnixPath("config/hardhat"),
- "@nomiclabs/hardhat-ethers",
- "npm:hardhat-deploy-ethers@0.3.0-beta.13",
- )
- assert.NilError(t, err, "failure to find package")
- assert.Assert(t, pkg.Found)
- assert.DeepEqual(t, pkg.Key, "/hardhat-deploy-ethers/0.3.0-beta.13_yab2ug5tvye2kp6e24l5x3z7uy")
- assert.DeepEqual(t, pkg.Version, "0.3.0-beta.13_yab2ug5tvye2kp6e24l5x3z7uy")
-}
-
-func Test_DepPathParsing(t *testing.T) {
- type testCase struct {
- input string
- dp depPath
- }
- testCases := []testCase{
- {
- "/foo/1.0.0",
- depPath{
- name: "foo",
- version: "1.0.0",
- },
- },
- {
- "/@foo/bar/1.0.0",
- depPath{
- name: "@foo/bar",
- version: "1.0.0",
- },
- },
- {
- "example.org/foo/1.0.0",
- depPath{
- host: "example.org",
- name: "foo",
- version: "1.0.0",
- },
- },
- {
- "/foo/1.0.0_bar@1.0.0",
- depPath{
- name: "foo",
- version: "1.0.0",
- peerSuffix: "bar@1.0.0",
- },
- },
- {
- "/foo/1.0.0(bar@1.0.0)",
- depPath{
- name: "foo",
- version: "1.0.0",
- peerSuffix: "(bar@1.0.0)",
- },
- },
- {
- "/foo/1.0.0_patchHash_peerHash",
- depPath{
- name: "foo",
- version: "1.0.0",
- peerSuffix: "patchHash_peerHash",
- },
- },
- {
- "/@babel/helper-string-parser/7.19.4(patch_hash=wjhgmpzh47qmycrzgpeyoyh3ce)(@babel/core@7.21.0)",
- depPath{
- name: "@babel/helper-string-parser",
- version: "7.19.4",
- peerSuffix: "(patch_hash=wjhgmpzh47qmycrzgpeyoyh3ce)(@babel/core@7.21.0)",
- },
- },
- }
-
- for _, tc := range testCases {
- assert.Equal(t, parseDepPath(tc.input), tc.dp, tc.input)
- }
-}
-
-func Test_PnpmAliasesOverlap(t *testing.T) {
- contents, err := getFixture(t, "pnpm-absolute.yaml")
- assert.NilError(t, err)
-
- lockfile, err := DecodePnpmLockfile(contents)
- assert.NilError(t, err)
-
- closure, err := transitiveClosure("packages/a", map[string]string{"@scope/parent": "^1.0.0", "another": "^1.0.0", "special": "npm:Special@1.2.3"}, lockfile)
- assert.NilError(t, err)
-
- deps := []Package{}
-
- for _, v := range closure.ToSlice() {
- dep := v.(Package)
- deps = append(deps, dep)
- }
- sort.Sort(ByKey(deps))
-
- assert.DeepEqual(t, deps, []Package{
- {"/@scope/child/1.0.0", "1.0.0", true},
- {"/@scope/parent/1.0.0", "1.0.0", true},
- {"/Special/1.2.3", "1.2.3", true},
- {"/another/1.0.0", "1.0.0", true},
- {"/foo/1.0.0", "1.0.0", true},
- })
-}
diff --git a/cli/internal/lockfile/testdata/berry.lock b/cli/internal/lockfile/testdata/berry.lock
deleted file mode 100644
index f4436e4..0000000
--- a/cli/internal/lockfile/testdata/berry.lock
+++ /dev/null
@@ -1,3283 +0,0 @@
-# This file is generated by running "yarn install" inside your project.
-# Manual changes might be lost - proceed with caution!
-
-__metadata:
- version: 6
- cacheKey: 8c0
-
-"@ampproject/remapping@npm:^2.1.0":
- version: 2.2.0
- resolution: "@ampproject/remapping@npm:2.2.0"
- dependencies:
- "@jridgewell/gen-mapping": ^0.1.0
- "@jridgewell/trace-mapping": ^0.3.9
- checksum: d74d170d06468913921d72430259424b7e4c826b5a7d39ff839a29d547efb97dc577caa8ba3fb5cf023624e9af9d09651afc3d4112a45e2050328abc9b3a2292
- languageName: node
- linkType: hard
-
-"@babel/code-frame@npm:7.12.11":
- version: 7.12.11
- resolution: "@babel/code-frame@npm:7.12.11"
- dependencies:
- "@babel/highlight": ^7.10.4
- checksum: 3963eff3ebfb0e091c7e6f99596ef4b258683e4ba8a134e4e95f77afe85be5c931e184fff6435fb4885d12eba04a5e25532f7fbc292ca13b48e7da943474e2f3
- languageName: node
- linkType: hard
-
-"@babel/code-frame@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/code-frame@npm:7.18.6"
- dependencies:
- "@babel/highlight": ^7.18.6
- checksum: 195e2be3172d7684bf95cff69ae3b7a15a9841ea9d27d3c843662d50cdd7d6470fd9c8e64be84d031117e4a4083486effba39f9aef6bbb2c89f7f21bcfba33ba
- languageName: node
- linkType: hard
-
-"@babel/compat-data@npm:^7.19.1":
- version: 7.19.1
- resolution: "@babel/compat-data@npm:7.19.1"
- checksum: f985887ea08a140e4af87a94d3fb17af0345491eb97f5a85b1840255c2e2a97429f32a8fd12a7aae9218af5f1024f1eb12a5cd280d2d69b2337583c17ea506ba
- languageName: node
- linkType: hard
-
-"@babel/core@npm:^7.0.0":
- version: 7.19.1
- resolution: "@babel/core@npm:7.19.1"
- dependencies:
- "@ampproject/remapping": ^2.1.0
- "@babel/code-frame": ^7.18.6
- "@babel/generator": ^7.19.0
- "@babel/helper-compilation-targets": ^7.19.1
- "@babel/helper-module-transforms": ^7.19.0
- "@babel/helpers": ^7.19.0
- "@babel/parser": ^7.19.1
- "@babel/template": ^7.18.10
- "@babel/traverse": ^7.19.1
- "@babel/types": ^7.19.0
- convert-source-map: ^1.7.0
- debug: ^4.1.0
- gensync: ^1.0.0-beta.2
- json5: ^2.2.1
- semver: ^6.3.0
- checksum: 941c8c119b80bdba5fafc80bbaa424d51146b6d3c30b8fae35879358dd37c11d3d0926bc7e970a0861229656eedaa8c884d4a3a25cc904086eb73b827a2f1168
- languageName: node
- linkType: hard
-
-"@babel/generator@npm:^7.19.0":
- version: 7.19.0
- resolution: "@babel/generator@npm:7.19.0"
- dependencies:
- "@babel/types": ^7.19.0
- "@jridgewell/gen-mapping": ^0.3.2
- jsesc: ^2.5.1
- checksum: aa3d5785cf8f8e81672dcc61aef351188efeadb20d9f66d79113d82cbcf3bbbdeb829989fa14582108572ddbc4e4027bdceb06ccaf5ec40fa93c2dda8fbcd4aa
- languageName: node
- linkType: hard
-
-"@babel/helper-compilation-targets@npm:^7.19.1":
- version: 7.19.1
- resolution: "@babel/helper-compilation-targets@npm:7.19.1"
- dependencies:
- "@babel/compat-data": ^7.19.1
- "@babel/helper-validator-option": ^7.18.6
- browserslist: ^4.21.3
- semver: ^6.3.0
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: c2d3039265e498b341a6b597f855f2fcef02659050fefedf36ad4e6815e6aafe1011a761214cc80d98260ed07ab15a8cbe959a0458e97bec5f05a450e1b1741b
- languageName: node
- linkType: hard
-
-"@babel/helper-environment-visitor@npm:^7.18.9":
- version: 7.18.9
- resolution: "@babel/helper-environment-visitor@npm:7.18.9"
- checksum: b25101f6162ddca2d12da73942c08ad203d7668e06663df685634a8fde54a98bc015f6f62938e8554457a592a024108d45b8f3e651fd6dcdb877275b73cc4420
- languageName: node
- linkType: hard
-
-"@babel/helper-function-name@npm:^7.19.0":
- version: 7.19.0
- resolution: "@babel/helper-function-name@npm:7.19.0"
- dependencies:
- "@babel/template": ^7.18.10
- "@babel/types": ^7.19.0
- checksum: eac1f5db428ba546270c2b8d750c24eb528b8fcfe50c81de2e0bdebf0e20f24bec688d4331533b782e4a907fad435244621ca2193cfcf80a86731299840e0f6e
- languageName: node
- linkType: hard
-
-"@babel/helper-hoist-variables@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/helper-hoist-variables@npm:7.18.6"
- dependencies:
- "@babel/types": ^7.18.6
- checksum: fd9c35bb435fda802bf9ff7b6f2df06308a21277c6dec2120a35b09f9de68f68a33972e2c15505c1a1a04b36ec64c9ace97d4a9e26d6097b76b4396b7c5fa20f
- languageName: node
- linkType: hard
-
-"@babel/helper-module-imports@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/helper-module-imports@npm:7.18.6"
- dependencies:
- "@babel/types": ^7.18.6
- checksum: f393f8a3b3304b1b7a288a38c10989de754f01d29caf62ce7c4e5835daf0a27b81f3ac687d9d2780d39685aae7b55267324b512150e7b2be967b0c493b6a1def
- languageName: node
- linkType: hard
-
-"@babel/helper-module-transforms@npm:^7.19.0":
- version: 7.19.0
- resolution: "@babel/helper-module-transforms@npm:7.19.0"
- dependencies:
- "@babel/helper-environment-visitor": ^7.18.9
- "@babel/helper-module-imports": ^7.18.6
- "@babel/helper-simple-access": ^7.18.6
- "@babel/helper-split-export-declaration": ^7.18.6
- "@babel/helper-validator-identifier": ^7.18.6
- "@babel/template": ^7.18.10
- "@babel/traverse": ^7.19.0
- "@babel/types": ^7.19.0
- checksum: 4483276c66f56cf3b5b063634092ad9438c2593725de5c143ba277dda82f1501e6d73b311c1b28036f181dbe36eaeff29f24726cde37a599d4e735af294e5359
- languageName: node
- linkType: hard
-
-"@babel/helper-simple-access@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/helper-simple-access@npm:7.18.6"
- dependencies:
- "@babel/types": ^7.18.6
- checksum: 37cd36eef199e0517845763c1e6ff6ea5e7876d6d707a6f59c9267c547a50aa0e84260ba9285d49acfaf2cfa0a74a772d92967f32ac1024c961517d40b6c16a5
- languageName: node
- linkType: hard
-
-"@babel/helper-split-export-declaration@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/helper-split-export-declaration@npm:7.18.6"
- dependencies:
- "@babel/types": ^7.18.6
- checksum: c6d3dede53878f6be1d869e03e9ffbbb36f4897c7cc1527dc96c56d127d834ffe4520a6f7e467f5b6f3c2843ea0e81a7819d66ae02f707f6ac057f3d57943a2b
- languageName: node
- linkType: hard
-
-"@babel/helper-string-parser@npm:^7.18.10":
- version: 7.18.10
- resolution: "@babel/helper-string-parser@npm:7.18.10"
- checksum: d554a4393365b624916b5c00a4cc21c990c6617e7f3fe30be7d9731f107f12c33229a7a3db9d829bfa110d2eb9f04790745d421640e3bd245bb412dc0ea123c1
- languageName: node
- linkType: hard
-
-"@babel/helper-validator-identifier@npm:^7.18.6":
- version: 7.19.1
- resolution: "@babel/helper-validator-identifier@npm:7.19.1"
- checksum: 0eca5e86a729162af569b46c6c41a63e18b43dbe09fda1d2a3c8924f7d617116af39cac5e4cd5d431bb760b4dca3c0970e0c444789b1db42bcf1fa41fbad0a3a
- languageName: node
- linkType: hard
-
-"@babel/helper-validator-option@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/helper-validator-option@npm:7.18.6"
- checksum: f9cc6eb7cc5d759c5abf006402180f8d5e4251e9198197428a97e05d65eb2f8ae5a0ce73b1dfd2d35af41d0eb780627a64edf98a4e71f064eeeacef8de58f2cf
- languageName: node
- linkType: hard
-
-"@babel/helpers@npm:^7.19.0":
- version: 7.19.0
- resolution: "@babel/helpers@npm:7.19.0"
- dependencies:
- "@babel/template": ^7.18.10
- "@babel/traverse": ^7.19.0
- "@babel/types": ^7.19.0
- checksum: e50e78e0dbb0435075fa3f85021a6bcae529589800bca0292721afd7f7c874bea54508d6dc57eca16e5b8224f8142c6b0e32e3b0140029dc09865da747da4623
- languageName: node
- linkType: hard
-
-"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/highlight@npm:7.18.6"
- dependencies:
- "@babel/helper-validator-identifier": ^7.18.6
- chalk: ^2.0.0
- js-tokens: ^4.0.0
- checksum: 92d8ee61549de5ff5120e945e774728e5ccd57fd3b2ed6eace020ec744823d4a98e242be1453d21764a30a14769ecd62170fba28539b211799bbaf232bbb2789
- languageName: node
- linkType: hard
-
-"@babel/parser@npm:^7.18.10, @babel/parser@npm:^7.19.1":
- version: 7.19.1
- resolution: "@babel/parser@npm:7.19.1"
- bin:
- parser: ./bin/babel-parser.js
- checksum: b1e0acb346b2a533c857e1e97ac0886cdcbd76aafef67835a2b23f760c10568eb53ad8a27dd5f862d8ba4e583742e6067f107281ccbd68959d61bc61e4ddaa51
- languageName: node
- linkType: hard
-
-"@babel/runtime-corejs3@npm:^7.10.2":
- version: 7.19.1
- resolution: "@babel/runtime-corejs3@npm:7.19.1"
- dependencies:
- core-js-pure: ^3.25.1
- regenerator-runtime: ^0.13.4
- checksum: 38a1e8fcd2ba1f76c951259c98a5a11052123923adbf30ec8b2fec202dbbe38c6db61658ef9398e00c30f799e2e54ea036e56a09f43229261918bf5ec1b7d03a
- languageName: node
- linkType: hard
-
-"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.18.9":
- version: 7.19.0
- resolution: "@babel/runtime@npm:7.19.0"
- dependencies:
- regenerator-runtime: ^0.13.4
- checksum: fa69c351bb05e1db3ceb9a02fdcf620c234180af68cdda02152d3561015f6d55277265d3109815992f96d910f3db709458cae4f8df1c3def66f32e0867d82294
- languageName: node
- linkType: hard
-
-"@babel/template@npm:^7.18.10":
- version: 7.18.10
- resolution: "@babel/template@npm:7.18.10"
- dependencies:
- "@babel/code-frame": ^7.18.6
- "@babel/parser": ^7.18.10
- "@babel/types": ^7.18.10
- checksum: 93a6aa094af5f355a72bd55f67fa1828a046c70e46f01b1606e6118fa1802b6df535ca06be83cc5a5e834022be95c7b714f0a268b5f20af984465a71e28f1473
- languageName: node
- linkType: hard
-
-"@babel/traverse@npm:^7.19.0, @babel/traverse@npm:^7.19.1":
- version: 7.19.1
- resolution: "@babel/traverse@npm:7.19.1"
- dependencies:
- "@babel/code-frame": ^7.18.6
- "@babel/generator": ^7.19.0
- "@babel/helper-environment-visitor": ^7.18.9
- "@babel/helper-function-name": ^7.19.0
- "@babel/helper-hoist-variables": ^7.18.6
- "@babel/helper-split-export-declaration": ^7.18.6
- "@babel/parser": ^7.19.1
- "@babel/types": ^7.19.0
- debug: ^4.1.0
- globals: ^11.1.0
- checksum: 9d782b5089ebc989e54c2406814ed1206cb745ed2734e6602dee3e23d4b6ebbb703ff86e536276630f8de83fda6cde99f0634e3c3d847ddb40572d0303ba8800
- languageName: node
- linkType: hard
-
-"@babel/types@npm:^7.18.10, @babel/types@npm:^7.18.6, @babel/types@npm:^7.19.0, @babel/types@npm:^7.8.3":
- version: 7.19.0
- resolution: "@babel/types@npm:7.19.0"
- dependencies:
- "@babel/helper-string-parser": ^7.18.10
- "@babel/helper-validator-identifier": ^7.18.6
- to-fast-properties: ^2.0.0
- checksum: 9b346715a68aeede70ba9c685a144b0b26c53bcd595d448e24c8fa8df4d5956a5712e56ebadb7c85dcc32f218ee42788e37b93d50d3295c992072224cb3ef3fe
- languageName: node
- linkType: hard
-
-"@eslint/eslintrc@npm:^0.4.3":
- version: 0.4.3
- resolution: "@eslint/eslintrc@npm:0.4.3"
- dependencies:
- ajv: ^6.12.4
- debug: ^4.1.1
- espree: ^7.3.0
- globals: ^13.9.0
- ignore: ^4.0.6
- import-fresh: ^3.2.1
- js-yaml: ^3.13.1
- minimatch: ^3.0.4
- strip-json-comments: ^3.1.1
- checksum: 03a7704150b868c318aab6a94d87a33d30dc2ec579d27374575014f06237ba1370ae11178db772f985ef680d469dc237e7b16a1c5d8edaaeb8c3733e7a95a6d3
- languageName: node
- linkType: hard
-
-"@humanwhocodes/config-array@npm:^0.5.0":
- version: 0.5.0
- resolution: "@humanwhocodes/config-array@npm:0.5.0"
- dependencies:
- "@humanwhocodes/object-schema": ^1.2.0
- debug: ^4.1.1
- minimatch: ^3.0.4
- checksum: 44ee6a9f05d93dd9d5935a006b17572328ba9caff8002442f601736cbda79c580cc0f5a49ce9eb88fbacc5c3a6b62098357c2e95326cd17bb9f1a6c61d6e95e7
- languageName: node
- linkType: hard
-
-"@humanwhocodes/object-schema@npm:^1.2.0":
- version: 1.2.1
- resolution: "@humanwhocodes/object-schema@npm:1.2.1"
- checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1
- languageName: node
- linkType: hard
-
-"@jridgewell/gen-mapping@npm:^0.1.0":
- version: 0.1.1
- resolution: "@jridgewell/gen-mapping@npm:0.1.1"
- dependencies:
- "@jridgewell/set-array": ^1.0.0
- "@jridgewell/sourcemap-codec": ^1.4.10
- checksum: 3bcc21fe786de6ffbf35c399a174faab05eb23ce6a03e8769569de28abbf4facc2db36a9ddb0150545ae23a8d35a7cf7237b2aa9e9356a7c626fb4698287d5cc
- languageName: node
- linkType: hard
-
-"@jridgewell/gen-mapping@npm:^0.3.2":
- version: 0.3.2
- resolution: "@jridgewell/gen-mapping@npm:0.3.2"
- dependencies:
- "@jridgewell/set-array": ^1.0.1
- "@jridgewell/sourcemap-codec": ^1.4.10
- "@jridgewell/trace-mapping": ^0.3.9
- checksum: 1832707a1c476afebe4d0fbbd4b9434fdb51a4c3e009ab1e9938648e21b7a97049fa6009393bdf05cab7504108413441df26d8a3c12193996e65493a4efb6882
- languageName: node
- linkType: hard
-
-"@jridgewell/resolve-uri@npm:^3.0.3":
- version: 3.1.0
- resolution: "@jridgewell/resolve-uri@npm:3.1.0"
- checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267
- languageName: node
- linkType: hard
-
-"@jridgewell/set-array@npm:^1.0.0, @jridgewell/set-array@npm:^1.0.1":
- version: 1.1.2
- resolution: "@jridgewell/set-array@npm:1.1.2"
- checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e
- languageName: node
- linkType: hard
-
-"@jridgewell/sourcemap-codec@npm:^1.4.10":
- version: 1.4.14
- resolution: "@jridgewell/sourcemap-codec@npm:1.4.14"
- checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97
- languageName: node
- linkType: hard
-
-"@jridgewell/trace-mapping@npm:^0.3.9":
- version: 0.3.15
- resolution: "@jridgewell/trace-mapping@npm:0.3.15"
- dependencies:
- "@jridgewell/resolve-uri": ^3.0.3
- "@jridgewell/sourcemap-codec": ^1.4.10
- checksum: 38917e9c2b014d469a9f51c016ed506acbe44dd16ec2f6f99b553ebf3764d22abadbf992f2367b6d2b3511f3eae8ed3a8963f6c1030093fda23efd35ecab2bae
- languageName: node
- linkType: hard
-
-"@next/env@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/env@npm:12.2.5"
- checksum: a44939e59b46d5951831529a43dba9daa2e4e467e8680ea96e21ae127d1bf7f11757aaf3a6cff8a51273abfe7af782903e1304405a481361c7ba3e66d47e3238
- languageName: node
- linkType: hard
-
-"@next/eslint-plugin-next@npm:12.3.0":
- version: 12.3.0
- resolution: "@next/eslint-plugin-next@npm:12.3.0"
- dependencies:
- glob: 7.1.7
- checksum: f08582b36ff01a776183b3c33d6d81be3a110c1c3c39c81a33aff91277ea822aa4a952d4f2271a08ce56692ca5c58c9e958aaf4e08348c10cc45a85213b208f0
- languageName: node
- linkType: hard
-
-"@next/swc-android-arm-eabi@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-android-arm-eabi@npm:12.2.5"
- conditions: os=android & cpu=arm
- languageName: node
- linkType: hard
-
-"@next/swc-android-arm64@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-android-arm64@npm:12.2.5"
- conditions: os=android & cpu=arm64
- languageName: node
- linkType: hard
-
-"@next/swc-darwin-arm64@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-darwin-arm64@npm:12.2.5"
- conditions: os=darwin & cpu=arm64
- languageName: node
- linkType: hard
-
-"@next/swc-darwin-x64@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-darwin-x64@npm:12.2.5"
- conditions: os=darwin & cpu=x64
- languageName: node
- linkType: hard
-
-"@next/swc-freebsd-x64@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-freebsd-x64@npm:12.2.5"
- conditions: os=freebsd & cpu=x64
- languageName: node
- linkType: hard
-
-"@next/swc-linux-arm-gnueabihf@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-linux-arm-gnueabihf@npm:12.2.5"
- conditions: os=linux & cpu=arm
- languageName: node
- linkType: hard
-
-"@next/swc-linux-arm64-gnu@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-linux-arm64-gnu@npm:12.2.5"
- conditions: os=linux & cpu=arm64 & libc=glibc
- languageName: node
- linkType: hard
-
-"@next/swc-linux-arm64-musl@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-linux-arm64-musl@npm:12.2.5"
- conditions: os=linux & cpu=arm64 & libc=musl
- languageName: node
- linkType: hard
-
-"@next/swc-linux-x64-gnu@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-linux-x64-gnu@npm:12.2.5"
- conditions: os=linux & cpu=x64 & libc=glibc
- languageName: node
- linkType: hard
-
-"@next/swc-linux-x64-musl@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-linux-x64-musl@npm:12.2.5"
- conditions: os=linux & cpu=x64 & libc=musl
- languageName: node
- linkType: hard
-
-"@next/swc-win32-arm64-msvc@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-win32-arm64-msvc@npm:12.2.5"
- conditions: os=win32 & cpu=arm64
- languageName: node
- linkType: hard
-
-"@next/swc-win32-ia32-msvc@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-win32-ia32-msvc@npm:12.2.5"
- conditions: os=win32 & cpu=ia32
- languageName: node
- linkType: hard
-
-"@next/swc-win32-x64-msvc@npm:12.2.5":
- version: 12.2.5
- resolution: "@next/swc-win32-x64-msvc@npm:12.2.5"
- conditions: os=win32 & cpu=x64
- languageName: node
- linkType: hard
-
-"@nodelib/fs.scandir@npm:2.1.5":
- version: 2.1.5
- resolution: "@nodelib/fs.scandir@npm:2.1.5"
- dependencies:
- "@nodelib/fs.stat": 2.0.5
- run-parallel: ^1.1.9
- checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59
- languageName: node
- linkType: hard
-
-"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2":
- version: 2.0.5
- resolution: "@nodelib/fs.stat@npm:2.0.5"
- checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0
- languageName: node
- linkType: hard
-
-"@nodelib/fs.walk@npm:^1.2.3":
- version: 1.2.8
- resolution: "@nodelib/fs.walk@npm:1.2.8"
- dependencies:
- "@nodelib/fs.scandir": 2.1.5
- fastq: ^1.6.0
- checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53
- languageName: node
- linkType: hard
-
-"@rushstack/eslint-patch@npm:^1.1.3":
- version: 1.2.0
- resolution: "@rushstack/eslint-patch@npm:1.2.0"
- checksum: faa749faae0e83c26ae9eb00ad36a897ac78f3cf27da8e8ff21c00bcf7973b598d823d8f2b3957ef66079288bcf577f94df831eae2d65f3f68d8ca32f18b6aff
- languageName: node
- linkType: hard
-
-"@swc/helpers@npm:0.4.3":
- version: 0.4.3
- resolution: "@swc/helpers@npm:0.4.3"
- dependencies:
- tslib: ^2.4.0
- checksum: 5c2f173e950dd3929d84ae48b3586a274d5a874e7cf2013b3d8081e4f8c723fa3a4d4e63b263e84bb7f06431f87b640e91a12655410463c81a3dc2bbc15eceda
- languageName: node
- linkType: hard
-
-"@types/json5@npm:^0.0.29":
- version: 0.0.29
- resolution: "@types/json5@npm:0.0.29"
- checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac
- languageName: node
- linkType: hard
-
-"@types/node@npm:^17.0.12":
- version: 17.0.45
- resolution: "@types/node@npm:17.0.45"
- checksum: aa04366b9103b7d6cfd6b2ef64182e0eaa7d4462c3f817618486ea0422984c51fc69fd0d436eae6c9e696ddfdbec9ccaa27a917f7c2e8c75c5d57827fe3d95e8
- languageName: node
- linkType: hard
-
-"@types/prop-types@npm:*":
- version: 15.7.5
- resolution: "@types/prop-types@npm:15.7.5"
- checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980
- languageName: node
- linkType: hard
-
-"@types/react-dom@npm:^17.0.11":
- version: 17.0.17
- resolution: "@types/react-dom@npm:17.0.17"
- dependencies:
- "@types/react": ^17
- checksum: 23caf98aa03e968811560f92a2c8f451694253ebe16b670929b24eaf0e7fa62ba549abe9db0ac028a9d8a9086acd6ab9c6c773f163fa21224845edbc00ba6232
- languageName: node
- linkType: hard
-
-"@types/react@npm:18.0.17":
- version: 18.0.17
- resolution: "@types/react@npm:18.0.17"
- dependencies:
- "@types/prop-types": "*"
- "@types/scheduler": "*"
- csstype: ^3.0.2
- checksum: 18cae64f5bfd6bb58fbd8ee2ba52ec82de844f114254e26de7b513e4b86621f643f9b71d7066958cd571b0d78cb86cbceda449c5289f9349ca573df29ab69252
- languageName: node
- linkType: hard
-
-"@types/react@npm:^17, @types/react@npm:^17.0.37":
- version: 17.0.50
- resolution: "@types/react@npm:17.0.50"
- dependencies:
- "@types/prop-types": "*"
- "@types/scheduler": "*"
- csstype: ^3.0.2
- checksum: b5629dff7c2f3e9fcba95a19b2b3bfd78d7cacc33ba5fc26413dba653d34afcac3b93ddabe563e8062382688a1eac7db68e93739bb8e712d27637a03aaafbbb8
- languageName: node
- linkType: hard
-
-"@types/scheduler@npm:*":
- version: 0.16.2
- resolution: "@types/scheduler@npm:0.16.2"
- checksum: b6b4dcfeae6deba2e06a70941860fb1435730576d3689225a421280b7742318d1548b3d22c1f66ab68e414f346a9542f29240bc955b6332c5b11e561077583bc
- languageName: node
- linkType: hard
-
-"@typescript-eslint/parser@npm:^5.21.0":
- version: 5.37.0
- resolution: "@typescript-eslint/parser@npm:5.37.0"
- dependencies:
- "@typescript-eslint/scope-manager": 5.37.0
- "@typescript-eslint/types": 5.37.0
- "@typescript-eslint/typescript-estree": 5.37.0
- debug: ^4.3.4
- peerDependencies:
- eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
- peerDependenciesMeta:
- typescript:
- optional: true
- checksum: 33343e27c9602820d43ee12de9797365d97a5cf3f716e750fa44de760f2a2c6800f3bc4fa54931ac70c0e0ede77a92224f8151da7f30fed3bf692a029d6659af
- languageName: node
- linkType: hard
-
-"@typescript-eslint/scope-manager@npm:5.37.0":
- version: 5.37.0
- resolution: "@typescript-eslint/scope-manager@npm:5.37.0"
- dependencies:
- "@typescript-eslint/types": 5.37.0
- "@typescript-eslint/visitor-keys": 5.37.0
- checksum: 1c439e21ffa63ebaadb8c8363e9d668132a835a28203e5b779366bfa56772f332e5dedb50d63dffb836839b9d9c4e66aa9e3ea47b8c59465b18a0cbd063ec7a3
- languageName: node
- linkType: hard
-
-"@typescript-eslint/types@npm:5.37.0":
- version: 5.37.0
- resolution: "@typescript-eslint/types@npm:5.37.0"
- checksum: 899e59e7775fa95c2d9fcac5cc02cc49d83af5f1ffc706df495046c3b3733f79d5489568b01bfaf8c9ae4636e057056866adc783113036f774580086d0189f21
- languageName: node
- linkType: hard
-
-"@typescript-eslint/typescript-estree@npm:5.37.0":
- version: 5.37.0
- resolution: "@typescript-eslint/typescript-estree@npm:5.37.0"
- dependencies:
- "@typescript-eslint/types": 5.37.0
- "@typescript-eslint/visitor-keys": 5.37.0
- debug: ^4.3.4
- globby: ^11.1.0
- is-glob: ^4.0.3
- semver: ^7.3.7
- tsutils: ^3.21.0
- peerDependenciesMeta:
- typescript:
- optional: true
- checksum: 80365a50fa11ed39bf54d9ef06e264fbbf3bdbcc55b7d7d555ef0be915edae40ec30e98d08b3f6ef048e1874450cbcb1e7d9f429d4f420dacbbde45d3376a7bc
- languageName: node
- linkType: hard
-
-"@typescript-eslint/visitor-keys@npm:5.37.0":
- version: 5.37.0
- resolution: "@typescript-eslint/visitor-keys@npm:5.37.0"
- dependencies:
- "@typescript-eslint/types": 5.37.0
- eslint-visitor-keys: ^3.3.0
- checksum: d6193550f77413aead0cb267e058df80b80a488c8fb4e39beb5f0a70b971c41682a6391903fbc5f3dd859a872016288c434d631b8efc3ac5a04edbdb7b63b5f6
- languageName: node
- linkType: hard
-
-"acorn-jsx@npm:^5.3.1":
- version: 5.3.2
- resolution: "acorn-jsx@npm:5.3.2"
- peerDependencies:
- acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950
- languageName: node
- linkType: hard
-
-"acorn@npm:^7.4.0":
- version: 7.4.1
- resolution: "acorn@npm:7.4.1"
- bin:
- acorn: bin/acorn
- checksum: 1860f23c2107c910c6177b7b7be71be350db9e1080d814493fae143ae37605189504152d1ba8743ba3178d0b37269ce1ffc42b101547fdc1827078f82671e407
- languageName: node
- linkType: hard
-
-"ajv@npm:^6.10.0, ajv@npm:^6.12.4":
- version: 6.12.6
- resolution: "ajv@npm:6.12.6"
- 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
- checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4
- languageName: node
- linkType: hard
-
-"ajv@npm:^8.0.1":
- version: 8.11.0
- resolution: "ajv@npm:8.11.0"
- dependencies:
- fast-deep-equal: ^3.1.1
- json-schema-traverse: ^1.0.0
- require-from-string: ^2.0.2
- uri-js: ^4.2.2
- checksum: 5e0ff226806763be73e93dd7805b634f6f5921e3e90ca04acdf8db81eed9d8d3f0d4c5f1213047f45ebbf8047ffe0c840fa1ef2ec42c3a644899f69aa72b5bef
- languageName: node
- linkType: hard
-
-"ansi-colors@npm:^4.1.1":
- version: 4.1.3
- resolution: "ansi-colors@npm:4.1.3"
- checksum: a9c2ec842038a1fabc7db9ece7d3177e2fe1c5dc6f0c51ecfbf5f39911427b89c00b5dc6b8bd95f82a26e9b16aaae2e83d45f060e98070ce4d1333038edceb0e
- languageName: node
- linkType: hard
-
-"ansi-regex@npm:^5.0.1":
- version: 5.0.1
- resolution: "ansi-regex@npm:5.0.1"
- checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b
- languageName: node
- linkType: hard
-
-"ansi-styles@npm:^3.2.1":
- version: 3.2.1
- resolution: "ansi-styles@npm:3.2.1"
- dependencies:
- color-convert: ^1.9.0
- checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665
- languageName: node
- linkType: hard
-
-"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0":
- version: 4.3.0
- resolution: "ansi-styles@npm:4.3.0"
- dependencies:
- color-convert: ^2.0.1
- checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4
- languageName: node
- linkType: hard
-
-"argparse@npm:^1.0.7":
- version: 1.0.10
- resolution: "argparse@npm:1.0.10"
- dependencies:
- sprintf-js: ~1.0.2
- checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945
- languageName: node
- linkType: hard
-
-"aria-query@npm:^4.2.2":
- version: 4.2.2
- resolution: "aria-query@npm:4.2.2"
- dependencies:
- "@babel/runtime": ^7.10.2
- "@babel/runtime-corejs3": ^7.10.2
- checksum: 38401a9a400f26f3dcc24b84997461a16b32869a9893d323602bed8da40a8bcc0243b8d2880e942249a1496cea7a7de769e93d21c0baa439f01e1ee936fed665
- languageName: node
- linkType: hard
-
-"array-includes@npm:^3.1.4, array-includes@npm:^3.1.5":
- version: 3.1.5
- resolution: "array-includes@npm:3.1.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.4
- es-abstract: ^1.19.5
- get-intrinsic: ^1.1.1
- is-string: ^1.0.7
- checksum: f6f24d834179604656b7bec3e047251d5cc87e9e87fab7c175c61af48e80e75acd296017abcde21fb52292ab6a2a449ab2ee37213ee48c8709f004d75983f9c5
- languageName: node
- linkType: hard
-
-"array-union@npm:^2.1.0":
- version: 2.1.0
- resolution: "array-union@npm:2.1.0"
- checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d
- languageName: node
- linkType: hard
-
-"array.prototype.flat@npm:^1.2.5":
- version: 1.3.0
- resolution: "array.prototype.flat@npm:1.3.0"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.2
- es-shim-unscopables: ^1.0.0
- checksum: 2a652b3e8dc0bebb6117e42a5ab5738af0203a14c27341d7bb2431467bdb4b348e2c5dc555dfcda8af0a5e4075c400b85311ded73861c87290a71a17c3e0a257
- languageName: node
- linkType: hard
-
-"array.prototype.flatmap@npm:^1.3.0":
- version: 1.3.0
- resolution: "array.prototype.flatmap@npm:1.3.0"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.2
- es-shim-unscopables: ^1.0.0
- checksum: 818538f39409c4045d874be85df0dbd195e1446b14d22f95bdcfefea44ae77db44e42dcd89a559254ec5a7c8b338cfc986cc6d641e3472f9a5326b21eb2976a2
- languageName: node
- linkType: hard
-
-"ast-types-flow@npm:^0.0.7":
- version: 0.0.7
- resolution: "ast-types-flow@npm:0.0.7"
- checksum: a26dcc2182ffee111cad7c471759b0bda22d3b7ebacf27c348b22c55f16896b18ab0a4d03b85b4020dce7f3e634b8f00b593888f622915096ea1927fa51866c4
- languageName: node
- linkType: hard
-
-"astral-regex@npm:^2.0.0":
- version: 2.0.0
- resolution: "astral-regex@npm:2.0.0"
- checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766
- languageName: node
- linkType: hard
-
-"axe-core@npm:^4.4.3":
- version: 4.4.3
- resolution: "axe-core@npm:4.4.3"
- checksum: c3ea000d9ace3ba0bc747c8feafc24b0de62a0f7d93021d0f77b19c73fca15341843510f6170da563d51535d6cfb7a46c5fc0ea36170549dbb44b170208450a2
- languageName: node
- linkType: hard
-
-"axobject-query@npm:^2.2.0":
- version: 2.2.0
- resolution: "axobject-query@npm:2.2.0"
- checksum: 96b8c7d807ca525f41ad9b286186e2089b561ba63a6d36c3e7d73dc08150714660995c7ad19cda05784458446a0793b45246db45894631e13853f48c1aa3117f
- languageName: node
- linkType: hard
-
-"balanced-match@npm:^1.0.0":
- version: 1.0.2
- resolution: "balanced-match@npm:1.0.2"
- checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65
- languageName: node
- linkType: hard
-
-"berry-patch@workspace:.":
- version: 0.0.0-use.local
- resolution: "berry-patch@workspace:."
- dependencies:
- eslint-config-custom: "*"
- prettier: latest
- turbo: latest
- languageName: unknown
- linkType: soft
-
-"brace-expansion@npm:^1.1.7":
- version: 1.1.11
- resolution: "brace-expansion@npm:1.1.11"
- dependencies:
- balanced-match: ^1.0.0
- concat-map: 0.0.1
- checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07
- languageName: node
- linkType: hard
-
-"braces@npm:^3.0.2":
- version: 3.0.2
- resolution: "braces@npm:3.0.2"
- dependencies:
- fill-range: ^7.0.1
- checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459
- languageName: node
- linkType: hard
-
-"browserslist@npm:^4.21.3":
- version: 4.21.4
- resolution: "browserslist@npm:4.21.4"
- dependencies:
- caniuse-lite: ^1.0.30001400
- electron-to-chromium: ^1.4.251
- node-releases: ^2.0.6
- update-browserslist-db: ^1.0.9
- bin:
- browserslist: cli.js
- checksum: 4af3793704dbb4615bcd29059ab472344dc7961c8680aa6c4bb84f05340e14038d06a5aead58724eae69455b8fade8b8c69f1638016e87e5578969d74c078b79
- languageName: node
- linkType: hard
-
-"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2":
- version: 1.0.2
- resolution: "call-bind@npm:1.0.2"
- dependencies:
- function-bind: ^1.1.1
- get-intrinsic: ^1.0.2
- checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0
- languageName: node
- linkType: hard
-
-"callsites@npm:^3.0.0":
- version: 3.1.0
- resolution: "callsites@npm:3.1.0"
- checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3
- languageName: node
- linkType: hard
-
-"caniuse-lite@npm:^1.0.30001332, caniuse-lite@npm:^1.0.30001400":
- version: 1.0.30001400
- resolution: "caniuse-lite@npm:1.0.30001400"
- checksum: 984e29d3c02fd02a59cc92ef4a5e9390fce250de3791056362347cf901f0d91041246961a57cfa8fed800538d03ee341bc4f7eaed19bf7be0ef8a181d94cd848
- languageName: node
- linkType: hard
-
-"chalk@npm:^2.0.0":
- version: 2.4.2
- resolution: "chalk@npm:2.4.2"
- dependencies:
- ansi-styles: ^3.2.1
- escape-string-regexp: ^1.0.5
- supports-color: ^5.3.0
- checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2
- languageName: node
- linkType: hard
-
-"chalk@npm:^4.0.0":
- version: 4.1.2
- resolution: "chalk@npm:4.1.2"
- dependencies:
- ansi-styles: ^4.1.0
- supports-color: ^7.1.0
- checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc
- languageName: node
- linkType: hard
-
-"color-convert@npm:^1.9.0":
- version: 1.9.3
- resolution: "color-convert@npm:1.9.3"
- dependencies:
- color-name: 1.1.3
- checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203
- languageName: node
- linkType: hard
-
-"color-convert@npm:^2.0.1":
- version: 2.0.1
- resolution: "color-convert@npm:2.0.1"
- dependencies:
- color-name: ~1.1.4
- checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336
- languageName: node
- linkType: hard
-
-"color-name@npm:1.1.3":
- version: 1.1.3
- resolution: "color-name@npm:1.1.3"
- checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d
- languageName: node
- linkType: hard
-
-"color-name@npm:~1.1.4":
- version: 1.1.4
- resolution: "color-name@npm:1.1.4"
- checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610
- languageName: node
- linkType: hard
-
-"concat-map@npm:0.0.1":
- version: 0.0.1
- resolution: "concat-map@npm:0.0.1"
- checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af
- languageName: node
- linkType: hard
-
-"convert-source-map@npm:^1.7.0":
- version: 1.8.0
- resolution: "convert-source-map@npm:1.8.0"
- dependencies:
- safe-buffer: ~5.1.1
- checksum: 985d974a2d33e1a2543ada51c93e1ba2f73eaed608dc39f229afc78f71dcc4c8b7d7c684aa647e3c6a3a204027444d69e53e169ce94e8d1fa8d7dee80c9c8fed
- languageName: node
- linkType: hard
-
-"core-js-pure@npm:^3.25.1":
- version: 3.25.1
- resolution: "core-js-pure@npm:3.25.1"
- checksum: 0123131ec7ab3a1e56f0b4df4ae659de03d9c245ce281637d4d0f18f9839d8e0cfbfa989bd577ce1b67826f889a7dcc734421f697cf1bbe59f605f29c537a678
- languageName: node
- linkType: hard
-
-"cross-spawn@npm:^7.0.2":
- version: 7.0.3
- resolution: "cross-spawn@npm:7.0.3"
- dependencies:
- path-key: ^3.1.0
- shebang-command: ^2.0.0
- which: ^2.0.1
- checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52
- languageName: node
- linkType: hard
-
-"csstype@npm:^3.0.2":
- version: 3.1.1
- resolution: "csstype@npm:3.1.1"
- checksum: 1f7b4f5fdd955b7444b18ebdddf3f5c699159f13e9cf8ac9027ae4a60ae226aef9bbb14a6e12ca7dba3358b007cee6354b116e720262867c398de6c955ea451d
- languageName: node
- linkType: hard
-
-"damerau-levenshtein@npm:^1.0.8":
- version: 1.0.8
- resolution: "damerau-levenshtein@npm:1.0.8"
- checksum: d240b7757544460ae0586a341a53110ab0a61126570ef2d8c731e3eab3f0cb6e488e2609e6a69b46727635de49be20b071688698744417ff1b6c1d7ccd03e0de
- languageName: node
- linkType: hard
-
-"debug@npm:^2.6.9":
- version: 2.6.9
- resolution: "debug@npm:2.6.9"
- dependencies:
- ms: 2.0.0
- checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6
- languageName: node
- linkType: hard
-
-"debug@npm:^3.2.7":
- version: 3.2.7
- resolution: "debug@npm:3.2.7"
- dependencies:
- ms: ^2.1.1
- checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c
- languageName: node
- linkType: hard
-
-"debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.4":
- version: 4.3.4
- resolution: "debug@npm:4.3.4"
- dependencies:
- ms: 2.1.2
- peerDependenciesMeta:
- supports-color:
- optional: true
- checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708
- languageName: node
- linkType: hard
-
-"deep-is@npm:^0.1.3":
- version: 0.1.4
- resolution: "deep-is@npm:0.1.4"
- checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804
- languageName: node
- linkType: hard
-
-"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4":
- version: 1.1.4
- resolution: "define-properties@npm:1.1.4"
- dependencies:
- has-property-descriptors: ^1.0.0
- object-keys: ^1.1.1
- checksum: ce0aef3f9eb193562b5cfb79b2d2c86b6a109dfc9fdcb5f45d680631a1a908c06824ddcdb72b7573b54e26ace07f0a23420aaba0d5c627b34d2c1de8ef527e2b
- languageName: node
- linkType: hard
-
-"dir-glob@npm:^3.0.1":
- version: 3.0.1
- resolution: "dir-glob@npm:3.0.1"
- dependencies:
- path-type: ^4.0.0
- checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615
- languageName: node
- linkType: hard
-
-"docs@workspace:apps/docs":
- version: 0.0.0-use.local
- resolution: "docs@workspace:apps/docs"
- dependencies:
- "@babel/core": ^7.0.0
- "@types/node": ^17.0.12
- "@types/react": 18.0.17
- eslint: 7.32.0
- eslint-config-custom: "*"
- lodash: ^4.17.21
- next: 12.2.5
- next-transpile-modules: 9.0.0
- react: 18.2.0
- react-dom: 18.2.0
- tsconfig: "*"
- typescript: ^4.5.3
- ui: "*"
- languageName: unknown
- linkType: soft
-
-"doctrine@npm:^2.1.0":
- version: 2.1.0
- resolution: "doctrine@npm:2.1.0"
- dependencies:
- esutils: ^2.0.2
- checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8
- languageName: node
- linkType: hard
-
-"doctrine@npm:^3.0.0":
- version: 3.0.0
- resolution: "doctrine@npm:3.0.0"
- dependencies:
- esutils: ^2.0.2
- checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce
- languageName: node
- linkType: hard
-
-"electron-to-chromium@npm:^1.4.251":
- version: 1.4.251
- resolution: "electron-to-chromium@npm:1.4.251"
- checksum: 470a04dfe1d34814f8bc7e1dde606851b6f787a6d78655a57df063844fc71feb64ce793c52a3a130ceac1fc368b8d3e25a4c55c847a1e9c02c3090f9dcbf40ac
- languageName: node
- linkType: hard
-
-"emoji-regex@npm:^8.0.0":
- version: 8.0.0
- resolution: "emoji-regex@npm:8.0.0"
- checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192
- languageName: node
- linkType: hard
-
-"emoji-regex@npm:^9.2.2":
- version: 9.2.2
- resolution: "emoji-regex@npm:9.2.2"
- checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601
- languageName: node
- linkType: hard
-
-"enhanced-resolve@npm:^5.7.0":
- version: 5.10.0
- resolution: "enhanced-resolve@npm:5.10.0"
- dependencies:
- graceful-fs: ^4.2.4
- tapable: ^2.2.0
- checksum: 0bb9830704db271610f900e8d79d70a740ea16f251263362b0c91af545576d09fe50103496606c1300a05e588372d6f9780a9bc2e30ce8ef9b827ec8f44687ff
- languageName: node
- linkType: hard
-
-"enquirer@npm:^2.3.5":
- version: 2.3.6
- resolution: "enquirer@npm:2.3.6"
- dependencies:
- ansi-colors: ^4.1.1
- checksum: 1c0911e14a6f8d26721c91e01db06092a5f7675159f0261d69c403396a385afd13dd76825e7678f66daffa930cfaa8d45f506fb35f818a2788463d022af1b884
- languageName: node
- linkType: hard
-
-"es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1, es-abstract@npm:^1.19.2, es-abstract@npm:^1.19.5":
- version: 1.20.2
- resolution: "es-abstract@npm:1.20.2"
- dependencies:
- call-bind: ^1.0.2
- es-to-primitive: ^1.2.1
- function-bind: ^1.1.1
- function.prototype.name: ^1.1.5
- get-intrinsic: ^1.1.2
- get-symbol-description: ^1.0.0
- has: ^1.0.3
- has-property-descriptors: ^1.0.0
- has-symbols: ^1.0.3
- internal-slot: ^1.0.3
- is-callable: ^1.2.4
- is-negative-zero: ^2.0.2
- is-regex: ^1.1.4
- is-shared-array-buffer: ^1.0.2
- is-string: ^1.0.7
- is-weakref: ^1.0.2
- object-inspect: ^1.12.2
- object-keys: ^1.1.1
- object.assign: ^4.1.4
- regexp.prototype.flags: ^1.4.3
- string.prototype.trimend: ^1.0.5
- string.prototype.trimstart: ^1.0.5
- unbox-primitive: ^1.0.2
- checksum: ab893dd1f849250f5a2da82656b4e21b511f76429b25a4aea5c8b2a3007ff01cb8e112987d0dd7693b9ad9e6399f8f7be133285d6196a5ebd1b13a4ee2258f70
- languageName: node
- linkType: hard
-
-"es-shim-unscopables@npm:^1.0.0":
- version: 1.0.0
- resolution: "es-shim-unscopables@npm:1.0.0"
- dependencies:
- has: ^1.0.3
- checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1
- languageName: node
- linkType: hard
-
-"es-to-primitive@npm:^1.2.1":
- version: 1.2.1
- resolution: "es-to-primitive@npm:1.2.1"
- dependencies:
- is-callable: ^1.1.4
- is-date-object: ^1.0.1
- is-symbol: ^1.0.2
- checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed
- languageName: node
- linkType: hard
-
-"escalade@npm:^3.1.1":
- version: 3.1.1
- resolution: "escalade@npm:3.1.1"
- checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133
- languageName: node
- linkType: hard
-
-"escape-string-regexp@npm:^1.0.5":
- version: 1.0.5
- resolution: "escape-string-regexp@npm:1.0.5"
- checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410
- languageName: node
- linkType: hard
-
-"escape-string-regexp@npm:^4.0.0":
- version: 4.0.0
- resolution: "escape-string-regexp@npm:4.0.0"
- checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5
- languageName: node
- linkType: hard
-
-"eslint-config-custom@*, eslint-config-custom@workspace:packages/eslint-config-custom":
- version: 0.0.0-use.local
- resolution: "eslint-config-custom@workspace:packages/eslint-config-custom"
- dependencies:
- eslint: ^7.23.0
- eslint-config-next: ^12.0.8
- eslint-config-prettier: ^8.3.0
- eslint-config-turbo: latest
- eslint-plugin-react: 7.31.7
- typescript: ^4.7.4
- languageName: unknown
- linkType: soft
-
-"eslint-config-next@npm:^12.0.8":
- version: 12.3.0
- resolution: "eslint-config-next@npm:12.3.0"
- dependencies:
- "@next/eslint-plugin-next": 12.3.0
- "@rushstack/eslint-patch": ^1.1.3
- "@typescript-eslint/parser": ^5.21.0
- eslint-import-resolver-node: ^0.3.6
- eslint-import-resolver-typescript: ^2.7.1
- eslint-plugin-import: ^2.26.0
- eslint-plugin-jsx-a11y: ^6.5.1
- eslint-plugin-react: ^7.29.4
- eslint-plugin-react-hooks: ^4.5.0
- peerDependencies:
- eslint: ^7.23.0 || ^8.0.0
- typescript: ">=3.3.1"
- peerDependenciesMeta:
- typescript:
- optional: true
- checksum: 50a2e43c515350c689cd848973b953c1d058303b84e05ecba5b5bf0f8feffe3935011de3b574ba35d48de8a5d7d5c42567d21d1a17f02189a701edeb6d76a8e0
- languageName: node
- linkType: hard
-
-"eslint-config-prettier@npm:^8.3.0":
- version: 8.5.0
- resolution: "eslint-config-prettier@npm:8.5.0"
- peerDependencies:
- eslint: ">=7.0.0"
- bin:
- eslint-config-prettier: bin/cli.js
- checksum: 0d0f5c32e7a0ad91249467ce71ca92394ccd343178277d318baf32063b79ea90216f4c81d1065d60f96366fdc60f151d4d68ae7811a58bd37228b84c2083f893
- languageName: node
- linkType: hard
-
-eslint-config-turbo@latest:
- version: 0.0.3
- resolution: "eslint-config-turbo@npm:0.0.3"
- dependencies:
- eslint-plugin-turbo: 0.0.3
- peerDependencies:
- eslint: ^7.23.0 || ^8.0.0
- checksum: c92255e91dd0865faeebc857eb3a862e8ca2ccb37fc54ffce93b73cd41e95ad456826ae6634772450dfa9c705b67c288f476e8e413fab3d8194dc271754528e2
- languageName: node
- linkType: hard
-
-"eslint-import-resolver-node@npm:^0.3.6":
- version: 0.3.6
- resolution: "eslint-import-resolver-node@npm:0.3.6"
- dependencies:
- debug: ^3.2.7
- resolve: ^1.20.0
- checksum: 6266733af1e112970e855a5bcc2d2058fb5ae16ad2a6d400705a86b29552b36131ffc5581b744c23d550de844206fb55e9193691619ee4dbf225c4bde526b1c8
- languageName: node
- linkType: hard
-
-"eslint-import-resolver-typescript@npm:^2.7.1":
- version: 2.7.1
- resolution: "eslint-import-resolver-typescript@npm:2.7.1"
- dependencies:
- debug: ^4.3.4
- glob: ^7.2.0
- is-glob: ^4.0.3
- resolve: ^1.22.0
- tsconfig-paths: ^3.14.1
- peerDependencies:
- eslint: "*"
- eslint-plugin-import: "*"
- checksum: 1d81b657b1f73bf95b8f0b745c0305574b91630c1db340318f3ca8918e206fce20a933b95e7c419338cc4452cb80bb2b2d92acaf01b6aa315c78a332d832545c
- languageName: node
- linkType: hard
-
-"eslint-module-utils@npm:^2.7.3":
- version: 2.7.4
- resolution: "eslint-module-utils@npm:2.7.4"
- dependencies:
- debug: ^3.2.7
- dependenciesMeta:
- debug@4.3.4:
- unplugged: true
- peerDependenciesMeta:
- eslint:
- optional: true
- checksum: 5da13645daff145a5c922896b258f8bba560722c3767254e458d894ff5fbb505d6dfd945bffa932a5b0ae06714da2379bd41011c4c20d2d59cc83e23895360f7
- languageName: node
- linkType: hard
-
-"eslint-plugin-import@npm:^2.26.0":
- version: 2.26.0
- resolution: "eslint-plugin-import@npm:2.26.0"
- dependencies:
- array-includes: ^3.1.4
- array.prototype.flat: ^1.2.5
- debug: ^2.6.9
- doctrine: ^2.1.0
- eslint-import-resolver-node: ^0.3.6
- eslint-module-utils: ^2.7.3
- has: ^1.0.3
- is-core-module: ^2.8.1
- is-glob: ^4.0.3
- minimatch: ^3.1.2
- object.values: ^1.1.5
- resolve: ^1.22.0
- tsconfig-paths: ^3.14.1
- peerDependencies:
- eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
- checksum: 0bf77ad80339554481eafa2b1967449e1f816b94c7a6f9614ce33fb4083c4e6c050f10d241dd50b4975d47922880a34de1e42ea9d8e6fd663ebb768baa67e655
- languageName: node
- linkType: hard
-
-"eslint-plugin-jsx-a11y@npm:^6.5.1":
- version: 6.6.1
- resolution: "eslint-plugin-jsx-a11y@npm:6.6.1"
- dependencies:
- "@babel/runtime": ^7.18.9
- aria-query: ^4.2.2
- array-includes: ^3.1.5
- ast-types-flow: ^0.0.7
- axe-core: ^4.4.3
- axobject-query: ^2.2.0
- damerau-levenshtein: ^1.0.8
- emoji-regex: ^9.2.2
- has: ^1.0.3
- jsx-ast-utils: ^3.3.2
- language-tags: ^1.0.5
- minimatch: ^3.1.2
- semver: ^6.3.0
- peerDependencies:
- eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
- checksum: baae7377f0e25a0cc9b34dc333a3dc6ead9ee8365e445451eff554c3ca267a0a6cb88127fe90395c578ab1b92cfed246aef7dc8d2b48b603389e10181799e144
- languageName: node
- linkType: hard
-
-"eslint-plugin-react-hooks@npm:^4.5.0":
- version: 4.6.0
- resolution: "eslint-plugin-react-hooks@npm:4.6.0"
- peerDependencies:
- eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
- checksum: 23001801f14c1d16bf0a837ca7970d9dd94e7b560384b41db378b49b6e32dc43d6e2790de1bd737a652a86f81a08d6a91f402525061b47719328f586a57e86c3
- languageName: node
- linkType: hard
-
-"eslint-plugin-react@npm:7.31.7":
- version: 7.31.7
- resolution: "eslint-plugin-react@npm:7.31.7"
- dependencies:
- array-includes: ^3.1.5
- array.prototype.flatmap: ^1.3.0
- doctrine: ^2.1.0
- estraverse: ^5.3.0
- jsx-ast-utils: ^2.4.1 || ^3.0.0
- minimatch: ^3.1.2
- object.entries: ^1.1.5
- object.fromentries: ^2.0.5
- object.hasown: ^1.1.1
- object.values: ^1.1.5
- prop-types: ^15.8.1
- resolve: ^2.0.0-next.3
- semver: ^6.3.0
- string.prototype.matchall: ^4.0.7
- peerDependencies:
- eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
- checksum: 582d422f531d7d3894fc09ac941ef8b6ad595782cfca5e1d52af5895ce117def7a0ff8afeea0166bff7b6ceae8baec2313614b1571754f539575cfa9351cd2da
- languageName: node
- linkType: hard
-
-"eslint-plugin-react@npm:^7.29.4":
- version: 7.31.8
- resolution: "eslint-plugin-react@npm:7.31.8"
- dependencies:
- array-includes: ^3.1.5
- array.prototype.flatmap: ^1.3.0
- doctrine: ^2.1.0
- estraverse: ^5.3.0
- jsx-ast-utils: ^2.4.1 || ^3.0.0
- minimatch: ^3.1.2
- object.entries: ^1.1.5
- object.fromentries: ^2.0.5
- object.hasown: ^1.1.1
- object.values: ^1.1.5
- prop-types: ^15.8.1
- resolve: ^2.0.0-next.3
- semver: ^6.3.0
- string.prototype.matchall: ^4.0.7
- peerDependencies:
- eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
- checksum: 0683e2a624a4df6f08264a3f6bc614a81e8f961c83173bdf2d8d3523f84ed5d234cddc976dbc6815913e007c5984df742ba61be0c0592b27c3daabe0f68165a3
- languageName: node
- linkType: hard
-
-"eslint-plugin-turbo@npm:0.0.3":
- version: 0.0.3
- resolution: "eslint-plugin-turbo@npm:0.0.3"
- peerDependencies:
- eslint: ^7.23.0 || ^8.0.0
- checksum: 18e2b13ede03eee7635d0c67ca792cf46483e90443143bdc06555bf231045fb5f70b2f6f1d67492365b7fe47620408eea22f7548879f3afcb07ccc070aec5c15
- languageName: node
- linkType: hard
-
-"eslint-scope@npm:^5.1.1":
- version: 5.1.1
- resolution: "eslint-scope@npm:5.1.1"
- dependencies:
- esrecurse: ^4.3.0
- estraverse: ^4.1.1
- checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb
- languageName: node
- linkType: hard
-
-"eslint-utils@npm:^2.1.0":
- version: 2.1.0
- resolution: "eslint-utils@npm:2.1.0"
- dependencies:
- eslint-visitor-keys: ^1.1.0
- checksum: 27500938f348da42100d9e6ad03ae29b3de19ba757ae1a7f4a087bdcf83ac60949bbb54286492ca61fac1f5f3ac8692dd21537ce6214240bf95ad0122f24d71d
- languageName: node
- linkType: hard
-
-"eslint-visitor-keys@npm:^1.1.0, eslint-visitor-keys@npm:^1.3.0":
- version: 1.3.0
- resolution: "eslint-visitor-keys@npm:1.3.0"
- checksum: 37a19b712f42f4c9027e8ba98c2b06031c17e0c0a4c696cd429bd9ee04eb43889c446f2cd545e1ff51bef9593fcec94ecd2c2ef89129fcbbf3adadbef520376a
- languageName: node
- linkType: hard
-
-"eslint-visitor-keys@npm:^2.0.0":
- version: 2.1.0
- resolution: "eslint-visitor-keys@npm:2.1.0"
- checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d
- languageName: node
- linkType: hard
-
-"eslint-visitor-keys@npm:^3.3.0":
- version: 3.3.0
- resolution: "eslint-visitor-keys@npm:3.3.0"
- checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808
- languageName: node
- linkType: hard
-
-"eslint@npm:7.32.0, eslint@npm:^7.23.0, eslint@npm:^7.32.0":
- version: 7.32.0
- resolution: "eslint@npm:7.32.0"
- dependencies:
- "@babel/code-frame": 7.12.11
- "@eslint/eslintrc": ^0.4.3
- "@humanwhocodes/config-array": ^0.5.0
- ajv: ^6.10.0
- chalk: ^4.0.0
- cross-spawn: ^7.0.2
- debug: ^4.0.1
- doctrine: ^3.0.0
- enquirer: ^2.3.5
- escape-string-regexp: ^4.0.0
- eslint-scope: ^5.1.1
- eslint-utils: ^2.1.0
- eslint-visitor-keys: ^2.0.0
- espree: ^7.3.1
- esquery: ^1.4.0
- esutils: ^2.0.2
- fast-deep-equal: ^3.1.3
- file-entry-cache: ^6.0.1
- functional-red-black-tree: ^1.0.1
- glob-parent: ^5.1.2
- globals: ^13.6.0
- ignore: ^4.0.6
- import-fresh: ^3.0.0
- imurmurhash: ^0.1.4
- is-glob: ^4.0.0
- js-yaml: ^3.13.1
- json-stable-stringify-without-jsonify: ^1.0.1
- levn: ^0.4.1
- lodash.merge: ^4.6.2
- minimatch: ^3.0.4
- natural-compare: ^1.4.0
- optionator: ^0.9.1
- progress: ^2.0.0
- regexpp: ^3.1.0
- semver: ^7.2.1
- strip-ansi: ^6.0.0
- strip-json-comments: ^3.1.0
- table: ^6.0.9
- text-table: ^0.2.0
- v8-compile-cache: ^2.0.3
- bin:
- eslint: bin/eslint.js
- checksum: cc85af9985a3a11085c011f3d27abe8111006d34cc274291b3c4d7bea51a4e2ff6135780249becd919ba7f6d6d1ecc38a6b73dacb6a7be08d38453b344dc8d37
- languageName: node
- linkType: hard
-
-"espree@npm:^7.3.0, espree@npm:^7.3.1":
- version: 7.3.1
- resolution: "espree@npm:7.3.1"
- dependencies:
- acorn: ^7.4.0
- acorn-jsx: ^5.3.1
- eslint-visitor-keys: ^1.3.0
- checksum: aa9b50dcce883449af2e23bc2b8d9abb77118f96f4cb313935d6b220f77137eaef7724a83c3f6243b96bc0e4ab14766198e60818caad99f9519ae5a336a39b45
- languageName: node
- linkType: hard
-
-"esprima@npm:^4.0.0":
- version: 4.0.1
- resolution: "esprima@npm:4.0.1"
- bin:
- esparse: ./bin/esparse.js
- esvalidate: ./bin/esvalidate.js
- checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628
- languageName: node
- linkType: hard
-
-"esquery@npm:^1.4.0":
- version: 1.4.0
- resolution: "esquery@npm:1.4.0"
- dependencies:
- estraverse: ^5.1.0
- checksum: a0807e17abd7fbe5fbd4fab673038d6d8a50675cdae6b04fbaa520c34581be0c5fa24582990e8acd8854f671dd291c78bb2efb9e0ed5b62f33bac4f9cf820210
- languageName: node
- linkType: hard
-
-"esrecurse@npm:^4.3.0":
- version: 4.3.0
- resolution: "esrecurse@npm:4.3.0"
- dependencies:
- estraverse: ^5.2.0
- checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837
- languageName: node
- linkType: hard
-
-"estraverse@npm:^4.1.1":
- version: 4.3.0
- resolution: "estraverse@npm:4.3.0"
- checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827
- languageName: node
- linkType: hard
-
-"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0":
- version: 5.3.0
- resolution: "estraverse@npm:5.3.0"
- checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b
- languageName: node
- linkType: hard
-
-"esutils@npm:^2.0.2":
- version: 2.0.3
- resolution: "esutils@npm:2.0.3"
- checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87
- languageName: node
- linkType: hard
-
-"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
- version: 3.1.3
- resolution: "fast-deep-equal@npm:3.1.3"
- checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d
- languageName: node
- linkType: hard
-
-"fast-glob@npm:^3.2.9":
- version: 3.2.12
- resolution: "fast-glob@npm:3.2.12"
- dependencies:
- "@nodelib/fs.stat": ^2.0.2
- "@nodelib/fs.walk": ^1.2.3
- glob-parent: ^5.1.2
- merge2: ^1.3.0
- micromatch: ^4.0.4
- checksum: 0b1990f6ce831c7e28c4d505edcdaad8e27e88ab9fa65eedadb730438cfc7cde4910d6c975d6b7b8dc8a73da4773702ebcfcd6e3518e73938bb1383badfe01c2
- languageName: node
- linkType: hard
-
-"fast-json-stable-stringify@npm:^2.0.0":
- version: 2.1.0
- resolution: "fast-json-stable-stringify@npm:2.1.0"
- checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb
- languageName: node
- linkType: hard
-
-"fast-levenshtein@npm:^2.0.6":
- version: 2.0.6
- resolution: "fast-levenshtein@npm:2.0.6"
- checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c
- languageName: node
- linkType: hard
-
-"fastq@npm:^1.6.0":
- version: 1.13.0
- resolution: "fastq@npm:1.13.0"
- dependencies:
- reusify: ^1.0.4
- checksum: 32cf15c29afe622af187d12fc9cd93e160a0cb7c31a3bb6ace86b7dea3b28e7b72acde89c882663f307b2184e14782c6c664fa315973c03626c7d4bff070bb0b
- languageName: node
- linkType: hard
-
-"file-entry-cache@npm:^6.0.1":
- version: 6.0.1
- resolution: "file-entry-cache@npm:6.0.1"
- dependencies:
- flat-cache: ^3.0.4
- checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74
- languageName: node
- linkType: hard
-
-"fill-range@npm:^7.0.1":
- version: 7.0.1
- resolution: "fill-range@npm:7.0.1"
- dependencies:
- to-regex-range: ^5.0.1
- checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917
- languageName: node
- linkType: hard
-
-"flat-cache@npm:^3.0.4":
- version: 3.0.4
- resolution: "flat-cache@npm:3.0.4"
- dependencies:
- flatted: ^3.1.0
- rimraf: ^3.0.2
- checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365
- languageName: node
- linkType: hard
-
-"flatted@npm:^3.1.0":
- version: 3.2.7
- resolution: "flatted@npm:3.2.7"
- checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35
- languageName: node
- linkType: hard
-
-"fs.realpath@npm:^1.0.0":
- version: 1.0.0
- resolution: "fs.realpath@npm:1.0.0"
- checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0
- languageName: node
- linkType: hard
-
-"function-bind@npm:^1.1.1":
- version: 1.1.1
- resolution: "function-bind@npm:1.1.1"
- checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a
- languageName: node
- linkType: hard
-
-"function.prototype.name@npm:^1.1.5":
- version: 1.1.5
- resolution: "function.prototype.name@npm:1.1.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.0
- functions-have-names: ^1.2.2
- checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27
- languageName: node
- linkType: hard
-
-"functional-red-black-tree@npm:^1.0.1":
- version: 1.0.1
- resolution: "functional-red-black-tree@npm:1.0.1"
- checksum: ca6c170f37640e2d94297da8bb4bf27a1d12bea3e00e6a3e007fd7aa32e37e000f5772acf941b4e4f3cf1c95c3752033d0c509af157ad8f526e7f00723b9eb9f
- languageName: node
- linkType: hard
-
-"functions-have-names@npm:^1.2.2":
- version: 1.2.3
- resolution: "functions-have-names@npm:1.2.3"
- checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5
- languageName: node
- linkType: hard
-
-"gensync@npm:^1.0.0-beta.2":
- version: 1.0.0-beta.2
- resolution: "gensync@npm:1.0.0-beta.2"
- checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec
- languageName: node
- linkType: hard
-
-"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.2":
- version: 1.1.3
- resolution: "get-intrinsic@npm:1.1.3"
- dependencies:
- function-bind: ^1.1.1
- has: ^1.0.3
- has-symbols: ^1.0.3
- checksum: 152d79e87251d536cf880ba75cfc3d6c6c50e12b3a64e1ea960e73a3752b47c69f46034456eae1b0894359ce3bc64c55c186f2811f8a788b75b638b06fab228a
- languageName: node
- linkType: hard
-
-"get-symbol-description@npm:^1.0.0":
- version: 1.0.0
- resolution: "get-symbol-description@npm:1.0.0"
- dependencies:
- call-bind: ^1.0.2
- get-intrinsic: ^1.1.1
- checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247
- languageName: node
- linkType: hard
-
-"glob-parent@npm:^5.1.2":
- version: 5.1.2
- resolution: "glob-parent@npm:5.1.2"
- dependencies:
- is-glob: ^4.0.1
- checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e
- languageName: node
- linkType: hard
-
-"glob@npm:7.1.7":
- version: 7.1.7
- resolution: "glob@npm:7.1.7"
- dependencies:
- fs.realpath: ^1.0.0
- inflight: ^1.0.4
- inherits: 2
- minimatch: ^3.0.4
- once: ^1.3.0
- path-is-absolute: ^1.0.0
- checksum: b61f48973bbdcf5159997b0874a2165db572b368b931135832599875919c237fc05c12984e38fe828e69aa8a921eb0e8a4997266211c517c9cfaae8a93988bb8
- languageName: node
- linkType: hard
-
-"glob@npm:^7.1.3, glob@npm:^7.2.0":
- version: 7.2.3
- resolution: "glob@npm:7.2.3"
- dependencies:
- fs.realpath: ^1.0.0
- inflight: ^1.0.4
- inherits: 2
- minimatch: ^3.1.1
- once: ^1.3.0
- path-is-absolute: ^1.0.0
- checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133
- languageName: node
- linkType: hard
-
-"globals@npm:^11.1.0":
- version: 11.12.0
- resolution: "globals@npm:11.12.0"
- checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e
- languageName: node
- linkType: hard
-
-"globals@npm:^13.6.0, globals@npm:^13.9.0":
- version: 13.17.0
- resolution: "globals@npm:13.17.0"
- dependencies:
- type-fest: ^0.20.2
- checksum: fbaf4112e59b92c9f5575e85ce65e9e17c0b82711196ec5f58beb08599bbd92fd72703d6dfc9b080381fd35b644e1b11dcf25b38cc2341ec21df942594cbc8ce
- languageName: node
- linkType: hard
-
-"globby@npm:^11.1.0":
- version: 11.1.0
- resolution: "globby@npm:11.1.0"
- dependencies:
- array-union: ^2.1.0
- dir-glob: ^3.0.1
- fast-glob: ^3.2.9
- ignore: ^5.2.0
- merge2: ^1.4.1
- slash: ^3.0.0
- checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6
- languageName: node
- linkType: hard
-
-"graceful-fs@npm:^4.2.4":
- version: 4.2.10
- resolution: "graceful-fs@npm:4.2.10"
- checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da
- languageName: node
- linkType: hard
-
-"has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2":
- version: 1.0.2
- resolution: "has-bigints@npm:1.0.2"
- checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b
- languageName: node
- linkType: hard
-
-"has-flag@npm:^3.0.0":
- version: 3.0.0
- resolution: "has-flag@npm:3.0.0"
- checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b
- languageName: node
- linkType: hard
-
-"has-flag@npm:^4.0.0":
- version: 4.0.0
- resolution: "has-flag@npm:4.0.0"
- checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad
- languageName: node
- linkType: hard
-
-"has-property-descriptors@npm:^1.0.0":
- version: 1.0.0
- resolution: "has-property-descriptors@npm:1.0.0"
- dependencies:
- get-intrinsic: ^1.1.1
- checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb
- languageName: node
- linkType: hard
-
-"has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3":
- version: 1.0.3
- resolution: "has-symbols@npm:1.0.3"
- checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410
- languageName: node
- linkType: hard
-
-"has-tostringtag@npm:^1.0.0":
- version: 1.0.0
- resolution: "has-tostringtag@npm:1.0.0"
- dependencies:
- has-symbols: ^1.0.2
- checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c
- languageName: node
- linkType: hard
-
-"has@npm:^1.0.3":
- version: 1.0.3
- resolution: "has@npm:1.0.3"
- dependencies:
- function-bind: ^1.1.1
- checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792
- languageName: node
- linkType: hard
-
-"ignore@npm:^4.0.6":
- version: 4.0.6
- resolution: "ignore@npm:4.0.6"
- checksum: 248f82e50a430906f9ee7f35e1158e3ec4c3971451dd9f99c9bc1548261b4db2b99709f60ac6c6cac9333494384176cc4cc9b07acbe42d52ac6a09cad734d800
- languageName: node
- linkType: hard
-
-"ignore@npm:^5.2.0":
- version: 5.2.0
- resolution: "ignore@npm:5.2.0"
- checksum: 6b1f926792d614f64c6c83da3a1f9c83f6196c2839aa41e1e32dd7b8d174cef2e329d75caabb62cb61ce9dc432f75e67d07d122a037312db7caa73166a1bdb77
- languageName: node
- linkType: hard
-
-"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1":
- version: 3.3.0
- resolution: "import-fresh@npm:3.3.0"
- dependencies:
- parent-module: ^1.0.0
- resolve-from: ^4.0.0
- checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa
- languageName: node
- linkType: hard
-
-"imurmurhash@npm:^0.1.4":
- version: 0.1.4
- resolution: "imurmurhash@npm:0.1.4"
- checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7
- languageName: node
- linkType: hard
-
-"inflight@npm:^1.0.4":
- version: 1.0.6
- resolution: "inflight@npm:1.0.6"
- dependencies:
- once: ^1.3.0
- wrappy: 1
- checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd
- languageName: node
- linkType: hard
-
-"inherits@npm:2":
- version: 2.0.4
- resolution: "inherits@npm:2.0.4"
- checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1
- languageName: node
- linkType: hard
-
-"internal-slot@npm:^1.0.3":
- version: 1.0.3
- resolution: "internal-slot@npm:1.0.3"
- dependencies:
- get-intrinsic: ^1.1.0
- has: ^1.0.3
- side-channel: ^1.0.4
- checksum: 1944f92e981e47aebc98a88ff0db579fd90543d937806104d0b96557b10c1f170c51fb777b97740a8b6ddeec585fca8c39ae99fd08a8e058dfc8ab70937238bf
- languageName: node
- linkType: hard
-
-"is-bigint@npm:^1.0.1":
- version: 1.0.4
- resolution: "is-bigint@npm:1.0.4"
- dependencies:
- has-bigints: ^1.0.1
- checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666
- languageName: node
- linkType: hard
-
-"is-boolean-object@npm:^1.1.0":
- version: 1.1.2
- resolution: "is-boolean-object@npm:1.1.2"
- dependencies:
- call-bind: ^1.0.2
- has-tostringtag: ^1.0.0
- checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222
- languageName: node
- linkType: hard
-
-"is-callable@npm:^1.1.4, is-callable@npm:^1.2.4":
- version: 1.2.6
- resolution: "is-callable@npm:1.2.6"
- checksum: 7667d6a6be66df00741cfa18c657877c46a00139ea7ea7765251e9db0182745c9ee173506941a329d6914e34e59e9cc80029fb3f68bbf8c22a6c155ee6ea77b3
- languageName: node
- linkType: hard
-
-"is-core-module@npm:^2.8.1, is-core-module@npm:^2.9.0":
- version: 2.10.0
- resolution: "is-core-module@npm:2.10.0"
- dependencies:
- has: ^1.0.3
- checksum: 0f3f77811f430af3256fa7bbc806f9639534b140f8ee69476f632c3e1eb4e28a38be0b9d1b8ecf596179c841b53576129279df95e7051d694dac4ceb6f967593
- languageName: node
- linkType: hard
-
-"is-date-object@npm:^1.0.1":
- version: 1.0.5
- resolution: "is-date-object@npm:1.0.5"
- dependencies:
- has-tostringtag: ^1.0.0
- checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc
- languageName: node
- linkType: hard
-
-"is-extglob@npm:^2.1.1":
- version: 2.1.1
- resolution: "is-extglob@npm:2.1.1"
- checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85
- languageName: node
- linkType: hard
-
-"is-fullwidth-code-point@npm:^3.0.0":
- version: 3.0.0
- resolution: "is-fullwidth-code-point@npm:3.0.0"
- checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348
- languageName: node
- linkType: hard
-
-"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3":
- version: 4.0.3
- resolution: "is-glob@npm:4.0.3"
- dependencies:
- is-extglob: ^2.1.1
- checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4
- languageName: node
- linkType: hard
-
-"is-negative-zero@npm:^2.0.2":
- version: 2.0.2
- resolution: "is-negative-zero@npm:2.0.2"
- checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a
- languageName: node
- linkType: hard
-
-"is-number-object@npm:^1.0.4":
- version: 1.0.7
- resolution: "is-number-object@npm:1.0.7"
- dependencies:
- has-tostringtag: ^1.0.0
- checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7
- languageName: node
- linkType: hard
-
-"is-number@npm:^7.0.0":
- version: 7.0.0
- resolution: "is-number@npm:7.0.0"
- checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a
- languageName: node
- linkType: hard
-
-"is-regex@npm:^1.1.4":
- version: 1.1.4
- resolution: "is-regex@npm:1.1.4"
- dependencies:
- call-bind: ^1.0.2
- has-tostringtag: ^1.0.0
- checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652
- languageName: node
- linkType: hard
-
-"is-shared-array-buffer@npm:^1.0.2":
- version: 1.0.2
- resolution: "is-shared-array-buffer@npm:1.0.2"
- dependencies:
- call-bind: ^1.0.2
- checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a
- languageName: node
- linkType: hard
-
-"is-string@npm:^1.0.5, is-string@npm:^1.0.7":
- version: 1.0.7
- resolution: "is-string@npm:1.0.7"
- dependencies:
- has-tostringtag: ^1.0.0
- checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989
- languageName: node
- linkType: hard
-
-"is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3":
- version: 1.0.4
- resolution: "is-symbol@npm:1.0.4"
- dependencies:
- has-symbols: ^1.0.2
- checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510
- languageName: node
- linkType: hard
-
-"is-weakref@npm:^1.0.2":
- version: 1.0.2
- resolution: "is-weakref@npm:1.0.2"
- dependencies:
- call-bind: ^1.0.2
- checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de
- languageName: node
- linkType: hard
-
-"isexe@npm:^2.0.0":
- version: 2.0.0
- resolution: "isexe@npm:2.0.0"
- checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62
- languageName: node
- linkType: hard
-
-"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
- version: 4.0.0
- resolution: "js-tokens@npm:4.0.0"
- checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78
- languageName: node
- linkType: hard
-
-"js-yaml@npm:^3.13.1":
- version: 3.14.1
- resolution: "js-yaml@npm:3.14.1"
- dependencies:
- argparse: ^1.0.7
- esprima: ^4.0.0
- bin:
- js-yaml: bin/js-yaml.js
- checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c
- languageName: node
- linkType: hard
-
-"jsesc@npm:^2.5.1":
- version: 2.5.2
- resolution: "jsesc@npm:2.5.2"
- bin:
- jsesc: bin/jsesc
- checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d
- languageName: node
- linkType: hard
-
-"json-schema-traverse@npm:^0.4.1":
- version: 0.4.1
- resolution: "json-schema-traverse@npm:0.4.1"
- checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b
- languageName: node
- linkType: hard
-
-"json-schema-traverse@npm:^1.0.0":
- version: 1.0.0
- resolution: "json-schema-traverse@npm:1.0.0"
- checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad
- languageName: node
- linkType: hard
-
-"json-stable-stringify-without-jsonify@npm:^1.0.1":
- version: 1.0.1
- resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
- checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215
- languageName: node
- linkType: hard
-
-"json5@npm:^1.0.1":
- version: 1.0.1
- resolution: "json5@npm:1.0.1"
- dependencies:
- minimist: ^1.2.0
- bin:
- json5: lib/cli.js
- checksum: e76ea23dbb8fc1348c143da628134a98adf4c5a4e8ea2adaa74a80c455fc2cdf0e2e13e6398ef819bfe92306b610ebb2002668ed9fc1af386d593691ef346fc3
- languageName: node
- linkType: hard
-
-"json5@npm:^2.2.1":
- version: 2.2.1
- resolution: "json5@npm:2.2.1"
- bin:
- json5: lib/cli.js
- checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b
- languageName: node
- linkType: hard
-
-"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.2":
- version: 3.3.3
- resolution: "jsx-ast-utils@npm:3.3.3"
- dependencies:
- array-includes: ^3.1.5
- object.assign: ^4.1.3
- checksum: a2ed78cac49a0f0c4be8b1eafe3c5257a1411341d8e7f1ac740debae003de04e5f6372bfcfbd9d082e954ffd99aac85bcda85b7c6bc11609992483f4cdc0f745
- languageName: node
- linkType: hard
-
-"language-subtag-registry@npm:~0.3.2":
- version: 0.3.22
- resolution: "language-subtag-registry@npm:0.3.22"
- checksum: 8ab70a7e0e055fe977ac16ea4c261faec7205ac43db5e806f72e5b59606939a3b972c4bd1e10e323b35d6ffa97c3e1c4c99f6553069dad2dfdd22020fa3eb56a
- languageName: node
- linkType: hard
-
-"language-tags@npm:^1.0.5":
- version: 1.0.5
- resolution: "language-tags@npm:1.0.5"
- dependencies:
- language-subtag-registry: ~0.3.2
- checksum: c81b5d8b9f5f9cfd06ee71ada6ddfe1cf83044dd5eeefcd1e420ad491944da8957688db4a0a9bc562df4afdc2783425cbbdfd152c01d93179cf86888903123cf
- languageName: node
- linkType: hard
-
-"levn@npm:^0.4.1":
- version: 0.4.1
- resolution: "levn@npm:0.4.1"
- dependencies:
- prelude-ls: ^1.2.1
- type-check: ~0.4.0
- checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4
- languageName: node
- linkType: hard
-
-"lodash.merge@npm:^4.6.2":
- version: 4.6.2
- resolution: "lodash.merge@npm:4.6.2"
- checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005
- languageName: node
- linkType: hard
-
-"lodash.truncate@npm:^4.4.2":
- version: 4.4.2
- resolution: "lodash.truncate@npm:4.4.2"
- checksum: b463d8a382cfb5f0e71c504dcb6f807a7bd379ff1ea216669aa42c52fc28c54e404bfbd96791aa09e6df0de2c1d7b8f1b7f4b1a61f324d38fe98bc535aeee4f5
- languageName: node
- linkType: hard
-
-"lodash@npm:4.17.21":
- version: 4.17.21
- resolution: "lodash@npm:4.17.21"
- checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
- languageName: node
- linkType: hard
-
-"lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch::locator=berry-patch%40workspace%3A.":
- version: 4.17.21
- resolution: "lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch::version=4.17.21&hash=2c6e9e&locator=berry-patch%40workspace%3A."
- checksum: 0f54b5291a5cfa3322cc3cb85716df4e23503535b79a341f12a41231513baaa6285fd9808d9894100dcea8b36bf91644360c4f783db1814719a4e103a04f59f3
- languageName: node
- linkType: hard
-
-"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0":
- version: 1.4.0
- resolution: "loose-envify@npm:1.4.0"
- dependencies:
- js-tokens: ^3.0.0 || ^4.0.0
- bin:
- loose-envify: cli.js
- checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4
- languageName: node
- linkType: hard
-
-"lru-cache@npm:^6.0.0":
- version: 6.0.0
- resolution: "lru-cache@npm:6.0.0"
- dependencies:
- yallist: ^4.0.0
- checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297
- languageName: node
- linkType: hard
-
-"merge2@npm:^1.3.0, merge2@npm:^1.4.1":
- version: 1.4.1
- resolution: "merge2@npm:1.4.1"
- checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2
- languageName: node
- linkType: hard
-
-"micromatch@npm:^4.0.4":
- version: 4.0.5
- resolution: "micromatch@npm:4.0.5"
- dependencies:
- braces: ^3.0.2
- picomatch: ^2.3.1
- checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc
- languageName: node
- linkType: hard
-
-"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
- version: 3.1.2
- resolution: "minimatch@npm:3.1.2"
- dependencies:
- brace-expansion: ^1.1.7
- checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a
- languageName: node
- linkType: hard
-
-"minimist@npm:^1.2.0, minimist@npm:^1.2.6":
- version: 1.2.6
- resolution: "minimist@npm:1.2.6"
- checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb
- languageName: node
- linkType: hard
-
-"ms@npm:2.0.0":
- version: 2.0.0
- resolution: "ms@npm:2.0.0"
- checksum: 0e6a22b8b746d2e0b65a430519934fefd41b6db0682e3477c10f60c76e947c4c0ad06f63ffdf1d78d335f83edee8c0aa928aa66a36c7cd95b69b26f468d527f4
- languageName: node
- linkType: hard
-
-"ms@npm:2.1.2":
- version: 2.1.2
- resolution: "ms@npm:2.1.2"
- checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f
- languageName: node
- linkType: hard
-
-"ms@npm:^2.1.1":
- version: 2.1.3
- resolution: "ms@npm:2.1.3"
- checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
- languageName: node
- linkType: hard
-
-"nanoid@npm:^3.3.4":
- version: 3.3.4
- resolution: "nanoid@npm:3.3.4"
- bin:
- nanoid: bin/nanoid.cjs
- checksum: 2fddd6dee994b7676f008d3ffa4ab16035a754f4bb586c61df5a22cf8c8c94017aadd360368f47d653829e0569a92b129979152ff97af23a558331e47e37cd9c
- languageName: node
- linkType: hard
-
-"natural-compare@npm:^1.4.0":
- version: 1.4.0
- resolution: "natural-compare@npm:1.4.0"
- checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d
- languageName: node
- linkType: hard
-
-"next-transpile-modules@npm:9.0.0":
- version: 9.0.0
- resolution: "next-transpile-modules@npm:9.0.0"
- dependencies:
- enhanced-resolve: ^5.7.0
- escalade: ^3.1.1
- checksum: 9a5d86d80cedc2404b2b1d5bd4994f2f7bf60e5e20f24e8cc5cfec34da1418b4a439916f37a95ca336bcf6d81094c3647354ac6a0c6737b3df59e62b6380507d
- languageName: node
- linkType: hard
-
-"next@npm:12.2.5":
- version: 12.2.5
- resolution: "next@npm:12.2.5"
- dependencies:
- "@next/env": 12.2.5
- "@next/swc-android-arm-eabi": 12.2.5
- "@next/swc-android-arm64": 12.2.5
- "@next/swc-darwin-arm64": 12.2.5
- "@next/swc-darwin-x64": 12.2.5
- "@next/swc-freebsd-x64": 12.2.5
- "@next/swc-linux-arm-gnueabihf": 12.2.5
- "@next/swc-linux-arm64-gnu": 12.2.5
- "@next/swc-linux-arm64-musl": 12.2.5
- "@next/swc-linux-x64-gnu": 12.2.5
- "@next/swc-linux-x64-musl": 12.2.5
- "@next/swc-win32-arm64-msvc": 12.2.5
- "@next/swc-win32-ia32-msvc": 12.2.5
- "@next/swc-win32-x64-msvc": 12.2.5
- "@swc/helpers": 0.4.3
- caniuse-lite: ^1.0.30001332
- postcss: 8.4.14
- styled-jsx: 5.0.4
- use-sync-external-store: 1.2.0
- peerDependencies:
- fibers: ">= 3.1.0"
- node-sass: ^6.0.0 || ^7.0.0
- react: ^17.0.2 || ^18.0.0-0
- react-dom: ^17.0.2 || ^18.0.0-0
- sass: ^1.3.0
- dependenciesMeta:
- "@next/swc-android-arm-eabi":
- optional: true
- "@next/swc-android-arm64":
- optional: true
- "@next/swc-darwin-arm64":
- optional: true
- "@next/swc-darwin-x64":
- optional: true
- "@next/swc-freebsd-x64":
- optional: true
- "@next/swc-linux-arm-gnueabihf":
- optional: true
- "@next/swc-linux-arm64-gnu":
- optional: true
- "@next/swc-linux-arm64-musl":
- optional: true
- "@next/swc-linux-x64-gnu":
- optional: true
- "@next/swc-linux-x64-musl":
- optional: true
- "@next/swc-win32-arm64-msvc":
- optional: true
- "@next/swc-win32-ia32-msvc":
- optional: true
- "@next/swc-win32-x64-msvc":
- optional: true
- peerDependenciesMeta:
- fibers:
- optional: true
- node-sass:
- optional: true
- sass:
- optional: true
- bin:
- next: dist/bin/next
- checksum: e8fcbd93d74fda81640fd174a9d380f22db404d3ce0893730db3db806317ae18c86d1dbb502e63e47c92fb21a93812de62639c2f1204330cb569fdac4d3d0573
- languageName: node
- linkType: hard
-
-"node-releases@npm:^2.0.6":
- version: 2.0.6
- resolution: "node-releases@npm:2.0.6"
- checksum: e86a926dc9fbb3b41b4c4a89d998afdf140e20a4e8dbe6c0a807f7b2948b42ea97d7fd3ad4868041487b6e9ee98409829c6e4d84a734a4215dff060a7fbeb4bf
- languageName: node
- linkType: hard
-
-"object-assign@npm:^4.1.1":
- version: 4.1.1
- resolution: "object-assign@npm:4.1.1"
- checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f
- languageName: node
- linkType: hard
-
-"object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0":
- version: 1.12.2
- resolution: "object-inspect@npm:1.12.2"
- checksum: a534fc1b8534284ed71f25ce3a496013b7ea030f3d1b77118f6b7b1713829262be9e6243acbcb3ef8c626e2b64186112cb7f6db74e37b2789b9c789ca23048b2
- languageName: node
- linkType: hard
-
-"object-keys@npm:^1.1.1":
- version: 1.1.1
- resolution: "object-keys@npm:1.1.1"
- checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a
- languageName: node
- linkType: hard
-
-"object.assign@npm:^4.1.3, object.assign@npm:^4.1.4":
- version: 4.1.4
- resolution: "object.assign@npm:4.1.4"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.4
- has-symbols: ^1.0.3
- object-keys: ^1.1.1
- checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864
- languageName: node
- linkType: hard
-
-"object.entries@npm:^1.1.5":
- version: 1.1.5
- resolution: "object.entries@npm:1.1.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.1
- checksum: d658696f74fd222060d8428d2a9fda2ce736b700cb06f6bdf4a16a1892d145afb746f453502b2fa55d1dca8ead6f14ddbcf66c545df45adadea757a6c4cd86c7
- languageName: node
- linkType: hard
-
-"object.fromentries@npm:^2.0.5":
- version: 2.0.5
- resolution: "object.fromentries@npm:2.0.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.1
- checksum: 61a0b565ded97b76df9e30b569729866e1824cce902f98e90bb106e84f378aea20163366f66dc75c9000e2aad2ed0caf65c6f530cb2abc4c0c0f6c982102db4b
- languageName: node
- linkType: hard
-
-"object.hasown@npm:^1.1.1":
- version: 1.1.1
- resolution: "object.hasown@npm:1.1.1"
- dependencies:
- define-properties: ^1.1.4
- es-abstract: ^1.19.5
- checksum: d8ed4907ce57f48b93e3b53c418fd6787bf226a51e8d698c91e39b78e80fe5b124cb6282f6a9d5be21cf9e2c7829ab10206dcc6112b7748860eefe641880c793
- languageName: node
- linkType: hard
-
-"object.values@npm:^1.1.5":
- version: 1.1.5
- resolution: "object.values@npm:1.1.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.1
- checksum: 0f17e99741ebfbd0fa55ce942f6184743d3070c61bd39221afc929c8422c4907618c8da694c6915bc04a83ab3224260c779ba37fc07bb668bdc5f33b66a902a4
- languageName: node
- linkType: hard
-
-"once@npm:^1.3.0":
- version: 1.4.0
- resolution: "once@npm:1.4.0"
- dependencies:
- wrappy: 1
- checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68
- languageName: node
- linkType: hard
-
-"optionator@npm:^0.9.1":
- version: 0.9.1
- resolution: "optionator@npm:0.9.1"
- dependencies:
- deep-is: ^0.1.3
- fast-levenshtein: ^2.0.6
- levn: ^0.4.1
- prelude-ls: ^1.2.1
- type-check: ^0.4.0
- word-wrap: ^1.2.3
- checksum: dbc6fa065604b24ea57d734261914e697bd73b69eff7f18e967e8912aa2a40a19a9f599a507fa805be6c13c24c4eae8c71306c239d517d42d4c041c942f508a0
- languageName: node
- linkType: hard
-
-"parent-module@npm:^1.0.0":
- version: 1.0.1
- resolution: "parent-module@npm:1.0.1"
- dependencies:
- callsites: ^3.0.0
- checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff
- languageName: node
- linkType: hard
-
-"path-is-absolute@npm:^1.0.0":
- version: 1.0.1
- resolution: "path-is-absolute@npm:1.0.1"
- checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8
- languageName: node
- linkType: hard
-
-"path-key@npm:^3.1.0":
- version: 3.1.1
- resolution: "path-key@npm:3.1.1"
- checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020
- languageName: node
- linkType: hard
-
-"path-parse@npm:^1.0.7":
- version: 1.0.7
- resolution: "path-parse@npm:1.0.7"
- checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a
- languageName: node
- linkType: hard
-
-"path-type@npm:^4.0.0":
- version: 4.0.0
- resolution: "path-type@npm:4.0.0"
- checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45
- languageName: node
- linkType: hard
-
-"picocolors@npm:^1.0.0":
- version: 1.0.0
- resolution: "picocolors@npm:1.0.0"
- checksum: a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981
- languageName: node
- linkType: hard
-
-"picomatch@npm:^2.3.1":
- version: 2.3.1
- resolution: "picomatch@npm:2.3.1"
- checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf
- languageName: node
- linkType: hard
-
-"postcss@npm:8.4.14":
- version: 8.4.14
- resolution: "postcss@npm:8.4.14"
- dependencies:
- nanoid: ^3.3.4
- picocolors: ^1.0.0
- source-map-js: ^1.0.2
- checksum: fe58766ff32e4becf65a7d57678995cfd239df6deed2fe0557f038b47c94e4132e7e5f68b5aa820c13adfec32e523b693efaeb65798efb995ce49ccd83953816
- languageName: node
- linkType: hard
-
-"prelude-ls@npm:^1.2.1":
- version: 1.2.1
- resolution: "prelude-ls@npm:1.2.1"
- checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a
- languageName: node
- linkType: hard
-
-prettier@latest:
- version: 2.7.1
- resolution: "prettier@npm:2.7.1"
- bin:
- prettier: bin-prettier.js
- checksum: 55a4409182260866ab31284d929b3cb961e5fdb91fe0d2e099dac92eaecec890f36e524b4c19e6ceae839c99c6d7195817579cdffc8e2c80da0cb794463a748b
- languageName: node
- linkType: hard
-
-"progress@npm:^2.0.0":
- version: 2.0.3
- resolution: "progress@npm:2.0.3"
- checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7
- languageName: node
- linkType: hard
-
-"prop-types@npm:^15.8.1":
- version: 15.8.1
- resolution: "prop-types@npm:15.8.1"
- dependencies:
- loose-envify: ^1.4.0
- object-assign: ^4.1.1
- react-is: ^16.13.1
- checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459
- languageName: node
- linkType: hard
-
-"punycode@npm:^2.1.0":
- version: 2.1.1
- resolution: "punycode@npm:2.1.1"
- checksum: 823bf443c6dd14f669984dea25757b37993f67e8d94698996064035edd43bed8a5a17a9f12e439c2b35df1078c6bec05a6c86e336209eb1061e8025c481168e8
- languageName: node
- linkType: hard
-
-"queue-microtask@npm:^1.2.2":
- version: 1.2.3
- resolution: "queue-microtask@npm:1.2.3"
- checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4
- languageName: node
- linkType: hard
-
-"react-dom@npm:18.2.0":
- version: 18.2.0
- resolution: "react-dom@npm:18.2.0"
- dependencies:
- loose-envify: ^1.1.0
- scheduler: ^0.23.0
- peerDependencies:
- react: ^18.2.0
- checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc
- languageName: node
- linkType: hard
-
-"react-is@npm:^16.13.1":
- version: 16.13.1
- resolution: "react-is@npm:16.13.1"
- checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f
- languageName: node
- linkType: hard
-
-"react@npm:18.2.0, react@npm:^18.2.0":
- version: 18.2.0
- resolution: "react@npm:18.2.0"
- dependencies:
- loose-envify: ^1.1.0
- checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b
- languageName: node
- linkType: hard
-
-"regenerator-runtime@npm:^0.13.4":
- version: 0.13.9
- resolution: "regenerator-runtime@npm:0.13.9"
- checksum: 65ed455fe5afd799e2897baf691ca21c2772e1a969d19bb0c4695757c2d96249eb74ee3553ea34a91062b2a676beedf630b4c1551cc6299afb937be1426ec55e
- languageName: node
- linkType: hard
-
-"regexp.prototype.flags@npm:^1.4.1, regexp.prototype.flags@npm:^1.4.3":
- version: 1.4.3
- resolution: "regexp.prototype.flags@npm:1.4.3"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- functions-have-names: ^1.2.2
- checksum: 51228bae732592adb3ededd5e15426be25f289e9c4ef15212f4da73f4ec3919b6140806374b8894036a86020d054a8d2657d3fee6bb9b4d35d8939c20030b7a6
- languageName: node
- linkType: hard
-
-"regexpp@npm:^3.1.0":
- version: 3.2.0
- resolution: "regexpp@npm:3.2.0"
- checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8
- languageName: node
- linkType: hard
-
-"require-from-string@npm:^2.0.2":
- version: 2.0.2
- resolution: "require-from-string@npm:2.0.2"
- checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b
- languageName: node
- linkType: hard
-
-"resolve-from@npm:^4.0.0":
- version: 4.0.0
- resolution: "resolve-from@npm:4.0.0"
- checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f
- languageName: node
- linkType: hard
-
-"resolve@npm:^1.20.0, resolve@npm:^1.22.0":
- version: 1.22.1
- resolution: "resolve@npm:1.22.1"
- dependencies:
- is-core-module: ^2.9.0
- path-parse: ^1.0.7
- supports-preserve-symlinks-flag: ^1.0.0
- bin:
- resolve: bin/resolve
- checksum: 07af5fc1e81aa1d866cbc9e9460fbb67318a10fa3c4deadc35c3ad8a898ee9a71a86a65e4755ac3195e0ea0cfbe201eb323ebe655ce90526fd61917313a34e4e
- languageName: node
- linkType: hard
-
-"resolve@npm:^2.0.0-next.3":
- version: 2.0.0-next.4
- resolution: "resolve@npm:2.0.0-next.4"
- dependencies:
- is-core-module: ^2.9.0
- path-parse: ^1.0.7
- supports-preserve-symlinks-flag: ^1.0.0
- bin:
- resolve: bin/resolve
- checksum: c438ac9a650f2030fd074219d7f12ceb983b475da2d89ad3d6dd05fbf6b7a0a8cd37d4d10b43cb1f632bc19f22246ab7f36ebda54d84a29bfb2910a0680906d3
- languageName: node
- linkType: hard
-
-"resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.0#~builtin<compat/resolve>":
- version: 1.22.1
- resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin<compat/resolve>::version=1.22.1&hash=07638b"
- dependencies:
- is-core-module: ^2.9.0
- path-parse: ^1.0.7
- supports-preserve-symlinks-flag: ^1.0.0
- bin:
- resolve: bin/resolve
- checksum: 5656f4d0bedcf8eb52685c1abdf8fbe73a1603bb1160a24d716e27a57f6cecbe2432ff9c89c2bd57542c3a7b9d14b1882b73bfe2e9d7849c9a4c0b8b39f02b8b
- languageName: node
- linkType: hard
-
-"resolve@patch:resolve@^2.0.0-next.3#~builtin<compat/resolve>":
- version: 2.0.0-next.4
- resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin<compat/resolve>::version=2.0.0-next.4&hash=07638b"
- dependencies:
- is-core-module: ^2.9.0
- path-parse: ^1.0.7
- supports-preserve-symlinks-flag: ^1.0.0
- bin:
- resolve: bin/resolve
- checksum: 4bf9f4f8a458607af90518ff73c67a4bc1a38b5a23fef2bb0ccbd45e8be89820a1639b637b0ba377eb2be9eedfb1739a84cde24fe4cd670c8207d8fea922b011
- languageName: node
- linkType: hard
-
-"reusify@npm:^1.0.4":
- version: 1.0.4
- resolution: "reusify@npm:1.0.4"
- checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc
- languageName: node
- linkType: hard
-
-"rimraf@npm:^3.0.2":
- version: 3.0.2
- resolution: "rimraf@npm:3.0.2"
- dependencies:
- glob: ^7.1.3
- bin:
- rimraf: bin.js
- checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0
- languageName: node
- linkType: hard
-
-"run-parallel@npm:^1.1.9":
- version: 1.2.0
- resolution: "run-parallel@npm:1.2.0"
- dependencies:
- queue-microtask: ^1.2.2
- checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d
- languageName: node
- linkType: hard
-
-"safe-buffer@npm:~5.1.1":
- version: 5.1.2
- resolution: "safe-buffer@npm:5.1.2"
- checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c
- languageName: node
- linkType: hard
-
-"scheduler@npm:^0.23.0":
- version: 0.23.0
- resolution: "scheduler@npm:0.23.0"
- dependencies:
- loose-envify: ^1.1.0
- checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a
- languageName: node
- linkType: hard
-
-"semver@npm:^6.3.0":
- version: 6.3.0
- resolution: "semver@npm:6.3.0"
- bin:
- semver: ./bin/semver.js
- checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9
- languageName: node
- linkType: hard
-
-"semver@npm:^7.2.1, semver@npm:^7.3.7":
- version: 7.3.7
- resolution: "semver@npm:7.3.7"
- dependencies:
- lru-cache: ^6.0.0
- bin:
- semver: bin/semver.js
- checksum: 2fa3e877568cd6ce769c75c211beaed1f9fce80b28338cadd9d0b6c40f2e2862bafd62c19a6cff42f3d54292b7c623277bcab8816a2b5521cf15210d43e75232
- languageName: node
- linkType: hard
-
-"shebang-command@npm:^2.0.0":
- version: 2.0.0
- resolution: "shebang-command@npm:2.0.0"
- dependencies:
- shebang-regex: ^3.0.0
- checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa
- languageName: node
- linkType: hard
-
-"shebang-regex@npm:^3.0.0":
- version: 3.0.0
- resolution: "shebang-regex@npm:3.0.0"
- checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222
- languageName: node
- linkType: hard
-
-"side-channel@npm:^1.0.4":
- version: 1.0.4
- resolution: "side-channel@npm:1.0.4"
- dependencies:
- call-bind: ^1.0.0
- get-intrinsic: ^1.0.2
- object-inspect: ^1.9.0
- checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245
- languageName: node
- linkType: hard
-
-"slash@npm:^3.0.0":
- version: 3.0.0
- resolution: "slash@npm:3.0.0"
- checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c
- languageName: node
- linkType: hard
-
-"slice-ansi@npm:^4.0.0":
- version: 4.0.0
- resolution: "slice-ansi@npm:4.0.0"
- dependencies:
- ansi-styles: ^4.0.0
- astral-regex: ^2.0.0
- is-fullwidth-code-point: ^3.0.0
- checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756
- languageName: node
- linkType: hard
-
-"source-map-js@npm:^1.0.2":
- version: 1.0.2
- resolution: "source-map-js@npm:1.0.2"
- checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c
- languageName: node
- linkType: hard
-
-"sprintf-js@npm:~1.0.2":
- version: 1.0.3
- resolution: "sprintf-js@npm:1.0.3"
- checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3
- languageName: node
- linkType: hard
-
-"string-width@npm:^4.2.3":
- version: 4.2.3
- resolution: "string-width@npm:4.2.3"
- dependencies:
- emoji-regex: ^8.0.0
- is-fullwidth-code-point: ^3.0.0
- strip-ansi: ^6.0.1
- checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb
- languageName: node
- linkType: hard
-
-"string.prototype.matchall@npm:^4.0.7":
- version: 4.0.7
- resolution: "string.prototype.matchall@npm:4.0.7"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.3
- es-abstract: ^1.19.1
- get-intrinsic: ^1.1.1
- has-symbols: ^1.0.3
- internal-slot: ^1.0.3
- regexp.prototype.flags: ^1.4.1
- side-channel: ^1.0.4
- checksum: fc09f3ccbfb325de0472bcc87a6be0598a7499e0b4a31db5789676155b15754a4cc4bb83924f15fc9ed48934dac7366ee52c8b9bd160bed6fd072c93b489e75c
- languageName: node
- linkType: hard
-
-"string.prototype.trimend@npm:^1.0.5":
- version: 1.0.5
- resolution: "string.prototype.trimend@npm:1.0.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.4
- es-abstract: ^1.19.5
- checksum: d44f543833112f57224e79182debadc9f4f3bf9d48a0414d6f0cbd2a86f2b3e8c0ca1f95c3f8e5b32ae83e91554d79d932fc746b411895f03f93d89ed3dfb6bc
- languageName: node
- linkType: hard
-
-"string.prototype.trimstart@npm:^1.0.5":
- version: 1.0.5
- resolution: "string.prototype.trimstart@npm:1.0.5"
- dependencies:
- call-bind: ^1.0.2
- define-properties: ^1.1.4
- es-abstract: ^1.19.5
- checksum: a4857c5399ad709d159a77371eeaa8f9cc284469a0b5e1bfe405de16f1fd4166a8ea6f4180e55032f348d1b679b1599fd4301fbc7a8b72bdb3e795e43f7b1048
- languageName: node
- linkType: hard
-
-"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1":
- version: 6.0.1
- resolution: "strip-ansi@npm:6.0.1"
- dependencies:
- ansi-regex: ^5.0.1
- checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c
- languageName: node
- linkType: hard
-
-"strip-bom@npm:^3.0.0":
- version: 3.0.0
- resolution: "strip-bom@npm:3.0.0"
- checksum: 8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b
- languageName: node
- linkType: hard
-
-"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1":
- version: 3.1.1
- resolution: "strip-json-comments@npm:3.1.1"
- checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443
- languageName: node
- linkType: hard
-
-"styled-jsx@npm:5.0.4":
- version: 5.0.4
- resolution: "styled-jsx@npm:5.0.4"
- peerDependencies:
- react: ">= 16.8.0 || 17.x.x || ^18.0.0-0"
- peerDependenciesMeta:
- "@babel/core":
- optional: true
- babel-plugin-macros:
- optional: true
- checksum: db7530155626e5eebc9d80ca117ea5aed6219b0a65469196b0b5727550fbe743117d7eea1499d80511ccb312d31f4a1027a58d1f94a83f0986c9acfdcce8bdd1
- languageName: node
- linkType: hard
-
-"supports-color@npm:^5.3.0":
- version: 5.5.0
- resolution: "supports-color@npm:5.5.0"
- dependencies:
- has-flag: ^3.0.0
- checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac
- languageName: node
- linkType: hard
-
-"supports-color@npm:^7.1.0":
- version: 7.2.0
- resolution: "supports-color@npm:7.2.0"
- dependencies:
- has-flag: ^4.0.0
- checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a
- languageName: node
- linkType: hard
-
-"supports-preserve-symlinks-flag@npm:^1.0.0":
- version: 1.0.0
- resolution: "supports-preserve-symlinks-flag@npm:1.0.0"
- checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae
- languageName: node
- linkType: hard
-
-"table@npm:^6.0.9":
- version: 6.8.0
- resolution: "table@npm:6.8.0"
- dependencies:
- ajv: ^8.0.1
- lodash.truncate: ^4.4.2
- slice-ansi: ^4.0.0
- string-width: ^4.2.3
- strip-ansi: ^6.0.1
- checksum: 5b07fe462ee03d2e1fac02cbb578efd2e0b55ac07e3d3db2e950aa9570ade5a4a2b8d3c15e9f25c89e4e50b646bc4269934601ee1eef4ca7968ad31960977690
- languageName: node
- linkType: hard
-
-"tapable@npm:^2.2.0":
- version: 2.2.1
- resolution: "tapable@npm:2.2.1"
- checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51
- languageName: node
- linkType: hard
-
-"text-table@npm:^0.2.0":
- version: 0.2.0
- resolution: "text-table@npm:0.2.0"
- checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a
- languageName: node
- linkType: hard
-
-"to-fast-properties@npm:^2.0.0":
- version: 2.0.0
- resolution: "to-fast-properties@npm:2.0.0"
- checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168
- languageName: node
- linkType: hard
-
-"to-regex-range@npm:^5.0.1":
- version: 5.0.1
- resolution: "to-regex-range@npm:5.0.1"
- dependencies:
- is-number: ^7.0.0
- checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed
- languageName: node
- linkType: hard
-
-"tsconfig-paths@npm:^3.14.1":
- version: 3.14.1
- resolution: "tsconfig-paths@npm:3.14.1"
- dependencies:
- "@types/json5": ^0.0.29
- json5: ^1.0.1
- minimist: ^1.2.6
- strip-bom: ^3.0.0
- checksum: 8afa01c673ebb4782ba53d3a12df97fa837ce524f8ad38ee4e2b2fd57f5ac79abc21c574e9e9eb014d93efe7fe8214001b96233b5c6ea75bd1ea82afe17a4c6d
- languageName: node
- linkType: hard
-
-"tsconfig@*, tsconfig@workspace:packages/tsconfig":
- version: 0.0.0-use.local
- resolution: "tsconfig@workspace:packages/tsconfig"
- languageName: unknown
- linkType: soft
-
-"tslib@npm:^1.8.1":
- version: 1.14.1
- resolution: "tslib@npm:1.14.1"
- checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd
- languageName: node
- linkType: hard
-
-"tslib@npm:^2.4.0":
- version: 2.4.0
- resolution: "tslib@npm:2.4.0"
- checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113
- languageName: node
- linkType: hard
-
-"tsutils@npm:^3.21.0":
- version: 3.21.0
- resolution: "tsutils@npm:3.21.0"
- dependencies:
- tslib: ^1.8.1
- peerDependencies:
- typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48
- languageName: node
- linkType: hard
-
-"turbo-android-arm64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-android-arm64@npm:1.4.6"
- conditions: os=android & cpu=arm64
- languageName: node
- linkType: hard
-
-"turbo-darwin-64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-darwin-64@npm:1.4.6"
- conditions: os=darwin & cpu=x64
- languageName: node
- linkType: hard
-
-"turbo-darwin-arm64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-darwin-arm64@npm:1.4.6"
- conditions: os=darwin & cpu=arm64
- languageName: node
- linkType: hard
-
-"turbo-freebsd-64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-freebsd-64@npm:1.4.6"
- conditions: os=freebsd & cpu=x64
- languageName: node
- linkType: hard
-
-"turbo-freebsd-arm64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-freebsd-arm64@npm:1.4.6"
- conditions: os=freebsd & cpu=arm64
- languageName: node
- linkType: hard
-
-"turbo-linux-32@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-linux-32@npm:1.4.6"
- conditions: os=linux & cpu=ia32
- languageName: node
- linkType: hard
-
-"turbo-linux-64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-linux-64@npm:1.4.6"
- conditions: os=linux & cpu=x64
- languageName: node
- linkType: hard
-
-"turbo-linux-arm64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-linux-arm64@npm:1.4.6"
- conditions: os=linux & cpu=arm64
- languageName: node
- linkType: hard
-
-"turbo-linux-arm@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-linux-arm@npm:1.4.6"
- conditions: os=linux & cpu=arm
- languageName: node
- linkType: hard
-
-"turbo-linux-mips64le@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-linux-mips64le@npm:1.4.6"
- conditions: os=linux & cpu=mipsel
- languageName: node
- linkType: hard
-
-"turbo-linux-ppc64le@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-linux-ppc64le@npm:1.4.6"
- conditions: os=linux & cpu=ppc64
- languageName: node
- linkType: hard
-
-"turbo-windows-32@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-windows-32@npm:1.4.6"
- conditions: os=win32 & cpu=ia32
- languageName: node
- linkType: hard
-
-"turbo-windows-64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-windows-64@npm:1.4.6"
- conditions: os=win32 & cpu=x64
- languageName: node
- linkType: hard
-
-"turbo-windows-arm64@npm:1.4.6":
- version: 1.4.6
- resolution: "turbo-windows-arm64@npm:1.4.6"
- conditions: os=win32 & cpu=arm64
- languageName: node
- linkType: hard
-
-turbo@latest:
- version: 1.4.6
- resolution: "turbo@npm:1.4.6"
- dependencies:
- turbo-android-arm64: 1.4.6
- turbo-darwin-64: 1.4.6
- turbo-darwin-arm64: 1.4.6
- turbo-freebsd-64: 1.4.6
- turbo-freebsd-arm64: 1.4.6
- turbo-linux-32: 1.4.6
- turbo-linux-64: 1.4.6
- turbo-linux-arm: 1.4.6
- turbo-linux-arm64: 1.4.6
- turbo-linux-mips64le: 1.4.6
- turbo-linux-ppc64le: 1.4.6
- turbo-windows-32: 1.4.6
- turbo-windows-64: 1.4.6
- turbo-windows-arm64: 1.4.6
- dependenciesMeta:
- turbo-android-arm64:
- optional: true
- turbo-darwin-64:
- optional: true
- turbo-darwin-arm64:
- optional: true
- turbo-freebsd-64:
- optional: true
- turbo-freebsd-arm64:
- optional: true
- turbo-linux-32:
- optional: true
- turbo-linux-64:
- optional: true
- turbo-linux-arm:
- optional: true
- turbo-linux-arm64:
- optional: true
- turbo-linux-mips64le:
- optional: true
- turbo-linux-ppc64le:
- optional: true
- turbo-windows-32:
- optional: true
- turbo-windows-64:
- optional: true
- turbo-windows-arm64:
- optional: true
- bin:
- turbo: bin/turbo
- checksum: f7191f36e0abddf6dc88eb9a83a007a8616ebed1edd44c37f9b19e0451f3ce90c4406699f6166a99c0a6f8d39cc1f24d96513b7ef16b21747863827538b9c966
- languageName: node
- linkType: hard
-
-"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
- version: 0.4.0
- resolution: "type-check@npm:0.4.0"
- dependencies:
- prelude-ls: ^1.2.1
- checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a
- languageName: node
- linkType: hard
-
-"type-fest@npm:^0.20.2":
- version: 0.20.2
- resolution: "type-fest@npm:0.20.2"
- checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73
- languageName: node
- linkType: hard
-
-"typescript@npm:^4.5.2, typescript@npm:^4.5.3, typescript@npm:^4.7.4":
- version: 4.8.3
- resolution: "typescript@npm:4.8.3"
- bin:
- tsc: bin/tsc
- tsserver: bin/tsserver
- checksum: 8286a5edcaf3d68e65c451aa1e7150ad1cf53ee0813c07ec35b7abdfdb10f355ecaa13c6a226a694ae7a67785fd7eeebf89f845da0b4f7e4a35561ddc459aba0
- languageName: node
- linkType: hard
-
-"typescript@patch:typescript@^4.5.2#~builtin<compat/typescript>, typescript@patch:typescript@^4.5.3#~builtin<compat/typescript>, typescript@patch:typescript@^4.7.4#~builtin<compat/typescript>":
- version: 4.8.3
- resolution: "typescript@patch:typescript@npm%3A4.8.3#~builtin<compat/typescript>::version=4.8.3&hash=a1c5e5"
- bin:
- tsc: bin/tsc
- tsserver: bin/tsserver
- checksum: 2222d2382fb3146089b1d27ce2b55e9d1f99cc64118f1aba75809b693b856c5d3c324f052f60c75b577947fc538bc1c27bad0eb76cbdba9a63a253489504ba7e
- languageName: node
- linkType: hard
-
-"ui@*, ui@workspace:packages/ui":
- version: 0.0.0-use.local
- resolution: "ui@workspace:packages/ui"
- dependencies:
- "@types/react": ^17.0.37
- "@types/react-dom": ^17.0.11
- eslint: ^7.32.0
- eslint-config-custom: "*"
- react: ^18.2.0
- tsconfig: "*"
- typescript: ^4.5.2
- languageName: unknown
- linkType: soft
-
-"unbox-primitive@npm:^1.0.2":
- version: 1.0.2
- resolution: "unbox-primitive@npm:1.0.2"
- dependencies:
- call-bind: ^1.0.2
- has-bigints: ^1.0.2
- has-symbols: ^1.0.3
- which-boxed-primitive: ^1.0.2
- checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9
- languageName: node
- linkType: hard
-
-"update-browserslist-db@npm:^1.0.9":
- version: 1.0.9
- resolution: "update-browserslist-db@npm:1.0.9"
- dependencies:
- escalade: ^3.1.1
- picocolors: ^1.0.0
- peerDependencies:
- browserslist: ">= 4.21.0"
- bin:
- browserslist-lint: cli.js
- checksum: f625899b236f6a4d7f62b56be1b8da230c5563d1fef84d3ef148f2e1a3f11a5a4b3be4fd7e3703e51274c116194017775b10afb4de09eb2c0d09d36b90f1f578
- languageName: node
- linkType: hard
-
-"uri-js@npm:^4.2.2":
- version: 4.4.1
- resolution: "uri-js@npm:4.4.1"
- dependencies:
- punycode: ^2.1.0
- checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633
- languageName: node
- linkType: hard
-
-"use-sync-external-store@npm:1.2.0":
- version: 1.2.0
- resolution: "use-sync-external-store@npm:1.2.0"
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a
- languageName: node
- linkType: hard
-
-"v8-compile-cache@npm:^2.0.3":
- version: 2.3.0
- resolution: "v8-compile-cache@npm:2.3.0"
- checksum: adb0a271eaa2297f2f4c536acbfee872d0dd26ec2d76f66921aa7fc437319132773483344207bdbeee169225f4739016d8d2dbf0553913a52bb34da6d0334f8e
- languageName: node
- linkType: hard
-
-"web@workspace:apps/web":
- version: 0.0.0-use.local
- resolution: "web@workspace:apps/web"
- dependencies:
- "@babel/core": ^7.0.0
- "@types/node": ^17.0.12
- "@types/react": 18.0.17
- eslint: 7.32.0
- eslint-config-custom: "*"
- next: 12.2.5
- next-transpile-modules: 9.0.0
- react: 18.2.0
- react-dom: 18.2.0
- tsconfig: "*"
- typescript: ^4.5.3
- ui: "*"
- languageName: unknown
- linkType: soft
-
-"which-boxed-primitive@npm:^1.0.2":
- version: 1.0.2
- resolution: "which-boxed-primitive@npm:1.0.2"
- dependencies:
- is-bigint: ^1.0.1
- is-boolean-object: ^1.1.0
- is-number-object: ^1.0.4
- is-string: ^1.0.5
- is-symbol: ^1.0.3
- checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e
- languageName: node
- linkType: hard
-
-"which@npm:^2.0.1":
- version: 2.0.2
- resolution: "which@npm:2.0.2"
- dependencies:
- isexe: ^2.0.0
- bin:
- node-which: ./bin/node-which
- checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1
- languageName: node
- linkType: hard
-
-"word-wrap@npm:^1.2.3":
- version: 1.2.3
- resolution: "word-wrap@npm:1.2.3"
- checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f
- languageName: node
- linkType: hard
-
-"wrappy@npm:1":
- version: 1.0.2
- resolution: "wrappy@npm:1.0.2"
- checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5
- languageName: node
- linkType: hard
-
-"yallist@npm:^4.0.0":
- version: 4.0.0
- resolution: "yallist@npm:4.0.0"
- checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5
- languageName: node
- linkType: hard
diff --git a/cli/internal/lockfile/testdata/minimal-berry.lock b/cli/internal/lockfile/testdata/minimal-berry.lock
deleted file mode 100644
index 3844ce3..0000000
--- a/cli/internal/lockfile/testdata/minimal-berry.lock
+++ /dev/null
@@ -1,45 +0,0 @@
-# This file is generated by running "yarn install" inside your project.
-# Manual changes might be lost - proceed with caution!
-
-__metadata:
- version: 6
- cacheKey: 8c8
-
-"a@workspace:packages/a":
- version: 0.0.0-use.local
- resolution: "a@workspace:packages/a"
- dependencies:
- c: "*"
- lodash: ^4.17.0
- peerDependencies:
- lodash: ^3.0.0 || ^4.0.0
- languageName: unknown
- linkType: soft
-
-"b@workspace:packages/b":
- version: 0.0.0-use.local
- resolution: "b@workspace:packages/b"
- dependencies:
- c: "*"
- lodash: ^3.0.0 || ^4.0.0
- languageName: unknown
- linkType: soft
-
-"c@*, c@workspace:packages/c":
- version: 0.0.0-use.local
- resolution: "c@workspace:packages/c"
- languageName: unknown
- linkType: soft
-
-"lodash@npm:^3.0.0 || ^4.0.0, lodash@npm:^4.17.0":
- version: 4.17.21
- resolution: "lodash@npm:4.17.21"
- checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
- languageName: node
- linkType: hard
-
-"minimal-berry@workspace:.":
- version: 0.0.0-use.local
- resolution: "minimal-berry@workspace:."
- languageName: unknown
- linkType: soft
diff --git a/cli/internal/lockfile/testdata/npm-lock-workspace-variation.json b/cli/internal/lockfile/testdata/npm-lock-workspace-variation.json
deleted file mode 100644
index 4dcfc2d..0000000
--- a/cli/internal/lockfile/testdata/npm-lock-workspace-variation.json
+++ /dev/null
@@ -1,186 +0,0 @@
-{
- "name": "npm-prune-workspace-variation",
- "version": "0.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "npm-prune",
- "version": "0.0.0",
- "workspaces": { "packages": ["apps/*", "packages/*"] },
- "devDependencies": {
- "eslint-config-custom": "*",
- "prettier": "latest",
- "turbo": "latest"
- },
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "apps/docs": {
- "version": "0.0.0",
- "dependencies": {
- "lodash": "^3.0.0",
- "next": "12.3.0",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "ui": "*"
- },
- "devDependencies": {
- "@babel/core": "^7.0.0",
- "@types/node": "^17.0.12",
- "@types/react": "18.0.17",
- "eslint": "7.32.0",
- "eslint-config-custom": "*",
- "next-transpile-modules": "9.0.0",
- "tsconfig": "*",
- "typescript": "^4.5.3"
- }
- },
- "apps/web": {
- "version": "0.0.0",
- "dependencies": {
- "lodash": "^4.17.21",
- "next": "12.3.0",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "ui": "*"
- },
- "devDependencies": {
- "@babel/core": "^7.0.0",
- "@types/node": "^17.0.12",
- "@types/react": "18.0.17",
- "eslint": "7.32.0",
- "eslint-config-custom": "*",
- "next-transpile-modules": "9.0.0",
- "tsconfig": "*",
- "typescript": "^4.5.3"
- }
- },
- "apps/web/node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "engines": ["node >= 0.8.0"]
- },
- "node_modules/@ampproject/remapping": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
- "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.1.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
- "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz",
- "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz",
- "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==",
- "dev": true,
- "dependencies": {
- "@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.19.3",
- "@babel/helper-compilation-targets": "^7.19.3",
- "@babel/helper-module-transforms": "^7.19.0",
- "@babel/helpers": "^7.19.0",
- "@babel/parser": "^7.19.3",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.3",
- "@babel/types": "^7.19.3",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.1",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
- }
- },
- "node_modules/@babel/generator": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz",
- "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.19.3",
- "@jridgewell/gen-mapping": "^0.3.2",
- "jsesc": "^2.5.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz",
- "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.19.3",
- "@babel/helper-validator-option": "^7.18.6",
- "browserslist": "^4.21.3",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- }
- }
-}
diff --git a/cli/internal/lockfile/testdata/npm-lock.json b/cli/internal/lockfile/testdata/npm-lock.json
deleted file mode 100644
index c5607f1..0000000
--- a/cli/internal/lockfile/testdata/npm-lock.json
+++ /dev/null
@@ -1,6472 +0,0 @@
-{
- "name": "npm-prune",
- "version": "0.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "npm-prune",
- "version": "0.0.0",
- "workspaces": ["apps/*", "packages/*"],
- "devDependencies": {
- "eslint-config-custom": "*",
- "prettier": "latest",
- "turbo": "latest"
- },
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "apps/docs": {
- "version": "0.0.0",
- "dependencies": {
- "lodash": "^3.0.0",
- "next": "12.3.0",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "ui": "*"
- },
- "devDependencies": {
- "@babel/core": "^7.0.0",
- "@types/node": "^17.0.12",
- "@types/react": "18.0.17",
- "eslint": "7.32.0",
- "eslint-config-custom": "*",
- "next-transpile-modules": "9.0.0",
- "tsconfig": "*",
- "typescript": "^4.5.3"
- }
- },
- "apps/web": {
- "version": "0.0.0",
- "dependencies": {
- "lodash": "^4.17.21",
- "next": "12.3.0",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "ui": "*"
- },
- "devDependencies": {
- "@babel/core": "^7.0.0",
- "@types/node": "^17.0.12",
- "@types/react": "18.0.17",
- "eslint": "7.32.0",
- "eslint-config-custom": "*",
- "next-transpile-modules": "9.0.0",
- "tsconfig": "*",
- "typescript": "^4.5.3"
- }
- },
- "apps/web/node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "engines": ["node >= 0.8.0"]
- },
- "node_modules/@ampproject/remapping": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
- "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.1.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
- "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz",
- "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz",
- "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==",
- "dev": true,
- "dependencies": {
- "@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.19.3",
- "@babel/helper-compilation-targets": "^7.19.3",
- "@babel/helper-module-transforms": "^7.19.0",
- "@babel/helpers": "^7.19.0",
- "@babel/parser": "^7.19.3",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.3",
- "@babel/types": "^7.19.3",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.1",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
- }
- },
- "node_modules/@babel/generator": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz",
- "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.19.3",
- "@jridgewell/gen-mapping": "^0.3.2",
- "jsesc": "^2.5.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz",
- "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.19.3",
- "@babel/helper-validator-option": "^7.18.6",
- "browserslist": "^4.21.3",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-function-name": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
- "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.18.10",
- "@babel/types": "^7.19.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-hoist-variables": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
- "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
- "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz",
- "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-simple-access": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/helper-validator-identifier": "^7.18.6",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.0",
- "@babel/types": "^7.19.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-simple-access": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
- "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-split-export-declaration": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
- "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
- "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-option": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
- "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helpers": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz",
- "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.0",
- "@babel/types": "^7.19.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
- "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.18.6",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz",
- "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==",
- "dev": true,
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz",
- "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==",
- "dependencies": {
- "regenerator-runtime": "^0.13.4"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/runtime-corejs3": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz",
- "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==",
- "dependencies": {
- "core-js-pure": "^3.25.1",
- "regenerator-runtime": "^0.13.4"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/template": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
- "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.18.6",
- "@babel/parser": "^7.18.10",
- "@babel/types": "^7.18.10"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz",
- "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.19.3",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/parser": "^7.19.3",
- "@babel/types": "^7.19.3",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz",
- "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-string-parser": "^7.18.10",
- "@babel/helper-validator-identifier": "^7.19.1",
- "to-fast-properties": "^2.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
- "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^13.9.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "13.17.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
- "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
- "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
- "dependencies": {
- "@humanwhocodes/object-schema": "^1.2.0",
- "debug": "^4.1.1",
- "minimatch": "^3.0.4"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
- },
- "node_modules/@jridgewell/gen-mapping": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
- "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.0",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.14",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "dev": true
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
- "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
- "dev": true,
- "dependencies": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "node_modules/@next/env": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.0.tgz",
- "integrity": "sha512-PTJpjAFVbzBQ9xXpzMTroShvD5YDIIy46jQ7d4LrWpY+/5a8H90Tm8hE3Hvkc5RBRspVo7kvEOnqQms0A+2Q6w=="
- },
- "node_modules/@next/eslint-plugin-next": {
- "version": "12.3.1",
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-12.3.1.tgz",
- "integrity": "sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==",
- "dependencies": {
- "glob": "7.1.7"
- }
- },
- "node_modules/@next/swc-android-arm-eabi": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.0.tgz",
- "integrity": "sha512-/PuirPnAKsYBw93w/7Q9hqy+KGOU9mjYprZ/faxMUJh/dc6v3rYLxkZKNG9nFPIW4QKNTCnhP40xF9hLnxO+xg==",
- "cpu": ["arm"],
- "optional": true,
- "os": ["android"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-android-arm64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.0.tgz",
- "integrity": "sha512-OaI+FhAM6P9B6Ybwbn0Zl8YwWido0lLwhDBi9WiYCh4RQmIXAyVIoIJPHo4fP05+mXaJ/k1trvDvuURvHOq2qw==",
- "cpu": ["arm64"],
- "optional": true,
- "os": ["android"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-darwin-arm64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.0.tgz",
- "integrity": "sha512-9s4d3Mhii+WFce8o8Jok7WC3Bawkr9wEUU++SJRptjU1L5tsfYJMrSYCACHLhZujziNDLyExe4Hwwsccps1sfg==",
- "cpu": ["arm64"],
- "optional": true,
- "os": ["darwin"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-darwin-x64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.0.tgz",
- "integrity": "sha512-2scC4MqUTwGwok+wpVxP+zWp7WcCAVOtutki2E1n99rBOTnUOX6qXkgxSy083yBN6GqwuC/dzHeN7hIKjavfRA==",
- "cpu": ["x64"],
- "optional": true,
- "os": ["darwin"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-freebsd-x64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.0.tgz",
- "integrity": "sha512-xAlruUREij/bFa+qsE1tmsP28t7vz02N4ZDHt2lh3uJUniE0Ne9idyIDLc1Ed0IF2RjfgOp4ZVunuS3OM0sngw==",
- "cpu": ["x64"],
- "optional": true,
- "os": ["freebsd"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm-gnueabihf": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.0.tgz",
- "integrity": "sha512-jin2S4VT/cugc2dSZEUIabhYDJNgrUh7fufbdsaAezgcQzqfdfJqfxl4E9GuafzB4cbRPTaqA0V5uqbp0IyGkQ==",
- "cpu": ["arm"],
- "optional": true,
- "os": ["linux"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm64-gnu": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.0.tgz",
- "integrity": "sha512-RqJHDKe0WImeUrdR0kayTkRWgp4vD/MS7g0r6Xuf8+ellOFH7JAAJffDW3ayuVZeMYOa7RvgNFcOoWnrTUl9Nw==",
- "cpu": ["arm64"],
- "optional": true,
- "os": ["linux"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm64-musl": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.0.tgz",
- "integrity": "sha512-nvNWoUieMjvDjpYJ/4SQe9lQs2xMj6ZRs8N+bmTrVu9leY2Fg3WD6W9p/1uU9hGO8u+OdF13wc4iRShu/WYIHg==",
- "cpu": ["arm64"],
- "optional": true,
- "os": ["linux"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-x64-gnu": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.0.tgz",
- "integrity": "sha512-4ajhIuVU9PeQCMMhdDgZTLrHmjbOUFuIyg6J19hZqwEwDTSqQyrSLkbJs2Nd7IRiM6Ul/XyrtEFCpk4k+xD2+w==",
- "cpu": ["x64"],
- "optional": true,
- "os": ["linux"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-x64-musl": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.0.tgz",
- "integrity": "sha512-U092RBYbaGxoMAwpauePJEu2PuZSEoUCGJBvsptQr2/2XIMwAJDYM4c/M5NfYEsBr+yjvsYNsOpYfeQ88D82Yg==",
- "cpu": ["x64"],
- "optional": true,
- "os": ["linux"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-arm64-msvc": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.0.tgz",
- "integrity": "sha512-pzSzaxjDEJe67bUok9Nxf9rykbJfHXW0owICFsPBsqHyc+cr8vpF7g9e2APTCddtVhvjkga9ILoZJ9NxWS7Yiw==",
- "cpu": ["arm64"],
- "optional": true,
- "os": ["win32"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-ia32-msvc": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.0.tgz",
- "integrity": "sha512-MQGUpMbYhQmTZ06a9e0hPQJnxFMwETo2WtyAotY3GEzbNCQVbCGhsvqEKcl+ZEHgShlHXUWvSffq1ZscY6gK7A==",
- "cpu": ["ia32"],
- "optional": true,
- "os": ["win32"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-x64-msvc": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.0.tgz",
- "integrity": "sha512-C/nw6OgQpEULWqs+wgMHXGvlJLguPRFFGqR2TAqWBerQ8J+Sg3z1ZTqwelkSi4FoqStGuZ2UdFHIDN1ySmR1xA==",
- "cpu": ["x64"],
- "optional": true,
- "os": ["win32"],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@rushstack/eslint-patch": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
- "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg=="
- },
- "node_modules/@swc/helpers": {
- "version": "0.4.11",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
- "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==",
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
- },
- "node_modules/@types/node": {
- "version": "17.0.45",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
- "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
- "dev": true
- },
- "node_modules/@types/prop-types": {
- "version": "15.7.5",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
- "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
- "dev": true
- },
- "node_modules/@types/react": {
- "version": "18.0.17",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz",
- "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==",
- "dev": true,
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/@types/react-dom": {
- "version": "17.0.17",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz",
- "integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==",
- "dev": true,
- "dependencies": {
- "@types/react": "^17"
- }
- },
- "node_modules/@types/react-dom/node_modules/@types/react": {
- "version": "17.0.50",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz",
- "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==",
- "dev": true,
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/@types/scheduler": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
- "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
- "dev": true
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz",
- "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==",
- "dependencies": {
- "@typescript-eslint/scope-manager": "5.39.0",
- "@typescript-eslint/types": "5.39.0",
- "@typescript-eslint/typescript-estree": "5.39.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz",
- "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==",
- "dependencies": {
- "@typescript-eslint/types": "5.39.0",
- "@typescript-eslint/visitor-keys": "5.39.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz",
- "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz",
- "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==",
- "dependencies": {
- "@typescript-eslint/types": "5.39.0",
- "@typescript-eslint/visitor-keys": "5.39.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
- "version": "7.3.7",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
- "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz",
- "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==",
- "dependencies": {
- "@typescript-eslint/types": "5.39.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "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/ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/aria-query": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
- "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
- "dependencies": {
- "@babel/runtime": "^7.10.2",
- "@babel/runtime-corejs3": "^7.10.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/array-includes": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
- "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5",
- "get-intrinsic": "^1.1.1",
- "is-string": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/array.prototype.flat": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz",
- "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.2",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flatmap": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz",
- "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.2",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/ast-types-flow": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
- "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag=="
- },
- "node_modules/astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/axe-core": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
- "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/axobject-query": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
- "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/browserslist": {
- "version": "4.21.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
- "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- }
- ],
- "dependencies": {
- "caniuse-lite": "^1.0.30001400",
- "electron-to-chromium": "^1.4.251",
- "node-releases": "^2.0.6",
- "update-browserslist-db": "^1.0.9"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001414",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
- "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- }
- ]
- },
- "node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
- },
- "node_modules/convert-source-map": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
- "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.1.1"
- }
- },
- "node_modules/core-js-pure": {
- "version": "3.25.5",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz",
- "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==",
- "hasInstallScript": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "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==",
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/csstype": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
- "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
- "dev": true
- },
- "node_modules/damerau-levenshtein": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
- "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="
- },
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
- },
- "node_modules/define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dependencies": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/docs": {
- "resolved": "apps/docs",
- "link": true
- },
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/electron-to-chromium": {
- "version": "1.4.270",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz",
- "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==",
- "dev": true
- },
- "node_modules/emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
- },
- "node_modules/enhanced-resolve": {
- "version": "5.10.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
- "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/enquirer": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
- "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
- "dependencies": {
- "ansi-colors": "^4.1.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/es-abstract": {
- "version": "1.20.3",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz",
- "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.6",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "dependencies": {
- "has": "^1.0.3"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dependencies": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/eslint": {
- "version": "7.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
- "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
- "dependencies": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.3",
- "@humanwhocodes/config-array": "^0.5.0",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.1.2",
- "globals": "^13.6.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.0.4",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.9",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-config-custom": {
- "resolved": "packages/eslint-config-custom",
- "link": true
- },
- "node_modules/eslint-config-next": {
- "version": "12.3.1",
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-12.3.1.tgz",
- "integrity": "sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==",
- "dependencies": {
- "@next/eslint-plugin-next": "12.3.1",
- "@rushstack/eslint-patch": "^1.1.3",
- "@typescript-eslint/parser": "^5.21.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-import-resolver-typescript": "^2.7.1",
- "eslint-plugin-import": "^2.26.0",
- "eslint-plugin-jsx-a11y": "^6.5.1",
- "eslint-plugin-react": "^7.31.7",
- "eslint-plugin-react-hooks": "^4.5.0"
- },
- "peerDependencies": {
- "eslint": "^7.23.0 || ^8.0.0",
- "typescript": ">=3.3.1"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-config-prettier": {
- "version": "8.5.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
- "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
- "bin": {
- "eslint-config-prettier": "bin/cli.js"
- },
- "peerDependencies": {
- "eslint": ">=7.0.0"
- }
- },
- "node_modules/eslint-config-turbo": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/eslint-config-turbo/-/eslint-config-turbo-0.0.4.tgz",
- "integrity": "sha512-HErPS/wfWkSdV9Yd2dDkhZt3W2B78Ih/aWPFfaHmCMjzPalh+5KxRRGTf8MOBQLCebcWJX0lP1Zvc1rZIHlXGg==",
- "dependencies": {
- "eslint-plugin-turbo": "0.0.4"
- },
- "peerDependencies": {
- "eslint": "^7.23.0 || ^8.0.0"
- }
- },
- "node_modules/eslint-import-resolver-node": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
- "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
- "dependencies": {
- "debug": "^3.2.7",
- "resolve": "^1.20.0"
- }
- },
- "node_modules/eslint-import-resolver-node/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-import-resolver-typescript": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz",
- "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==",
- "dependencies": {
- "debug": "^4.3.4",
- "glob": "^7.2.0",
- "is-glob": "^4.0.3",
- "resolve": "^1.22.0",
- "tsconfig-paths": "^3.14.1"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "*",
- "eslint-plugin-import": "*"
- }
- },
- "node_modules/eslint-import-resolver-typescript/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/eslint-module-utils": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
- "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
- "dependencies": {
- "debug": "^3.2.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependenciesMeta": {
- "eslint": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-module-utils/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-import": {
- "version": "2.26.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
- "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
- "dependencies": {
- "array-includes": "^3.1.4",
- "array.prototype.flat": "^1.2.5",
- "debug": "^2.6.9",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-module-utils": "^2.7.3",
- "has": "^1.0.3",
- "is-core-module": "^2.8.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.values": "^1.1.5",
- "resolve": "^1.22.0",
- "tsconfig-paths": "^3.14.1"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/eslint-plugin-jsx-a11y": {
- "version": "6.6.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz",
- "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==",
- "dependencies": {
- "@babel/runtime": "^7.18.9",
- "aria-query": "^4.2.2",
- "array-includes": "^3.1.5",
- "ast-types-flow": "^0.0.7",
- "axe-core": "^4.4.3",
- "axobject-query": "^2.2.0",
- "damerau-levenshtein": "^1.0.8",
- "emoji-regex": "^9.2.2",
- "has": "^1.0.3",
- "jsx-ast-utils": "^3.3.2",
- "language-tags": "^1.0.5",
- "minimatch": "^3.1.2",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=4.0"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
- }
- },
- "node_modules/eslint-plugin-react": {
- "version": "7.31.8",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz",
- "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==",
- "dependencies": {
- "array-includes": "^3.1.5",
- "array.prototype.flatmap": "^1.3.0",
- "doctrine": "^2.1.0",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.5",
- "object.fromentries": "^2.0.5",
- "object.hasown": "^1.1.1",
- "object.values": "^1.1.5",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.3",
- "semver": "^6.3.0",
- "string.prototype.matchall": "^4.0.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
- }
- },
- "node_modules/eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/resolve": {
- "version": "2.0.0-next.4",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
- "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/eslint-plugin-turbo": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-0.0.4.tgz",
- "integrity": "sha512-dfmYE/iPvoJInQq+5E/0mj140y/rYwKtzZkn3uVK8+nvwC5zmWKQ6ehMWrL4bYBkGzSgpOndZM+jOXhPQ2m8Cg==",
- "peerDependencies": {
- "eslint": "^7.23.0 || ^8.0.0"
- }
- },
- "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==",
- "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==",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "dependencies": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint/node_modules/@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "dependencies": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "node_modules/eslint/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "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/eslint/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/eslint/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "node_modules/eslint/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/globals": {
- "version": "13.17.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
- "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/semver": {
- "version": "7.3.7",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
- "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
- "dependencies": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "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==",
- "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",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "engines": {
- "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=="
- },
- "node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "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",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
- },
- "node_modules/fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "node_modules/function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/glob": {
- "version": "7.1.7",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
- "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globby/node_modules/ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dependencies": {
- "get-intrinsic": "^1.1.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "dependencies": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "dependencies": {
- "has-bigints": "^1.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
- "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true,
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "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=="
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
- },
- "node_modules/json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
- "dev": true,
- "bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/jsx-ast-utils": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
- "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
- "dependencies": {
- "array-includes": "^3.1.5",
- "object.assign": "^4.1.3"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/language-subtag-registry": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
- "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w=="
- },
- "node_modules/language-tags": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
- "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
- "dependencies": {
- "language-subtag-registry": "~0.3.2"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/lodash": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
- "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ=="
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
- },
- "node_modules/lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dependencies": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "node_modules/nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
- },
- "node_modules/next": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/next/-/next-12.3.0.tgz",
- "integrity": "sha512-GpzI6me9V1+XYtfK0Ae9WD0mKqHyzQlGq1xH1rzNIYMASo4Tkl4rTe9jSqtBpXFhOS33KohXs9ZY38Akkhdciw==",
- "dependencies": {
- "@next/env": "12.3.0",
- "@swc/helpers": "0.4.11",
- "caniuse-lite": "^1.0.30001332",
- "postcss": "8.4.14",
- "styled-jsx": "5.0.6",
- "use-sync-external-store": "1.2.0"
- },
- "bin": {
- "next": "dist/bin/next"
- },
- "engines": {
- "node": ">=12.22.0"
- },
- "optionalDependencies": {
- "@next/swc-android-arm-eabi": "12.3.0",
- "@next/swc-android-arm64": "12.3.0",
- "@next/swc-darwin-arm64": "12.3.0",
- "@next/swc-darwin-x64": "12.3.0",
- "@next/swc-freebsd-x64": "12.3.0",
- "@next/swc-linux-arm-gnueabihf": "12.3.0",
- "@next/swc-linux-arm64-gnu": "12.3.0",
- "@next/swc-linux-arm64-musl": "12.3.0",
- "@next/swc-linux-x64-gnu": "12.3.0",
- "@next/swc-linux-x64-musl": "12.3.0",
- "@next/swc-win32-arm64-msvc": "12.3.0",
- "@next/swc-win32-ia32-msvc": "12.3.0",
- "@next/swc-win32-x64-msvc": "12.3.0"
- },
- "peerDependencies": {
- "fibers": ">= 3.1.0",
- "node-sass": "^6.0.0 || ^7.0.0",
- "react": "^17.0.2 || ^18.0.0-0",
- "react-dom": "^17.0.2 || ^18.0.0-0",
- "sass": "^1.3.0"
- },
- "peerDependenciesMeta": {
- "fibers": {
- "optional": true
- },
- "node-sass": {
- "optional": true
- },
- "sass": {
- "optional": true
- }
- }
- },
- "node_modules/next-transpile-modules": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz",
- "integrity": "sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ==",
- "dev": true,
- "dependencies": {
- "enhanced-resolve": "^5.7.0",
- "escalade": "^3.1.1"
- }
- },
- "node_modules/node-releases": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
- "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
- "dev": true
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.assign": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.entries": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
- "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.fromentries": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz",
- "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.hasown": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz",
- "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==",
- "dependencies": {
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.values": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
- "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "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==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
- },
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/postcss": {
- "version": "8.4.14",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
- "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.4",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prettier": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
- "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
- "dev": true,
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "node_modules/punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- },
- "peerDependencies": {
- "react": "^18.2.0"
- }
- },
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "node_modules/safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
- },
- "node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "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==",
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "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==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dependencies": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
- }
- },
- "node_modules/slice-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/slice-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/slice-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
- },
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- },
- "node_modules/string.prototype.matchall": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz",
- "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "regexp.prototype.flags": "^1.4.1",
- "side-channel": "^1.0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
- "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
- "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/styled-jsx": {
- "version": "5.0.6",
- "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.6.tgz",
- "integrity": "sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==",
- "engines": {
- "node": ">= 12.0.0"
- },
- "peerDependencies": {
- "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
- },
- "peerDependenciesMeta": {
- "@babel/core": {
- "optional": true
- },
- "babel-plugin-macros": {
- "optional": true
- }
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/table": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
- "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
- "dependencies": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/table/node_modules/ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/table/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
- },
- "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/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/tsconfig": {
- "resolved": "packages/tsconfig",
- "link": true
- },
- "node_modules/tsconfig-paths": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
- "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
- "dependencies": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.1",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- }
- },
- "node_modules/tsconfig-paths/node_modules/json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "dependencies": {
- "minimist": "^1.2.0"
- },
- "bin": {
- "json5": "lib/cli.js"
- }
- },
- "node_modules/tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
- },
- "node_modules/tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "engines": {
- "node": ">= 6"
- },
- "peerDependencies": {
- "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- }
- },
- "node_modules/tsutils/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/turbo": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.5.5.tgz",
- "integrity": "sha512-PVQSDl0STC9WXIyHcYUWs9gXsf8JjQig/FuHfuB8N6+XlgCGB3mPbfMEE6zrChGz2hufH4/guKRX1XJuNL6XTA==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "turbo": "bin/turbo"
- },
- "optionalDependencies": {
- "turbo-darwin-64": "1.5.5",
- "turbo-darwin-arm64": "1.5.5",
- "turbo-linux-64": "1.5.5",
- "turbo-linux-arm64": "1.5.5",
- "turbo-windows-64": "1.5.5",
- "turbo-windows-arm64": "1.5.5"
- }
- },
- "node_modules/turbo-darwin-64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.5.5.tgz",
- "integrity": "sha512-HvEn6P2B+NXDekq9LRpRgUjcT9/oygLTcK47U0qsAJZXRBSq/2hvD7lx4nAwgY/4W3rhYJeWtHTzbhoN6BXqGQ==",
- "cpu": ["x64"],
- "dev": true,
- "optional": true,
- "os": ["darwin"]
- },
- "node_modules/turbo-darwin-arm64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.5.5.tgz",
- "integrity": "sha512-Dmxr09IUy6M0nc7/xWod9galIO2DD500B75sJSkHeT+CCdJOWnlinux0ZPF8CSygNqymwYO8AO2l15/6yxcycg==",
- "cpu": ["arm64"],
- "dev": true,
- "optional": true,
- "os": ["darwin"]
- },
- "node_modules/turbo-linux-64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.5.5.tgz",
- "integrity": "sha512-wd07TZ4zXXWjzZE00FcFMLmkybQQK/NV9ff66vvAV0vdiuacSMBCNLrD6Mm4ncfrUPW/rwFW5kU/7hyuEqqtDw==",
- "cpu": ["x64"],
- "dev": true,
- "optional": true,
- "os": ["linux"]
- },
- "node_modules/turbo-linux-arm64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.5.5.tgz",
- "integrity": "sha512-q3q33tuo74R7gicnfvFbnZZvqmlq7Vakcvx0eshifnJw4PR+oMnTCb4w8ElVFx070zsb8DVTibq99y8NJH8T1Q==",
- "cpu": ["arm64"],
- "dev": true,
- "optional": true,
- "os": ["linux"]
- },
- "node_modules/turbo-windows-64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.5.5.tgz",
- "integrity": "sha512-lPp9kHonNFfqgovbaW+UAPO5cLmoAN+m3G3FzqcrRPnlzt97vXYsDhDd/4Zy3oAKoAcprtP4CGy0ddisqsKTVw==",
- "cpu": ["x64"],
- "dev": true,
- "optional": true,
- "os": ["win32"]
- },
- "node_modules/turbo-windows-arm64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.5.5.tgz",
- "integrity": "sha512-3AfGULKNZiZVrEzsIE+W79ZRW1+f5r4nM4wLlJ1PTBHyRxBZdD6KTH1tijGfy/uTlcV5acYnKHEkDc6Q9PAXGQ==",
- "cpu": ["arm64"],
- "dev": true,
- "optional": true,
- "os": ["win32"]
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typescript": {
- "version": "4.8.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
- "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=4.2.0"
- }
- },
- "node_modules/ui": {
- "resolved": "packages/ui",
- "link": true
- },
- "node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/update-browserslist-db": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz",
- "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- }
- ],
- "dependencies": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- },
- "bin": {
- "browserslist-lint": "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==",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/v8-compile-cache": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
- "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
- },
- "node_modules/web": {
- "resolved": "apps/web",
- "link": true
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "dependencies": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "packages/eslint-config-custom": {
- "version": "0.0.0",
- "license": "MIT",
- "dependencies": {
- "eslint": "^7.23.0",
- "eslint-config-next": "^12.0.8",
- "eslint-config-prettier": "^8.3.0",
- "eslint-config-turbo": "latest",
- "eslint-plugin-react": "7.31.8"
- },
- "devDependencies": {
- "typescript": "^4.7.4"
- }
- },
- "packages/tsconfig": {
- "version": "0.0.0"
- },
- "packages/ui": {
- "version": "0.0.0",
- "license": "MIT",
- "devDependencies": {
- "@types/react": "^17.0.37",
- "@types/react-dom": "^17.0.11",
- "eslint": "^7.32.0",
- "eslint-config-custom": "*",
- "react": "^18.2.0",
- "tsconfig": "*",
- "typescript": "^4.5.2"
- }
- },
- "packages/ui/node_modules/@types/react": {
- "version": "17.0.50",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz",
- "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==",
- "dev": true,
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- }
- },
- "dependencies": {
- "@ampproject/remapping": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
- "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
- "dev": true,
- "requires": {
- "@jridgewell/gen-mapping": "^0.1.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "@babel/code-frame": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
- "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.18.6"
- }
- },
- "@babel/compat-data": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz",
- "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz",
- "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==",
- "dev": true,
- "requires": {
- "@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.19.3",
- "@babel/helper-compilation-targets": "^7.19.3",
- "@babel/helper-module-transforms": "^7.19.0",
- "@babel/helpers": "^7.19.0",
- "@babel/parser": "^7.19.3",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.3",
- "@babel/types": "^7.19.3",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.1",
- "semver": "^6.3.0"
- }
- },
- "@babel/generator": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz",
- "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.19.3",
- "@jridgewell/gen-mapping": "^0.3.2",
- "jsesc": "^2.5.1"
- },
- "dependencies": {
- "@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "requires": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- }
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz",
- "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.19.3",
- "@babel/helper-validator-option": "^7.18.6",
- "browserslist": "^4.21.3",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
- "dev": true
- },
- "@babel/helper-function-name": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
- "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.18.10",
- "@babel/types": "^7.19.0"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
- "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
- "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz",
- "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-simple-access": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/helper-validator-identifier": "^7.18.6",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.0",
- "@babel/types": "^7.19.0"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
- "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
- "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-string-parser": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
- "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
- "dev": true
- },
- "@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
- },
- "@babel/helper-validator-option": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
- "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz",
- "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.19.0",
- "@babel/types": "^7.19.0"
- }
- },
- "@babel/highlight": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
- "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.18.6",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz",
- "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==",
- "dev": true
- },
- "@babel/runtime": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz",
- "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==",
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@babel/runtime-corejs3": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz",
- "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==",
- "requires": {
- "core-js-pure": "^3.25.1",
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@babel/template": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
- "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.18.6",
- "@babel/parser": "^7.18.10",
- "@babel/types": "^7.18.10"
- }
- },
- "@babel/traverse": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz",
- "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.19.3",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/parser": "^7.19.3",
- "@babel/types": "^7.19.3",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.19.3",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz",
- "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==",
- "dev": true,
- "requires": {
- "@babel/helper-string-parser": "^7.18.10",
- "@babel/helper-validator-identifier": "^7.19.1",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@eslint/eslintrc": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
- "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^13.9.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "globals": {
- "version": "13.17.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
- "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
- "requires": {
- "type-fest": "^0.20.2"
- }
- }
- }
- },
- "@humanwhocodes/config-array": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
- "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
- "requires": {
- "@humanwhocodes/object-schema": "^1.2.0",
- "debug": "^4.1.1",
- "minimatch": "^3.0.4"
- }
- },
- "@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
- },
- "@jridgewell/gen-mapping": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
- "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
- "dev": true,
- "requires": {
- "@jridgewell/set-array": "^1.0.0",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "@jridgewell/resolve-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true
- },
- "@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true
- },
- "@jridgewell/sourcemap-codec": {
- "version": "1.4.14",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "dev": true
- },
- "@jridgewell/trace-mapping": {
- "version": "0.3.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
- "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
- "dev": true,
- "requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "@next/env": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.0.tgz",
- "integrity": "sha512-PTJpjAFVbzBQ9xXpzMTroShvD5YDIIy46jQ7d4LrWpY+/5a8H90Tm8hE3Hvkc5RBRspVo7kvEOnqQms0A+2Q6w=="
- },
- "@next/eslint-plugin-next": {
- "version": "12.3.1",
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-12.3.1.tgz",
- "integrity": "sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==",
- "requires": {
- "glob": "7.1.7"
- }
- },
- "@next/swc-android-arm-eabi": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.0.tgz",
- "integrity": "sha512-/PuirPnAKsYBw93w/7Q9hqy+KGOU9mjYprZ/faxMUJh/dc6v3rYLxkZKNG9nFPIW4QKNTCnhP40xF9hLnxO+xg==",
- "optional": true
- },
- "@next/swc-android-arm64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.0.tgz",
- "integrity": "sha512-OaI+FhAM6P9B6Ybwbn0Zl8YwWido0lLwhDBi9WiYCh4RQmIXAyVIoIJPHo4fP05+mXaJ/k1trvDvuURvHOq2qw==",
- "optional": true
- },
- "@next/swc-darwin-arm64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.0.tgz",
- "integrity": "sha512-9s4d3Mhii+WFce8o8Jok7WC3Bawkr9wEUU++SJRptjU1L5tsfYJMrSYCACHLhZujziNDLyExe4Hwwsccps1sfg==",
- "optional": true
- },
- "@next/swc-darwin-x64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.0.tgz",
- "integrity": "sha512-2scC4MqUTwGwok+wpVxP+zWp7WcCAVOtutki2E1n99rBOTnUOX6qXkgxSy083yBN6GqwuC/dzHeN7hIKjavfRA==",
- "optional": true
- },
- "@next/swc-freebsd-x64": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.0.tgz",
- "integrity": "sha512-xAlruUREij/bFa+qsE1tmsP28t7vz02N4ZDHt2lh3uJUniE0Ne9idyIDLc1Ed0IF2RjfgOp4ZVunuS3OM0sngw==",
- "optional": true
- },
- "@next/swc-linux-arm-gnueabihf": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.0.tgz",
- "integrity": "sha512-jin2S4VT/cugc2dSZEUIabhYDJNgrUh7fufbdsaAezgcQzqfdfJqfxl4E9GuafzB4cbRPTaqA0V5uqbp0IyGkQ==",
- "optional": true
- },
- "@next/swc-linux-arm64-gnu": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.0.tgz",
- "integrity": "sha512-RqJHDKe0WImeUrdR0kayTkRWgp4vD/MS7g0r6Xuf8+ellOFH7JAAJffDW3ayuVZeMYOa7RvgNFcOoWnrTUl9Nw==",
- "optional": true
- },
- "@next/swc-linux-arm64-musl": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.0.tgz",
- "integrity": "sha512-nvNWoUieMjvDjpYJ/4SQe9lQs2xMj6ZRs8N+bmTrVu9leY2Fg3WD6W9p/1uU9hGO8u+OdF13wc4iRShu/WYIHg==",
- "optional": true
- },
- "@next/swc-linux-x64-gnu": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.0.tgz",
- "integrity": "sha512-4ajhIuVU9PeQCMMhdDgZTLrHmjbOUFuIyg6J19hZqwEwDTSqQyrSLkbJs2Nd7IRiM6Ul/XyrtEFCpk4k+xD2+w==",
- "optional": true
- },
- "@next/swc-linux-x64-musl": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.0.tgz",
- "integrity": "sha512-U092RBYbaGxoMAwpauePJEu2PuZSEoUCGJBvsptQr2/2XIMwAJDYM4c/M5NfYEsBr+yjvsYNsOpYfeQ88D82Yg==",
- "optional": true
- },
- "@next/swc-win32-arm64-msvc": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.0.tgz",
- "integrity": "sha512-pzSzaxjDEJe67bUok9Nxf9rykbJfHXW0owICFsPBsqHyc+cr8vpF7g9e2APTCddtVhvjkga9ILoZJ9NxWS7Yiw==",
- "optional": true
- },
- "@next/swc-win32-ia32-msvc": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.0.tgz",
- "integrity": "sha512-MQGUpMbYhQmTZ06a9e0hPQJnxFMwETo2WtyAotY3GEzbNCQVbCGhsvqEKcl+ZEHgShlHXUWvSffq1ZscY6gK7A==",
- "optional": true
- },
- "@next/swc-win32-x64-msvc": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.0.tgz",
- "integrity": "sha512-C/nw6OgQpEULWqs+wgMHXGvlJLguPRFFGqR2TAqWBerQ8J+Sg3z1ZTqwelkSi4FoqStGuZ2UdFHIDN1ySmR1xA==",
- "optional": true
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "requires": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="
- },
- "@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "requires": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- }
- },
- "@rushstack/eslint-patch": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
- "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg=="
- },
- "@swc/helpers": {
- "version": "0.4.11",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
- "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==",
- "requires": {
- "tslib": "^2.4.0"
- }
- },
- "@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
- },
- "@types/node": {
- "version": "17.0.45",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
- "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
- "dev": true
- },
- "@types/prop-types": {
- "version": "15.7.5",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
- "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
- "dev": true
- },
- "@types/react": {
- "version": "18.0.17",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz",
- "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "@types/react-dom": {
- "version": "17.0.17",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz",
- "integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==",
- "dev": true,
- "requires": {
- "@types/react": "^17"
- },
- "dependencies": {
- "@types/react": {
- "version": "17.0.50",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz",
- "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- }
- }
- },
- "@types/scheduler": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
- "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
- "dev": true
- },
- "@typescript-eslint/parser": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz",
- "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==",
- "requires": {
- "@typescript-eslint/scope-manager": "5.39.0",
- "@typescript-eslint/types": "5.39.0",
- "@typescript-eslint/typescript-estree": "5.39.0",
- "debug": "^4.3.4"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz",
- "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==",
- "requires": {
- "@typescript-eslint/types": "5.39.0",
- "@typescript-eslint/visitor-keys": "5.39.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz",
- "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw=="
- },
- "@typescript-eslint/typescript-estree": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz",
- "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==",
- "requires": {
- "@typescript-eslint/types": "5.39.0",
- "@typescript-eslint/visitor-keys": "5.39.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.7",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
- "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "5.39.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz",
- "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==",
- "requires": {
- "@typescript-eslint/types": "5.39.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA=="
- }
- }
- },
- "acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
- },
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "requires": {}
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="
- },
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "aria-query": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
- "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
- "requires": {
- "@babel/runtime": "^7.10.2",
- "@babel/runtime-corejs3": "^7.10.2"
- }
- },
- "array-includes": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
- "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5",
- "get-intrinsic": "^1.1.1",
- "is-string": "^1.0.7"
- }
- },
- "array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
- },
- "array.prototype.flat": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz",
- "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.2",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "array.prototype.flatmap": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz",
- "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.2",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "ast-types-flow": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
- "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag=="
- },
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
- },
- "axe-core": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
- "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w=="
- },
- "axobject-query": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
- "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "browserslist": {
- "version": "4.21.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
- "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001400",
- "electron-to-chromium": "^1.4.251",
- "node-releases": "^2.0.6",
- "update-browserslist-db": "^1.0.9"
- }
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
- },
- "caniuse-lite": {
- "version": "1.0.30001414",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
- "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg=="
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
- },
- "convert-source-map": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
- "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.1"
- }
- },
- "core-js-pure": {
- "version": "3.25.5",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz",
- "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg=="
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "csstype": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
- "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
- "dev": true
- },
- "damerau-levenshtein": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
- "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
- },
- "define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "requires": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- }
- },
- "dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "requires": {
- "path-type": "^4.0.0"
- }
- },
- "docs": {
- "version": "file:apps/docs",
- "requires": {
- "@babel/core": "^7.0.0",
- "@types/node": "^17.0.12",
- "@types/react": "18.0.17",
- "eslint": "7.32.0",
- "eslint-config-custom": "*",
- "lodash": "^3.0.0",
- "next": "12.3.0",
- "next-transpile-modules": "9.0.0",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "tsconfig": "*",
- "typescript": "^4.5.3",
- "ui": "*"
- }
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "electron-to-chromium": {
- "version": "1.4.270",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz",
- "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==",
- "dev": true
- },
- "emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
- },
- "enhanced-resolve": {
- "version": "5.10.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
- "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- }
- },
- "enquirer": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
- "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
- "requires": {
- "ansi-colors": "^4.1.1"
- }
- },
- "es-abstract": {
- "version": "1.20.3",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz",
- "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==",
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.6",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
- }
- },
- "es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- }
- },
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- },
- "eslint": {
- "version": "7.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
- "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
- "requires": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.3",
- "@humanwhocodes/config-array": "^0.5.0",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.1.2",
- "globals": "^13.6.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.0.4",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.9",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "requires": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
- },
- "globals": {
- "version": "13.17.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
- "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "semver": {
- "version": "7.3.7",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
- "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "eslint-config-custom": {
- "version": "file:packages/eslint-config-custom",
- "requires": {
- "eslint": "^7.23.0",
- "eslint-config-next": "^12.0.8",
- "eslint-config-prettier": "^8.3.0",
- "eslint-config-turbo": "latest",
- "eslint-plugin-react": "7.31.8",
- "typescript": "^4.7.4"
- }
- },
- "eslint-config-next": {
- "version": "12.3.1",
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-12.3.1.tgz",
- "integrity": "sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==",
- "requires": {
- "@next/eslint-plugin-next": "12.3.1",
- "@rushstack/eslint-patch": "^1.1.3",
- "@typescript-eslint/parser": "^5.21.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-import-resolver-typescript": "^2.7.1",
- "eslint-plugin-import": "^2.26.0",
- "eslint-plugin-jsx-a11y": "^6.5.1",
- "eslint-plugin-react": "^7.31.7",
- "eslint-plugin-react-hooks": "^4.5.0"
- }
- },
- "eslint-config-prettier": {
- "version": "8.5.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
- "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
- "requires": {}
- },
- "eslint-config-turbo": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/eslint-config-turbo/-/eslint-config-turbo-0.0.4.tgz",
- "integrity": "sha512-HErPS/wfWkSdV9Yd2dDkhZt3W2B78Ih/aWPFfaHmCMjzPalh+5KxRRGTf8MOBQLCebcWJX0lP1Zvc1rZIHlXGg==",
- "requires": {
- "eslint-plugin-turbo": "0.0.4"
- }
- },
- "eslint-import-resolver-node": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
- "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
- "requires": {
- "debug": "^3.2.7",
- "resolve": "^1.20.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "eslint-import-resolver-typescript": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz",
- "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==",
- "requires": {
- "debug": "^4.3.4",
- "glob": "^7.2.0",
- "is-glob": "^4.0.3",
- "resolve": "^1.22.0",
- "tsconfig-paths": "^3.14.1"
- },
- "dependencies": {
- "glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- }
- }
- },
- "eslint-module-utils": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
- "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
- "requires": {
- "debug": "^3.2.7"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "eslint-plugin-import": {
- "version": "2.26.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
- "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
- "requires": {
- "array-includes": "^3.1.4",
- "array.prototype.flat": "^1.2.5",
- "debug": "^2.6.9",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-module-utils": "^2.7.3",
- "has": "^1.0.3",
- "is-core-module": "^2.8.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.values": "^1.1.5",
- "resolve": "^1.22.0",
- "tsconfig-paths": "^3.14.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- }
- }
- },
- "eslint-plugin-jsx-a11y": {
- "version": "6.6.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz",
- "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==",
- "requires": {
- "@babel/runtime": "^7.18.9",
- "aria-query": "^4.2.2",
- "array-includes": "^3.1.5",
- "ast-types-flow": "^0.0.7",
- "axe-core": "^4.4.3",
- "axobject-query": "^2.2.0",
- "damerau-levenshtein": "^1.0.8",
- "emoji-regex": "^9.2.2",
- "has": "^1.0.3",
- "jsx-ast-utils": "^3.3.2",
- "language-tags": "^1.0.5",
- "minimatch": "^3.1.2",
- "semver": "^6.3.0"
- }
- },
- "eslint-plugin-react": {
- "version": "7.31.8",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz",
- "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==",
- "requires": {
- "array-includes": "^3.1.5",
- "array.prototype.flatmap": "^1.3.0",
- "doctrine": "^2.1.0",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.5",
- "object.fromentries": "^2.0.5",
- "object.hasown": "^1.1.1",
- "object.values": "^1.1.5",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.3",
- "semver": "^6.3.0",
- "string.prototype.matchall": "^4.0.7"
- },
- "dependencies": {
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "resolve": {
- "version": "2.0.0-next.4",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
- "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
- "requires": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- }
- }
- },
- "eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "requires": {}
- },
- "eslint-plugin-turbo": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-0.0.4.tgz",
- "integrity": "sha512-dfmYE/iPvoJInQq+5E/0mj140y/rYwKtzZkn3uVK8+nvwC5zmWKQ6ehMWrL4bYBkGzSgpOndZM+jOXhPQ2m8Cg==",
- "requires": {}
- },
- "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==",
- "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=="
- }
- }
- },
- "eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "requires": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
- },
- "espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
- "requires": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
- },
- "esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "requires": {
- "estraverse": "^5.1.0"
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "requires": {
- "estraverse": "^5.2.0"
- }
- },
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
- },
- "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=="
- },
- "fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
- "requires": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- }
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
- },
- "fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- }
- },
- "functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="
- },
- "functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
- },
- "gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true
- },
- "get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- }
- },
- "get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- }
- },
- "glob": {
- "version": "7.1.7",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
- "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "requires": {
- "is-glob": "^4.0.1"
- }
- },
- "globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true
- },
- "globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
- }
- }
- },
- "graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ=="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
- },
- "has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "requires": {
- "get-intrinsic": "^1.1.1"
- }
- },
- "has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
- },
- "has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "requires": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- }
- },
- "is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "requires": {
- "has-bigints": "^1.0.1"
- }
- },
- "is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="
- },
- "is-core-module": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
- "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
- },
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
- },
- "is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true
- },
- "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=="
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
- },
- "json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
- "dev": true
- },
- "jsx-ast-utils": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
- "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
- "requires": {
- "array-includes": "^3.1.5",
- "object.assign": "^4.1.3"
- }
- },
- "language-subtag-registry": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
- "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w=="
- },
- "language-tags": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
- "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
- "requires": {
- "language-subtag-registry": "~0.3.2"
- }
- },
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
- "lodash": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
- "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ=="
- },
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
- },
- "lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
- },
- "micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "requires": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- }
- },
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
- },
- "next": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/next/-/next-12.3.0.tgz",
- "integrity": "sha512-GpzI6me9V1+XYtfK0Ae9WD0mKqHyzQlGq1xH1rzNIYMASo4Tkl4rTe9jSqtBpXFhOS33KohXs9ZY38Akkhdciw==",
- "requires": {
- "@next/env": "12.3.0",
- "@next/swc-android-arm-eabi": "12.3.0",
- "@next/swc-android-arm64": "12.3.0",
- "@next/swc-darwin-arm64": "12.3.0",
- "@next/swc-darwin-x64": "12.3.0",
- "@next/swc-freebsd-x64": "12.3.0",
- "@next/swc-linux-arm-gnueabihf": "12.3.0",
- "@next/swc-linux-arm64-gnu": "12.3.0",
- "@next/swc-linux-arm64-musl": "12.3.0",
- "@next/swc-linux-x64-gnu": "12.3.0",
- "@next/swc-linux-x64-musl": "12.3.0",
- "@next/swc-win32-arm64-msvc": "12.3.0",
- "@next/swc-win32-ia32-msvc": "12.3.0",
- "@next/swc-win32-x64-msvc": "12.3.0",
- "@swc/helpers": "0.4.11",
- "caniuse-lite": "^1.0.30001332",
- "postcss": "8.4.14",
- "styled-jsx": "5.0.6",
- "use-sync-external-store": "1.2.0"
- }
- },
- "next-transpile-modules": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz",
- "integrity": "sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ==",
- "dev": true,
- "requires": {
- "enhanced-resolve": "^5.7.0",
- "escalade": "^3.1.1"
- }
- },
- "node-releases": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
- "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
- },
- "object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
- },
- "object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
- },
- "object.assign": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- }
- },
- "object.entries": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
- "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- }
- },
- "object.fromentries": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz",
- "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- }
- },
- "object.hasown": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz",
- "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==",
- "requires": {
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- }
- },
- "object.values": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
- "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "requires": {
- "wrappy": "1"
- }
- },
- "optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "requires": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- }
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
- },
- "path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
- },
- "postcss": {
- "version": "8.4.14",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
- "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
- "requires": {
- "nanoid": "^3.3.4",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- }
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
- },
- "prettier": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
- "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
- "dev": true
- },
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
- },
- "prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
- },
- "queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
- },
- "react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
- "requires": {
- "loose-envify": "^1.1.0"
- }
- },
- "react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
- "requires": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- }
- },
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
- },
- "regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
- },
- "regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- }
- },
- "regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="
- },
- "require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
- },
- "resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
- "requires": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
- },
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "requires": {
- "queue-microtask": "^1.2.2"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- }
- },
- "scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "requires": {
- "loose-envify": "^1.1.0"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- },
- "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==",
- "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=="
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
- },
- "slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- }
- }
- },
- "source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- }
- }
- },
- "string.prototype.matchall": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz",
- "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "regexp.prototype.flags": "^1.4.1",
- "side-channel": "^1.0.4"
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
- "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
- "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- },
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="
- },
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
- },
- "styled-jsx": {
- "version": "5.0.6",
- "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.6.tgz",
- "integrity": "sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==",
- "requires": {}
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
- },
- "table": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
- "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
- "requires": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
- }
- }
- },
- "tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "tsconfig": {
- "version": "file:packages/tsconfig"
- },
- "tsconfig-paths": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
- "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
- "requires": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.1",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- }
- }
- },
- "tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
- },
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "requires": {
- "tslib": "^1.8.1"
- },
- "dependencies": {
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- }
- }
- },
- "turbo": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.5.5.tgz",
- "integrity": "sha512-PVQSDl0STC9WXIyHcYUWs9gXsf8JjQig/FuHfuB8N6+XlgCGB3mPbfMEE6zrChGz2hufH4/guKRX1XJuNL6XTA==",
- "dev": true,
- "requires": {
- "turbo-darwin-64": "1.5.5",
- "turbo-darwin-arm64": "1.5.5",
- "turbo-linux-64": "1.5.5",
- "turbo-linux-arm64": "1.5.5",
- "turbo-windows-64": "1.5.5",
- "turbo-windows-arm64": "1.5.5"
- }
- },
- "turbo-darwin-64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.5.5.tgz",
- "integrity": "sha512-HvEn6P2B+NXDekq9LRpRgUjcT9/oygLTcK47U0qsAJZXRBSq/2hvD7lx4nAwgY/4W3rhYJeWtHTzbhoN6BXqGQ==",
- "dev": true,
- "optional": true
- },
- "turbo-darwin-arm64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.5.5.tgz",
- "integrity": "sha512-Dmxr09IUy6M0nc7/xWod9galIO2DD500B75sJSkHeT+CCdJOWnlinux0ZPF8CSygNqymwYO8AO2l15/6yxcycg==",
- "dev": true,
- "optional": true
- },
- "turbo-linux-64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.5.5.tgz",
- "integrity": "sha512-wd07TZ4zXXWjzZE00FcFMLmkybQQK/NV9ff66vvAV0vdiuacSMBCNLrD6Mm4ncfrUPW/rwFW5kU/7hyuEqqtDw==",
- "dev": true,
- "optional": true
- },
- "turbo-linux-arm64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.5.5.tgz",
- "integrity": "sha512-q3q33tuo74R7gicnfvFbnZZvqmlq7Vakcvx0eshifnJw4PR+oMnTCb4w8ElVFx070zsb8DVTibq99y8NJH8T1Q==",
- "dev": true,
- "optional": true
- },
- "turbo-windows-64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.5.5.tgz",
- "integrity": "sha512-lPp9kHonNFfqgovbaW+UAPO5cLmoAN+m3G3FzqcrRPnlzt97vXYsDhDd/4Zy3oAKoAcprtP4CGy0ddisqsKTVw==",
- "dev": true,
- "optional": true
- },
- "turbo-windows-arm64": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.5.5.tgz",
- "integrity": "sha512-3AfGULKNZiZVrEzsIE+W79ZRW1+f5r4nM4wLlJ1PTBHyRxBZdD6KTH1tijGfy/uTlcV5acYnKHEkDc6Q9PAXGQ==",
- "dev": true,
- "optional": true
- },
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="
- },
- "typescript": {
- "version": "4.8.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
- "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ=="
- },
- "ui": {
- "version": "file:packages/ui",
- "requires": {
- "@types/react": "^17.0.37",
- "@types/react-dom": "^17.0.11",
- "eslint": "^7.32.0",
- "eslint-config-custom": "*",
- "react": "^18.2.0",
- "tsconfig": "*",
- "typescript": "^4.5.2"
- },
- "dependencies": {
- "@types/react": {
- "version": "17.0.50",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz",
- "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- }
- }
- },
- "unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- }
- },
- "update-browserslist-db": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz",
- "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==",
- "dev": true,
- "requires": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- }
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "requires": {}
- },
- "v8-compile-cache": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
- "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
- },
- "web": {
- "version": "file:apps/web",
- "requires": {
- "@babel/core": "^7.0.0",
- "@types/node": "^17.0.12",
- "@types/react": "18.0.17",
- "eslint": "7.32.0",
- "eslint-config-custom": "*",
- "lodash": "^4.17.21",
- "next": "12.3.0",
- "next-transpile-modules": "9.0.0",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "tsconfig": "*",
- "typescript": "^4.5.3",
- "ui": "*"
- },
- "dependencies": {
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- }
- }
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "requires": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- }
- },
- "word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- }
- }
-}
diff --git a/cli/internal/lockfile/testdata/pnpm-absolute-v6.yaml b/cli/internal/lockfile/testdata/pnpm-absolute-v6.yaml
deleted file mode 100644
index dc5d0e6..0000000
--- a/cli/internal/lockfile/testdata/pnpm-absolute-v6.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-lockfileVersion: "6.0"
-importers:
- packages/a:
- dependencies:
- "@scope/parent":
- specifier: ^1.0.0
- version: 1.0.0
-
-packages:
- /@scope/parent@1.0.0:
- resolution: { integrity: junk }
- dependencies:
- child: /@scope/child@1.0.0
- dev: false
-
- /@scope/child@1.0.0:
- resolution: { integrity: junk }
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm-absolute.yaml b/cli/internal/lockfile/testdata/pnpm-absolute.yaml
deleted file mode 100644
index d39f802..0000000
--- a/cli/internal/lockfile/testdata/pnpm-absolute.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-lockfileVersion: 5.4
-importers:
- packages/a:
- specifiers:
- another: ^1.0.0
- "@scope/parent": ^1.0.0
- special: npm:Special@1.2.3
- dependencies:
- another: 1.0.0
- "@scope/parent": 1.0.0
- special: /Special/1.2.3
-
-packages:
- /@scope/parent/1.0.0:
- resolution: { integrity: junk }
- dependencies:
- child: /@scope/child/1.0.0
- dev: false
-
- /@scope/child/1.0.0:
- resolution: { integrity: junk }
- dev: false
-
- /another/1.0.0:
- resolution: { integrity: junk }
- dev: false
- dependencies:
- foo: 1.0.0
-
- /foo/1.0.0:
- resolution: { integrity: junk }
- dev: false
- dependencies:
- Special: 1.2.3
-
- /Special/1.2.3:
- resolution: { integrity: junk }
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm-patch-v6.yaml b/cli/internal/lockfile/testdata/pnpm-patch-v6.yaml
deleted file mode 100644
index b620472..0000000
--- a/cli/internal/lockfile/testdata/pnpm-patch-v6.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-lockfileVersion: "6.0"
-
-patchedDependencies:
- lodash@4.17.21:
- hash: lgum37zgng4nfkynzh3cs7wdeq
- path: patches/lodash@4.17.21.patch
- "@babel/helper-string-parser@7.19.4":
- hash: wjhgmpzh47qmycrzgpeyoyh3ce
- path: patches/@babel__helper-string-parser@7.19.4.patch
-
-importers:
- .: {}
-
- packages/a:
- dependencies:
- lodash:
- specifier: ^4.17.21
- version: 4.17.21(patch_hash=lgum37zgng4nfkynzh3cs7wdeq)
-
- packages/b:
- dependencies:
- "@babel/helper-string-parser":
- specifier: ^7.19.4
- version: 7.19.4(patch_hash=wjhgmpzh47qmycrzgpeyoyh3ce)(@babel/core@7.21.0)
-
-packages:
- /@babel/helper-string-parser@7.19.4(patch_hash=wjhgmpzh47qmycrzgpeyoyh3ce)(@babel/core@7.21.0):
- resolution:
- {
- integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==,
- }
- engines: { node: ">=6.9.0" }
- dev: false
-
- /lodash@4.17.21(patch_hash=lgum37zgng4nfkynzh3cs7wdeq):
- resolution:
- {
- integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==,
- }
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm-patch.yaml b/cli/internal/lockfile/testdata/pnpm-patch.yaml
deleted file mode 100644
index ea84d72..0000000
--- a/cli/internal/lockfile/testdata/pnpm-patch.yaml
+++ /dev/null
@@ -1,63 +0,0 @@
-lockfileVersion: 5.4
-
-patchedDependencies:
- is-odd@3.0.1:
- hash: nrrwwz7lemethtlvvm75r5bmhq
- path: patches/is-odd@3.0.1.patch
- "@babel/core@7.20.12":
- hash: 3hyn7hbvzkemudbydlwjmrb65y
- path: patches/@babel__core@7.20.12.patch
- moleculer@0.14.28:
- hash: 5pk7ojv7qbqha75ozglk4y4f74
- path: patches/moleculer@0.14.28.patch
-
-importers:
- .:
- specifiers: {}
-
- packages/dependency:
- specifiers:
- is-odd: ^3.0.1
- "@babel/core": ^7.20.12
- dependencies:
- is-odd: 3.0.1_nrrwwz7lemethtlvvm75r5bmhq
- "@babel/core": 7.20.12_3hyn7hbvzkemudbydlwjmrb65y
-
-packages:
- /@babel/core/7.20.12_3hyn7hbvzkemudbydlwjmrb65y:
- resolution:
- {
- integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==,
- }
- engines: { node: ">=6.9.0" }
- dev: false
-
- /is-number/6.0.0:
- resolution:
- {
- integrity: sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==,
- }
- engines: { node: ">=0.10.0" }
- dev: false
-
- /is-odd/3.0.1_nrrwwz7lemethtlvvm75r5bmhq:
- resolution:
- {
- integrity: sha512-CQpnWPrDwmP1+SMHXZhtLtJv90yiyVfluGsX5iNCVkrhQtU3TQHsUWPG9wkdk9Lgd5yNpAg9jQEo90CBaXgWMA==,
- }
- engines: { node: ">=4" }
- dependencies:
- is-number: 6.0.0
- dev: false
- patched: true
-
- /moleculer/0.14.28_5pk7ojv7qbqha75ozglk4y4f74_kumip57h7zlinbhp4gz3jrbqry:
- resolution:
- {
- integrity: sha512-CQpnWPrDwmP1+SMHXZhtLtJv90yiyVfluGsX5iNCVkrhQtU3TQHsUWPG9wkdk9Lgd5yNpAg9jQEo90CBaXgWMA==,
- }
- engines: { node: ">=4" }
- dependencies:
- is-number: 6.0.0
- dev: false
- patched: true
diff --git a/cli/internal/lockfile/testdata/pnpm-peer-v6.yaml b/cli/internal/lockfile/testdata/pnpm-peer-v6.yaml
deleted file mode 100644
index feddd07..0000000
--- a/cli/internal/lockfile/testdata/pnpm-peer-v6.yaml
+++ /dev/null
@@ -1,67 +0,0 @@
-lockfileVersion: "6.0"
-
-importers:
- .: {}
-
- apps/web:
- dependencies:
- next:
- specifier: 13.0.4
- version: 13.0.4(react-dom@18.2.0)(react@18.2.0)
- react:
- specifier: 18.2.0
- version: 18.2.0
- react-dom:
- specifier: 18.2.0
- version: 18.2.0(react@18.2.0)
-
- packages/next-config: {}
-
- packages/package-for-ci: {}
-
- packages/tsconfig: {}
-
-packages:
- /next@13.0.4:
- resolution:
- {
- integrity: sha512-4P0MvbjPCI1E/UPL1GrTXtYlgFnbBbY3JQ+AMY8jYE2SwyvCWctEJySoRjveznAHjrl6TIjuAJeB8u1c2StYUQ==,
- }
- engines: { node: ">=14.6.0" }
- hasBin: true
- peerDependencies:
- fibers: ">= 3.1.0"
- node-sass: ^6.0.0 || ^7.0.0
- react: ^18.2.0
- react-dom: ^18.2.0
- sass: ^1.3.0
- peerDependenciesMeta:
- fibers:
- optional: true
- node-sass:
- optional: true
- sass:
- optional: true
- dev: true
-
- /next@13.0.4(react-dom@18.2.0)(react@18.2.0):
- resolution:
- {
- integrity: sha512-4P0MvbjPCI1E/UPL1GrTXtYlgFnbBbY3JQ+AMY8jYE2SwyvCWctEJySoRjveznAHjrl6TIjuAJeB8u1c2StYUQ==,
- }
- engines: { node: ">=14.6.0" }
- hasBin: true
- peerDependencies:
- fibers: ">= 3.1.0"
- node-sass: ^6.0.0 || ^7.0.0
- react: ^18.2.0
- react-dom: ^18.2.0
- sass: ^1.3.0
- peerDependenciesMeta:
- fibers:
- optional: true
- node-sass:
- optional: true
- sass:
- optional: true
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm-top-level-dupe.yaml b/cli/internal/lockfile/testdata/pnpm-top-level-dupe.yaml
deleted file mode 100644
index 6837f22..0000000
--- a/cli/internal/lockfile/testdata/pnpm-top-level-dupe.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-lockfileVersion: 5.4
-
-importers:
- packages/a:
- specifiers:
- ci-info: ^2.0.0
- is-ci: ^3.0.1
- dependencies:
- ci-info: 2.0.0
- is-ci: 3.0.1
-
-packages:
- /ci-info/2.0.0:
- resolution:
- {
- integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==,
- }
- dev: false
-
- /ci-info/3.7.1:
- resolution:
- {
- integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==,
- }
- engines: { node: ">=8" }
- dev: false
-
- /is-ci/3.0.1:
- resolution:
- {
- integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==,
- }
- hasBin: true
- dependencies:
- ci-info: 3.7.1
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm6-workspace.yaml b/cli/internal/lockfile/testdata/pnpm6-workspace.yaml
deleted file mode 100644
index daf92b7..0000000
--- a/cli/internal/lockfile/testdata/pnpm6-workspace.yaml
+++ /dev/null
@@ -1,1704 +0,0 @@
-lockfileVersion: 5.3
-
-importers:
- .:
- specifiers:
- "@pnpm/make-dedicated-lockfile": ^0.3.19
- devDependencies:
- "@pnpm/make-dedicated-lockfile": 0.3.19
-
- packages/a:
- specifiers:
- b: workspace:*
- express: ^4.18.1
- dependencies:
- b: link:../b
- express: 4.18.1
-
- packages/b:
- specifiers:
- c: workspace:*
- lodash: ^4.17.21
- dependencies:
- c: link:../c
- lodash: 4.17.21
-
- packages/c:
- specifiers:
- chalk: ^5.0.1
- dependencies:
- chalk: 5.0.1
-
-packages:
- /@babel/code-frame/7.18.6:
- resolution:
- {
- integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/highlight": 7.18.6
- dev: true
-
- /@babel/helper-validator-identifier/7.18.6:
- resolution:
- {
- integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==,
- }
- engines: { node: ">=6.9.0" }
- dev: true
-
- /@babel/highlight/7.18.6:
- resolution:
- {
- integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/helper-validator-identifier": 7.18.6
- chalk: 2.4.2
- js-tokens: 4.0.0
- dev: true
-
- /@pnpm/constants/6.1.0:
- resolution:
- {
- integrity: sha512-L6AiU3OXv9kjKGTJN9j8n1TeJGDcLX9atQlZvAkthlvbXjvKc5SKNWESc/eXhr5nEfuMWhQhiKHDJCpYejmeCQ==,
- }
- engines: { node: ">=14.19" }
- dev: true
-
- /@pnpm/crypto.base32-hash/1.0.1:
- resolution:
- {
- integrity: sha512-pzAXNn6KxTA3kbcI3iEnYs4vtH51XEVqmK/1EiD18MaPKylhqy8UvMJK3zKG+jeP82cqQbozcTGm4yOQ8i3vNw==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- rfc4648: 1.5.2
- dev: true
-
- /@pnpm/error/3.0.1:
- resolution:
- {
- integrity: sha512-hMlbWbFcfcfolNfSjKjpeaZFow71kNg438LZ8rAd01swiVIYRUf/sRv8gGySru6AijYfz5UqslpIJRDbYBkgQA==,
- }
- engines: { node: ">=14.19" }
- dependencies:
- "@pnpm/constants": 6.1.0
- dev: true
-
- /@pnpm/exec/2.0.0:
- resolution:
- {
- integrity: sha512-b5ALfWEOFQprWKntN7MF8XWCyslBk2c8u20GEDcDDQOs6c0HyHlWxX5lig8riQKdS000U6YyS4L4b32NOleXAQ==,
- }
- engines: { node: ">=10" }
- dependencies:
- "@pnpm/self-installer": 2.2.1
- command-exists: 1.2.9
- cross-spawn: 7.0.3
- dev: true
-
- /@pnpm/exportable-manifest/3.1.2:
- resolution:
- {
- integrity: sha512-IvTBwt3n73pXsU6iS1Y4OipBg3GBN37I/mUR8t3q5N0c5TkVxj9xAsra5/m7mX4dsYCv9BPL6Rw+MuKSV5P1hA==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/error": 3.0.1
- "@pnpm/read-project-manifest": 3.0.9
- "@pnpm/types": 8.5.0
- ramda: /@pnpm/ramda/0.28.1
- dev: true
-
- /@pnpm/find-workspace-dir/4.0.2:
- resolution:
- {
- integrity: sha512-gU7ycFSWuEGJh7RE/STa33Ch27geODTXIfc+ntiE1BietxfpJIAk34zz51kTUuCFthBkpHlO6yV7jgHD2Tuc3g==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/error": 3.0.1
- find-up: 5.0.0
- dev: true
-
- /@pnpm/git-utils/0.1.0:
- resolution:
- {
- integrity: sha512-W3zsG9585cKL+FqgcT+IfTgZX5C+CbNkFjOnJN+qbysT1N30+BbvEByCcDMsTy7QDrAk6oS7WU1Rym3U2xlh2Q==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- execa: /safe-execa/0.1.2
- dev: true
-
- /@pnpm/graceful-fs/2.0.0:
- resolution:
- {
- integrity: sha512-ogUZCGf0/UILZt6d8PsO4gA4pXh7f0BumXeFkcCe4AQ65PXPKfAkHC0C30Lheh2EgFOpLZm3twDP1Eiww18gew==,
- }
- engines: { node: ">=14.19" }
- dependencies:
- graceful-fs: 4.2.10
- dev: true
-
- /@pnpm/lockfile-file/5.3.3_@pnpm+logger@4.0.0:
- resolution:
- {
- integrity: sha512-IOvjeMRX+++osG9VsfSd7+hVa/sIzhqdrm/nFcL7AexFhC7wjXbWW3YMlN5Cw4v0fwm93fgRZlikIKJ7BmkBBA==,
- }
- engines: { node: ">=14.6" }
- peerDependencies:
- "@pnpm/logger": ^4.0.0
- dependencies:
- "@pnpm/constants": 6.1.0
- "@pnpm/error": 3.0.1
- "@pnpm/git-utils": 0.1.0
- "@pnpm/lockfile-types": 4.3.1
- "@pnpm/logger": 4.0.0
- "@pnpm/merge-lockfile-changes": 3.0.9
- "@pnpm/types": 8.5.0
- "@zkochan/rimraf": 2.1.2
- comver-to-semver: 1.0.0
- js-yaml: /@zkochan/js-yaml/0.0.6
- normalize-path: 3.0.0
- ramda: /@pnpm/ramda/0.28.1
- semver: 7.3.7
- sort-keys: 4.2.0
- strip-bom: 4.0.0
- write-file-atomic: 3.0.3
- dev: true
-
- /@pnpm/lockfile-types/4.3.1:
- resolution:
- {
- integrity: sha512-xoorF+CuuUvpjfi8Uw/xkf8LI9VDzs9W1gjSxkKS8UwK60zU5fu4agILJfVVGlHO1tnjJeGRuspBjp7UZ8ufMA==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/types": 8.5.0
- dev: true
-
- /@pnpm/logger/4.0.0:
- resolution:
- {
- integrity: sha512-SIShw+k556e7S7tLZFVSIHjCdiVog1qWzcKW2RbLEHPItdisAFVNIe34kYd9fMSswTlSRLS/qRjw3ZblzWmJ9Q==,
- }
- engines: { node: ">=12.17" }
- dependencies:
- bole: 4.0.1
- ndjson: 2.0.0
- dev: true
-
- /@pnpm/make-dedicated-lockfile/0.3.19:
- resolution:
- {
- integrity: sha512-VHllqMh5zviSHds2kOlWSiwmxos3LLGWCVIHpo+HX45D3TXx+oMOgE8k6WB0dSOTVIuGKduoCNTGeSW4p2bD2w==,
- }
- engines: { node: ">=14.6" }
- hasBin: true
- dependencies:
- "@pnpm/error": 3.0.1
- "@pnpm/exec": 2.0.0
- "@pnpm/exportable-manifest": 3.1.2
- "@pnpm/find-workspace-dir": 4.0.2
- "@pnpm/lockfile-file": 5.3.3_@pnpm+logger@4.0.0
- "@pnpm/logger": 4.0.0
- "@pnpm/prune-lockfile": 4.0.14
- "@pnpm/read-project-manifest": 3.0.9
- "@pnpm/types": 8.5.0
- ramda: /@pnpm/ramda/0.28.1
- rename-overwrite: 4.0.2
- dev: true
-
- /@pnpm/merge-lockfile-changes/3.0.9:
- resolution:
- {
- integrity: sha512-UOl3AYsi13R8bvQNJPNUml8sZYKBRns0xjAcPQomoX3WTU0dv+KzVyv86Iv86YlApP0aJj9MS8Vq++JOC10RKg==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/lockfile-types": 4.3.1
- comver-to-semver: 1.0.0
- ramda: /@pnpm/ramda/0.28.1
- semver: 7.3.7
- dev: true
-
- /@pnpm/prune-lockfile/4.0.14:
- resolution:
- {
- integrity: sha512-lICCgm9j3e2Bu75zK4PA1FKjpu9pCcagRbZWruONBf44byyEkHcnTf8b8a9M1MvtoiArhmKOmyOVJ2OFyBBRyA==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/constants": 6.1.0
- "@pnpm/lockfile-types": 4.3.1
- "@pnpm/types": 8.5.0
- dependency-path: 9.2.4
- ramda: /@pnpm/ramda/0.28.1
- dev: true
-
- /@pnpm/ramda/0.28.1:
- resolution:
- {
- integrity: sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==,
- }
- dev: true
-
- /@pnpm/read-project-manifest/3.0.9:
- resolution:
- {
- integrity: sha512-27j40C48hA/tqsCiqk9ApJxp2g6WGrrj2RSs0NKhsSHynxAuA1tIvwatNISQbAiMjZiu1lfhzhq8m1QdblyNmA==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/error": 3.0.1
- "@pnpm/graceful-fs": 2.0.0
- "@pnpm/types": 8.5.0
- "@pnpm/write-project-manifest": 3.0.7
- detect-indent: 6.1.0
- fast-deep-equal: 3.1.3
- is-windows: 1.0.2
- json5: 2.2.1
- parse-json: 5.2.0
- read-yaml-file: 2.1.0
- sort-keys: 4.2.0
- strip-bom: 4.0.0
- dev: true
-
- /@pnpm/self-installer/2.2.1:
- resolution:
- {
- integrity: sha512-aefLe96wAWghkx6q1PwbVS1Iz1iGE+HKwkTmtzWLFXeGhbknaIdG2voMwaBGIYGCSxm8sDKR1uLO4aRRAYuc+Q==,
- }
- engines: { node: ">=4" }
- hasBin: true
- dev: true
-
- /@pnpm/types/8.5.0:
- resolution:
- {
- integrity: sha512-PSKnhkwgiZtp9dcWZR9mPz2W9UopmADr9o8FTqazo5kjUSh2xQmDUSJOJ/ZWcfNziO64Ix/VbcxKIZeplhog1Q==,
- }
- engines: { node: ">=14.6" }
- dev: true
-
- /@pnpm/write-project-manifest/3.0.7:
- resolution:
- {
- integrity: sha512-rMgIWR52asESg1D7Cp/vBi3dBsv18iUWPvvtYNynrcOjRdE3NsH5CAdfZP/XN6HJF6CSY8rS9W4YC5Q3JGtxiw==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/types": 8.5.0
- json5: 2.2.1
- write-file-atomic: 3.0.3
- write-yaml-file: 4.2.0
- dev: true
-
- /@zkochan/js-yaml/0.0.6:
- resolution:
- {
- integrity: sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==,
- }
- hasBin: true
- dependencies:
- argparse: 2.0.1
- dev: true
-
- /@zkochan/rimraf/2.1.2:
- resolution:
- {
- integrity: sha512-Lc2oK51J6aQWcLWTloobJun5ZF41BbTDdLvE+aMcexoVWFoFqvZmnZoyXR2IZk6NJEVoZW8tjgtvQLfTsmRs2Q==,
- }
- engines: { node: ">=12.10" }
- dependencies:
- rimraf: 3.0.2
- dev: true
-
- /@zkochan/which/2.0.3:
- resolution:
- {
- integrity: sha512-C1ReN7vt2/2O0fyTsx5xnbQuxBrmG5NMSbcIkPKCCfCTJgpZBsuRYzFXHj3nVq8vTfK7vxHUmzfCpSHgO7j4rg==,
- }
- engines: { node: ">= 8" }
- hasBin: true
- dependencies:
- isexe: 2.0.0
- dev: true
-
- /accepts/1.3.8:
- resolution:
- {
- integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==,
- }
- engines: { node: ">= 0.6" }
- dependencies:
- mime-types: 2.1.35
- negotiator: 0.6.3
- dev: false
-
- /ansi-styles/3.2.1:
- resolution:
- {
- integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==,
- }
- engines: { node: ">=4" }
- dependencies:
- color-convert: 1.9.3
- dev: true
-
- /argparse/2.0.1:
- resolution:
- {
- integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==,
- }
- dev: true
-
- /array-flatten/1.1.1:
- resolution:
- {
- integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==,
- }
- dev: false
-
- /balanced-match/1.0.2:
- resolution:
- {
- integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==,
- }
- dev: true
-
- /body-parser/1.20.0:
- resolution:
- {
- integrity: sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==,
- }
- engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 }
- dependencies:
- bytes: 3.1.2
- content-type: 1.0.4
- debug: 2.6.9
- depd: 2.0.0
- destroy: 1.2.0
- http-errors: 2.0.0
- iconv-lite: 0.4.24
- on-finished: 2.4.1
- qs: 6.10.3
- raw-body: 2.5.1
- type-is: 1.6.18
- unpipe: 1.0.0
- dev: false
-
- /bole/4.0.1:
- resolution:
- {
- integrity: sha512-42r0aSOJFJti2l6LasBHq2BuWJzohGs349olQnH/ETlJo87XnoWw7UT8pGE6UstjxzOKkwz7tjoFcmSr6L16vg==,
- }
- dependencies:
- fast-safe-stringify: 2.1.1
- individual: 3.0.0
- dev: true
-
- /brace-expansion/1.1.11:
- resolution:
- {
- integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==,
- }
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
- dev: true
-
- /bytes/3.1.2:
- resolution:
- {
- integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /call-bind/1.0.2:
- resolution:
- {
- integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==,
- }
- dependencies:
- function-bind: 1.1.1
- get-intrinsic: 1.1.2
- dev: false
-
- /chalk/2.4.2:
- resolution:
- {
- integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==,
- }
- engines: { node: ">=4" }
- dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
- dev: true
-
- /chalk/5.0.1:
- resolution:
- {
- integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==,
- }
- engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 }
- dev: false
-
- /color-convert/1.9.3:
- resolution:
- {
- integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==,
- }
- dependencies:
- color-name: 1.1.3
- dev: true
-
- /color-name/1.1.3:
- resolution:
- {
- integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==,
- }
- dev: true
-
- /command-exists/1.2.9:
- resolution:
- {
- integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==,
- }
- dev: true
-
- /comver-to-semver/1.0.0:
- resolution:
- {
- integrity: sha512-gcGtbRxjwROQOdXLUWH1fQAXqThUVRZ219aAwgtX3KfYw429/Zv6EIJRf5TBSzWdAGwePmqH7w70WTaX4MDqag==,
- }
- engines: { node: ">=12.17" }
- dev: true
-
- /concat-map/0.0.1:
- resolution:
- {
- integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==,
- }
- dev: true
-
- /content-disposition/0.5.4:
- resolution:
- {
- integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==,
- }
- engines: { node: ">= 0.6" }
- dependencies:
- safe-buffer: 5.2.1
- dev: false
-
- /content-type/1.0.4:
- resolution:
- {
- integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /cookie-signature/1.0.6:
- resolution:
- {
- integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==,
- }
- dev: false
-
- /cookie/0.5.0:
- resolution:
- {
- integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /cross-spawn/7.0.3:
- resolution:
- {
- integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==,
- }
- engines: { node: ">= 8" }
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
- dev: true
-
- /debug/2.6.9:
- resolution:
- {
- integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==,
- }
- dependencies:
- ms: 2.0.0
- dev: false
-
- /depd/2.0.0:
- resolution:
- {
- integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /dependency-path/9.2.4:
- resolution:
- {
- integrity: sha512-bH29ZcKyo/i5nr4SgnVZGksuoZzroOWpHtKbq8fKdKgJDr0SdUIPu2EwjJkjzbw9SqRzWd912e0opHYJTkFf6w==,
- }
- engines: { node: ">=14.6" }
- dependencies:
- "@pnpm/crypto.base32-hash": 1.0.1
- "@pnpm/types": 8.5.0
- encode-registry: 3.0.0
- semver: 7.3.7
- dev: true
-
- /destroy/1.2.0:
- resolution:
- {
- integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==,
- }
- engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 }
- dev: false
-
- /detect-indent/6.1.0:
- resolution:
- {
- integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /ee-first/1.1.1:
- resolution:
- {
- integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==,
- }
- dev: false
-
- /encode-registry/3.0.0:
- resolution:
- {
- integrity: sha512-2fRYji8K6FwYuQ6EPBKR/J9mcqb7kIoNqt1vGvJr3NrvKfncRiNm00Oxo6gi/YJF8R5Sp2bNFSFdGKTG0rje1Q==,
- }
- engines: { node: ">=10" }
- dependencies:
- mem: 8.1.1
- dev: true
-
- /encodeurl/1.0.2:
- resolution:
- {
- integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /error-ex/1.3.2:
- resolution:
- {
- integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==,
- }
- dependencies:
- is-arrayish: 0.2.1
- dev: true
-
- /escape-html/1.0.3:
- resolution:
- {
- integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==,
- }
- dev: false
-
- /escape-string-regexp/1.0.5:
- resolution:
- {
- integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==,
- }
- engines: { node: ">=0.8.0" }
- dev: true
-
- /etag/1.8.1:
- resolution:
- {
- integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /execa/5.1.1:
- resolution:
- {
- integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==,
- }
- engines: { node: ">=10" }
- dependencies:
- cross-spawn: 7.0.3
- get-stream: 6.0.1
- human-signals: 2.1.0
- is-stream: 2.0.1
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
- dev: true
-
- /express/4.18.1:
- resolution:
- {
- integrity: sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==,
- }
- engines: { node: ">= 0.10.0" }
- dependencies:
- accepts: 1.3.8
- array-flatten: 1.1.1
- body-parser: 1.20.0
- content-disposition: 0.5.4
- content-type: 1.0.4
- cookie: 0.5.0
- cookie-signature: 1.0.6
- debug: 2.6.9
- depd: 2.0.0
- encodeurl: 1.0.2
- escape-html: 1.0.3
- etag: 1.8.1
- finalhandler: 1.2.0
- fresh: 0.5.2
- http-errors: 2.0.0
- merge-descriptors: 1.0.1
- methods: 1.1.2
- on-finished: 2.4.1
- parseurl: 1.3.3
- path-to-regexp: 0.1.7
- proxy-addr: 2.0.7
- qs: 6.10.3
- range-parser: 1.2.1
- safe-buffer: 5.2.1
- send: 0.18.0
- serve-static: 1.15.0
- setprototypeof: 1.2.0
- statuses: 2.0.1
- type-is: 1.6.18
- utils-merge: 1.0.1
- vary: 1.1.2
- dev: false
-
- /fast-deep-equal/3.1.3:
- resolution:
- {
- integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
- }
- dev: true
-
- /fast-safe-stringify/2.1.1:
- resolution:
- {
- integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==,
- }
- dev: true
-
- /finalhandler/1.2.0:
- resolution:
- {
- integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==,
- }
- engines: { node: ">= 0.8" }
- dependencies:
- debug: 2.6.9
- encodeurl: 1.0.2
- escape-html: 1.0.3
- on-finished: 2.4.1
- parseurl: 1.3.3
- statuses: 2.0.1
- unpipe: 1.0.0
- dev: false
-
- /find-up/5.0.0:
- resolution:
- {
- integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==,
- }
- engines: { node: ">=10" }
- dependencies:
- locate-path: 6.0.0
- path-exists: 4.0.0
- dev: true
-
- /forwarded/0.2.0:
- resolution:
- {
- integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /fresh/0.5.2:
- resolution:
- {
- integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /fs.realpath/1.0.0:
- resolution:
- {
- integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==,
- }
- dev: true
-
- /function-bind/1.1.1:
- resolution:
- {
- integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==,
- }
- dev: false
-
- /get-intrinsic/1.1.2:
- resolution:
- {
- integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==,
- }
- dependencies:
- function-bind: 1.1.1
- has: 1.0.3
- has-symbols: 1.0.3
- dev: false
-
- /get-stream/6.0.1:
- resolution:
- {
- integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==,
- }
- engines: { node: ">=10" }
- dev: true
-
- /glob/7.2.3:
- resolution:
- {
- integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==,
- }
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
- dev: true
-
- /graceful-fs/4.2.10:
- resolution:
- {
- integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==,
- }
- dev: true
-
- /has-flag/3.0.0:
- resolution:
- {
- integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==,
- }
- engines: { node: ">=4" }
- dev: true
-
- /has-symbols/1.0.3:
- resolution:
- {
- integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==,
- }
- engines: { node: ">= 0.4" }
- dev: false
-
- /has/1.0.3:
- resolution:
- {
- integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==,
- }
- engines: { node: ">= 0.4.0" }
- dependencies:
- function-bind: 1.1.1
- dev: false
-
- /http-errors/2.0.0:
- resolution:
- {
- integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==,
- }
- engines: { node: ">= 0.8" }
- dependencies:
- depd: 2.0.0
- inherits: 2.0.4
- setprototypeof: 1.2.0
- statuses: 2.0.1
- toidentifier: 1.0.1
- dev: false
-
- /human-signals/2.1.0:
- resolution:
- {
- integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==,
- }
- engines: { node: ">=10.17.0" }
- dev: true
-
- /iconv-lite/0.4.24:
- resolution:
- {
- integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- safer-buffer: 2.1.2
- dev: false
-
- /imurmurhash/0.1.4:
- resolution:
- {
- integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==,
- }
- engines: { node: ">=0.8.19" }
- dev: true
-
- /individual/3.0.0:
- resolution:
- {
- integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==,
- }
- dev: true
-
- /inflight/1.0.6:
- resolution:
- {
- integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==,
- }
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
- dev: true
-
- /inherits/2.0.4:
- resolution:
- {
- integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==,
- }
- dev: false
-
- /ipaddr.js/1.9.1:
- resolution:
- {
- integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==,
- }
- engines: { node: ">= 0.10" }
- dev: false
-
- /is-arrayish/0.2.1:
- resolution:
- {
- integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==,
- }
- dev: true
-
- /is-plain-obj/2.1.0:
- resolution:
- {
- integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /is-stream/2.0.1:
- resolution:
- {
- integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /is-typedarray/1.0.0:
- resolution:
- {
- integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==,
- }
- dev: true
-
- /is-windows/1.0.2:
- resolution:
- {
- integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==,
- }
- engines: { node: ">=0.10.0" }
- dev: true
-
- /isexe/2.0.0:
- resolution:
- {
- integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==,
- }
- dev: true
-
- /js-tokens/4.0.0:
- resolution:
- {
- integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==,
- }
- dev: true
-
- /js-yaml/4.1.0:
- resolution:
- {
- integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==,
- }
- hasBin: true
- dependencies:
- argparse: 2.0.1
- dev: true
-
- /json-parse-even-better-errors/2.3.1:
- resolution:
- {
- integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==,
- }
- dev: true
-
- /json-stringify-safe/5.0.1:
- resolution:
- {
- integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==,
- }
- dev: true
-
- /json5/2.2.1:
- resolution:
- {
- integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==,
- }
- engines: { node: ">=6" }
- hasBin: true
- dev: true
-
- /lines-and-columns/1.2.4:
- resolution:
- {
- integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==,
- }
- dev: true
-
- /locate-path/6.0.0:
- resolution:
- {
- integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==,
- }
- engines: { node: ">=10" }
- dependencies:
- p-locate: 5.0.0
- dev: true
-
- /lodash/4.17.21:
- resolution:
- {
- integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==,
- }
- dev: false
-
- /lru-cache/6.0.0:
- resolution:
- {
- integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==,
- }
- engines: { node: ">=10" }
- dependencies:
- yallist: 4.0.0
- dev: true
-
- /map-age-cleaner/0.1.3:
- resolution:
- {
- integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==,
- }
- engines: { node: ">=6" }
- dependencies:
- p-defer: 1.0.0
- dev: true
-
- /media-typer/0.3.0:
- resolution:
- {
- integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /mem/8.1.1:
- resolution:
- {
- integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==,
- }
- engines: { node: ">=10" }
- dependencies:
- map-age-cleaner: 0.1.3
- mimic-fn: 3.1.0
- dev: true
-
- /merge-descriptors/1.0.1:
- resolution:
- {
- integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==,
- }
- dev: false
-
- /merge-stream/2.0.0:
- resolution:
- {
- integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==,
- }
- dev: true
-
- /methods/1.1.2:
- resolution:
- {
- integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /mime-db/1.52.0:
- resolution:
- {
- integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /mime-types/2.1.35:
- resolution:
- {
- integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==,
- }
- engines: { node: ">= 0.6" }
- dependencies:
- mime-db: 1.52.0
- dev: false
-
- /mime/1.6.0:
- resolution:
- {
- integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==,
- }
- engines: { node: ">=4" }
- hasBin: true
- dev: false
-
- /mimic-fn/2.1.0:
- resolution:
- {
- integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==,
- }
- engines: { node: ">=6" }
- dev: true
-
- /mimic-fn/3.1.0:
- resolution:
- {
- integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /minimatch/3.1.2:
- resolution:
- {
- integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==,
- }
- dependencies:
- brace-expansion: 1.1.11
- dev: true
-
- /minimist/1.2.6:
- resolution:
- {
- integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==,
- }
- dev: true
-
- /ms/2.0.0:
- resolution:
- {
- integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==,
- }
- dev: false
-
- /ms/2.1.3:
- resolution:
- {
- integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==,
- }
- dev: false
-
- /ndjson/2.0.0:
- resolution:
- {
- integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==,
- }
- engines: { node: ">=10" }
- hasBin: true
- dependencies:
- json-stringify-safe: 5.0.1
- minimist: 1.2.6
- readable-stream: 3.6.0
- split2: 3.2.2
- through2: 4.0.2
- dev: true
-
- /negotiator/0.6.3:
- resolution:
- {
- integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /normalize-path/3.0.0:
- resolution:
- {
- integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==,
- }
- engines: { node: ">=0.10.0" }
- dev: true
-
- /npm-run-path/4.0.1:
- resolution:
- {
- integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==,
- }
- engines: { node: ">=8" }
- dependencies:
- path-key: 3.1.1
- dev: true
-
- /object-inspect/1.12.2:
- resolution:
- {
- integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==,
- }
- dev: false
-
- /on-finished/2.4.1:
- resolution:
- {
- integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==,
- }
- engines: { node: ">= 0.8" }
- dependencies:
- ee-first: 1.1.1
- dev: false
-
- /once/1.4.0:
- resolution:
- {
- integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==,
- }
- dependencies:
- wrappy: 1.0.2
- dev: true
-
- /onetime/5.1.2:
- resolution:
- {
- integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==,
- }
- engines: { node: ">=6" }
- dependencies:
- mimic-fn: 2.1.0
- dev: true
-
- /p-defer/1.0.0:
- resolution:
- {
- integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==,
- }
- engines: { node: ">=4" }
- dev: true
-
- /p-limit/3.1.0:
- resolution:
- {
- integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==,
- }
- engines: { node: ">=10" }
- dependencies:
- yocto-queue: 0.1.0
- dev: true
-
- /p-locate/5.0.0:
- resolution:
- {
- integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==,
- }
- engines: { node: ">=10" }
- dependencies:
- p-limit: 3.1.0
- dev: true
-
- /parse-json/5.2.0:
- resolution:
- {
- integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==,
- }
- engines: { node: ">=8" }
- dependencies:
- "@babel/code-frame": 7.18.6
- error-ex: 1.3.2
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
- dev: true
-
- /parseurl/1.3.3:
- resolution:
- {
- integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /path-exists/4.0.0:
- resolution:
- {
- integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /path-is-absolute/1.0.1:
- resolution:
- {
- integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==,
- }
- engines: { node: ">=0.10.0" }
- dev: true
-
- /path-key/3.1.1:
- resolution:
- {
- integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /path-name/1.0.0:
- resolution:
- {
- integrity: sha512-/dcAb5vMXH0f51yvMuSUqFpxUcA8JelbRmE5mW/p4CUJxrNgK24IkstnV7ENtg2IDGBOu6izKTG6eilbnbNKWQ==,
- }
- dev: true
-
- /path-to-regexp/0.1.7:
- resolution:
- {
- integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==,
- }
- dev: false
-
- /proxy-addr/2.0.7:
- resolution:
- {
- integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==,
- }
- engines: { node: ">= 0.10" }
- dependencies:
- forwarded: 0.2.0
- ipaddr.js: 1.9.1
- dev: false
-
- /qs/6.10.3:
- resolution:
- {
- integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==,
- }
- engines: { node: ">=0.6" }
- dependencies:
- side-channel: 1.0.4
- dev: false
-
- /range-parser/1.2.1:
- resolution:
- {
- integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==,
- }
- engines: { node: ">= 0.6" }
- dev: false
-
- /raw-body/2.5.1:
- resolution:
- {
- integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==,
- }
- engines: { node: ">= 0.8" }
- dependencies:
- bytes: 3.1.2
- http-errors: 2.0.0
- iconv-lite: 0.4.24
- unpipe: 1.0.0
- dev: false
-
- /read-yaml-file/2.1.0:
- resolution:
- {
- integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==,
- }
- engines: { node: ">=10.13" }
- dependencies:
- js-yaml: 4.1.0
- strip-bom: 4.0.0
- dev: true
-
- /readable-stream/3.6.0:
- resolution:
- {
- integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==,
- }
- engines: { node: ">= 6" }
- dependencies:
- inherits: 2.0.4
- string_decoder: 1.3.0
- util-deprecate: 1.0.2
- dev: true
-
- /rename-overwrite/4.0.2:
- resolution:
- {
- integrity: sha512-L1sgBgagVgOgb1Z6QZr1yJgSMHI4SXQqAH0l/UbeyHnLKxECvKIlyVEmBo4BqsCAZGg0SBSyjCh68lis5PgC7g==,
- }
- engines: { node: ">=12.10" }
- dependencies:
- "@zkochan/rimraf": 2.1.2
- dev: true
-
- /rfc4648/1.5.2:
- resolution:
- {
- integrity: sha512-tLOizhR6YGovrEBLatX1sdcuhoSCXddw3mqNVAcKxGJ+J0hFeJ+SjeWCv5UPA/WU3YzWPPuCVYgXBKZUPGpKtg==,
- }
- dev: true
-
- /rimraf/3.0.2:
- resolution:
- {
- integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==,
- }
- hasBin: true
- dependencies:
- glob: 7.2.3
- dev: true
-
- /safe-buffer/5.2.1:
- resolution:
- {
- integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==,
- }
- dev: false
-
- /safe-execa/0.1.2:
- resolution:
- {
- integrity: sha512-vdTshSQ2JsRCgT8eKZWNJIL26C6bVqy1SOmuCMlKHegVeo8KYRobRrefOdUq9OozSPUUiSxrylteeRmLOMFfWg==,
- }
- engines: { node: ">=12" }
- dependencies:
- "@zkochan/which": 2.0.3
- execa: 5.1.1
- path-name: 1.0.0
- dev: true
-
- /safer-buffer/2.1.2:
- resolution:
- {
- integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==,
- }
- dev: false
-
- /semver/7.3.7:
- resolution:
- {
- integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==,
- }
- engines: { node: ">=10" }
- hasBin: true
- dependencies:
- lru-cache: 6.0.0
- dev: true
-
- /send/0.18.0:
- resolution:
- {
- integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==,
- }
- engines: { node: ">= 0.8.0" }
- dependencies:
- debug: 2.6.9
- depd: 2.0.0
- destroy: 1.2.0
- encodeurl: 1.0.2
- escape-html: 1.0.3
- etag: 1.8.1
- fresh: 0.5.2
- http-errors: 2.0.0
- mime: 1.6.0
- ms: 2.1.3
- on-finished: 2.4.1
- range-parser: 1.2.1
- statuses: 2.0.1
- dev: false
-
- /serve-static/1.15.0:
- resolution:
- {
- integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==,
- }
- engines: { node: ">= 0.8.0" }
- dependencies:
- encodeurl: 1.0.2
- escape-html: 1.0.3
- parseurl: 1.3.3
- send: 0.18.0
- dev: false
-
- /setprototypeof/1.2.0:
- resolution:
- {
- integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==,
- }
- dev: false
-
- /shebang-command/2.0.0:
- resolution:
- {
- integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==,
- }
- engines: { node: ">=8" }
- dependencies:
- shebang-regex: 3.0.0
- dev: true
-
- /shebang-regex/3.0.0:
- resolution:
- {
- integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /side-channel/1.0.4:
- resolution:
- {
- integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==,
- }
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.1.2
- object-inspect: 1.12.2
- dev: false
-
- /signal-exit/3.0.7:
- resolution:
- {
- integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==,
- }
- dev: true
-
- /sort-keys/4.2.0:
- resolution:
- {
- integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==,
- }
- engines: { node: ">=8" }
- dependencies:
- is-plain-obj: 2.1.0
- dev: true
-
- /split2/3.2.2:
- resolution:
- {
- integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==,
- }
- dependencies:
- readable-stream: 3.6.0
- dev: true
-
- /statuses/2.0.1:
- resolution:
- {
- integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /string_decoder/1.3.0:
- resolution:
- {
- integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==,
- }
- dependencies:
- safe-buffer: 5.2.1
- dev: true
-
- /strip-bom/4.0.0:
- resolution:
- {
- integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==,
- }
- engines: { node: ">=8" }
- dev: true
-
- /strip-final-newline/2.0.0:
- resolution:
- {
- integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==,
- }
- engines: { node: ">=6" }
- dev: true
-
- /supports-color/5.5.0:
- resolution:
- {
- integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==,
- }
- engines: { node: ">=4" }
- dependencies:
- has-flag: 3.0.0
- dev: true
-
- /through2/4.0.2:
- resolution:
- {
- integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==,
- }
- dependencies:
- readable-stream: 3.6.0
- dev: true
-
- /toidentifier/1.0.1:
- resolution:
- {
- integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==,
- }
- engines: { node: ">=0.6" }
- dev: false
-
- /type-is/1.6.18:
- resolution:
- {
- integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==,
- }
- engines: { node: ">= 0.6" }
- dependencies:
- media-typer: 0.3.0
- mime-types: 2.1.35
- dev: false
-
- /typedarray-to-buffer/3.1.5:
- resolution:
- {
- integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==,
- }
- dependencies:
- is-typedarray: 1.0.0
- dev: true
-
- /unpipe/1.0.0:
- resolution:
- {
- integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /util-deprecate/1.0.2:
- resolution:
- {
- integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==,
- }
- dev: true
-
- /utils-merge/1.0.1:
- resolution:
- {
- integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==,
- }
- engines: { node: ">= 0.4.0" }
- dev: false
-
- /vary/1.1.2:
- resolution:
- {
- integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==,
- }
- engines: { node: ">= 0.8" }
- dev: false
-
- /which/2.0.2:
- resolution:
- {
- integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==,
- }
- engines: { node: ">= 8" }
- hasBin: true
- dependencies:
- isexe: 2.0.0
- dev: true
-
- /wrappy/1.0.2:
- resolution:
- {
- integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==,
- }
- dev: true
-
- /write-file-atomic/3.0.3:
- resolution:
- {
- integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==,
- }
- dependencies:
- imurmurhash: 0.1.4
- is-typedarray: 1.0.0
- signal-exit: 3.0.7
- typedarray-to-buffer: 3.1.5
- dev: true
-
- /write-yaml-file/4.2.0:
- resolution:
- {
- integrity: sha512-LwyucHy0uhWqbrOkh9cBluZBeNVxzHjDaE9mwepZG3n3ZlbM4v3ndrFw51zW/NXYFFqP+QWZ72ihtLWTh05e4Q==,
- }
- engines: { node: ">=10.13" }
- dependencies:
- js-yaml: 4.1.0
- write-file-atomic: 3.0.3
- dev: true
-
- /yallist/4.0.0:
- resolution:
- {
- integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==,
- }
- dev: true
-
- /yocto-queue/0.1.0:
- resolution:
- {
- integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==,
- }
- engines: { node: ">=10" }
- dev: true
diff --git a/cli/internal/lockfile/testdata/pnpm7-workspace.yaml b/cli/internal/lockfile/testdata/pnpm7-workspace.yaml
deleted file mode 100644
index 2f7b663..0000000
--- a/cli/internal/lockfile/testdata/pnpm7-workspace.yaml
+++ /dev/null
@@ -1,3445 +0,0 @@
-lockfileVersion: 5.4
-
-patchedDependencies:
- lodash@4.17.21:
- hash: ehchni3mpmovsvjxesffg2i5a4
- path: patches/lodash@4.17.21.patch
- underscore@1.13.4:
- hash: 3pbfs36izefyn2uycmknwkvuuy
- path: patches/underscore@1.13.4.patch
-
-importers:
- .:
- specifiers:
- eslint-config-custom: workspace:*
- prettier: latest
- turbo: latest
- devDependencies:
- eslint-config-custom: link:packages/eslint-config-custom
- prettier: 2.7.1
- turbo: 1.4.6
-
- apps/docs:
- specifiers:
- "@babel/core": ^7.0.0
- "@types/node": ^17.0.12
- "@types/react": 18.0.17
- dashboard-icons: github:peerigon/dashboard-icons
- eslint: 7.32.0
- eslint-config-custom: workspace:*
- next: 12.2.5
- next-transpile-modules: 9.0.0
- react: 18.2.0
- react-dom: 18.2.0
- tsconfig: workspace:*
- typescript: ^4.5.3
- ui: workspace:*
- underscore: ^1.13.4
- dependencies:
- dashboard-icons: github.com/peerigon/dashboard-icons/ce27ef933144e09cef3911025f3649040a8571b6
- next: 12.2.5_ir3quccc6i62x6qn6jjhyjjiey
- react: 18.2.0
- react-dom: 18.2.0_react@18.2.0
- ui: file:packages/ui
- underscore: 1.13.4_3pbfs36izefyn2uycmknwkvuuy
- devDependencies:
- "@babel/core": 7.19.1
- "@types/node": 17.0.45
- "@types/react": 18.0.17
- eslint: 7.32.0
- eslint-config-custom: link:../../packages/eslint-config-custom
- next-transpile-modules: 9.0.0
- tsconfig: link:../../packages/tsconfig
- typescript: 4.8.3
- dependenciesMeta:
- ui:
- injected: true
-
- apps/web:
- specifiers:
- "@babel/core": ^7.0.0
- "@types/node": ^17.0.12
- "@types/react": 18.0.17
- eslint: 7.32.0
- eslint-config-custom: workspace:*
- lodash: ^4.17.21
- next: 12.2.5
- next-transpile-modules: 9.0.0
- react: 18.2.0
- react-dom: 18.2.0
- tsconfig: workspace:*
- typescript: ^4.5.3
- ui: workspace:*
- dependencies:
- lodash: 4.17.21_ehchni3mpmovsvjxesffg2i5a4
- next: 12.2.5_ir3quccc6i62x6qn6jjhyjjiey
- react: 18.2.0
- react-dom: 18.2.0_react@18.2.0
- ui: link:../../packages/ui
- devDependencies:
- "@babel/core": 7.19.1
- "@types/node": 17.0.45
- "@types/react": 18.0.17
- eslint: 7.32.0
- eslint-config-custom: link:../../packages/eslint-config-custom
- next-transpile-modules: 9.0.0
- tsconfig: link:../../packages/tsconfig
- typescript: 4.8.3
-
- packages/eslint-config-custom:
- specifiers:
- eslint: ^7.23.0
- eslint-config-next: ^12.0.8
- eslint-config-prettier: ^8.3.0
- eslint-config-turbo: latest
- eslint-plugin-react: 7.31.7
- typescript: ^4.7.4
- dependencies:
- eslint: 7.32.0
- eslint-config-next: 12.3.0_dyxdave6dwjbccc5dgiifcmuza
- eslint-config-prettier: 8.5.0_eslint@7.32.0
- eslint-config-turbo: 0.0.3_eslint@7.32.0
- eslint-plugin-react: 7.31.7_eslint@7.32.0
- devDependencies:
- typescript: 4.8.3
-
- packages/tsconfig:
- specifiers: {}
-
- packages/ui:
- specifiers:
- "@types/react": ^18.0.17
- "@types/react-dom": ^18.0.6
- eslint: ^7.32.0
- eslint-config-custom: workspace:*
- react: ^18.2.0
- tsconfig: workspace:*
- typescript: ^4.5.2
- devDependencies:
- "@types/react": 18.0.20
- "@types/react-dom": 18.0.6
- eslint: 7.32.0
- eslint-config-custom: link:../eslint-config-custom
- react: 18.2.0
- tsconfig: link:../tsconfig
- typescript: 4.8.3
-
-packages:
- /@ampproject/remapping/2.2.0:
- resolution:
- {
- integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==,
- }
- engines: { node: ">=6.0.0" }
- dependencies:
- "@jridgewell/gen-mapping": 0.1.1
- "@jridgewell/trace-mapping": 0.3.15
-
- /@babel/code-frame/7.12.11:
- resolution:
- {
- integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==,
- }
- dependencies:
- "@babel/highlight": 7.18.6
-
- /@babel/code-frame/7.18.6:
- resolution:
- {
- integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/highlight": 7.18.6
-
- /@babel/compat-data/7.19.1:
- resolution:
- {
- integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==,
- }
- engines: { node: ">=6.9.0" }
-
- /@babel/core/7.19.1:
- resolution:
- {
- integrity: sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@ampproject/remapping": 2.2.0
- "@babel/code-frame": 7.18.6
- "@babel/generator": 7.19.0
- "@babel/helper-compilation-targets": 7.19.1_@babel+core@7.19.1
- "@babel/helper-module-transforms": 7.19.0
- "@babel/helpers": 7.19.0
- "@babel/parser": 7.19.1
- "@babel/template": 7.18.10
- "@babel/traverse": 7.19.1
- "@babel/types": 7.19.0
- convert-source-map: 1.8.0
- debug: 4.3.4
- gensync: 1.0.0-beta.2
- json5: 2.2.1
- semver: 6.3.0
- transitivePeerDependencies:
- - supports-color
-
- /@babel/generator/7.19.0:
- resolution:
- {
- integrity: sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/types": 7.19.0
- "@jridgewell/gen-mapping": 0.3.2
- jsesc: 2.5.2
-
- /@babel/helper-compilation-targets/7.19.1_@babel+core@7.19.1:
- resolution:
- {
- integrity: sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==,
- }
- engines: { node: ">=6.9.0" }
- peerDependencies:
- "@babel/core": ^7.0.0
- dependencies:
- "@babel/compat-data": 7.19.1
- "@babel/core": 7.19.1
- "@babel/helper-validator-option": 7.18.6
- browserslist: 4.21.3
- semver: 6.3.0
-
- /@babel/helper-environment-visitor/7.18.9:
- resolution:
- {
- integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==,
- }
- engines: { node: ">=6.9.0" }
-
- /@babel/helper-function-name/7.19.0:
- resolution:
- {
- integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/template": 7.18.10
- "@babel/types": 7.19.0
-
- /@babel/helper-hoist-variables/7.18.6:
- resolution:
- {
- integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/types": 7.19.0
-
- /@babel/helper-module-imports/7.18.6:
- resolution:
- {
- integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/types": 7.19.0
-
- /@babel/helper-module-transforms/7.19.0:
- resolution:
- {
- integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/helper-environment-visitor": 7.18.9
- "@babel/helper-module-imports": 7.18.6
- "@babel/helper-simple-access": 7.18.6
- "@babel/helper-split-export-declaration": 7.18.6
- "@babel/helper-validator-identifier": 7.19.1
- "@babel/template": 7.18.10
- "@babel/traverse": 7.19.1
- "@babel/types": 7.19.0
- transitivePeerDependencies:
- - supports-color
-
- /@babel/helper-simple-access/7.18.6:
- resolution:
- {
- integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/types": 7.19.0
-
- /@babel/helper-split-export-declaration/7.18.6:
- resolution:
- {
- integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/types": 7.19.0
-
- /@babel/helper-string-parser/7.18.10:
- resolution:
- {
- integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==,
- }
- engines: { node: ">=6.9.0" }
-
- /@babel/helper-validator-identifier/7.19.1:
- resolution:
- {
- integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==,
- }
- engines: { node: ">=6.9.0" }
-
- /@babel/helper-validator-option/7.18.6:
- resolution:
- {
- integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==,
- }
- engines: { node: ">=6.9.0" }
-
- /@babel/helpers/7.19.0:
- resolution:
- {
- integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/template": 7.18.10
- "@babel/traverse": 7.19.1
- "@babel/types": 7.19.0
- transitivePeerDependencies:
- - supports-color
-
- /@babel/highlight/7.18.6:
- resolution:
- {
- integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/helper-validator-identifier": 7.19.1
- chalk: 2.4.2
- js-tokens: 4.0.0
-
- /@babel/parser/7.19.1:
- resolution:
- {
- integrity: sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==,
- }
- engines: { node: ">=6.0.0" }
- hasBin: true
- dependencies:
- "@babel/types": 7.19.0
-
- /@babel/runtime-corejs3/7.19.1:
- resolution:
- {
- integrity: sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- core-js-pure: 3.25.1
- regenerator-runtime: 0.13.9
- dev: false
-
- /@babel/runtime/7.19.0:
- resolution:
- {
- integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- regenerator-runtime: 0.13.9
- dev: false
-
- /@babel/template/7.18.10:
- resolution:
- {
- integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/code-frame": 7.18.6
- "@babel/parser": 7.19.1
- "@babel/types": 7.19.0
-
- /@babel/traverse/7.19.1:
- resolution:
- {
- integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/code-frame": 7.18.6
- "@babel/generator": 7.19.0
- "@babel/helper-environment-visitor": 7.18.9
- "@babel/helper-function-name": 7.19.0
- "@babel/helper-hoist-variables": 7.18.6
- "@babel/helper-split-export-declaration": 7.18.6
- "@babel/parser": 7.19.1
- "@babel/types": 7.19.0
- debug: 4.3.4
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
-
- /@babel/types/7.19.0:
- resolution:
- {
- integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==,
- }
- engines: { node: ">=6.9.0" }
- dependencies:
- "@babel/helper-string-parser": 7.18.10
- "@babel/helper-validator-identifier": 7.19.1
- to-fast-properties: 2.0.0
-
- /@eslint/eslintrc/0.4.3:
- resolution:
- {
- integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==,
- }
- engines: { node: ^10.12.0 || >=12.0.0 }
- dependencies:
- ajv: 6.12.6
- debug: 4.3.4
- espree: 7.3.1
- globals: 13.17.0
- ignore: 4.0.6
- import-fresh: 3.3.0
- js-yaml: 3.14.1
- minimatch: 3.1.2
- strip-json-comments: 3.1.1
- transitivePeerDependencies:
- - supports-color
-
- /@humanwhocodes/config-array/0.5.0:
- resolution:
- {
- integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==,
- }
- engines: { node: ">=10.10.0" }
- dependencies:
- "@humanwhocodes/object-schema": 1.2.1
- debug: 4.3.4
- minimatch: 3.1.2
- transitivePeerDependencies:
- - supports-color
-
- /@humanwhocodes/object-schema/1.2.1:
- resolution:
- {
- integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==,
- }
-
- /@jridgewell/gen-mapping/0.1.1:
- resolution:
- {
- integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==,
- }
- engines: { node: ">=6.0.0" }
- dependencies:
- "@jridgewell/set-array": 1.1.2
- "@jridgewell/sourcemap-codec": 1.4.14
-
- /@jridgewell/gen-mapping/0.3.2:
- resolution:
- {
- integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==,
- }
- engines: { node: ">=6.0.0" }
- dependencies:
- "@jridgewell/set-array": 1.1.2
- "@jridgewell/sourcemap-codec": 1.4.14
- "@jridgewell/trace-mapping": 0.3.15
-
- /@jridgewell/resolve-uri/3.1.0:
- resolution:
- {
- integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==,
- }
- engines: { node: ">=6.0.0" }
-
- /@jridgewell/set-array/1.1.2:
- resolution:
- {
- integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==,
- }
- engines: { node: ">=6.0.0" }
-
- /@jridgewell/sourcemap-codec/1.4.14:
- resolution:
- {
- integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==,
- }
-
- /@jridgewell/trace-mapping/0.3.15:
- resolution:
- {
- integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==,
- }
- dependencies:
- "@jridgewell/resolve-uri": 3.1.0
- "@jridgewell/sourcemap-codec": 1.4.14
-
- /@next/env/12.2.5:
- resolution:
- {
- integrity: sha512-vLPLV3cpPGjUPT3PjgRj7e3nio9t6USkuew3JE/jMeon/9Mvp1WyR18v3iwnCuX7eUAm1HmAbJHHLAbcu/EJcw==,
- }
- dev: false
-
- /@next/eslint-plugin-next/12.3.0:
- resolution:
- {
- integrity: sha512-jVdq1qYTNDjUtulnE8/hkPv0pHILV4jMg5La99iaY/FFm20WxVnsAZtbNnMvlPbf8dc010oO304SX9yXbg5PAw==,
- }
- dependencies:
- glob: 7.1.7
- dev: false
-
- /@next/swc-android-arm-eabi/12.2.5:
- resolution:
- {
- integrity: sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==,
- }
- engines: { node: ">= 10" }
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-android-arm64/12.2.5:
- resolution:
- {
- integrity: sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==,
- }
- engines: { node: ">= 10" }
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-darwin-arm64/12.2.5:
- resolution:
- {
- integrity: sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==,
- }
- engines: { node: ">= 10" }
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-darwin-x64/12.2.5:
- resolution:
- {
- integrity: sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==,
- }
- engines: { node: ">= 10" }
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-freebsd-x64/12.2.5:
- resolution:
- {
- integrity: sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==,
- }
- engines: { node: ">= 10" }
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-linux-arm-gnueabihf/12.2.5:
- resolution:
- {
- integrity: sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==,
- }
- engines: { node: ">= 10" }
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-linux-arm64-gnu/12.2.5:
- resolution:
- {
- integrity: sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==,
- }
- engines: { node: ">= 10" }
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-linux-arm64-musl/12.2.5:
- resolution:
- {
- integrity: sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==,
- }
- engines: { node: ">= 10" }
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-linux-x64-gnu/12.2.5:
- resolution:
- {
- integrity: sha512-0szyAo8jMCClkjNK0hknjhmAngUppoRekW6OAezbEYwHXN/VNtsXbfzgYOqjKWxEx3OoAzrT3jLwAF0HdX2MEw==,
- }
- engines: { node: ">= 10" }
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-linux-x64-musl/12.2.5:
- resolution:
- {
- integrity: sha512-zg/Y6oBar1yVnW6Il1I/08/2ukWtOG6s3acdJdEyIdsCzyQi4RLxbbhkD/EGQyhqBvd3QrC6ZXQEXighQUAZ0g==,
- }
- engines: { node: ">= 10" }
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-win32-arm64-msvc/12.2.5:
- resolution:
- {
- integrity: sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==,
- }
- engines: { node: ">= 10" }
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-win32-ia32-msvc/12.2.5:
- resolution:
- {
- integrity: sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==,
- }
- engines: { node: ">= 10" }
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: false
- optional: true
-
- /@next/swc-win32-x64-msvc/12.2.5:
- resolution:
- {
- integrity: sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==,
- }
- engines: { node: ">= 10" }
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: false
- optional: true
-
- /@nodelib/fs.scandir/2.1.5:
- resolution:
- {
- integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==,
- }
- engines: { node: ">= 8" }
- dependencies:
- "@nodelib/fs.stat": 2.0.5
- run-parallel: 1.2.0
- dev: false
-
- /@nodelib/fs.stat/2.0.5:
- resolution:
- {
- integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==,
- }
- engines: { node: ">= 8" }
- dev: false
-
- /@nodelib/fs.walk/1.2.8:
- resolution:
- {
- integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==,
- }
- engines: { node: ">= 8" }
- dependencies:
- "@nodelib/fs.scandir": 2.1.5
- fastq: 1.13.0
- dev: false
-
- /@rushstack/eslint-patch/1.1.4:
- resolution:
- {
- integrity: sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==,
- }
- dev: false
-
- /@swc/helpers/0.4.3:
- resolution:
- {
- integrity: sha512-6JrF+fdUK2zbGpJIlN7G3v966PQjyx/dPt1T9km2wj+EUBqgrxCk3uX4Kct16MIm9gGxfKRcfax2hVf5jvlTzA==,
- }
- dependencies:
- tslib: 2.4.0
- dev: false
-
- /@types/json5/0.0.29:
- resolution:
- {
- integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==,
- }
- dev: false
-
- /@types/node/17.0.45:
- resolution:
- {
- integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==,
- }
- dev: true
-
- /@types/prop-types/15.7.5:
- resolution:
- {
- integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==,
- }
- dev: true
-
- /@types/react-dom/18.0.6:
- resolution:
- {
- integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==,
- }
- dependencies:
- "@types/react": 18.0.20
- dev: true
-
- /@types/react/18.0.17:
- resolution:
- {
- integrity: sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==,
- }
- dependencies:
- "@types/prop-types": 15.7.5
- "@types/scheduler": 0.16.2
- csstype: 3.1.1
- dev: true
-
- /@types/react/18.0.20:
- resolution:
- {
- integrity: sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==,
- }
- dependencies:
- "@types/prop-types": 15.7.5
- "@types/scheduler": 0.16.2
- csstype: 3.1.1
- dev: true
-
- /@types/scheduler/0.16.2:
- resolution:
- {
- integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==,
- }
- dev: true
-
- /@typescript-eslint/parser/5.37.0_dyxdave6dwjbccc5dgiifcmuza:
- resolution:
- {
- integrity: sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==,
- }
- engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
- peerDependencies:
- eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
- typescript: "*"
- peerDependenciesMeta:
- typescript:
- optional: true
- dependencies:
- "@typescript-eslint/scope-manager": 5.37.0
- "@typescript-eslint/types": 5.37.0
- "@typescript-eslint/typescript-estree": 5.37.0_typescript@4.8.3
- debug: 4.3.4
- eslint: 7.32.0
- typescript: 4.8.3
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /@typescript-eslint/scope-manager/5.37.0:
- resolution:
- {
- integrity: sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==,
- }
- engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
- dependencies:
- "@typescript-eslint/types": 5.37.0
- "@typescript-eslint/visitor-keys": 5.37.0
- dev: false
-
- /@typescript-eslint/types/5.37.0:
- resolution:
- {
- integrity: sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==,
- }
- engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
- dev: false
-
- /@typescript-eslint/typescript-estree/5.37.0_typescript@4.8.3:
- resolution:
- {
- integrity: sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==,
- }
- engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
- peerDependencies:
- typescript: "*"
- peerDependenciesMeta:
- typescript:
- optional: true
- dependencies:
- "@typescript-eslint/types": 5.37.0
- "@typescript-eslint/visitor-keys": 5.37.0
- debug: 4.3.4
- globby: 11.1.0
- is-glob: 4.0.3
- semver: 7.3.7
- tsutils: 3.21.0_typescript@4.8.3
- typescript: 4.8.3
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /@typescript-eslint/visitor-keys/5.37.0:
- resolution:
- {
- integrity: sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==,
- }
- engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
- dependencies:
- "@typescript-eslint/types": 5.37.0
- eslint-visitor-keys: 3.3.0
- dev: false
-
- /acorn-jsx/5.3.2_acorn@7.4.1:
- resolution:
- {
- integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==,
- }
- peerDependencies:
- acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- dependencies:
- acorn: 7.4.1
-
- /acorn/7.4.1:
- resolution:
- {
- integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==,
- }
- engines: { node: ">=0.4.0" }
- hasBin: true
-
- /ajv/6.12.6:
- resolution:
- {
- integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==,
- }
- dependencies:
- fast-deep-equal: 3.1.3
- fast-json-stable-stringify: 2.1.0
- json-schema-traverse: 0.4.1
- uri-js: 4.4.1
-
- /ajv/8.11.0:
- resolution:
- {
- integrity: sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==,
- }
- dependencies:
- fast-deep-equal: 3.1.3
- json-schema-traverse: 1.0.0
- require-from-string: 2.0.2
- uri-js: 4.4.1
-
- /ansi-colors/4.1.3:
- resolution:
- {
- integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==,
- }
- engines: { node: ">=6" }
-
- /ansi-regex/5.0.1:
- resolution:
- {
- integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==,
- }
- engines: { node: ">=8" }
-
- /ansi-styles/3.2.1:
- resolution:
- {
- integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==,
- }
- engines: { node: ">=4" }
- dependencies:
- color-convert: 1.9.3
-
- /ansi-styles/4.3.0:
- resolution:
- {
- integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==,
- }
- engines: { node: ">=8" }
- dependencies:
- color-convert: 2.0.1
-
- /argparse/1.0.10:
- resolution:
- {
- integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==,
- }
- dependencies:
- sprintf-js: 1.0.3
-
- /aria-query/4.2.2:
- resolution:
- {
- integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==,
- }
- engines: { node: ">=6.0" }
- dependencies:
- "@babel/runtime": 7.19.0
- "@babel/runtime-corejs3": 7.19.1
- dev: false
-
- /array-includes/3.1.5:
- resolution:
- {
- integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- get-intrinsic: 1.1.3
- is-string: 1.0.7
- dev: false
-
- /array-union/2.1.0:
- resolution:
- {
- integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==,
- }
- engines: { node: ">=8" }
- dev: false
-
- /array.prototype.flat/1.3.0:
- resolution:
- {
- integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- es-shim-unscopables: 1.0.0
- dev: false
-
- /array.prototype.flatmap/1.3.0:
- resolution:
- {
- integrity: sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- es-shim-unscopables: 1.0.0
- dev: false
-
- /ast-types-flow/0.0.7:
- resolution:
- {
- integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==,
- }
- dev: false
-
- /astral-regex/2.0.0:
- resolution:
- {
- integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==,
- }
- engines: { node: ">=8" }
-
- /axe-core/4.4.3:
- resolution:
- {
- integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==,
- }
- engines: { node: ">=4" }
- dev: false
-
- /axobject-query/2.2.0:
- resolution:
- {
- integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==,
- }
- dev: false
-
- /balanced-match/1.0.2:
- resolution:
- {
- integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==,
- }
-
- /brace-expansion/1.1.11:
- resolution:
- {
- integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==,
- }
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
-
- /braces/3.0.2:
- resolution:
- {
- integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==,
- }
- engines: { node: ">=8" }
- dependencies:
- fill-range: 7.0.1
- dev: false
-
- /browserslist/4.21.3:
- resolution:
- {
- integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==,
- }
- engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
- hasBin: true
- dependencies:
- caniuse-lite: 1.0.30001399
- electron-to-chromium: 1.4.249
- node-releases: 2.0.6
- update-browserslist-db: 1.0.9_browserslist@4.21.3
-
- /call-bind/1.0.2:
- resolution:
- {
- integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==,
- }
- dependencies:
- function-bind: 1.1.1
- get-intrinsic: 1.1.3
- dev: false
-
- /callsites/3.1.0:
- resolution:
- {
- integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==,
- }
- engines: { node: ">=6" }
-
- /caniuse-lite/1.0.30001399:
- resolution:
- {
- integrity: sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA==,
- }
-
- /chalk/2.4.2:
- resolution:
- {
- integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==,
- }
- engines: { node: ">=4" }
- dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
-
- /chalk/4.1.2:
- resolution:
- {
- integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==,
- }
- engines: { node: ">=10" }
- dependencies:
- ansi-styles: 4.3.0
- supports-color: 7.2.0
-
- /color-convert/1.9.3:
- resolution:
- {
- integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==,
- }
- dependencies:
- color-name: 1.1.3
-
- /color-convert/2.0.1:
- resolution:
- {
- integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==,
- }
- engines: { node: ">=7.0.0" }
- dependencies:
- color-name: 1.1.4
-
- /color-name/1.1.3:
- resolution:
- {
- integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==,
- }
-
- /color-name/1.1.4:
- resolution:
- {
- integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==,
- }
-
- /concat-map/0.0.1:
- resolution:
- {
- integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==,
- }
-
- /convert-source-map/1.8.0:
- resolution:
- {
- integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==,
- }
- dependencies:
- safe-buffer: 5.1.2
-
- /core-js-pure/3.25.1:
- resolution:
- {
- integrity: sha512-7Fr74bliUDdeJCBMxkkIuQ4xfxn/SwrVg+HkJUAoNEXVqYLv55l6Af0dJ5Lq2YBUW9yKqSkLXaS5SYPK6MGa/A==,
- }
- requiresBuild: true
- dev: false
-
- /cross-spawn/7.0.3:
- resolution:
- {
- integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==,
- }
- engines: { node: ">= 8" }
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
- /csstype/3.1.1:
- resolution:
- {
- integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==,
- }
- dev: true
-
- /damerau-levenshtein/1.0.8:
- resolution:
- {
- integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==,
- }
- dev: false
-
- /debug/2.6.9:
- resolution:
- {
- integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==,
- }
- peerDependencies:
- supports-color: "*"
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.0.0
- dev: false
-
- /debug/3.2.7:
- resolution:
- {
- integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==,
- }
- peerDependencies:
- supports-color: "*"
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.3
- dev: false
-
- /debug/4.3.4:
- resolution:
- {
- integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==,
- }
- engines: { node: ">=6.0" }
- peerDependencies:
- supports-color: "*"
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
-
- /deep-is/0.1.4:
- resolution:
- {
- integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==,
- }
-
- /define-properties/1.1.4:
- resolution:
- {
- integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- has-property-descriptors: 1.0.0
- object-keys: 1.1.1
- dev: false
-
- /dir-glob/3.0.1:
- resolution:
- {
- integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==,
- }
- engines: { node: ">=8" }
- dependencies:
- path-type: 4.0.0
- dev: false
-
- /doctrine/2.1.0:
- resolution:
- {
- integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- esutils: 2.0.3
- dev: false
-
- /doctrine/3.0.0:
- resolution:
- {
- integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==,
- }
- engines: { node: ">=6.0.0" }
- dependencies:
- esutils: 2.0.3
-
- /electron-to-chromium/1.4.249:
- resolution:
- {
- integrity: sha512-GMCxR3p2HQvIw47A599crTKYZprqihoBL4lDSAUmr7IYekXFK5t/WgEBrGJDCa2HWIZFQEkGuMqPCi05ceYqPQ==,
- }
-
- /emoji-regex/8.0.0:
- resolution:
- {
- integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==,
- }
-
- /emoji-regex/9.2.2:
- resolution:
- {
- integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==,
- }
- dev: false
-
- /enhanced-resolve/5.10.0:
- resolution:
- {
- integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==,
- }
- engines: { node: ">=10.13.0" }
- dependencies:
- graceful-fs: 4.2.10
- tapable: 2.2.1
- dev: true
-
- /enquirer/2.3.6:
- resolution:
- {
- integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==,
- }
- engines: { node: ">=8.6" }
- dependencies:
- ansi-colors: 4.1.3
-
- /es-abstract/1.20.2:
- resolution:
- {
- integrity: sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- es-to-primitive: 1.2.1
- function-bind: 1.1.1
- function.prototype.name: 1.1.5
- get-intrinsic: 1.1.3
- get-symbol-description: 1.0.0
- has: 1.0.3
- has-property-descriptors: 1.0.0
- has-symbols: 1.0.3
- internal-slot: 1.0.3
- is-callable: 1.2.5
- is-negative-zero: 2.0.2
- is-regex: 1.1.4
- is-shared-array-buffer: 1.0.2
- is-string: 1.0.7
- is-weakref: 1.0.2
- object-inspect: 1.12.2
- object-keys: 1.1.1
- object.assign: 4.1.4
- regexp.prototype.flags: 1.4.3
- string.prototype.trimend: 1.0.5
- string.prototype.trimstart: 1.0.5
- unbox-primitive: 1.0.2
- dev: false
-
- /es-shim-unscopables/1.0.0:
- resolution:
- {
- integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==,
- }
- dependencies:
- has: 1.0.3
- dev: false
-
- /es-to-primitive/1.2.1:
- resolution:
- {
- integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- is-callable: 1.2.5
- is-date-object: 1.0.5
- is-symbol: 1.0.4
- dev: false
-
- /escalade/3.1.1:
- resolution:
- {
- integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==,
- }
- engines: { node: ">=6" }
-
- /escape-string-regexp/1.0.5:
- resolution:
- {
- integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==,
- }
- engines: { node: ">=0.8.0" }
-
- /escape-string-regexp/4.0.0:
- resolution:
- {
- integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==,
- }
- engines: { node: ">=10" }
-
- /eslint-config-next/12.3.0_dyxdave6dwjbccc5dgiifcmuza:
- resolution:
- {
- integrity: sha512-guHSkNyKnTBB8HU35COgAMeMV0E026BiYRYvyEVVaTOeFcnU3i1EI8/Da0Rl7H3Sgua5FEvoA0vYd2s8kdIUXg==,
- }
- peerDependencies:
- eslint: ^7.23.0 || ^8.0.0
- typescript: ">=3.3.1"
- peerDependenciesMeta:
- typescript:
- optional: true
- dependencies:
- "@next/eslint-plugin-next": 12.3.0
- "@rushstack/eslint-patch": 1.1.4
- "@typescript-eslint/parser": 5.37.0_dyxdave6dwjbccc5dgiifcmuza
- eslint: 7.32.0
- eslint-import-resolver-node: 0.3.6
- eslint-import-resolver-typescript: 2.7.1_hpmu7kn6tcn2vnxpfzvv33bxmy
- eslint-plugin-import: 2.26.0_xag76ci373f5hzfwsxolrbhy4a
- eslint-plugin-jsx-a11y: 6.6.1_eslint@7.32.0
- eslint-plugin-react: 7.31.7_eslint@7.32.0
- eslint-plugin-react-hooks: 4.6.0_eslint@7.32.0
- typescript: 4.8.3
- transitivePeerDependencies:
- - eslint-import-resolver-webpack
- - supports-color
- dev: false
-
- /eslint-config-prettier/8.5.0_eslint@7.32.0:
- resolution:
- {
- integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==,
- }
- hasBin: true
- peerDependencies:
- eslint: ">=7.0.0"
- dependencies:
- eslint: 7.32.0
- dev: false
-
- /eslint-config-turbo/0.0.3_eslint@7.32.0:
- resolution:
- {
- integrity: sha512-hK5MlxDugUWZV9ZKcyfNwLXrlMuM2wPgAUk51cUFBC3nXRCVmCA9uSRFBZsyAIurN1wH7mS7G1NBo5F8VkF7lQ==,
- }
- peerDependencies:
- eslint: ^7.23.0 || ^8.0.0
- dependencies:
- eslint: 7.32.0
- eslint-plugin-turbo: 0.0.3_eslint@7.32.0
- dev: false
-
- /eslint-import-resolver-node/0.3.6:
- resolution:
- {
- integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==,
- }
- dependencies:
- debug: 3.2.7
- resolve: 1.22.1
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /eslint-import-resolver-typescript/2.7.1_hpmu7kn6tcn2vnxpfzvv33bxmy:
- resolution:
- {
- integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==,
- }
- engines: { node: ">=4" }
- peerDependencies:
- eslint: "*"
- eslint-plugin-import: "*"
- dependencies:
- debug: 4.3.4
- eslint: 7.32.0
- eslint-plugin-import: 2.26.0_xag76ci373f5hzfwsxolrbhy4a
- glob: 7.2.3
- is-glob: 4.0.3
- resolve: 1.22.1
- tsconfig-paths: 3.14.1
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /eslint-module-utils/2.7.4_qk4u2ghovatg5ueomqmuln4u2e:
- resolution:
- {
- integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==,
- }
- engines: { node: ">=4" }
- peerDependencies:
- "@typescript-eslint/parser": "*"
- eslint: "*"
- eslint-import-resolver-node: "*"
- eslint-import-resolver-typescript: "*"
- eslint-import-resolver-webpack: "*"
- peerDependenciesMeta:
- "@typescript-eslint/parser":
- optional: true
- eslint:
- optional: true
- eslint-import-resolver-node:
- optional: true
- eslint-import-resolver-typescript:
- optional: true
- eslint-import-resolver-webpack:
- optional: true
- dependencies:
- "@typescript-eslint/parser": 5.37.0_dyxdave6dwjbccc5dgiifcmuza
- debug: 3.2.7
- eslint: 7.32.0
- eslint-import-resolver-node: 0.3.6
- eslint-import-resolver-typescript: 2.7.1_hpmu7kn6tcn2vnxpfzvv33bxmy
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /eslint-plugin-import/2.26.0_xag76ci373f5hzfwsxolrbhy4a:
- resolution:
- {
- integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==,
- }
- engines: { node: ">=4" }
- peerDependencies:
- "@typescript-eslint/parser": "*"
- eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
- peerDependenciesMeta:
- "@typescript-eslint/parser":
- optional: true
- dependencies:
- "@typescript-eslint/parser": 5.37.0_dyxdave6dwjbccc5dgiifcmuza
- array-includes: 3.1.5
- array.prototype.flat: 1.3.0
- debug: 2.6.9
- doctrine: 2.1.0
- eslint: 7.32.0
- eslint-import-resolver-node: 0.3.6
- eslint-module-utils: 2.7.4_qk4u2ghovatg5ueomqmuln4u2e
- has: 1.0.3
- is-core-module: 2.10.0
- is-glob: 4.0.3
- minimatch: 3.1.2
- object.values: 1.1.5
- resolve: 1.22.1
- tsconfig-paths: 3.14.1
- transitivePeerDependencies:
- - eslint-import-resolver-typescript
- - eslint-import-resolver-webpack
- - supports-color
- dev: false
-
- /eslint-plugin-jsx-a11y/6.6.1_eslint@7.32.0:
- resolution:
- {
- integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==,
- }
- engines: { node: ">=4.0" }
- peerDependencies:
- eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
- dependencies:
- "@babel/runtime": 7.19.0
- aria-query: 4.2.2
- array-includes: 3.1.5
- ast-types-flow: 0.0.7
- axe-core: 4.4.3
- axobject-query: 2.2.0
- damerau-levenshtein: 1.0.8
- emoji-regex: 9.2.2
- eslint: 7.32.0
- has: 1.0.3
- jsx-ast-utils: 3.3.3
- language-tags: 1.0.5
- minimatch: 3.1.2
- semver: 6.3.0
- dev: false
-
- /eslint-plugin-react-hooks/4.6.0_eslint@7.32.0:
- resolution:
- {
- integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==,
- }
- engines: { node: ">=10" }
- peerDependencies:
- eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
- dependencies:
- eslint: 7.32.0
- dev: false
-
- /eslint-plugin-react/7.31.7_eslint@7.32.0:
- resolution:
- {
- integrity: sha512-8NldBTeYp/kQoTV1uT0XF6HcmDqbgZ0lNPkN0wlRw8DJKXEnaWu+oh/6gt3xIhzvQ35wB2Y545fJhIbJSZ2NNw==,
- }
- engines: { node: ">=4" }
- peerDependencies:
- eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
- dependencies:
- array-includes: 3.1.5
- array.prototype.flatmap: 1.3.0
- doctrine: 2.1.0
- eslint: 7.32.0
- estraverse: 5.3.0
- jsx-ast-utils: 3.3.3
- minimatch: 3.1.2
- object.entries: 1.1.5
- object.fromentries: 2.0.5
- object.hasown: 1.1.1
- object.values: 1.1.5
- prop-types: 15.8.1
- resolve: 2.0.0-next.4
- semver: 6.3.0
- string.prototype.matchall: 4.0.7
- dev: false
-
- /eslint-plugin-turbo/0.0.3_eslint@7.32.0:
- resolution:
- {
- integrity: sha512-QjidATGxWtaB9QUrD3NocUySmsgWKZlBMFlw4kX2IIjRLAxMPwukk90h3ZTaNXyRHuaQsrEgh7hhlCZoxP0TTw==,
- }
- peerDependencies:
- eslint: ^7.23.0 || ^8.0.0
- dependencies:
- eslint: 7.32.0
- dev: false
-
- /eslint-scope/5.1.1:
- resolution:
- {
- integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==,
- }
- engines: { node: ">=8.0.0" }
- dependencies:
- esrecurse: 4.3.0
- estraverse: 4.3.0
-
- /eslint-utils/2.1.0:
- resolution:
- {
- integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==,
- }
- engines: { node: ">=6" }
- dependencies:
- eslint-visitor-keys: 1.3.0
-
- /eslint-visitor-keys/1.3.0:
- resolution:
- {
- integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==,
- }
- engines: { node: ">=4" }
-
- /eslint-visitor-keys/2.1.0:
- resolution:
- {
- integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==,
- }
- engines: { node: ">=10" }
-
- /eslint-visitor-keys/3.3.0:
- resolution:
- {
- integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==,
- }
- engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
- dev: false
-
- /eslint/7.32.0:
- resolution:
- {
- integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==,
- }
- engines: { node: ^10.12.0 || >=12.0.0 }
- hasBin: true
- dependencies:
- "@babel/code-frame": 7.12.11
- "@eslint/eslintrc": 0.4.3
- "@humanwhocodes/config-array": 0.5.0
- ajv: 6.12.6
- chalk: 4.1.2
- cross-spawn: 7.0.3
- debug: 4.3.4
- doctrine: 3.0.0
- enquirer: 2.3.6
- escape-string-regexp: 4.0.0
- eslint-scope: 5.1.1
- eslint-utils: 2.1.0
- eslint-visitor-keys: 2.1.0
- espree: 7.3.1
- esquery: 1.4.0
- esutils: 2.0.3
- fast-deep-equal: 3.1.3
- file-entry-cache: 6.0.1
- functional-red-black-tree: 1.0.1
- glob-parent: 5.1.2
- globals: 13.17.0
- ignore: 4.0.6
- import-fresh: 3.3.0
- imurmurhash: 0.1.4
- is-glob: 4.0.3
- js-yaml: 3.14.1
- json-stable-stringify-without-jsonify: 1.0.1
- levn: 0.4.1
- lodash.merge: 4.6.2
- minimatch: 3.1.2
- natural-compare: 1.4.0
- optionator: 0.9.1
- progress: 2.0.3
- regexpp: 3.2.0
- semver: 7.3.7
- strip-ansi: 6.0.1
- strip-json-comments: 3.1.1
- table: 6.8.0
- text-table: 0.2.0
- v8-compile-cache: 2.3.0
- transitivePeerDependencies:
- - supports-color
-
- /espree/7.3.1:
- resolution:
- {
- integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==,
- }
- engines: { node: ^10.12.0 || >=12.0.0 }
- dependencies:
- acorn: 7.4.1
- acorn-jsx: 5.3.2_acorn@7.4.1
- eslint-visitor-keys: 1.3.0
-
- /esprima/4.0.1:
- resolution:
- {
- integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==,
- }
- engines: { node: ">=4" }
- hasBin: true
-
- /esquery/1.4.0:
- resolution:
- {
- integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==,
- }
- engines: { node: ">=0.10" }
- dependencies:
- estraverse: 5.3.0
-
- /esrecurse/4.3.0:
- resolution:
- {
- integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==,
- }
- engines: { node: ">=4.0" }
- dependencies:
- estraverse: 5.3.0
-
- /estraverse/4.3.0:
- resolution:
- {
- integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==,
- }
- engines: { node: ">=4.0" }
-
- /estraverse/5.3.0:
- resolution:
- {
- integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==,
- }
- engines: { node: ">=4.0" }
-
- /esutils/2.0.3:
- resolution:
- {
- integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==,
- }
- engines: { node: ">=0.10.0" }
-
- /fast-deep-equal/3.1.3:
- resolution:
- {
- integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
- }
-
- /fast-glob/3.2.12:
- resolution:
- {
- integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==,
- }
- engines: { node: ">=8.6.0" }
- dependencies:
- "@nodelib/fs.stat": 2.0.5
- "@nodelib/fs.walk": 1.2.8
- glob-parent: 5.1.2
- merge2: 1.4.1
- micromatch: 4.0.5
- dev: false
-
- /fast-json-stable-stringify/2.1.0:
- resolution:
- {
- integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==,
- }
-
- /fast-levenshtein/2.0.6:
- resolution:
- {
- integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==,
- }
-
- /fastq/1.13.0:
- resolution:
- {
- integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==,
- }
- dependencies:
- reusify: 1.0.4
- dev: false
-
- /file-entry-cache/6.0.1:
- resolution:
- {
- integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==,
- }
- engines: { node: ^10.12.0 || >=12.0.0 }
- dependencies:
- flat-cache: 3.0.4
-
- /fill-range/7.0.1:
- resolution:
- {
- integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==,
- }
- engines: { node: ">=8" }
- dependencies:
- to-regex-range: 5.0.1
- dev: false
-
- /flat-cache/3.0.4:
- resolution:
- {
- integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==,
- }
- engines: { node: ^10.12.0 || >=12.0.0 }
- dependencies:
- flatted: 3.2.7
- rimraf: 3.0.2
-
- /flatted/3.2.7:
- resolution:
- {
- integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==,
- }
-
- /fs.realpath/1.0.0:
- resolution:
- {
- integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==,
- }
-
- /function-bind/1.1.1:
- resolution:
- {
- integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==,
- }
- dev: false
-
- /function.prototype.name/1.1.5:
- resolution:
- {
- integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- functions-have-names: 1.2.3
- dev: false
-
- /functional-red-black-tree/1.0.1:
- resolution:
- {
- integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==,
- }
-
- /functions-have-names/1.2.3:
- resolution:
- {
- integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==,
- }
- dev: false
-
- /gensync/1.0.0-beta.2:
- resolution:
- {
- integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==,
- }
- engines: { node: ">=6.9.0" }
-
- /get-intrinsic/1.1.3:
- resolution:
- {
- integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==,
- }
- dependencies:
- function-bind: 1.1.1
- has: 1.0.3
- has-symbols: 1.0.3
- dev: false
-
- /get-symbol-description/1.0.0:
- resolution:
- {
- integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.1.3
- dev: false
-
- /glob-parent/5.1.2:
- resolution:
- {
- integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==,
- }
- engines: { node: ">= 6" }
- dependencies:
- is-glob: 4.0.3
-
- /glob/7.1.7:
- resolution:
- {
- integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==,
- }
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
- dev: false
-
- /glob/7.2.3:
- resolution:
- {
- integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==,
- }
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
-
- /globals/11.12.0:
- resolution:
- {
- integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==,
- }
- engines: { node: ">=4" }
-
- /globals/13.17.0:
- resolution:
- {
- integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==,
- }
- engines: { node: ">=8" }
- dependencies:
- type-fest: 0.20.2
-
- /globby/11.1.0:
- resolution:
- {
- integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==,
- }
- engines: { node: ">=10" }
- dependencies:
- array-union: 2.1.0
- dir-glob: 3.0.1
- fast-glob: 3.2.12
- ignore: 5.2.0
- merge2: 1.4.1
- slash: 3.0.0
- dev: false
-
- /graceful-fs/4.2.10:
- resolution:
- {
- integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==,
- }
- dev: true
-
- /has-bigints/1.0.2:
- resolution:
- {
- integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==,
- }
- dev: false
-
- /has-flag/3.0.0:
- resolution:
- {
- integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==,
- }
- engines: { node: ">=4" }
-
- /has-flag/4.0.0:
- resolution:
- {
- integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==,
- }
- engines: { node: ">=8" }
-
- /has-property-descriptors/1.0.0:
- resolution:
- {
- integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==,
- }
- dependencies:
- get-intrinsic: 1.1.3
- dev: false
-
- /has-symbols/1.0.3:
- resolution:
- {
- integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==,
- }
- engines: { node: ">= 0.4" }
- dev: false
-
- /has-tostringtag/1.0.0:
- resolution:
- {
- integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- has-symbols: 1.0.3
- dev: false
-
- /has/1.0.3:
- resolution:
- {
- integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==,
- }
- engines: { node: ">= 0.4.0" }
- dependencies:
- function-bind: 1.1.1
- dev: false
-
- /ignore/4.0.6:
- resolution:
- {
- integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==,
- }
- engines: { node: ">= 4" }
-
- /ignore/5.2.0:
- resolution:
- {
- integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==,
- }
- engines: { node: ">= 4" }
- dev: false
-
- /import-fresh/3.3.0:
- resolution:
- {
- integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==,
- }
- engines: { node: ">=6" }
- dependencies:
- parent-module: 1.0.1
- resolve-from: 4.0.0
-
- /imurmurhash/0.1.4:
- resolution:
- {
- integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==,
- }
- engines: { node: ">=0.8.19" }
-
- /inflight/1.0.6:
- resolution:
- {
- integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==,
- }
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
-
- /inherits/2.0.4:
- resolution:
- {
- integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==,
- }
-
- /internal-slot/1.0.3:
- resolution:
- {
- integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- get-intrinsic: 1.1.3
- has: 1.0.3
- side-channel: 1.0.4
- dev: false
-
- /is-bigint/1.0.4:
- resolution:
- {
- integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==,
- }
- dependencies:
- has-bigints: 1.0.2
- dev: false
-
- /is-boolean-object/1.1.2:
- resolution:
- {
- integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
- dev: false
-
- /is-callable/1.2.5:
- resolution:
- {
- integrity: sha512-ZIWRujF6MvYGkEuHMYtFRkL2wAtFw89EHfKlXrkPkjQZZRWeh9L1q3SV13NIfHnqxugjLvAOkEHx9mb1zcMnEw==,
- }
- engines: { node: ">= 0.4" }
- dev: false
-
- /is-core-module/2.10.0:
- resolution:
- {
- integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==,
- }
- dependencies:
- has: 1.0.3
- dev: false
-
- /is-date-object/1.0.5:
- resolution:
- {
- integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- has-tostringtag: 1.0.0
- dev: false
-
- /is-extglob/2.1.1:
- resolution:
- {
- integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==,
- }
- engines: { node: ">=0.10.0" }
-
- /is-fullwidth-code-point/3.0.0:
- resolution:
- {
- integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==,
- }
- engines: { node: ">=8" }
-
- /is-glob/4.0.3:
- resolution:
- {
- integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- is-extglob: 2.1.1
-
- /is-negative-zero/2.0.2:
- resolution:
- {
- integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==,
- }
- engines: { node: ">= 0.4" }
- dev: false
-
- /is-number-object/1.0.7:
- resolution:
- {
- integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- has-tostringtag: 1.0.0
- dev: false
-
- /is-number/7.0.0:
- resolution:
- {
- integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==,
- }
- engines: { node: ">=0.12.0" }
- dev: false
-
- /is-regex/1.1.4:
- resolution:
- {
- integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
- dev: false
-
- /is-shared-array-buffer/1.0.2:
- resolution:
- {
- integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==,
- }
- dependencies:
- call-bind: 1.0.2
- dev: false
-
- /is-string/1.0.7:
- resolution:
- {
- integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- has-tostringtag: 1.0.0
- dev: false
-
- /is-symbol/1.0.4:
- resolution:
- {
- integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- has-symbols: 1.0.3
- dev: false
-
- /is-weakref/1.0.2:
- resolution:
- {
- integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==,
- }
- dependencies:
- call-bind: 1.0.2
- dev: false
-
- /isexe/2.0.0:
- resolution:
- {
- integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==,
- }
-
- /js-tokens/4.0.0:
- resolution:
- {
- integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==,
- }
-
- /js-yaml/3.14.1:
- resolution:
- {
- integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==,
- }
- hasBin: true
- dependencies:
- argparse: 1.0.10
- esprima: 4.0.1
-
- /jsesc/2.5.2:
- resolution:
- {
- integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==,
- }
- engines: { node: ">=4" }
- hasBin: true
-
- /json-schema-traverse/0.4.1:
- resolution:
- {
- integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==,
- }
-
- /json-schema-traverse/1.0.0:
- resolution:
- {
- integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==,
- }
-
- /json-stable-stringify-without-jsonify/1.0.1:
- resolution:
- {
- integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==,
- }
-
- /json5/1.0.1:
- resolution:
- {
- integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==,
- }
- hasBin: true
- dependencies:
- minimist: 1.2.6
- dev: false
-
- /json5/2.2.1:
- resolution:
- {
- integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==,
- }
- engines: { node: ">=6" }
- hasBin: true
-
- /jsx-ast-utils/3.3.3:
- resolution:
- {
- integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==,
- }
- engines: { node: ">=4.0" }
- dependencies:
- array-includes: 3.1.5
- object.assign: 4.1.4
- dev: false
-
- /language-subtag-registry/0.3.22:
- resolution:
- {
- integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==,
- }
- dev: false
-
- /language-tags/1.0.5:
- resolution:
- {
- integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==,
- }
- dependencies:
- language-subtag-registry: 0.3.22
- dev: false
-
- /levn/0.4.1:
- resolution:
- {
- integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==,
- }
- engines: { node: ">= 0.8.0" }
- dependencies:
- prelude-ls: 1.2.1
- type-check: 0.4.0
-
- /lodash.merge/4.6.2:
- resolution:
- {
- integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==,
- }
-
- /lodash.truncate/4.4.2:
- resolution:
- {
- integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==,
- }
-
- /lodash/4.17.21_ehchni3mpmovsvjxesffg2i5a4:
- resolution:
- {
- integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==,
- }
- dev: false
- patched: true
-
- /loose-envify/1.4.0:
- resolution:
- {
- integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==,
- }
- hasBin: true
- dependencies:
- js-tokens: 4.0.0
-
- /lru-cache/6.0.0:
- resolution:
- {
- integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==,
- }
- engines: { node: ">=10" }
- dependencies:
- yallist: 4.0.0
-
- /merge2/1.4.1:
- resolution:
- {
- integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==,
- }
- engines: { node: ">= 8" }
- dev: false
-
- /micromatch/4.0.5:
- resolution:
- {
- integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==,
- }
- engines: { node: ">=8.6" }
- dependencies:
- braces: 3.0.2
- picomatch: 2.3.1
- dev: false
-
- /minimatch/3.1.2:
- resolution:
- {
- integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==,
- }
- dependencies:
- brace-expansion: 1.1.11
-
- /minimist/1.2.6:
- resolution:
- {
- integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==,
- }
- dev: false
-
- /ms/2.0.0:
- resolution:
- {
- integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==,
- }
- dev: false
-
- /ms/2.1.2:
- resolution:
- {
- integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==,
- }
-
- /ms/2.1.3:
- resolution:
- {
- integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==,
- }
- dev: false
-
- /nanoid/3.3.4:
- resolution:
- {
- integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==,
- }
- engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
- hasBin: true
- dev: false
-
- /natural-compare/1.4.0:
- resolution:
- {
- integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==,
- }
-
- /next-transpile-modules/9.0.0:
- resolution:
- {
- integrity: sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ==,
- }
- dependencies:
- enhanced-resolve: 5.10.0
- escalade: 3.1.1
- dev: true
-
- /next/12.2.5_ir3quccc6i62x6qn6jjhyjjiey:
- resolution:
- {
- integrity: sha512-tBdjqX5XC/oFs/6gxrZhjmiq90YWizUYU6qOWAfat7zJwrwapJ+BYgX2PmiacunXMaRpeVT4vz5MSPSLgNkrpA==,
- }
- engines: { node: ">=12.22.0" }
- hasBin: true
- peerDependencies:
- fibers: ">= 3.1.0"
- node-sass: ^6.0.0 || ^7.0.0
- react: ^17.0.2 || ^18.0.0-0
- react-dom: ^17.0.2 || ^18.0.0-0
- sass: ^1.3.0
- peerDependenciesMeta:
- fibers:
- optional: true
- node-sass:
- optional: true
- sass:
- optional: true
- dependencies:
- "@next/env": 12.2.5
- "@swc/helpers": 0.4.3
- caniuse-lite: 1.0.30001399
- postcss: 8.4.14
- react: 18.2.0
- react-dom: 18.2.0_react@18.2.0
- styled-jsx: 5.0.4_3toe27fv7etiytxb5kxc7fxaw4
- use-sync-external-store: 1.2.0_react@18.2.0
- optionalDependencies:
- "@next/swc-android-arm-eabi": 12.2.5
- "@next/swc-android-arm64": 12.2.5
- "@next/swc-darwin-arm64": 12.2.5
- "@next/swc-darwin-x64": 12.2.5
- "@next/swc-freebsd-x64": 12.2.5
- "@next/swc-linux-arm-gnueabihf": 12.2.5
- "@next/swc-linux-arm64-gnu": 12.2.5
- "@next/swc-linux-arm64-musl": 12.2.5
- "@next/swc-linux-x64-gnu": 12.2.5
- "@next/swc-linux-x64-musl": 12.2.5
- "@next/swc-win32-arm64-msvc": 12.2.5
- "@next/swc-win32-ia32-msvc": 12.2.5
- "@next/swc-win32-x64-msvc": 12.2.5
- transitivePeerDependencies:
- - "@babel/core"
- - babel-plugin-macros
- dev: false
-
- /node-releases/2.0.6:
- resolution:
- {
- integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==,
- }
-
- /object-assign/4.1.1:
- resolution:
- {
- integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==,
- }
- engines: { node: ">=0.10.0" }
- dev: false
-
- /object-inspect/1.12.2:
- resolution:
- {
- integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==,
- }
- dev: false
-
- /object-keys/1.1.1:
- resolution:
- {
- integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==,
- }
- engines: { node: ">= 0.4" }
- dev: false
-
- /object.assign/4.1.4:
- resolution:
- {
- integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- has-symbols: 1.0.3
- object-keys: 1.1.1
- dev: false
-
- /object.entries/1.1.5:
- resolution:
- {
- integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- dev: false
-
- /object.fromentries/2.0.5:
- resolution:
- {
- integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- dev: false
-
- /object.hasown/1.1.1:
- resolution:
- {
- integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==,
- }
- dependencies:
- define-properties: 1.1.4
- es-abstract: 1.20.2
- dev: false
-
- /object.values/1.1.5:
- resolution:
- {
- integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- dev: false
-
- /once/1.4.0:
- resolution:
- {
- integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==,
- }
- dependencies:
- wrappy: 1.0.2
-
- /optionator/0.9.1:
- resolution:
- {
- integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==,
- }
- engines: { node: ">= 0.8.0" }
- dependencies:
- deep-is: 0.1.4
- fast-levenshtein: 2.0.6
- levn: 0.4.1
- prelude-ls: 1.2.1
- type-check: 0.4.0
- word-wrap: 1.2.3
-
- /parent-module/1.0.1:
- resolution:
- {
- integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==,
- }
- engines: { node: ">=6" }
- dependencies:
- callsites: 3.1.0
-
- /path-is-absolute/1.0.1:
- resolution:
- {
- integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==,
- }
- engines: { node: ">=0.10.0" }
-
- /path-key/3.1.1:
- resolution:
- {
- integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==,
- }
- engines: { node: ">=8" }
-
- /path-parse/1.0.7:
- resolution:
- {
- integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==,
- }
- dev: false
-
- /path-type/4.0.0:
- resolution:
- {
- integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==,
- }
- engines: { node: ">=8" }
- dev: false
-
- /picocolors/1.0.0:
- resolution:
- {
- integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==,
- }
-
- /picomatch/2.3.1:
- resolution:
- {
- integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==,
- }
- engines: { node: ">=8.6" }
- dev: false
-
- /postcss/8.4.14:
- resolution:
- {
- integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==,
- }
- engines: { node: ^10 || ^12 || >=14 }
- dependencies:
- nanoid: 3.3.4
- picocolors: 1.0.0
- source-map-js: 1.0.2
- dev: false
-
- /prelude-ls/1.2.1:
- resolution:
- {
- integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==,
- }
- engines: { node: ">= 0.8.0" }
-
- /prettier/2.7.1:
- resolution:
- {
- integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==,
- }
- engines: { node: ">=10.13.0" }
- hasBin: true
- dev: true
-
- /progress/2.0.3:
- resolution:
- {
- integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==,
- }
- engines: { node: ">=0.4.0" }
-
- /prop-types/15.8.1:
- resolution:
- {
- integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==,
- }
- dependencies:
- loose-envify: 1.4.0
- object-assign: 4.1.1
- react-is: 16.13.1
- dev: false
-
- /punycode/2.1.1:
- resolution:
- {
- integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==,
- }
- engines: { node: ">=6" }
-
- /queue-microtask/1.2.3:
- resolution:
- {
- integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==,
- }
- dev: false
-
- /react-dom/18.2.0_react@18.2.0:
- resolution:
- {
- integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==,
- }
- peerDependencies:
- react: ^18.2.0
- dependencies:
- loose-envify: 1.4.0
- react: 18.2.0
- scheduler: 0.23.0
- dev: false
-
- /react-is/16.13.1:
- resolution:
- {
- integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==,
- }
- dev: false
-
- /react/18.2.0:
- resolution:
- {
- integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- loose-envify: 1.4.0
-
- /regenerator-runtime/0.13.9:
- resolution:
- {
- integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==,
- }
- dev: false
-
- /regexp.prototype.flags/1.4.3:
- resolution:
- {
- integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==,
- }
- engines: { node: ">= 0.4" }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- functions-have-names: 1.2.3
- dev: false
-
- /regexpp/3.2.0:
- resolution:
- {
- integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==,
- }
- engines: { node: ">=8" }
-
- /require-from-string/2.0.2:
- resolution:
- {
- integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==,
- }
- engines: { node: ">=0.10.0" }
-
- /resolve-from/4.0.0:
- resolution:
- {
- integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==,
- }
- engines: { node: ">=4" }
-
- /resolve/1.22.1:
- resolution:
- {
- integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==,
- }
- hasBin: true
- dependencies:
- is-core-module: 2.10.0
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
- dev: false
-
- /resolve/2.0.0-next.4:
- resolution:
- {
- integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==,
- }
- hasBin: true
- dependencies:
- is-core-module: 2.10.0
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
- dev: false
-
- /reusify/1.0.4:
- resolution:
- {
- integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==,
- }
- engines: { iojs: ">=1.0.0", node: ">=0.10.0" }
- dev: false
-
- /rimraf/3.0.2:
- resolution:
- {
- integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==,
- }
- hasBin: true
- dependencies:
- glob: 7.2.3
-
- /run-parallel/1.2.0:
- resolution:
- {
- integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==,
- }
- dependencies:
- queue-microtask: 1.2.3
- dev: false
-
- /safe-buffer/5.1.2:
- resolution:
- {
- integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==,
- }
-
- /scheduler/0.23.0:
- resolution:
- {
- integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==,
- }
- dependencies:
- loose-envify: 1.4.0
- dev: false
-
- /semver/6.3.0:
- resolution:
- {
- integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==,
- }
- hasBin: true
-
- /semver/7.3.7:
- resolution:
- {
- integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==,
- }
- engines: { node: ">=10" }
- hasBin: true
- dependencies:
- lru-cache: 6.0.0
-
- /shebang-command/2.0.0:
- resolution:
- {
- integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==,
- }
- engines: { node: ">=8" }
- dependencies:
- shebang-regex: 3.0.0
-
- /shebang-regex/3.0.0:
- resolution:
- {
- integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==,
- }
- engines: { node: ">=8" }
-
- /side-channel/1.0.4:
- resolution:
- {
- integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==,
- }
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.1.3
- object-inspect: 1.12.2
- dev: false
-
- /slash/3.0.0:
- resolution:
- {
- integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==,
- }
- engines: { node: ">=8" }
- dev: false
-
- /slice-ansi/4.0.0:
- resolution:
- {
- integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==,
- }
- engines: { node: ">=10" }
- dependencies:
- ansi-styles: 4.3.0
- astral-regex: 2.0.0
- is-fullwidth-code-point: 3.0.0
-
- /source-map-js/1.0.2:
- resolution:
- {
- integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==,
- }
- engines: { node: ">=0.10.0" }
- dev: false
-
- /sprintf-js/1.0.3:
- resolution:
- {
- integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==,
- }
-
- /string-width/4.2.3:
- resolution:
- {
- integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==,
- }
- engines: { node: ">=8" }
- dependencies:
- emoji-regex: 8.0.0
- is-fullwidth-code-point: 3.0.0
- strip-ansi: 6.0.1
-
- /string.prototype.matchall/4.0.7:
- resolution:
- {
- integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==,
- }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- get-intrinsic: 1.1.3
- has-symbols: 1.0.3
- internal-slot: 1.0.3
- regexp.prototype.flags: 1.4.3
- side-channel: 1.0.4
- dev: false
-
- /string.prototype.trimend/1.0.5:
- resolution:
- {
- integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==,
- }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- dev: false
-
- /string.prototype.trimstart/1.0.5:
- resolution:
- {
- integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==,
- }
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.1.4
- es-abstract: 1.20.2
- dev: false
-
- /strip-ansi/6.0.1:
- resolution:
- {
- integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==,
- }
- engines: { node: ">=8" }
- dependencies:
- ansi-regex: 5.0.1
-
- /strip-bom/3.0.0:
- resolution:
- {
- integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==,
- }
- engines: { node: ">=4" }
- dev: false
-
- /strip-json-comments/3.1.1:
- resolution:
- {
- integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==,
- }
- engines: { node: ">=8" }
-
- /styled-jsx/5.0.4_3toe27fv7etiytxb5kxc7fxaw4:
- resolution:
- {
- integrity: sha512-sDFWLbg4zR+UkNzfk5lPilyIgtpddfxXEULxhujorr5jtePTUqiPDc5BC0v1NRqTr/WaFBGQQUoYToGlF4B2KQ==,
- }
- engines: { node: ">= 12.0.0" }
- peerDependencies:
- "@babel/core": "*"
- babel-plugin-macros: "*"
- react: ">= 16.8.0 || 17.x.x || ^18.0.0-0"
- peerDependenciesMeta:
- "@babel/core":
- optional: true
- babel-plugin-macros:
- optional: true
- dependencies:
- "@babel/core": 7.19.1
- react: 18.2.0
- dev: false
-
- /supports-color/5.5.0:
- resolution:
- {
- integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==,
- }
- engines: { node: ">=4" }
- dependencies:
- has-flag: 3.0.0
-
- /supports-color/7.2.0:
- resolution:
- {
- integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==,
- }
- engines: { node: ">=8" }
- dependencies:
- has-flag: 4.0.0
-
- /supports-preserve-symlinks-flag/1.0.0:
- resolution:
- {
- integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==,
- }
- engines: { node: ">= 0.4" }
- dev: false
-
- /table/6.8.0:
- resolution:
- {
- integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==,
- }
- engines: { node: ">=10.0.0" }
- dependencies:
- ajv: 8.11.0
- lodash.truncate: 4.4.2
- slice-ansi: 4.0.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
-
- /tapable/2.2.1:
- resolution:
- {
- integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==,
- }
- engines: { node: ">=6" }
- dev: true
-
- /text-table/0.2.0:
- resolution:
- {
- integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==,
- }
-
- /to-fast-properties/2.0.0:
- resolution:
- {
- integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==,
- }
- engines: { node: ">=4" }
-
- /to-regex-range/5.0.1:
- resolution:
- {
- integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==,
- }
- engines: { node: ">=8.0" }
- dependencies:
- is-number: 7.0.0
- dev: false
-
- /tsconfig-paths/3.14.1:
- resolution:
- {
- integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==,
- }
- dependencies:
- "@types/json5": 0.0.29
- json5: 1.0.1
- minimist: 1.2.6
- strip-bom: 3.0.0
- dev: false
-
- /tslib/1.14.1:
- resolution:
- {
- integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==,
- }
- dev: false
-
- /tslib/2.4.0:
- resolution:
- {
- integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==,
- }
- dev: false
-
- /tsutils/3.21.0_typescript@4.8.3:
- resolution:
- {
- integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==,
- }
- engines: { node: ">= 6" }
- peerDependencies:
- typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- dependencies:
- tslib: 1.14.1
- typescript: 4.8.3
- dev: false
-
- /turbo-android-arm64/1.4.6:
- resolution:
- {
- integrity: sha512-YxSlHc64CF5J7yNUMiLBHkeLyzrpe75Oy7tivWb3z7ySG44BXPikk4HDJZPh0T1ELvukDwuPKkvDukJ2oCLJpA==,
- }
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-darwin-64/1.4.6:
- resolution:
- {
- integrity: sha512-f6uto7LLpjwZ6iZSF+8uaDpuiTji6xmnWDxNuW23DBE8iv5mxehHd+6Ys851uKDRrPb3QdCu9ctyigKTAla5Vg==,
- }
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-darwin-arm64/1.4.6:
- resolution:
- {
- integrity: sha512-o9C6e5XyuMHQwE0fEhUxfpXxvNr2QXXWX8nxIjygxeF19AqKbk/s08vZBOEmXV6/gx/pRhZ1S2nf0PIUjKBD/Q==,
- }
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-freebsd-64/1.4.6:
- resolution:
- {
- integrity: sha512-Gg9VOUo6McXYKGevcYjGUSmMryZyZggvpdPh7Dw3QTcT8Tsy6OBtq6WnJ2O4kFDsMigyKtEOJPceD9vDMZt3yQ==,
- }
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-freebsd-arm64/1.4.6:
- resolution:
- {
- integrity: sha512-W7VrcneWFN1QENKt5cpAPSsf9ArYBBAm3VtPBZEO5tX8kuahGlah1SKdKJXrRxYOY82wyNxDagS/rHpBlrAAzw==,
- }
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-linux-32/1.4.6:
- resolution:
- {
- integrity: sha512-76j/zsui6mWPX8pZVMGgF8eiKHPmKuGa2lo0A/Ja0HUvdYCOGUfHsWJGVVIeYbuEp3jsKyVt7OnMDeH9CqO6bg==,
- }
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-linux-64/1.4.6:
- resolution:
- {
- integrity: sha512-z4A37Xm7lZyO9ddtGnvQHWMrsAKX6vFBxdbtb9MY76VRblo7lWSuk4LwCeM+T+ZDJ9LBFiF7aD/diRShlLx9jA==,
- }
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-linux-arm/1.4.6:
- resolution:
- {
- integrity: sha512-Uh/V3oaAdhyZW6FKPpKihAxQo3EbvLaVNnzzkBmBnvHRkqoDJHhpuG72V7nn8pzxVbJ1++NEVjvbc2kmKFvGjg==,
- }
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-linux-arm64/1.4.6:
- resolution:
- {
- integrity: sha512-FW1jmOpZfOoVVvml338N0MPnYjiMyYWTaMb4T+IosgGYymcUE3xJjfXJcqfU/9/uKTyY8zG0qr9/5rw2kpMS2Q==,
- }
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-linux-mips64le/1.4.6:
- resolution:
- {
- integrity: sha512-iWaL3Pwj52BH3T2M8nXScmbSnq4+x47MYK7lJMG7FsZGAIoT5ToO1Wt1iX3GRHTcnIZYm/kCfJ1ptK/NCossLA==,
- }
- cpu: [mipsel]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-linux-ppc64le/1.4.6:
- resolution:
- {
- integrity: sha512-Af/KlUmpiORDyELxT7byXNWl3fefErGQMJfeqXEtAdhs8OCKQWuU+lchcZbiBZYNpL+lZoa3PAmP9Fpx7R4plA==,
- }
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-windows-32/1.4.6:
- resolution:
- {
- integrity: sha512-NBd+XPlRSaR//lVN13Q9DOqK3CbowSvafIyGsO4jfvMsGTdyNDL6AYtFsvTKW91/G7ZhATmSEkPn2pZRuhP/DA==,
- }
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-windows-64/1.4.6:
- resolution:
- {
- integrity: sha512-86AbmG+CjzVTpn4RGtwU2CYy4zSyAc9bIQ4pDGLIpCJg6JlD11duaiMJh0SCU/HCqWLJjWDI4qD+f9WNbgPsyQ==,
- }
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo-windows-arm64/1.4.6:
- resolution:
- {
- integrity: sha512-V+pWcqhTtmQQ3ew8qEjYtUwzyW6tO1RgvP+6OKzItYzTnMTr1Fe42Q21V+tqRNxuNfFDKsgVJdk2p5wB87bvyQ==,
- }
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /turbo/1.4.6:
- resolution:
- {
- integrity: sha512-FKtBXlOJ7YjSK22yj4sJLCtDcHFElypt7xw9cZN7Wyv9x4XBrTmh5KP6RmcGnRR1/GJlTNwD2AY2T9QTPnHh+g==,
- }
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- turbo-android-arm64: 1.4.6
- turbo-darwin-64: 1.4.6
- turbo-darwin-arm64: 1.4.6
- turbo-freebsd-64: 1.4.6
- turbo-freebsd-arm64: 1.4.6
- turbo-linux-32: 1.4.6
- turbo-linux-64: 1.4.6
- turbo-linux-arm: 1.4.6
- turbo-linux-arm64: 1.4.6
- turbo-linux-mips64le: 1.4.6
- turbo-linux-ppc64le: 1.4.6
- turbo-windows-32: 1.4.6
- turbo-windows-64: 1.4.6
- turbo-windows-arm64: 1.4.6
- dev: true
-
- /type-check/0.4.0:
- resolution:
- {
- integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==,
- }
- engines: { node: ">= 0.8.0" }
- dependencies:
- prelude-ls: 1.2.1
-
- /type-fest/0.20.2:
- resolution:
- {
- integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==,
- }
- engines: { node: ">=10" }
-
- /typescript/4.8.3:
- resolution:
- {
- integrity: sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==,
- }
- engines: { node: ">=4.2.0" }
- hasBin: true
-
- /unbox-primitive/1.0.2:
- resolution:
- {
- integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==,
- }
- dependencies:
- call-bind: 1.0.2
- has-bigints: 1.0.2
- has-symbols: 1.0.3
- which-boxed-primitive: 1.0.2
- dev: false
-
- /underscore/1.13.4_3pbfs36izefyn2uycmknwkvuuy:
- resolution:
- {
- integrity: sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==,
- }
- dev: false
- patched: true
-
- /update-browserslist-db/1.0.9_browserslist@4.21.3:
- resolution:
- {
- integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==,
- }
- hasBin: true
- peerDependencies:
- browserslist: ">= 4.21.0"
- dependencies:
- browserslist: 4.21.3
- escalade: 3.1.1
- picocolors: 1.0.0
-
- /uri-js/4.4.1:
- resolution:
- {
- integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==,
- }
- dependencies:
- punycode: 2.1.1
-
- /use-sync-external-store/1.2.0_react@18.2.0:
- resolution:
- {
- integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==,
- }
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- dependencies:
- react: 18.2.0
- dev: false
-
- /v8-compile-cache/2.3.0:
- resolution:
- {
- integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==,
- }
-
- /which-boxed-primitive/1.0.2:
- resolution:
- {
- integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==,
- }
- dependencies:
- is-bigint: 1.0.4
- is-boolean-object: 1.1.2
- is-number-object: 1.0.7
- is-string: 1.0.7
- is-symbol: 1.0.4
- dev: false
-
- /which/2.0.2:
- resolution:
- {
- integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==,
- }
- engines: { node: ">= 8" }
- hasBin: true
- dependencies:
- isexe: 2.0.0
-
- /word-wrap/1.2.3:
- resolution:
- {
- integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==,
- }
- engines: { node: ">=0.10.0" }
-
- /wrappy/1.0.2:
- resolution:
- {
- integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==,
- }
-
- /yallist/4.0.0:
- resolution:
- {
- integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==,
- }
-
- file:packages/ui:
- resolution: { directory: packages/ui, type: directory }
- name: ui
- version: 0.0.0
- dev: false
-
- github.com/peerigon/dashboard-icons/ce27ef933144e09cef3911025f3649040a8571b6:
- resolution:
- {
- tarball: https://codeload.github.com/peerigon/dashboard-icons/tar.gz/ce27ef933144e09cef3911025f3649040a8571b,
- }
- name: dashboard-icons
- version: 1.0.0
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm8.yaml b/cli/internal/lockfile/testdata/pnpm8.yaml
deleted file mode 100644
index d7d9e27..0000000
--- a/cli/internal/lockfile/testdata/pnpm8.yaml
+++ /dev/null
@@ -1,107 +0,0 @@
-lockfileVersion: "6.0"
-
-patchedDependencies:
- is-even@1.0.0:
- hash: trwuddosrpxsvtoqztvint6pca
- path: patches/is-even@1.0.0.patch
-
-importers:
- .: {}
-
- packages/a:
- dependencies:
- c:
- specifier: workspace:*
- version: link:../c
- is-odd:
- specifier: ^3.0.1
- version: 3.0.1
-
- packages/b:
- dependencies:
- c:
- specifier: workspace:*
- version: link:../c
- is-even:
- specifier: ^1.0.0
- version: 1.0.0_trwuddosrpxsvtoqztvint6pca
-
- packages/c:
- dependencies:
- lodash:
- specifier: ^4.17.21
- version: 4.17.21
-
-packages:
- /is-buffer@1.1.6:
- resolution:
- {
- integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==,
- }
- dev: false
-
- /is-even@1.0.0_trwuddosrpxsvtoqztvint6pca:
- resolution:
- {
- integrity: sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- is-odd: 0.1.2
- dev: false
- patched: true
-
- /is-number@3.0.0:
- resolution:
- {
- integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- kind-of: 3.2.2
- dev: false
-
- /is-number@6.0.0:
- resolution:
- {
- integrity: sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==,
- }
- engines: { node: ">=0.10.0" }
- dev: false
-
- /is-odd@0.1.2:
- resolution:
- {
- integrity: sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- is-number: 3.0.0
- dev: false
-
- /is-odd@3.0.1:
- resolution:
- {
- integrity: sha512-CQpnWPrDwmP1+SMHXZhtLtJv90yiyVfluGsX5iNCVkrhQtU3TQHsUWPG9wkdk9Lgd5yNpAg9jQEo90CBaXgWMA==,
- }
- engines: { node: ">=4" }
- dependencies:
- is-number: 6.0.0
- dev: false
-
- /kind-of@3.2.2:
- resolution:
- {
- integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==,
- }
- engines: { node: ">=0.10.0" }
- dependencies:
- is-buffer: 1.1.6
- dev: false
-
- /lodash@4.17.21:
- resolution:
- {
- integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==,
- }
- dev: false
diff --git a/cli/internal/lockfile/testdata/pnpm_override.yaml b/cli/internal/lockfile/testdata/pnpm_override.yaml
deleted file mode 100644
index 2102192..0000000
--- a/cli/internal/lockfile/testdata/pnpm_override.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-lockfileVersion: 5.4
-
-overrides:
- "@nomiclabs/hardhat-ethers": npm:hardhat-deploy-ethers@^0.3.0-beta.13
-
-importers:
- config/hardhat:
- specifiers:
- "@nomiclabs/hardhat-ethers": npm:hardhat-deploy-ethers@^0.3.0-beta.13
- dependencies:
- "@nomiclabs/hardhat-ethers": /hardhat-deploy-ethers/0.3.0-beta.13_yab2ug5tvye2kp6e24l5x3z7uy
-
-packages:
- /hardhat-deploy-ethers/0.3.0-beta.13_yab2ug5tvye2kp6e24l5x3z7uy:
- resolution:
- {
- integrity: sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==,
- }
- peerDependencies:
- ethers: ^5.0.0
- hardhat: ^2.0.0
- dependencies:
- ethers: 5.7.2
- hardhat: 2.12.4_typescript@4.9.4
diff --git a/cli/internal/lockfile/testdata/yarn.lock b/cli/internal/lockfile/testdata/yarn.lock
deleted file mode 100644
index f4272d1..0000000
--- a/cli/internal/lockfile/testdata/yarn.lock
+++ /dev/null
@@ -1,2304 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@ampproject/remapping@^2.1.0":
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
- integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==
- dependencies:
- "@jridgewell/gen-mapping" "^0.1.0"
- "@jridgewell/trace-mapping" "^0.3.9"
-
-"@babel/code-frame@7.12.11":
- version "7.12.11"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
- integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
- dependencies:
- "@babel/highlight" "^7.10.4"
-
-"@babel/code-frame@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
- integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
- dependencies:
- "@babel/highlight" "^7.18.6"
-
-"@babel/compat-data@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.0.tgz#2a592fd89bacb1fcde68de31bee4f2f2dacb0e86"
- integrity sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==
-
-"@babel/core@^7.0.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.0.tgz#d2f5f4f2033c00de8096be3c9f45772563e150c3"
- integrity sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==
- dependencies:
- "@ampproject/remapping" "^2.1.0"
- "@babel/code-frame" "^7.18.6"
- "@babel/generator" "^7.19.0"
- "@babel/helper-compilation-targets" "^7.19.0"
- "@babel/helper-module-transforms" "^7.19.0"
- "@babel/helpers" "^7.19.0"
- "@babel/parser" "^7.19.0"
- "@babel/template" "^7.18.10"
- "@babel/traverse" "^7.19.0"
- "@babel/types" "^7.19.0"
- convert-source-map "^1.7.0"
- debug "^4.1.0"
- gensync "^1.0.0-beta.2"
- json5 "^2.2.1"
- semver "^6.3.0"
-
-"@babel/generator@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.0.tgz#785596c06425e59334df2ccee63ab166b738419a"
- integrity sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==
- dependencies:
- "@babel/types" "^7.19.0"
- "@jridgewell/gen-mapping" "^0.3.2"
- jsesc "^2.5.1"
-
-"@babel/helper-compilation-targets@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz#537ec8339d53e806ed422f1e06c8f17d55b96bb0"
- integrity sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==
- dependencies:
- "@babel/compat-data" "^7.19.0"
- "@babel/helper-validator-option" "^7.18.6"
- browserslist "^4.20.2"
- semver "^6.3.0"
-
-"@babel/helper-environment-visitor@^7.18.9":
- version "7.18.9"
- resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
- integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
-
-"@babel/helper-function-name@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
- integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
- dependencies:
- "@babel/template" "^7.18.10"
- "@babel/types" "^7.19.0"
-
-"@babel/helper-hoist-variables@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
- integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
- dependencies:
- "@babel/types" "^7.18.6"
-
-"@babel/helper-module-imports@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
- integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
- dependencies:
- "@babel/types" "^7.18.6"
-
-"@babel/helper-module-transforms@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz#309b230f04e22c58c6a2c0c0c7e50b216d350c30"
- integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==
- dependencies:
- "@babel/helper-environment-visitor" "^7.18.9"
- "@babel/helper-module-imports" "^7.18.6"
- "@babel/helper-simple-access" "^7.18.6"
- "@babel/helper-split-export-declaration" "^7.18.6"
- "@babel/helper-validator-identifier" "^7.18.6"
- "@babel/template" "^7.18.10"
- "@babel/traverse" "^7.19.0"
- "@babel/types" "^7.19.0"
-
-"@babel/helper-simple-access@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
- integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
- dependencies:
- "@babel/types" "^7.18.6"
-
-"@babel/helper-split-export-declaration@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
- integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
- dependencies:
- "@babel/types" "^7.18.6"
-
-"@babel/helper-string-parser@^7.18.10":
- version "7.18.10"
- resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
- integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
-
-"@babel/helper-validator-identifier@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
- integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
-
-"@babel/helper-validator-option@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
- integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
-
-"@babel/helpers@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18"
- integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==
- dependencies:
- "@babel/template" "^7.18.10"
- "@babel/traverse" "^7.19.0"
- "@babel/types" "^7.19.0"
-
-"@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
- integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
- dependencies:
- "@babel/helper-validator-identifier" "^7.18.6"
- chalk "^2.0.0"
- js-tokens "^4.0.0"
-
-"@babel/parser@^7.18.10", "@babel/parser@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c"
- integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==
-
-"@babel/runtime-corejs3@^7.10.2":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.19.0.tgz#0df75cb8e5ecba3ca9e658898694e5326d52397f"
- integrity sha512-JyXXoCu1N8GLuKc2ii8y5RGma5FMpFeO2nAQIe0Yzrbq+rQnN+sFj47auLblR5ka6aHNGPDgv8G/iI2Grb0ldQ==
- dependencies:
- core-js-pure "^3.20.2"
- regenerator-runtime "^0.13.4"
-
-"@babel/runtime@^7.10.2", "@babel/runtime@^7.18.9":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
- integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
- dependencies:
- regenerator-runtime "^0.13.4"
-
-"@babel/template@^7.18.10":
- version "7.18.10"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
- integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
- dependencies:
- "@babel/code-frame" "^7.18.6"
- "@babel/parser" "^7.18.10"
- "@babel/types" "^7.18.10"
-
-"@babel/traverse@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.0.tgz#eb9c561c7360005c592cc645abafe0c3c4548eed"
- integrity sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==
- dependencies:
- "@babel/code-frame" "^7.18.6"
- "@babel/generator" "^7.19.0"
- "@babel/helper-environment-visitor" "^7.18.9"
- "@babel/helper-function-name" "^7.19.0"
- "@babel/helper-hoist-variables" "^7.18.6"
- "@babel/helper-split-export-declaration" "^7.18.6"
- "@babel/parser" "^7.19.0"
- "@babel/types" "^7.19.0"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600"
- integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==
- dependencies:
- "@babel/helper-string-parser" "^7.18.10"
- "@babel/helper-validator-identifier" "^7.18.6"
- to-fast-properties "^2.0.0"
-
-"@eslint/eslintrc@^0.4.3":
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
- integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
- dependencies:
- ajv "^6.12.4"
- debug "^4.1.1"
- espree "^7.3.0"
- globals "^13.9.0"
- ignore "^4.0.6"
- import-fresh "^3.2.1"
- js-yaml "^3.13.1"
- minimatch "^3.0.4"
- strip-json-comments "^3.1.1"
-
-"@humanwhocodes/config-array@^0.5.0":
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9"
- integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
- dependencies:
- "@humanwhocodes/object-schema" "^1.2.0"
- debug "^4.1.1"
- minimatch "^3.0.4"
-
-"@humanwhocodes/object-schema@^1.2.0":
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
- integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
-
-"@jridgewell/gen-mapping@^0.1.0":
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996"
- integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==
- dependencies:
- "@jridgewell/set-array" "^1.0.0"
- "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@jridgewell/gen-mapping@^0.3.2":
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
- integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
- dependencies:
- "@jridgewell/set-array" "^1.0.1"
- "@jridgewell/sourcemap-codec" "^1.4.10"
- "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/resolve-uri@^3.0.3":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
- integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
-
-"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
- integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-
-"@jridgewell/sourcemap-codec@^1.4.10":
- version "1.4.14"
- resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
- integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
-
-"@jridgewell/trace-mapping@^0.3.9":
- version "0.3.15"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
- integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
- dependencies:
- "@jridgewell/resolve-uri" "^3.0.3"
- "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@next/env@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/env/-/env-12.2.5.tgz#d908c57b35262b94db3e431e869b72ac3e1ad3e3"
- integrity sha512-vLPLV3cpPGjUPT3PjgRj7e3nio9t6USkuew3JE/jMeon/9Mvp1WyR18v3iwnCuX7eUAm1HmAbJHHLAbcu/EJcw==
-
-"@next/eslint-plugin-next@12.3.0":
- version "12.3.0"
- resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.3.0.tgz#302c1f03618d5001ce92ea6826c329268759128e"
- integrity sha512-jVdq1qYTNDjUtulnE8/hkPv0pHILV4jMg5La99iaY/FFm20WxVnsAZtbNnMvlPbf8dc010oO304SX9yXbg5PAw==
- dependencies:
- glob "7.1.7"
-
-"@next/swc-android-arm-eabi@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.5.tgz#903a5479ab4c2705d9c08d080907475f7bacf94d"
- integrity sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==
-
-"@next/swc-android-arm64@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.2.5.tgz#2f9a98ec4166c7860510963b31bda1f57a77c792"
- integrity sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==
-
-"@next/swc-darwin-arm64@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.5.tgz#31b1c3c659d54be546120c488a1e1bad21c24a1d"
- integrity sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==
-
-"@next/swc-darwin-x64@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.5.tgz#2e44dd82b2b7fef88238d1bc4d3bead5884cedfd"
- integrity sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==
-
-"@next/swc-freebsd-x64@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.5.tgz#e24e75d8c2581bfebc75e4f08f6ddbd116ce9dbd"
- integrity sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==
-
-"@next/swc-linux-arm-gnueabihf@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.5.tgz#46d8c514d834d2b5f67086013f0bd5e3081e10b9"
- integrity sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==
-
-"@next/swc-linux-arm64-gnu@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.5.tgz#91f725ac217d3a1f4f9f53b553615ba582fd3d9f"
- integrity sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==
-
-"@next/swc-linux-arm64-musl@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.5.tgz#e627e8c867920995810250303cd9b8e963598383"
- integrity sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==
-
-"@next/swc-linux-x64-gnu@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.5.tgz#83a5e224fbc4d119ef2e0f29d0d79c40cc43887e"
- integrity sha512-0szyAo8jMCClkjNK0hknjhmAngUppoRekW6OAezbEYwHXN/VNtsXbfzgYOqjKWxEx3OoAzrT3jLwAF0HdX2MEw==
-
-"@next/swc-linux-x64-musl@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.5.tgz#be700d48471baac1ec2e9539396625584a317e95"
- integrity sha512-zg/Y6oBar1yVnW6Il1I/08/2ukWtOG6s3acdJdEyIdsCzyQi4RLxbbhkD/EGQyhqBvd3QrC6ZXQEXighQUAZ0g==
-
-"@next/swc-win32-arm64-msvc@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.5.tgz#a93e958133ad3310373fda33a79aa10af2a0aa97"
- integrity sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==
-
-"@next/swc-win32-ia32-msvc@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.5.tgz#4f5f7ba0a98ff89a883625d4af0125baed8b2e19"
- integrity sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==
-
-"@next/swc-win32-x64-msvc@12.2.5":
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.5.tgz#20fed129b04a0d3f632c6d0de135345bb623b1e4"
- integrity sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==
-
-"@nodelib/fs.scandir@2.1.5":
- version "2.1.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
- integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
- dependencies:
- "@nodelib/fs.stat" "2.0.5"
- run-parallel "^1.1.9"
-
-"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
- integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
-
-"@nodelib/fs.walk@^1.2.3":
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
- integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
- dependencies:
- "@nodelib/fs.scandir" "2.1.5"
- fastq "^1.6.0"
-
-"@rushstack/eslint-patch@^1.1.3":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz#0c8b74c50f29ee44f423f7416829c0bf8bb5eb27"
- integrity sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==
-
-"@swc/helpers@0.4.3":
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.3.tgz#16593dfc248c53b699d4b5026040f88ddb497012"
- integrity sha512-6JrF+fdUK2zbGpJIlN7G3v966PQjyx/dPt1T9km2wj+EUBqgrxCk3uX4Kct16MIm9gGxfKRcfax2hVf5jvlTzA==
- dependencies:
- tslib "^2.4.0"
-
-"@types/json5@^0.0.29":
- version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
- integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
-
-"@types/node@^17.0.12":
- version "17.0.45"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190"
- integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==
-
-"@types/prop-types@*":
- version "15.7.5"
- resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
- integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
-
-"@types/react-dom@^17.0.11":
- version "17.0.17"
- resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1"
- integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==
- dependencies:
- "@types/react" "^17"
-
-"@types/react@18.0.17":
- version "18.0.17"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.17.tgz#4583d9c322d67efe4b39a935d223edcc7050ccf4"
- integrity sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==
- dependencies:
- "@types/prop-types" "*"
- "@types/scheduler" "*"
- csstype "^3.0.2"
-
-"@types/react@^17", "@types/react@^17.0.37":
- version "17.0.49"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.49.tgz#df87ba4ca8b7942209c3dc655846724539dc1049"
- integrity sha512-CCBPMZaPhcKkYUTqFs/hOWqKjPxhTEmnZWjlHHgIMop67DsXywf9B5Os9Hz8KSacjNOgIdnZVJamwl232uxoPg==
- dependencies:
- "@types/prop-types" "*"
- "@types/scheduler" "*"
- csstype "^3.0.2"
-
-"@types/scheduler@*":
- version "0.16.2"
- resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
- integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
-
-"@typescript-eslint/parser@^5.21.0":
- version "5.36.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.36.2.tgz#3ddf323d3ac85a25295a55fcb9c7a49ab4680ddd"
- integrity sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==
- dependencies:
- "@typescript-eslint/scope-manager" "5.36.2"
- "@typescript-eslint/types" "5.36.2"
- "@typescript-eslint/typescript-estree" "5.36.2"
- debug "^4.3.4"
-
-"@typescript-eslint/scope-manager@5.36.2":
- version "5.36.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz#a75eb588a3879ae659514780831370642505d1cd"
- integrity sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==
- dependencies:
- "@typescript-eslint/types" "5.36.2"
- "@typescript-eslint/visitor-keys" "5.36.2"
-
-"@typescript-eslint/types@5.36.2":
- version "5.36.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.36.2.tgz#a5066e500ebcfcee36694186ccc57b955c05faf9"
- integrity sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==
-
-"@typescript-eslint/typescript-estree@5.36.2":
- version "5.36.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz#0c93418b36c53ba0bc34c61fe9405c4d1d8fe560"
- integrity sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==
- dependencies:
- "@typescript-eslint/types" "5.36.2"
- "@typescript-eslint/visitor-keys" "5.36.2"
- debug "^4.3.4"
- globby "^11.1.0"
- is-glob "^4.0.3"
- semver "^7.3.7"
- tsutils "^3.21.0"
-
-"@typescript-eslint/visitor-keys@5.36.2":
- version "5.36.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz#2f8f78da0a3bad3320d2ac24965791ac39dace5a"
- integrity sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==
- dependencies:
- "@typescript-eslint/types" "5.36.2"
- eslint-visitor-keys "^3.3.0"
-
-acorn-jsx@^5.3.1:
- version "5.3.2"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
- integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-
-acorn@^7.4.0:
- version "7.4.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
- integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-
-ajv@^6.10.0, ajv@^6.12.4:
- version "6.12.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
- integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
- 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"
-
-ajv@^8.0.1:
- version "8.11.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f"
- integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
- dependencies:
- fast-deep-equal "^3.1.1"
- json-schema-traverse "^1.0.0"
- require-from-string "^2.0.2"
- uri-js "^4.2.2"
-
-ansi-colors@^4.1.1:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
- integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
-
-ansi-regex@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
- integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
-
-ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
-ansi-styles@^4.0.0, ansi-styles@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
- integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
- dependencies:
- color-convert "^2.0.1"
-
-argparse@^1.0.7:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
- integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
- dependencies:
- sprintf-js "~1.0.2"
-
-aria-query@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
- integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
- dependencies:
- "@babel/runtime" "^7.10.2"
- "@babel/runtime-corejs3" "^7.10.2"
-
-array-includes@^3.1.4, array-includes@^3.1.5:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb"
- integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
- get-intrinsic "^1.1.1"
- is-string "^1.0.7"
-
-array-union@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
- integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
-array.prototype.flat@^1.2.5:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b"
- integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.2"
- es-shim-unscopables "^1.0.0"
-
-array.prototype.flatmap@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f"
- integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.2"
- es-shim-unscopables "^1.0.0"
-
-ast-types-flow@^0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
- integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==
-
-astral-regex@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
- integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
-
-axe-core@^4.4.3:
- version "4.4.3"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.3.tgz#11c74d23d5013c0fa5d183796729bc3482bd2f6f"
- integrity sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==
-
-axobject-query@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
- integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
-
-balanced-match@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
- integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-braces@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
- integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
- dependencies:
- fill-range "^7.0.1"
-
-browserslist@^4.20.2:
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
- integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
- dependencies:
- caniuse-lite "^1.0.30001370"
- electron-to-chromium "^1.4.202"
- node-releases "^2.0.6"
- update-browserslist-db "^1.0.5"
-
-call-bind@^1.0.0, call-bind@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
- integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
- dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.2"
-
-callsites@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
- integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
-caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001370:
- version "1.0.30001393"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001393.tgz#1aa161e24fe6af2e2ccda000fc2b94be0b0db356"
- integrity sha512-N/od11RX+Gsk+1qY/jbPa0R6zJupEa0lxeBG598EbrtblxVCTJsQwbRBm6+V+rxpc5lHKdsXb9RY83cZIPLseA==
-
-chalk@^2.0.0:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^4.0.0:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
- integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-color-convert@^1.9.0:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
- integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
- dependencies:
- color-name "1.1.3"
-
-color-convert@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
- integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
- dependencies:
- color-name "~1.1.4"
-
-color-name@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-
-color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
-
-convert-source-map@^1.7.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
- integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
- dependencies:
- safe-buffer "~5.1.1"
-
-core-js-pure@^3.20.2:
- version "3.25.1"
- resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.25.1.tgz#79546518ae87cc362c991d9c2d211f45107991ee"
- integrity sha512-7Fr74bliUDdeJCBMxkkIuQ4xfxn/SwrVg+HkJUAoNEXVqYLv55l6Af0dJ5Lq2YBUW9yKqSkLXaS5SYPK6MGa/A==
-
-cross-spawn@^7.0.2:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
- integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-csstype@^3.0.2:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
- integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
-
-damerau-levenshtein@^1.0.8:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
- integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
-
-debug@^2.6.9:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
-debug@^3.2.7:
- version "3.2.7"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
- integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.4:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
- integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
- dependencies:
- ms "2.1.2"
-
-deep-is@^0.1.3:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
- integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
-
-define-properties@^1.1.3, define-properties@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
- integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
- dependencies:
- has-property-descriptors "^1.0.0"
- object-keys "^1.1.1"
-
-dir-glob@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
- integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
- dependencies:
- path-type "^4.0.0"
-
-doctrine@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
- integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
- dependencies:
- esutils "^2.0.2"
-
-doctrine@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
- integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
- dependencies:
- esutils "^2.0.2"
-
-electron-to-chromium@^1.4.202:
- version "1.4.244"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.244.tgz#ae9b56ed4ae2107e3a860dad80ed662c936e369e"
- integrity sha512-E21saXLt2eTDaTxgUtiJtBUqanF9A32wZasAwDZ8gvrqXoxrBrbwtDCx7c/PQTLp81wj4X0OLDeoGQg7eMo3+w==
-
-emoji-regex@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
- integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-
-emoji-regex@^9.2.2:
- version "9.2.2"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
- integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
-
-enhanced-resolve@^5.7.0:
- version "5.10.0"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
- integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
- dependencies:
- graceful-fs "^4.2.4"
- tapable "^2.2.0"
-
-enquirer@^2.3.5:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
- integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
- dependencies:
- ansi-colors "^4.1.1"
-
-es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
- version "1.20.2"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.2.tgz#8495a07bc56d342a3b8ea3ab01bd986700c2ccb3"
- integrity sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==
- dependencies:
- call-bind "^1.0.2"
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- function.prototype.name "^1.1.5"
- get-intrinsic "^1.1.2"
- get-symbol-description "^1.0.0"
- has "^1.0.3"
- has-property-descriptors "^1.0.0"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- is-callable "^1.2.4"
- is-negative-zero "^2.0.2"
- is-regex "^1.1.4"
- is-shared-array-buffer "^1.0.2"
- is-string "^1.0.7"
- is-weakref "^1.0.2"
- object-inspect "^1.12.2"
- object-keys "^1.1.1"
- object.assign "^4.1.4"
- regexp.prototype.flags "^1.4.3"
- string.prototype.trimend "^1.0.5"
- string.prototype.trimstart "^1.0.5"
- unbox-primitive "^1.0.2"
-
-es-shim-unscopables@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
- integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
- dependencies:
- has "^1.0.3"
-
-es-to-primitive@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
- dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.0.2"
-
-escalade@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
- integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-escape-string-regexp@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
-
-escape-string-regexp@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
- integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-
-eslint-config-next@^12.0.8:
- version "12.3.0"
- resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.3.0.tgz#d887ab2d143fe1a2b308e9321e932a613e610800"
- integrity sha512-guHSkNyKnTBB8HU35COgAMeMV0E026BiYRYvyEVVaTOeFcnU3i1EI8/Da0Rl7H3Sgua5FEvoA0vYd2s8kdIUXg==
- dependencies:
- "@next/eslint-plugin-next" "12.3.0"
- "@rushstack/eslint-patch" "^1.1.3"
- "@typescript-eslint/parser" "^5.21.0"
- eslint-import-resolver-node "^0.3.6"
- eslint-import-resolver-typescript "^2.7.1"
- eslint-plugin-import "^2.26.0"
- eslint-plugin-jsx-a11y "^6.5.1"
- eslint-plugin-react "^7.29.4"
- eslint-plugin-react-hooks "^4.5.0"
-
-eslint-config-prettier@^8.3.0:
- version "8.5.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1"
- integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==
-
-eslint-config-turbo@latest:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-0.0.3.tgz#61a3b6fdc4186bb6832ab4b48bb6ed2d3bad57a8"
- integrity sha512-hK5MlxDugUWZV9ZKcyfNwLXrlMuM2wPgAUk51cUFBC3nXRCVmCA9uSRFBZsyAIurN1wH7mS7G1NBo5F8VkF7lQ==
- dependencies:
- eslint-plugin-turbo "0.0.3"
-
-eslint-import-resolver-node@^0.3.6:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
- integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
- dependencies:
- debug "^3.2.7"
- resolve "^1.20.0"
-
-eslint-import-resolver-typescript@^2.7.1:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz#a90a4a1c80da8d632df25994c4c5fdcdd02b8751"
- integrity sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==
- dependencies:
- debug "^4.3.4"
- glob "^7.2.0"
- is-glob "^4.0.3"
- resolve "^1.22.0"
- tsconfig-paths "^3.14.1"
-
-eslint-module-utils@^2.7.3:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974"
- integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==
- dependencies:
- debug "^3.2.7"
-
-eslint-plugin-import@^2.26.0:
- version "2.26.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"
- integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==
- dependencies:
- array-includes "^3.1.4"
- array.prototype.flat "^1.2.5"
- debug "^2.6.9"
- doctrine "^2.1.0"
- eslint-import-resolver-node "^0.3.6"
- eslint-module-utils "^2.7.3"
- has "^1.0.3"
- is-core-module "^2.8.1"
- is-glob "^4.0.3"
- minimatch "^3.1.2"
- object.values "^1.1.5"
- resolve "^1.22.0"
- tsconfig-paths "^3.14.1"
-
-eslint-plugin-jsx-a11y@^6.5.1:
- version "6.6.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz#93736fc91b83fdc38cc8d115deedfc3091aef1ff"
- integrity sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==
- dependencies:
- "@babel/runtime" "^7.18.9"
- aria-query "^4.2.2"
- array-includes "^3.1.5"
- ast-types-flow "^0.0.7"
- axe-core "^4.4.3"
- axobject-query "^2.2.0"
- damerau-levenshtein "^1.0.8"
- emoji-regex "^9.2.2"
- has "^1.0.3"
- jsx-ast-utils "^3.3.2"
- language-tags "^1.0.5"
- minimatch "^3.1.2"
- semver "^6.3.0"
-
-eslint-plugin-react-hooks@^4.5.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
- integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
-
-eslint-plugin-react@7.31.7, eslint-plugin-react@^7.29.4:
- version "7.31.7"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.7.tgz#36fb1c611a7db5f757fce09cbbcc01682f8b0fbb"
- integrity sha512-8NldBTeYp/kQoTV1uT0XF6HcmDqbgZ0lNPkN0wlRw8DJKXEnaWu+oh/6gt3xIhzvQ35wB2Y545fJhIbJSZ2NNw==
- dependencies:
- array-includes "^3.1.5"
- array.prototype.flatmap "^1.3.0"
- doctrine "^2.1.0"
- estraverse "^5.3.0"
- jsx-ast-utils "^2.4.1 || ^3.0.0"
- minimatch "^3.1.2"
- object.entries "^1.1.5"
- object.fromentries "^2.0.5"
- object.hasown "^1.1.1"
- object.values "^1.1.5"
- prop-types "^15.8.1"
- resolve "^2.0.0-next.3"
- semver "^6.3.0"
- string.prototype.matchall "^4.0.7"
-
-eslint-plugin-turbo@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-0.0.3.tgz#9d86895732f95b0c236d6363177a52368fffdc71"
- integrity sha512-QjidATGxWtaB9QUrD3NocUySmsgWKZlBMFlw4kX2IIjRLAxMPwukk90h3ZTaNXyRHuaQsrEgh7hhlCZoxP0TTw==
-
-eslint-scope@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
- integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
- dependencies:
- esrecurse "^4.3.0"
- estraverse "^4.1.1"
-
-eslint-utils@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
- integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
- dependencies:
- eslint-visitor-keys "^1.1.0"
-
-eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
- integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
-
-eslint-visitor-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
- integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
-
-eslint-visitor-keys@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
- integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-
-eslint@7.32.0, eslint@^7.23.0, eslint@^7.32.0:
- version "7.32.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
- integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
- dependencies:
- "@babel/code-frame" "7.12.11"
- "@eslint/eslintrc" "^0.4.3"
- "@humanwhocodes/config-array" "^0.5.0"
- ajv "^6.10.0"
- chalk "^4.0.0"
- cross-spawn "^7.0.2"
- debug "^4.0.1"
- doctrine "^3.0.0"
- enquirer "^2.3.5"
- escape-string-regexp "^4.0.0"
- eslint-scope "^5.1.1"
- eslint-utils "^2.1.0"
- eslint-visitor-keys "^2.0.0"
- espree "^7.3.1"
- esquery "^1.4.0"
- esutils "^2.0.2"
- fast-deep-equal "^3.1.3"
- file-entry-cache "^6.0.1"
- functional-red-black-tree "^1.0.1"
- glob-parent "^5.1.2"
- globals "^13.6.0"
- ignore "^4.0.6"
- import-fresh "^3.0.0"
- imurmurhash "^0.1.4"
- is-glob "^4.0.0"
- js-yaml "^3.13.1"
- json-stable-stringify-without-jsonify "^1.0.1"
- levn "^0.4.1"
- lodash.merge "^4.6.2"
- minimatch "^3.0.4"
- natural-compare "^1.4.0"
- optionator "^0.9.1"
- progress "^2.0.0"
- regexpp "^3.1.0"
- semver "^7.2.1"
- strip-ansi "^6.0.0"
- strip-json-comments "^3.1.0"
- table "^6.0.9"
- text-table "^0.2.0"
- v8-compile-cache "^2.0.3"
-
-espree@^7.3.0, espree@^7.3.1:
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
- integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
- dependencies:
- acorn "^7.4.0"
- acorn-jsx "^5.3.1"
- eslint-visitor-keys "^1.3.0"
-
-esprima@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
- integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
-esquery@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
- integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
- dependencies:
- estraverse "^5.1.0"
-
-esrecurse@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
- integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
- dependencies:
- estraverse "^5.2.0"
-
-estraverse@^4.1.1:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
- integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
-
-estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
- integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
-
-esutils@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
- integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-
-fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
- integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-
-fast-glob@^3.2.9:
- version "3.2.11"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
- integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
- dependencies:
- "@nodelib/fs.stat" "^2.0.2"
- "@nodelib/fs.walk" "^1.2.3"
- glob-parent "^5.1.2"
- merge2 "^1.3.0"
- micromatch "^4.0.4"
-
-fast-json-stable-stringify@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
- integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
-
-fast-levenshtein@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
- integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
-
-fastq@^1.6.0:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
- integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
- dependencies:
- reusify "^1.0.4"
-
-file-entry-cache@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
- integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
- dependencies:
- flat-cache "^3.0.4"
-
-fill-range@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
- integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
- dependencies:
- to-regex-range "^5.0.1"
-
-flat-cache@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
- integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
- dependencies:
- flatted "^3.1.0"
- rimraf "^3.0.2"
-
-flatted@^3.1.0:
- version "3.2.7"
- resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
- integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-function.prototype.name@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
- integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.0"
- functions-have-names "^1.2.2"
-
-functional-red-black-tree@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
- integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
-
-functions-have-names@^1.2.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
- integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
-
-gensync@^1.0.0-beta.2:
- version "1.0.0-beta.2"
- resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
- integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-
-get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
- integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.3"
-
-get-symbol-description@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
- integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
- dependencies:
- call-bind "^1.0.2"
- get-intrinsic "^1.1.1"
-
-glob-parent@^5.1.2:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
- integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
- dependencies:
- is-glob "^4.0.1"
-
-glob@7.1.7:
- version "7.1.7"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
- integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.1.3, glob@^7.2.0:
- version "7.2.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
- integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.1.1"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-globals@^11.1.0:
- version "11.12.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
- integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
-globals@^13.6.0, globals@^13.9.0:
- version "13.17.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
- integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==
- dependencies:
- type-fest "^0.20.2"
-
-globby@^11.1.0:
- version "11.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
- integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
- dependencies:
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.2.9"
- ignore "^5.2.0"
- merge2 "^1.4.1"
- slash "^3.0.0"
-
-graceful-fs@^4.2.4:
- version "4.2.10"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
- integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
-
-has-bigints@^1.0.1, has-bigints@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
- integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
-
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
-
-has-flag@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
- integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has-property-descriptors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
- integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
- dependencies:
- get-intrinsic "^1.1.1"
-
-has-symbols@^1.0.2, has-symbols@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
- integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
-
-has-tostringtag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
- integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
- dependencies:
- has-symbols "^1.0.2"
-
-has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
- dependencies:
- function-bind "^1.1.1"
-
-ignore@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
- integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
-
-ignore@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
- integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
-
-import-fresh@^3.0.0, import-fresh@^3.2.1:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
- integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-imurmurhash@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
- integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
- integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-internal-slot@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
- integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
- dependencies:
- get-intrinsic "^1.1.0"
- has "^1.0.3"
- side-channel "^1.0.4"
-
-is-bigint@^1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
- integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
- dependencies:
- has-bigints "^1.0.1"
-
-is-boolean-object@^1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
- integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
- dependencies:
- call-bind "^1.0.2"
- has-tostringtag "^1.0.0"
-
-is-callable@^1.1.4, is-callable@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
- integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
-
-is-core-module@^2.8.1, is-core-module@^2.9.0:
- version "2.10.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
- integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
- dependencies:
- has "^1.0.3"
-
-is-date-object@^1.0.1:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
- integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
- dependencies:
- has-tostringtag "^1.0.0"
-
-is-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
-
-is-fullwidth-code-point@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
- integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
- integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
- dependencies:
- is-extglob "^2.1.1"
-
-is-negative-zero@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
- integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
-
-is-number-object@^1.0.4:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
- integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
- dependencies:
- has-tostringtag "^1.0.0"
-
-is-number@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
- integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-regex@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
- integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
- dependencies:
- call-bind "^1.0.2"
- has-tostringtag "^1.0.0"
-
-is-shared-array-buffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
- integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
- dependencies:
- call-bind "^1.0.2"
-
-is-string@^1.0.5, is-string@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
- integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
- dependencies:
- has-tostringtag "^1.0.0"
-
-is-symbol@^1.0.2, is-symbol@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
- integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
- dependencies:
- has-symbols "^1.0.2"
-
-is-weakref@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
- integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
- dependencies:
- call-bind "^1.0.2"
-
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
-
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
- integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-
-js-yaml@^3.13.1:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
- integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
- dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
-
-jsesc@^2.5.1:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
- integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-
-json-schema-traverse@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
- integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
-
-json-schema-traverse@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
- integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
-
-json-stable-stringify-without-jsonify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
- integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
-
-json5@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
- integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
- dependencies:
- minimist "^1.2.0"
-
-json5@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
- integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
-
-"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.2:
- version "3.3.3"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea"
- integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==
- dependencies:
- array-includes "^3.1.5"
- object.assign "^4.1.3"
-
-language-subtag-registry@~0.3.2:
- version "0.3.22"
- resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
- integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==
-
-language-tags@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a"
- integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==
- dependencies:
- language-subtag-registry "~0.3.2"
-
-levn@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
- integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
- dependencies:
- prelude-ls "^1.2.1"
- type-check "~0.4.0"
-
-lodash.merge@^4.6.2:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
- integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-
-lodash.truncate@^4.4.2:
- version "4.4.2"
- resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
- integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==
-
-lodash@^4.17.21:
- version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
- integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-loose-envify@^1.1.0, loose-envify@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
- dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
-
-lru-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
- integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
- dependencies:
- yallist "^4.0.0"
-
-merge2@^1.3.0, merge2@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
- integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-
-micromatch@^4.0.4:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
- integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
- dependencies:
- braces "^3.0.2"
- picomatch "^2.3.1"
-
-minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
- integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@^1.2.0, minimist@^1.2.6:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
- integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-
-ms@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
-
-ms@2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
- integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-ms@^2.1.1:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
- integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
-nanoid@^3.3.4:
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
- integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
-
-natural-compare@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
- integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
-
-next-transpile-modules@9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz#133b1742af082e61cc76b02a0f12ffd40ce2bf90"
- integrity sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ==
- dependencies:
- enhanced-resolve "^5.7.0"
- escalade "^3.1.1"
-
-next@12.2.5:
- version "12.2.5"
- resolved "https://registry.yarnpkg.com/next/-/next-12.2.5.tgz#14fb5975e8841fad09553b8ef41fe1393602b717"
- integrity sha512-tBdjqX5XC/oFs/6gxrZhjmiq90YWizUYU6qOWAfat7zJwrwapJ+BYgX2PmiacunXMaRpeVT4vz5MSPSLgNkrpA==
- dependencies:
- "@next/env" "12.2.5"
- "@swc/helpers" "0.4.3"
- caniuse-lite "^1.0.30001332"
- postcss "8.4.14"
- styled-jsx "5.0.4"
- use-sync-external-store "1.2.0"
- optionalDependencies:
- "@next/swc-android-arm-eabi" "12.2.5"
- "@next/swc-android-arm64" "12.2.5"
- "@next/swc-darwin-arm64" "12.2.5"
- "@next/swc-darwin-x64" "12.2.5"
- "@next/swc-freebsd-x64" "12.2.5"
- "@next/swc-linux-arm-gnueabihf" "12.2.5"
- "@next/swc-linux-arm64-gnu" "12.2.5"
- "@next/swc-linux-arm64-musl" "12.2.5"
- "@next/swc-linux-x64-gnu" "12.2.5"
- "@next/swc-linux-x64-musl" "12.2.5"
- "@next/swc-win32-arm64-msvc" "12.2.5"
- "@next/swc-win32-ia32-msvc" "12.2.5"
- "@next/swc-win32-x64-msvc" "12.2.5"
-
-node-releases@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
- integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
-
-object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
-
-object-inspect@^1.12.2, object-inspect@^1.9.0:
- version "1.12.2"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
- integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
-
-object-keys@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
- integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-
-object.assign@^4.1.3, object.assign@^4.1.4:
- version "4.1.4"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
- integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- has-symbols "^1.0.3"
- object-keys "^1.1.1"
-
-object.entries@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861"
- integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
-
-object.fromentries@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251"
- integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
-
-object.hasown@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3"
- integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==
- dependencies:
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-object.values@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac"
- integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
-
-once@^1.3.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
- dependencies:
- wrappy "1"
-
-optionator@^0.9.1:
- version "0.9.1"
- resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
- integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
- dependencies:
- deep-is "^0.1.3"
- fast-levenshtein "^2.0.6"
- levn "^0.4.1"
- prelude-ls "^1.2.1"
- type-check "^0.4.0"
- word-wrap "^1.2.3"
-
-parent-module@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
- integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
- dependencies:
- callsites "^3.0.0"
-
-path-is-absolute@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-
-path-key@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
- integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-
-path-parse@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
- integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-
-path-type@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
- integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-
-picocolors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
- integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-
-picomatch@^2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
- integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-
-postcss@8.4.14:
- version "8.4.14"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
- integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
- dependencies:
- nanoid "^3.3.4"
- picocolors "^1.0.0"
- source-map-js "^1.0.2"
-
-prelude-ls@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
- integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-
-prettier@latest:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
- integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
-
-progress@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
- integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
-
-prop-types@^15.8.1:
- version "15.8.1"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
- integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
- dependencies:
- loose-envify "^1.4.0"
- object-assign "^4.1.1"
- react-is "^16.13.1"
-
-punycode@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
- integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-
-queue-microtask@^1.2.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
- integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
-
-react-dom@18.2.0:
- version "18.2.0"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
- integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
- dependencies:
- loose-envify "^1.1.0"
- scheduler "^0.23.0"
-
-react-is@^16.13.1:
- version "16.13.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
- integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-
-react@18.2.0, react@^18.2.0:
- version "18.2.0"
- resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
- integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
- dependencies:
- loose-envify "^1.1.0"
-
-regenerator-runtime@^0.13.4:
- version "0.13.9"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
- integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
-
-regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
- integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- functions-have-names "^1.2.2"
-
-regexpp@^3.1.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
- integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
-
-require-from-string@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
- integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
-
-resolve-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
- integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
-resolve@^1.20.0, resolve@^1.22.0:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
- dependencies:
- is-core-module "^2.9.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-resolve@^2.0.0-next.3:
- version "2.0.0-next.4"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660"
- integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==
- dependencies:
- is-core-module "^2.9.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-reusify@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
- integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-
-rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
-run-parallel@^1.1.9:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
- integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
- dependencies:
- queue-microtask "^1.2.2"
-
-safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-scheduler@^0.23.0:
- version "0.23.0"
- resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
- integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
- dependencies:
- loose-envify "^1.1.0"
-
-semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-semver@^7.2.1, semver@^7.3.7:
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
- integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
- dependencies:
- lru-cache "^6.0.0"
-
-shebang-command@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
- integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
- dependencies:
- shebang-regex "^3.0.0"
-
-shebang-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
- integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-
-side-channel@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
- integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
- dependencies:
- call-bind "^1.0.0"
- get-intrinsic "^1.0.2"
- object-inspect "^1.9.0"
-
-slash@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
- integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-
-slice-ansi@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
- integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
- dependencies:
- ansi-styles "^4.0.0"
- astral-regex "^2.0.0"
- is-fullwidth-code-point "^3.0.0"
-
-source-map-js@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
- integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-
-sprintf-js@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
- integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
-
-string-width@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-string.prototype.matchall@^4.0.7:
- version "4.0.7"
- resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d"
- integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
- get-intrinsic "^1.1.1"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- regexp.prototype.flags "^1.4.1"
- side-channel "^1.0.4"
-
-string.prototype.trimend@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
- integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-string.prototype.trimstart@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
- integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
-strip-bom@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
- integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
-
-strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
- integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-
-styled-jsx@5.0.4:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.4.tgz#5b1bd0b9ab44caae3dd1361295559706e044aa53"
- integrity sha512-sDFWLbg4zR+UkNzfk5lPilyIgtpddfxXEULxhujorr5jtePTUqiPDc5BC0v1NRqTr/WaFBGQQUoYToGlF4B2KQ==
-
-supports-color@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
- integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^7.1.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
- integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
- dependencies:
- has-flag "^4.0.0"
-
-supports-preserve-symlinks-flag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
- integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-
-table@^6.0.9:
- version "6.8.0"
- resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"
- integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==
- dependencies:
- ajv "^8.0.1"
- lodash.truncate "^4.4.2"
- slice-ansi "^4.0.0"
- string-width "^4.2.3"
- strip-ansi "^6.0.1"
-
-tapable@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
- integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
-
-text-table@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
- integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
-
-to-fast-properties@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
- integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
-
-to-regex-range@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
- integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
- dependencies:
- is-number "^7.0.0"
-
-tsconfig-paths@^3.14.1:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
- integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
- dependencies:
- "@types/json5" "^0.0.29"
- json5 "^1.0.1"
- minimist "^1.2.6"
- strip-bom "^3.0.0"
-
-tslib@^1.8.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
- integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-
-tslib@^2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
- integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
-
-tsutils@^3.21.0:
- version "3.21.0"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
- integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
- dependencies:
- tslib "^1.8.1"
-
-turbo-android-arm64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-android-arm64/-/turbo-android-arm64-1.4.6.tgz#2127110335a86a50856852c2728eb75f7f61b77b"
- integrity sha512-YxSlHc64CF5J7yNUMiLBHkeLyzrpe75Oy7tivWb3z7ySG44BXPikk4HDJZPh0T1ELvukDwuPKkvDukJ2oCLJpA==
-
-turbo-darwin-64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.4.6.tgz#8b3d930ed0d0b8c358d87ed2347381496f4283dd"
- integrity sha512-f6uto7LLpjwZ6iZSF+8uaDpuiTji6xmnWDxNuW23DBE8iv5mxehHd+6Ys851uKDRrPb3QdCu9ctyigKTAla5Vg==
-
-turbo-darwin-arm64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.4.6.tgz#7f045cbfbb1d6ac18ea28122b9a6a5fdc629488a"
- integrity sha512-o9C6e5XyuMHQwE0fEhUxfpXxvNr2QXXWX8nxIjygxeF19AqKbk/s08vZBOEmXV6/gx/pRhZ1S2nf0PIUjKBD/Q==
-
-turbo-freebsd-64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-freebsd-64/-/turbo-freebsd-64-1.4.6.tgz#b16c5617f2e818a709627351f1e14d1fd8dcf0e7"
- integrity sha512-Gg9VOUo6McXYKGevcYjGUSmMryZyZggvpdPh7Dw3QTcT8Tsy6OBtq6WnJ2O4kFDsMigyKtEOJPceD9vDMZt3yQ==
-
-turbo-freebsd-arm64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-freebsd-arm64/-/turbo-freebsd-arm64-1.4.6.tgz#462b8ba68cccac93d169c80cf458d221c662a770"
- integrity sha512-W7VrcneWFN1QENKt5cpAPSsf9ArYBBAm3VtPBZEO5tX8kuahGlah1SKdKJXrRxYOY82wyNxDagS/rHpBlrAAzw==
-
-turbo-linux-32@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-linux-32/-/turbo-linux-32-1.4.6.tgz#0a0859be0941e4bcdc4bff81b97ee36f02cc1ffd"
- integrity sha512-76j/zsui6mWPX8pZVMGgF8eiKHPmKuGa2lo0A/Ja0HUvdYCOGUfHsWJGVVIeYbuEp3jsKyVt7OnMDeH9CqO6bg==
-
-turbo-linux-64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.4.6.tgz#0a7d76fab78d7850c26d9d6b372c40ffca9835f8"
- integrity sha512-z4A37Xm7lZyO9ddtGnvQHWMrsAKX6vFBxdbtb9MY76VRblo7lWSuk4LwCeM+T+ZDJ9LBFiF7aD/diRShlLx9jA==
-
-turbo-linux-arm64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.4.6.tgz#c66d3c6917ccbdb34cd7ce37c900613f4d690ebc"
- integrity sha512-FW1jmOpZfOoVVvml338N0MPnYjiMyYWTaMb4T+IosgGYymcUE3xJjfXJcqfU/9/uKTyY8zG0qr9/5rw2kpMS2Q==
-
-turbo-linux-arm@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-linux-arm/-/turbo-linux-arm-1.4.6.tgz#9a9d73a722bdd6acb40276d0616c155168a32172"
- integrity sha512-Uh/V3oaAdhyZW6FKPpKihAxQo3EbvLaVNnzzkBmBnvHRkqoDJHhpuG72V7nn8pzxVbJ1++NEVjvbc2kmKFvGjg==
-
-turbo-linux-mips64le@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-linux-mips64le/-/turbo-linux-mips64le-1.4.6.tgz#eb74c333c16ef03aa30dcb83fcc29d58218656e4"
- integrity sha512-iWaL3Pwj52BH3T2M8nXScmbSnq4+x47MYK7lJMG7FsZGAIoT5ToO1Wt1iX3GRHTcnIZYm/kCfJ1ptK/NCossLA==
-
-turbo-linux-ppc64le@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-linux-ppc64le/-/turbo-linux-ppc64le-1.4.6.tgz#74597f4c30fe73c92ef8912e4bf25ccbe7c7ec7e"
- integrity sha512-Af/KlUmpiORDyELxT7byXNWl3fefErGQMJfeqXEtAdhs8OCKQWuU+lchcZbiBZYNpL+lZoa3PAmP9Fpx7R4plA==
-
-turbo-windows-32@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-windows-32/-/turbo-windows-32-1.4.6.tgz#df1f3c25fea0bbccf7c5b44111ddbcd57f6fe547"
- integrity sha512-NBd+XPlRSaR//lVN13Q9DOqK3CbowSvafIyGsO4jfvMsGTdyNDL6AYtFsvTKW91/G7ZhATmSEkPn2pZRuhP/DA==
-
-turbo-windows-64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.4.6.tgz#6a7d8897bb60234b6bc4b5d013adb00fac6f2beb"
- integrity sha512-86AbmG+CjzVTpn4RGtwU2CYy4zSyAc9bIQ4pDGLIpCJg6JlD11duaiMJh0SCU/HCqWLJjWDI4qD+f9WNbgPsyQ==
-
-turbo-windows-arm64@1.4.6:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.4.6.tgz#4c80528c6670ef50129053ad8279c832190b7234"
- integrity sha512-V+pWcqhTtmQQ3ew8qEjYtUwzyW6tO1RgvP+6OKzItYzTnMTr1Fe42Q21V+tqRNxuNfFDKsgVJdk2p5wB87bvyQ==
-
-turbo@latest:
- version "1.4.6"
- resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.4.6.tgz#c97c23cf898380bedabd04c5a91ab4eb9829bcdc"
- integrity sha512-FKtBXlOJ7YjSK22yj4sJLCtDcHFElypt7xw9cZN7Wyv9x4XBrTmh5KP6RmcGnRR1/GJlTNwD2AY2T9QTPnHh+g==
- optionalDependencies:
- turbo-android-arm64 "1.4.6"
- turbo-darwin-64 "1.4.6"
- turbo-darwin-arm64 "1.4.6"
- turbo-freebsd-64 "1.4.6"
- turbo-freebsd-arm64 "1.4.6"
- turbo-linux-32 "1.4.6"
- turbo-linux-64 "1.4.6"
- turbo-linux-arm "1.4.6"
- turbo-linux-arm64 "1.4.6"
- turbo-linux-mips64le "1.4.6"
- turbo-linux-ppc64le "1.4.6"
- turbo-windows-32 "1.4.6"
- turbo-windows-64 "1.4.6"
- turbo-windows-arm64 "1.4.6"
-
-type-check@^0.4.0, type-check@~0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
- integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
- dependencies:
- prelude-ls "^1.2.1"
-
-type-fest@^0.20.2:
- version "0.20.2"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
- integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
-
-typescript@^4.5.2, typescript@^4.5.3, typescript@^4.7.4:
- version "4.8.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88"
- integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==
-
-unbox-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
- integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
- dependencies:
- call-bind "^1.0.2"
- has-bigints "^1.0.2"
- has-symbols "^1.0.3"
- which-boxed-primitive "^1.0.2"
-
-update-browserslist-db@^1.0.5:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz#16279639cff1d0f800b14792de43d97df2d11b7d"
- integrity sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==
- dependencies:
- escalade "^3.1.1"
- picocolors "^1.0.0"
-
-uri-js@^4.2.2:
- version "4.4.1"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
- integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
- dependencies:
- punycode "^2.1.0"
-
-use-sync-external-store@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
- integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
-
-v8-compile-cache@^2.0.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
- integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
-
-which-boxed-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
- integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
- dependencies:
- is-bigint "^1.0.1"
- is-boolean-object "^1.1.0"
- is-number-object "^1.0.4"
- is-string "^1.0.5"
- is-symbol "^1.0.3"
-
-which@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
- integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
- dependencies:
- isexe "^2.0.0"
-
-word-wrap@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
- integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
-
-yallist@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
- integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
diff --git a/cli/internal/lockfile/yarn_lockfile.go b/cli/internal/lockfile/yarn_lockfile.go
deleted file mode 100644
index 99d7764..0000000
--- a/cli/internal/lockfile/yarn_lockfile.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package lockfile
-
-import (
- "bytes"
- "fmt"
- "io"
-
- "github.com/andybalholm/crlf"
- "github.com/iseki0/go-yarnlock"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-var _crlfLiteral = []byte("\r\n")
-
-// YarnLockfile representation of yarn lockfile
-type YarnLockfile struct {
- inner yarnlock.LockFile
- hasCRLF bool
-}
-
-var _ Lockfile = (*YarnLockfile)(nil)
-
-// ResolvePackage Given a package and version returns the key, resolved version, and if it was found
-func (l *YarnLockfile) ResolvePackage(_workspacePath turbopath.AnchoredUnixPath, name string, version string) (Package, error) {
- for _, key := range yarnPossibleKeys(name, version) {
- if entry, ok := (l.inner)[key]; ok {
- return Package{
- Found: true,
- Key: key,
- Version: entry.Version,
- }, nil
- }
- }
-
- return Package{}, nil
-}
-
-// AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package
-func (l *YarnLockfile) AllDependencies(key string) (map[string]string, bool) {
- deps := map[string]string{}
- entry, ok := (l.inner)[key]
- if !ok {
- return deps, false
- }
-
- for name, version := range entry.Dependencies {
- deps[name] = version
- }
- for name, version := range entry.OptionalDependencies {
- deps[name] = version
- }
-
- return deps, true
-}
-
-// Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given
-func (l *YarnLockfile) Subgraph(_ []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) {
- lockfile := make(map[string]yarnlock.LockFileEntry, len(packages))
- for _, key := range packages {
- entry, ok := (l.inner)[key]
- if ok {
- lockfile[key] = entry
- }
- }
-
- return &YarnLockfile{lockfile, l.hasCRLF}, nil
-}
-
-// Encode encode the lockfile representation and write it to the given writer
-func (l *YarnLockfile) Encode(w io.Writer) error {
- writer := w
- if l.hasCRLF {
- writer = crlf.NewWriter(w)
- }
- if err := l.inner.Encode(writer); err != nil {
- return errors.Wrap(err, "Unable to encode yarn.lock")
- }
- return nil
-}
-
-// Patches return a list of patches used in the lockfile
-func (l *YarnLockfile) Patches() []turbopath.AnchoredUnixPath {
- return nil
-}
-
-// DecodeYarnLockfile Takes the contents of a yarn lockfile and returns a struct representation
-func DecodeYarnLockfile(contents []byte) (*YarnLockfile, error) {
- lockfile, err := yarnlock.ParseLockFileData(contents)
- hasCRLF := bytes.HasSuffix(contents, _crlfLiteral)
- newline := []byte("\n")
-
- // there's no trailing newline for this file, need to inspect more to see newline style
- if !hasCRLF && !bytes.HasSuffix(contents, newline) {
- firstNewline := bytes.IndexByte(contents, newline[0])
- if firstNewline != -1 && firstNewline != 0 {
- byteBeforeNewline := contents[firstNewline-1]
- hasCRLF = byteBeforeNewline == '\r'
- }
- }
-
- if err != nil {
- return nil, errors.Wrap(err, "Unable to decode yarn.lock")
- }
-
- return &YarnLockfile{lockfile, hasCRLF}, nil
-}
-
-// GlobalChange checks if there are any differences between lockfiles that would completely invalidate
-// the cache.
-func (l *YarnLockfile) GlobalChange(other Lockfile) bool {
- _, ok := other.(*YarnLockfile)
- return !ok
-}
-
-func yarnPossibleKeys(name string, version string) []string {
- return []string{
- fmt.Sprintf("%v@%v", name, version),
- fmt.Sprintf("%v@npm:%v", name, version),
- fmt.Sprintf("%v@file:%v", name, version),
- fmt.Sprintf("%v@workspace:%v", name, version),
- fmt.Sprintf("%v@yarn:%v", name, version),
- }
-}
diff --git a/cli/internal/lockfile/yarn_lockfile_test.go b/cli/internal/lockfile/yarn_lockfile_test.go
deleted file mode 100644
index ef4fcb0..0000000
--- a/cli/internal/lockfile/yarn_lockfile_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package lockfile
-
-import (
- "bytes"
- "testing"
-
- "gotest.tools/v3/assert"
-)
-
-func TestRoundtrip(t *testing.T) {
- content, err := getFixture(t, "yarn.lock")
- if err != nil {
- t.Error(err)
- }
-
- lockfile, err := DecodeYarnLockfile(content)
- if err != nil {
- t.Error(err)
- }
-
- var b bytes.Buffer
- if err := lockfile.Encode(&b); err != nil {
- t.Error(err)
- }
-
- assert.DeepEqual(t, string(content), b.String())
-}
-
-func TestKeySplitting(t *testing.T) {
- content, err := getFixture(t, "yarn.lock")
- if err != nil {
- t.Error(err)
- }
-
- lockfile, err := DecodeYarnLockfile(content)
- if err != nil {
- t.Error(err)
- }
-
- // @babel/types has multiple entries, these should all appear in the lockfile struct
- keys := []string{
- "@babel/types@^7.18.10",
- "@babel/types@^7.18.6",
- "@babel/types@^7.19.0",
- }
-
- for _, key := range keys {
- _, ok := lockfile.inner[key]
- assert.Assert(t, ok, "Unable to find entry for %s in parsed lockfile", key)
- }
-}
diff --git a/cli/internal/logstreamer/logstreamer.go b/cli/internal/logstreamer/logstreamer.go
deleted file mode 100644
index 4379c25..0000000
--- a/cli/internal/logstreamer/logstreamer.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2013 Kevin van Zonneveld <kevin@vanzonneveld.net>. All rights reserved.
-// Source: https://github.com/kvz/logstreamer
-// SPDX-License-Identifier: MIT
-package logstreamer
-
-import (
- "bytes"
- "io"
- "log"
- "os"
- "strings"
-)
-
-type Logstreamer struct {
- Logger *log.Logger
- buf *bytes.Buffer
- // If prefix == stdout, colors green
- // If prefix == stderr, colors red
- // Else, prefix is taken as-is, and prepended to anything
- // you throw at Write()
- prefix string
- // if true, saves output in memory
- record bool
- persist string
-
- // Adds color to stdout & stderr if terminal supports it
- colorOkay string
- colorFail string
- colorReset string
-}
-
-func NewLogstreamer(logger *log.Logger, prefix string, record bool) *Logstreamer {
- streamer := &Logstreamer{
- Logger: logger,
- buf: bytes.NewBuffer([]byte("")),
- prefix: prefix,
- record: record,
- persist: "",
- colorOkay: "",
- colorFail: "",
- colorReset: "",
- }
-
- if strings.HasPrefix(os.Getenv("TERM"), "xterm") {
- streamer.colorOkay = "\x1b[32m"
- streamer.colorFail = "\x1b[31m"
- streamer.colorReset = "\x1b[0m"
- }
-
- return streamer
-}
-
-func (l *Logstreamer) Write(p []byte) (n int, err error) {
- if n, err = l.buf.Write(p); err != nil {
- return
- }
-
- err = l.OutputLines()
- return
-}
-
-func (l *Logstreamer) Close() error {
- if err := l.Flush(); err != nil {
- return err
- }
- l.buf = bytes.NewBuffer([]byte(""))
- return nil
-}
-
-func (l *Logstreamer) Flush() error {
- p := make([]byte, l.buf.Len())
- if _, err := l.buf.Read(p); err != nil {
- return err
- }
-
- l.out(string(p))
- return nil
-}
-
-func (l *Logstreamer) OutputLines() error {
- for {
- line, err := l.buf.ReadString('\n')
-
- if len(line) > 0 {
- if strings.HasSuffix(line, "\n") {
- l.out(line)
- } else {
- // put back into buffer, it's not a complete line yet
- // Close() or Flush() have to be used to flush out
- // the last remaining line if it does not end with a newline
- if _, err := l.buf.WriteString(line); err != nil {
- return err
- }
- }
- }
-
- if err == io.EOF {
- break
- }
-
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (l *Logstreamer) FlushRecord() string {
- buffer := l.persist
- l.persist = ""
- return buffer
-}
-
-func (l *Logstreamer) out(str string) {
- if len(str) < 1 {
- return
- }
-
- if l.record {
- l.persist = l.persist + str
- }
-
- if l.prefix == "stdout" {
- str = l.colorOkay + l.prefix + l.colorReset + " " + str
- } else if l.prefix == "stderr" {
- str = l.colorFail + l.prefix + l.colorReset + " " + str
- }
-
- l.Logger.Print(str)
-}
-
-// PrettyStdoutWriter wraps an ioWriter so it can add string
-// prefixes to every message it writes to stdout.
-type PrettyStdoutWriter struct {
- w io.Writer
- Prefix string
-}
-
-var _ io.Writer = (*PrettyStdoutWriter)(nil)
-
-// NewPrettyStdoutWriter returns an instance of PrettyStdoutWriter
-func NewPrettyStdoutWriter(prefix string) *PrettyStdoutWriter {
- return &PrettyStdoutWriter{
- w: os.Stdout,
- Prefix: prefix,
- }
-}
-
-func (psw *PrettyStdoutWriter) Write(p []byte) (int, error) {
- str := psw.Prefix + string(p)
- n, err := psw.w.Write([]byte(str))
-
- if err != nil {
- return n, err
- }
-
- return len(p), nil
-}
diff --git a/cli/internal/logstreamer/logstreamer_test.go b/cli/internal/logstreamer/logstreamer_test.go
deleted file mode 100644
index 94d8a82..0000000
--- a/cli/internal/logstreamer/logstreamer_test.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2013 Kevin van Zonneveld <kevin@vanzonneveld.net>. All rights reserved.
-// Source: https://github.com/kvz/logstreamer
-// SPDX-License-Identifier: MIT
-package logstreamer
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "log"
- "os"
- "os/exec"
- "strings"
- "testing"
-)
-
-func TestLogstreamerOk(t *testing.T) {
- // Create a logger (your app probably already has one)
- logger := log.New(os.Stdout, "--> ", log.Ldate|log.Ltime)
-
- // Setup a streamer that we'll pipe cmd.Stdout to
- logStreamerOut := NewLogstreamer(logger, "stdout", false)
- defer logStreamerOut.Close()
- // Setup a streamer that we'll pipe cmd.Stderr to.
- // We want to record/buffer anything that's written to this (3rd argument true)
- logStreamerErr := NewLogstreamer(logger, "stderr", true)
- defer logStreamerErr.Close()
-
- // Execute something that succeeds
- cmd := exec.Command(
- "ls",
- "-al",
- )
- cmd.Stderr = logStreamerErr
- cmd.Stdout = logStreamerOut
-
- // Reset any error we recorded
- logStreamerErr.FlushRecord()
-
- // Execute command
- err := cmd.Start()
-
- // Failed to spawn?
- if err != nil {
- t.Fatal("ERROR could not spawn command.", err.Error())
- }
-
- // Failed to execute?
- err = cmd.Wait()
- if err != nil {
- t.Fatal("ERROR command finished with error. ", err.Error(), logStreamerErr.FlushRecord())
- }
-}
-
-func TestLogstreamerErr(t *testing.T) {
- // Create a logger (your app probably already has one)
- logger := log.New(os.Stdout, "--> ", log.Ldate|log.Ltime)
-
- // Setup a streamer that we'll pipe cmd.Stdout to
- logStreamerOut := NewLogstreamer(logger, "stdout", false)
- defer logStreamerOut.Close()
- // Setup a streamer that we'll pipe cmd.Stderr to.
- // We want to record/buffer anything that's written to this (3rd argument true)
- logStreamerErr := NewLogstreamer(logger, "stderr", true)
- defer logStreamerErr.Close()
-
- // Execute something that succeeds
- cmd := exec.Command(
- "ls",
- "nonexisting",
- )
- cmd.Stderr = logStreamerErr
- cmd.Stdout = logStreamerOut
-
- // Reset any error we recorded
- logStreamerErr.FlushRecord()
-
- // Execute command
- err := cmd.Start()
-
- // Failed to spawn?
- if err != nil {
- logger.Print("ERROR could not spawn command. ")
- }
-
- // Failed to execute?
- err = cmd.Wait()
- if err != nil {
- fmt.Printf("Good. command finished with %s. %s. \n", err.Error(), logStreamerErr.FlushRecord())
- } else {
- t.Fatal("This command should have failed")
- }
-}
-
-func TestLogstreamerFlush(t *testing.T) {
- const text = "Text without newline"
-
- var buffer bytes.Buffer
- byteWriter := bufio.NewWriter(&buffer)
-
- logger := log.New(byteWriter, "", 0)
- logStreamerOut := NewLogstreamer(logger, "", false)
- defer logStreamerOut.Close()
-
- logStreamerOut.Write([]byte(text))
- logStreamerOut.Flush()
- byteWriter.Flush()
-
- s := strings.TrimSpace(buffer.String())
-
- if s != text {
- t.Fatalf("Expected '%s', got '%s'.", text, s)
- }
-}
diff --git a/cli/internal/nodes/packagetask.go b/cli/internal/nodes/packagetask.go
deleted file mode 100644
index e2dcb27..0000000
--- a/cli/internal/nodes/packagetask.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Package nodes defines the nodes that are present in the execution graph used by turbo.
-package nodes
-
-import (
- "fmt"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// PackageTask represents running a particular task in a particular package
-type PackageTask struct {
- TaskID string
- Task string
- PackageName string
- Pkg *fs.PackageJSON
- EnvMode util.EnvMode
- TaskDefinition *fs.TaskDefinition
- Dir string
- Command string
- Outputs []string
- ExcludedOutputs []string
- LogFile string
- Hash string
-}
-
-// OutputPrefix returns the prefix to be used for logging and ui for this task
-func (pt *PackageTask) OutputPrefix(isSinglePackage bool) string {
- if isSinglePackage {
- return pt.Task
- }
- return fmt.Sprintf("%v:%v", pt.PackageName, pt.Task)
-}
-
-// HashableOutputs returns the package-relative globs for files to be considered outputs
-// of this task
-func (pt *PackageTask) HashableOutputs() fs.TaskOutputs {
- inclusionOutputs := []string{fmt.Sprintf(".turbo/turbo-%v.log", pt.Task)}
- inclusionOutputs = append(inclusionOutputs, pt.TaskDefinition.Outputs.Inclusions...)
-
- return fs.TaskOutputs{
- Inclusions: inclusionOutputs,
- Exclusions: pt.TaskDefinition.Outputs.Exclusions,
- }
-}
diff --git a/cli/internal/packagemanager/berry.go b/cli/internal/packagemanager/berry.go
deleted file mode 100644
index d6264b1..0000000
--- a/cli/internal/packagemanager/berry.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package packagemanager
-
-import (
- "fmt"
- "os/exec"
- "strings"
-
- "github.com/Masterminds/semver"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-var nodejsBerry = PackageManager{
- Name: "nodejs-berry",
- Slug: "yarn",
- Command: "yarn",
- Specfile: "package.json",
- Lockfile: "yarn.lock",
- PackageDir: "node_modules",
-
- getWorkspaceGlobs: func(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- pkg, err := fs.ReadPackageJSON(rootpath.UntypedJoin("package.json"))
- if err != nil {
- return nil, fmt.Errorf("package.json: %w", err)
- }
- if len(pkg.Workspaces) == 0 {
- return nil, fmt.Errorf("package.json: no workspaces found. Turborepo requires Yarn workspaces to be defined in the root package.json")
- }
- return pkg.Workspaces, nil
- },
-
- getWorkspaceIgnores: func(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- // Matches upstream values:
- // Key code: https://github.com/yarnpkg/berry/blob/8e0c4b897b0881878a1f901230ea49b7c8113fbe/packages/yarnpkg-core/sources/Workspace.ts#L64-L70
- return []string{
- "**/node_modules",
- "**/.git",
- "**/.yarn",
- }, nil
- },
-
- canPrune: func(cwd turbopath.AbsoluteSystemPath) (bool, error) {
- if isNMLinker, err := util.IsNMLinker(cwd.ToStringDuringMigration()); err != nil {
- return false, errors.Wrap(err, "could not determine if yarn is using `nodeLinker: node-modules`")
- } else if !isNMLinker {
- return false, errors.New("only yarn v2/v3 with `nodeLinker: node-modules` is supported at this time")
- }
- return true, nil
- },
-
- // Versions newer than 2.0 are berry, and before that we simply call them yarn.
- Matches: func(manager string, version string) (bool, error) {
- if manager != "yarn" {
- return false, nil
- }
-
- v, err := semver.NewVersion(version)
- if err != nil {
- return false, fmt.Errorf("could not parse yarn version: %w", err)
- }
- // -0 allows pre-releases versions to be considered valid
- c, err := semver.NewConstraint(">=2.0.0-0")
- if err != nil {
- return false, fmt.Errorf("could not create constraint: %w", err)
- }
-
- return c.Check(v), nil
- },
-
- // Detect for berry needs to identify which version of yarn is running on the system.
- // Further, berry can be configured in an incompatible way, so we check for compatibility here as well.
- detect: func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error) {
- specfileExists := projectDirectory.UntypedJoin(packageManager.Specfile).FileExists()
- lockfileExists := projectDirectory.UntypedJoin(packageManager.Lockfile).FileExists()
-
- // Short-circuit, definitely not Yarn.
- if !specfileExists || !lockfileExists {
- return false, nil
- }
-
- cmd := exec.Command("yarn", "--version")
- cmd.Dir = projectDirectory.ToString()
- out, err := cmd.Output()
- if err != nil {
- return false, fmt.Errorf("could not detect yarn version: %w", err)
- }
-
- // See if we're a match when we compare these two things.
- matches, _ := packageManager.Matches(packageManager.Slug, string(out))
-
- // Short-circuit, definitely not Berry because version number says we're Yarn.
- if !matches {
- return false, nil
- }
-
- // We're Berry!
-
- // Check for supported configuration.
- isNMLinker, err := util.IsNMLinker(projectDirectory.ToStringDuringMigration())
-
- if err != nil {
- // Failed to read the linker state, so we treat an unknown configuration as a failure.
- return false, fmt.Errorf("could not check if yarn is using nm-linker: %w", err)
- } else if !isNMLinker {
- // Not using nm-linker, so unsupported configuration.
- return false, fmt.Errorf("only yarn nm-linker is supported")
- }
-
- // Berry, supported configuration.
- return true, nil
- },
-
- UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) {
- return lockfile.DecodeBerryLockfile(contents)
- },
-
- prunePatches: func(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error {
- pkgJSON.Mu.Lock()
- defer pkgJSON.Mu.Unlock()
-
- keysToDelete := []string{}
- resolutions, ok := pkgJSON.RawJSON["resolutions"].(map[string]interface{})
- if !ok {
- return fmt.Errorf("Invalid structure for resolutions field in package.json")
- }
-
- for dependency, untypedPatch := range resolutions {
- inPatches := false
- patch, ok := untypedPatch.(string)
- if !ok {
- return fmt.Errorf("Expected value of %s in package.json to be a string, got %v", dependency, untypedPatch)
- }
-
- for _, wantedPatch := range patches {
- if strings.HasSuffix(patch, wantedPatch.ToString()) {
- inPatches = true
- break
- }
- }
-
- // We only want to delete unused patches as they are the only ones that throw if unused
- if !inPatches && strings.HasSuffix(patch, ".patch") {
- keysToDelete = append(keysToDelete, dependency)
- }
- }
-
- for _, key := range keysToDelete {
- delete(resolutions, key)
- }
-
- return nil
- },
-}
diff --git a/cli/internal/packagemanager/fixtures/package.json b/cli/internal/packagemanager/fixtures/package.json
deleted file mode 100644
index 6b27f7c..0000000
--- a/cli/internal/packagemanager/fixtures/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "fixture",
- "workspaces": [
- "apps/*",
- "packages/*"
- ]
-}
diff --git a/cli/internal/packagemanager/fixtures/pnpm-patches.json b/cli/internal/packagemanager/fixtures/pnpm-patches.json
deleted file mode 100644
index f772bc3..0000000
--- a/cli/internal/packagemanager/fixtures/pnpm-patches.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "turborepo-prune-removes-patched",
- "version": "1.0.0",
- "packageManager": "pnpm@7.15.0",
- "workspaces": ["packages/*"],
- "pnpm": {
- "patchedDependencies": {
- "is-odd@3.0.1": "patches/is-odd@3.0.1.patch"
- }
- }
-}
diff --git a/cli/internal/packagemanager/fixtures/pnpm-workspace.yaml b/cli/internal/packagemanager/fixtures/pnpm-workspace.yaml
deleted file mode 100644
index 7fbb770..0000000
--- a/cli/internal/packagemanager/fixtures/pnpm-workspace.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-packages:
- - "packages/*"
- - "!packages/skip"
diff --git a/cli/internal/packagemanager/infer_root.go b/cli/internal/packagemanager/infer_root.go
deleted file mode 100644
index 7920f12..0000000
--- a/cli/internal/packagemanager/infer_root.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package packagemanager
-
-import (
- "path/filepath"
-
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// PackageType represents the mode in which turbo is running.
-type PackageType string
-
-const (
- // Single is for single-package mode.
- Single PackageType = "single"
- // Multi is for monorepo mode.
- Multi PackageType = "multi"
-)
-
-func candidateDirectoryWorkspaceGlobs(directory turbopath.AbsoluteSystemPath) []string {
- packageManagers := []PackageManager{
- nodejsNpm,
- nodejsPnpm,
- }
-
- for _, pm := range packageManagers {
- globs, err := pm.getWorkspaceGlobs(directory)
- if err != nil {
- // Try the other package manager workspace formats.
- continue
- }
-
- return globs
- }
-
- return nil
-}
-
-func isOneOfTheWorkspaces(globs []string, nearestPackageJSONDir turbopath.AbsoluteSystemPath, currentPackageJSONDir turbopath.AbsoluteSystemPath) bool {
- for _, glob := range globs {
- globpattern := currentPackageJSONDir.UntypedJoin(filepath.FromSlash(glob)).ToString()
- match, _ := doublestar.PathMatch(globpattern, nearestPackageJSONDir.ToString())
- if match {
- return true
- }
- }
-
- return false
-}
-
-// InferRoot identifies which directory we should treat as the root, and which mode
-// turbo should be in when operating at that directory.
-func InferRoot(directory turbopath.AbsoluteSystemPath) (turbopath.AbsoluteSystemPath, PackageType) {
- // Go doesn't have iterators, so this is very not-elegant.
-
- // Scenarios:
- // 0. Has a turbo.json but doesn't have a peer package.json. directory + multi
- // 1. Nearest turbo.json, check peer package.json/pnpm-workspace.yaml.
- // A. Has workspaces, multi package mode.
- // B. No workspaces, single package mode.
- // 2. If no turbo.json find the closest package.json parent.
- // A. No parent package.json, default to current behavior.
- // B. Nearest package.json defines workspaces. Can't be in single-package mode, so we bail. (This could be changed in the future.)
- // 3. Closest package.json does not define workspaces. Traverse toward the root looking for package.jsons.
- // A. No parent package.json with workspaces. nearestPackageJson + single
- // B. Stop at the first one that has workspaces.
- // i. If we are one of the workspaces, directory + multi. (This could be changed in the future.)
- // ii. If we're not one of the workspaces, nearestPackageJson + single.
-
- nearestTurboJSON, findTurboJSONErr := directory.Findup("turbo.json")
- if nearestTurboJSON == "" || findTurboJSONErr != nil {
- // We didn't find a turbo.json. We're in situation 2 or 3.
-
- // Unroll the first loop for Scenario 2
- nearestPackageJSON, nearestPackageJSONErr := directory.Findup("package.json")
-
- // If we fail to find any package.json files we aren't in single package mode.
- // We let things go through our existing failure paths.
- // Scenario 2A.
- if nearestPackageJSON == "" || nearestPackageJSONErr != nil {
- return directory, Multi
- }
-
- // If we find a package.json which has workspaces we aren't in single package mode.
- // We let things go through our existing failure paths.
- // Scenario 2B.
- if candidateDirectoryWorkspaceGlobs(nearestPackageJSON.Dir()) != nil {
- // In a future world we could maybe change this behavior.
- // return nearestPackageJson.Dir(), Multi
- return directory, Multi
- }
-
- // Scenario 3.
- // Find the nearest package.json that has workspaces.
- // If found _and_ the nearestPackageJson is one of the workspaces, thatPackageJson + multi.
- // Else, nearestPackageJson + single
- cursor := nearestPackageJSON.Dir().UntypedJoin("..")
- for {
- nextPackageJSON, nextPackageJSONErr := cursor.Findup("package.json")
- if nextPackageJSON == "" || nextPackageJSONErr != nil {
- // We haven't found a parent defining workspaces.
- // So we're single package mode at nearestPackageJson.
- // Scenario 3A.
- return nearestPackageJSON.Dir(), Single
- }
-
- // Found a package.json file, see if it has workspaces.
- // Workspaces are not allowed to be recursive, so we know what to
- // return the moment we find something with workspaces.
- globs := candidateDirectoryWorkspaceGlobs(nextPackageJSON.Dir())
- if globs != nil {
- if isOneOfTheWorkspaces(globs, nearestPackageJSON.Dir(), nextPackageJSON.Dir()) {
- // If it has workspaces, and nearestPackageJson is one of them, we're multi.
- // We don't infer in this scenario.
- // Scenario 3BI.
- // TODO: return nextPackageJson.Dir(), Multi
- return directory, Multi
- }
-
- // We found a parent with workspaces, but we're not one of them.
- // We choose to operate in single package mode.
- // Scenario 3BII
- return nearestPackageJSON.Dir(), Single
- }
-
- // Loop around and see if we have another parent.
- cursor = nextPackageJSON.Dir().UntypedJoin("..")
- }
- } else {
- // If there is no sibling package.json we do no inference.
- siblingPackageJSONPath := nearestTurboJSON.Dir().UntypedJoin("package.json")
- if !siblingPackageJSONPath.Exists() {
- // We do no inference.
- // Scenario 0
- return directory, Multi
- }
-
- if candidateDirectoryWorkspaceGlobs(nearestTurboJSON.Dir()) != nil {
- // Scenario 1A.
- return nearestTurboJSON.Dir(), Multi
- }
-
- // Scenario 1B.
- return nearestTurboJSON.Dir(), Single
- }
-}
diff --git a/cli/internal/packagemanager/infer_root_test.go b/cli/internal/packagemanager/infer_root_test.go
deleted file mode 100644
index 2e37a80..0000000
--- a/cli/internal/packagemanager/infer_root_test.go
+++ /dev/null
@@ -1,347 +0,0 @@
-package packagemanager
-
-import (
- "reflect"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func TestInferRoot(t *testing.T) {
- type file struct {
- path turbopath.AnchoredSystemPath
- content []byte
- }
-
- tests := []struct {
- name string
- fs []file
- executionDirectory turbopath.AnchoredSystemPath
- rootPath turbopath.AnchoredSystemPath
- packageMode PackageType
- }{
- // Scenario 0
- {
- name: "turbo.json at current dir, no package.json",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- },
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "turbo.json at parent dir, no package.json",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- // This is "no inference"
- rootPath: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- packageMode: Multi,
- },
- // Scenario 1A
- {
- name: "turbo.json at current dir, has package.json, has workspaces key",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "turbo.json at parent dir, has package.json, has workspaces key",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "turbo.json at parent dir, has package.json, has pnpm workspaces",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("pnpm-workspace.yaml").ToSystemPath(),
- content: []byte("packages:\n - docs"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- // Scenario 1A aware of the weird thing we do for packages.
- {
- name: "turbo.json at current dir, has package.json, has packages key",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"packages\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Single,
- },
- {
- name: "turbo.json at parent dir, has package.json, has packages key",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"packages\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Single,
- },
- // Scenario 1A aware of the the weird thing we do for packages when both methods of specification exist.
- {
- name: "turbo.json at current dir, has package.json, has workspace and packages key",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"clobbered\" ], \"packages\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "turbo.json at parent dir, has package.json, has workspace and packages key",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"clobbered\" ], \"packages\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- // Scenario 1B
- {
- name: "turbo.json at current dir, has package.json, no workspaces",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Single,
- },
- {
- name: "turbo.json at parent dir, has package.json, no workspaces",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Single,
- },
- {
- name: "turbo.json at parent dir, has package.json, no workspaces, includes pnpm",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {path: turbopath.AnchoredUnixPath("turbo.json").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("pnpm-workspace.yaml").ToSystemPath(),
- content: []byte(""),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Single,
- },
- // Scenario 2A
- {
- name: "no turbo.json, no package.json at current",
- fs: []file{},
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "no turbo.json, no package.json at parent",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- packageMode: Multi,
- },
- // Scenario 2B
- {
- name: "no turbo.json, has package.json with workspaces at current",
- fs: []file{
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "no turbo.json, has package.json with workspaces at parent",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"exists\" ] }"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- packageMode: Multi,
- },
- {
- name: "no turbo.json, has package.json with pnpm workspaces at parent",
- fs: []file{
- {path: turbopath.AnchoredUnixPath("execution/path/subdir/.file").ToSystemPath()},
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"exists\" ] }"),
- },
- {
- path: turbopath.AnchoredUnixPath("pnpm-workspace.yaml").ToSystemPath(),
- content: []byte("packages:\n - docs"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("execution/path/subdir").ToSystemPath(),
- packageMode: Multi,
- },
- // Scenario 3A
- {
- name: "no turbo.json, lots of package.json files but no workspaces",
- fs: []file{
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/two/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/two/three/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("one/two/three").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("one/two/three").ToSystemPath(),
- packageMode: Single,
- },
- // Scenario 3BI
- {
- name: "no turbo.json, lots of package.json files, and a workspace at the root that matches execution directory",
- fs: []file{
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"one/two/three\" ] }"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/two/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/two/three/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("one/two/three").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("one/two/three").ToSystemPath(),
- packageMode: Multi,
- },
- // Scenario 3BII
- {
- name: "no turbo.json, lots of package.json files, and a workspace at the root that matches execution directory",
- fs: []file{
- {
- path: turbopath.AnchoredUnixPath("package.json").ToSystemPath(),
- content: []byte("{ \"workspaces\": [ \"does-not-exist\" ] }"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/two/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- {
- path: turbopath.AnchoredUnixPath("one/two/three/package.json").ToSystemPath(),
- content: []byte("{}"),
- },
- },
- executionDirectory: turbopath.AnchoredUnixPath("one/two/three").ToSystemPath(),
- rootPath: turbopath.AnchoredUnixPath("one/two/three").ToSystemPath(),
- packageMode: Single,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- fsRoot := turbopath.AbsoluteSystemPath(t.TempDir())
- for _, file := range tt.fs {
- path := file.path.RestoreAnchor(fsRoot)
- assert.NilError(t, path.Dir().MkdirAll(0777))
- assert.NilError(t, path.WriteFile(file.content, 0777))
- }
-
- turboRoot, packageMode := InferRoot(tt.executionDirectory.RestoreAnchor(fsRoot))
- if !reflect.DeepEqual(turboRoot, tt.rootPath.RestoreAnchor(fsRoot)) {
- t.Errorf("InferRoot() turboRoot = %v, want %v", turboRoot, tt.rootPath.RestoreAnchor(fsRoot))
- }
- if packageMode != tt.packageMode {
- t.Errorf("InferRoot() packageMode = %v, want %v", packageMode, tt.packageMode)
- }
- })
- }
-}
diff --git a/cli/internal/packagemanager/npm.go b/cli/internal/packagemanager/npm.go
deleted file mode 100644
index ce2eb8c..0000000
--- a/cli/internal/packagemanager/npm.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package packagemanager
-
-import (
- "fmt"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-var nodejsNpm = PackageManager{
- Name: "nodejs-npm",
- Slug: "npm",
- Command: "npm",
- Specfile: "package.json",
- Lockfile: "package-lock.json",
- PackageDir: "node_modules",
- ArgSeparator: []string{"--"},
-
- getWorkspaceGlobs: func(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- pkg, err := fs.ReadPackageJSON(rootpath.UntypedJoin("package.json"))
- if err != nil {
- return nil, fmt.Errorf("package.json: %w", err)
- }
- if len(pkg.Workspaces) == 0 {
- return nil, fmt.Errorf("package.json: no workspaces found. Turborepo requires npm workspaces to be defined in the root package.json")
- }
- return pkg.Workspaces, nil
- },
-
- getWorkspaceIgnores: func(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- // Matches upstream values:
- // function: https://github.com/npm/map-workspaces/blob/a46503543982cb35f51cc2d6253d4dcc6bca9b32/lib/index.js#L73
- // key code: https://github.com/npm/map-workspaces/blob/a46503543982cb35f51cc2d6253d4dcc6bca9b32/lib/index.js#L90-L96
- // call site: https://github.com/npm/cli/blob/7a858277171813b37d46a032e49db44c8624f78f/lib/workspaces/get-workspaces.js#L14
- return []string{
- "**/node_modules/**",
- }, nil
- },
-
- Matches: func(manager string, version string) (bool, error) {
- return manager == "npm", nil
- },
-
- detect: func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error) {
- specfileExists := projectDirectory.UntypedJoin(packageManager.Specfile).FileExists()
- lockfileExists := projectDirectory.UntypedJoin(packageManager.Lockfile).FileExists()
-
- return (specfileExists && lockfileExists), nil
- },
-
- canPrune: func(cwd turbopath.AbsoluteSystemPath) (bool, error) {
- return true, nil
- },
-
- UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) {
- return lockfile.DecodeNpmLockfile(contents)
- },
-}
diff --git a/cli/internal/packagemanager/packagemanager.go b/cli/internal/packagemanager/packagemanager.go
deleted file mode 100644
index dc5b966..0000000
--- a/cli/internal/packagemanager/packagemanager.go
+++ /dev/null
@@ -1,197 +0,0 @@
-// Adapted from https://github.com/replit/upm
-// Copyright (c) 2019 Neoreason d/b/a Repl.it. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package packagemanager
-
-import (
- "fmt"
- "path/filepath"
- "regexp"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/globby"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// PackageManager is an abstraction across package managers
-type PackageManager struct {
- // The descriptive name of the Package Manager.
- Name string
-
- // The unique identifier of the Package Manager.
- Slug string
-
- // The command used to invoke the Package Manager.
- Command string
-
- // The location of the package spec file used by the Package Manager.
- Specfile string
-
- // The location of the package lock file used by the Package Manager.
- Lockfile string
-
- // The directory in which package assets are stored by the Package Manager.
- PackageDir string
-
- // The location of the file that defines the workspace. Empty if workspaces defined in package.json
- WorkspaceConfigurationPath string
-
- // The separator that the Package Manger uses to identify arguments that
- // should be passed through to the underlying script.
- ArgSeparator []string
-
- // Return the list of workspace glob
- getWorkspaceGlobs func(rootpath turbopath.AbsoluteSystemPath) ([]string, error)
-
- // Return the list of workspace ignore globs
- getWorkspaceIgnores func(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error)
-
- // Detect if Turbo knows how to produce a pruned workspace for the project
- canPrune func(cwd turbopath.AbsoluteSystemPath) (bool, error)
-
- // Test a manager and version tuple to see if it is the Package Manager.
- Matches func(manager string, version string) (bool, error)
-
- // Detect if the project is using the Package Manager by inspecting the system.
- detect func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error)
-
- // Read a lockfile for a given package manager
- UnmarshalLockfile func(rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error)
-
- // Prune the given pkgJSON to only include references to the given patches
- prunePatches func(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error
-}
-
-var packageManagers = []PackageManager{
- nodejsYarn,
- nodejsBerry,
- nodejsNpm,
- nodejsPnpm,
- nodejsPnpm6,
-}
-
-var (
- packageManagerPattern = `(npm|pnpm|yarn)@(\d+)\.\d+\.\d+(-.+)?`
- packageManagerRegex = regexp.MustCompile(packageManagerPattern)
-)
-
-// ParsePackageManagerString takes a package manager version string parses it into consituent components
-func ParsePackageManagerString(packageManager string) (manager string, version string, err error) {
- match := packageManagerRegex.FindString(packageManager)
- if len(match) == 0 {
- return "", "", fmt.Errorf("We could not parse packageManager field in package.json, expected: %s, received: %s", packageManagerPattern, packageManager)
- }
-
- return strings.Split(match, "@")[0], strings.Split(match, "@")[1], nil
-}
-
-// GetPackageManager attempts all methods for identifying the package manager in use.
-func GetPackageManager(projectDirectory turbopath.AbsoluteSystemPath, pkg *fs.PackageJSON) (packageManager *PackageManager, err error) {
- result, _ := readPackageManager(pkg)
- if result != nil {
- return result, nil
- }
-
- return detectPackageManager(projectDirectory)
-}
-
-// readPackageManager attempts to read the package manager from the package.json.
-func readPackageManager(pkg *fs.PackageJSON) (packageManager *PackageManager, err error) {
- if pkg.PackageManager != "" {
- manager, version, err := ParsePackageManagerString(pkg.PackageManager)
- if err != nil {
- return nil, err
- }
-
- for _, packageManager := range packageManagers {
- isResponsible, err := packageManager.Matches(manager, version)
- if isResponsible && (err == nil) {
- return &packageManager, nil
- }
- }
- }
-
- return nil, errors.New(util.Sprintf("We did not find a package manager specified in your root package.json. Please set the \"packageManager\" property in your root package.json (${UNDERLINE}https://nodejs.org/api/packages.html#packagemanager)${RESET} or run `npx @turbo/codemod add-package-manager` in the root of your monorepo."))
-}
-
-// detectPackageManager attempts to detect the package manager by inspecting the project directory state.
-func detectPackageManager(projectDirectory turbopath.AbsoluteSystemPath) (packageManager *PackageManager, err error) {
- for _, packageManager := range packageManagers {
- isResponsible, err := packageManager.detect(projectDirectory, &packageManager)
- if err != nil {
- return nil, err
- }
- if isResponsible {
- return &packageManager, nil
- }
- }
-
- return nil, errors.New(util.Sprintf("We did not detect an in-use package manager for your project. Please set the \"packageManager\" property in your root package.json (${UNDERLINE}https://nodejs.org/api/packages.html#packagemanager)${RESET} or run `npx @turbo/codemod add-package-manager` in the root of your monorepo."))
-}
-
-// GetWorkspaces returns the list of package.json files for the current repository.
-func (pm PackageManager) GetWorkspaces(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- globs, err := pm.getWorkspaceGlobs(rootpath)
- if err != nil {
- return nil, err
- }
-
- justJsons := make([]string, len(globs))
- for i, space := range globs {
- justJsons[i] = filepath.Join(space, "package.json")
- }
-
- ignores, err := pm.getWorkspaceIgnores(pm, rootpath)
- if err != nil {
- return nil, err
- }
-
- f, err := globby.GlobFiles(rootpath.ToStringDuringMigration(), justJsons, ignores)
- if err != nil {
- return nil, err
- }
-
- return f, nil
-}
-
-// GetWorkspaceIgnores returns an array of globs not to search for workspaces.
-func (pm PackageManager) GetWorkspaceIgnores(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- return pm.getWorkspaceIgnores(pm, rootpath)
-}
-
-// CanPrune returns if turbo can produce a pruned workspace. Can error if fs issues occur
-func (pm PackageManager) CanPrune(projectDirectory turbopath.AbsoluteSystemPath) (bool, error) {
- if pm.canPrune != nil {
- return pm.canPrune(projectDirectory)
- }
- return false, nil
-}
-
-// ReadLockfile will read the applicable lockfile into memory
-func (pm PackageManager) ReadLockfile(projectDirectory turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON) (lockfile.Lockfile, error) {
- if pm.UnmarshalLockfile == nil {
- return nil, nil
- }
- contents, err := projectDirectory.UntypedJoin(pm.Lockfile).ReadFile()
- if err != nil {
- return nil, fmt.Errorf("reading %s: %w", pm.Lockfile, err)
- }
- lf, err := pm.UnmarshalLockfile(rootPackageJSON, contents)
- if err != nil {
- return nil, errors.Wrapf(err, "error in %v", pm.Lockfile)
- }
- return lf, nil
-}
-
-// PrunePatchedPackages will alter the provided pkgJSON to only reference the provided patches
-func (pm PackageManager) PrunePatchedPackages(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error {
- if pm.prunePatches != nil {
- return pm.prunePatches(pkgJSON, patches)
- }
- return nil
-}
diff --git a/cli/internal/packagemanager/packagemanager_test.go b/cli/internal/packagemanager/packagemanager_test.go
deleted file mode 100644
index a5dc472..0000000
--- a/cli/internal/packagemanager/packagemanager_test.go
+++ /dev/null
@@ -1,411 +0,0 @@
-package packagemanager
-
-import (
- "os"
- "path/filepath"
- "reflect"
- "sort"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func TestParsePackageManagerString(t *testing.T) {
- tests := []struct {
- name string
- packageManager string
- wantManager string
- wantVersion string
- wantErr bool
- }{
- {
- name: "errors with a tag version",
- packageManager: "npm@latest",
- wantManager: "",
- wantVersion: "",
- wantErr: true,
- },
- {
- name: "errors with no version",
- packageManager: "npm",
- wantManager: "",
- wantVersion: "",
- wantErr: true,
- },
- {
- name: "requires fully-qualified semver versions (one digit)",
- packageManager: "npm@1",
- wantManager: "",
- wantVersion: "",
- wantErr: true,
- },
- {
- name: "requires fully-qualified semver versions (two digits)",
- packageManager: "npm@1.2",
- wantManager: "",
- wantVersion: "",
- wantErr: true,
- },
- {
- name: "supports custom labels",
- packageManager: "npm@1.2.3-alpha.1",
- wantManager: "npm",
- wantVersion: "1.2.3-alpha.1",
- wantErr: false,
- },
- {
- name: "only supports specified package managers",
- packageManager: "pip@1.2.3",
- wantManager: "",
- wantVersion: "",
- wantErr: true,
- },
- {
- name: "supports npm",
- packageManager: "npm@0.0.1",
- wantManager: "npm",
- wantVersion: "0.0.1",
- wantErr: false,
- },
- {
- name: "supports pnpm",
- packageManager: "pnpm@0.0.1",
- wantManager: "pnpm",
- wantVersion: "0.0.1",
- wantErr: false,
- },
- {
- name: "supports yarn",
- packageManager: "yarn@111.0.1",
- wantManager: "yarn",
- wantVersion: "111.0.1",
- wantErr: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- gotManager, gotVersion, err := ParsePackageManagerString(tt.packageManager)
- if (err != nil) != tt.wantErr {
- t.Errorf("ParsePackageManagerString() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if gotManager != tt.wantManager {
- t.Errorf("ParsePackageManagerString() got manager = %v, want manager %v", gotManager, tt.wantManager)
- }
- if gotVersion != tt.wantVersion {
- t.Errorf("ParsePackageManagerString() got version = %v, want version %v", gotVersion, tt.wantVersion)
- }
- })
- }
-}
-
-func TestGetPackageManager(t *testing.T) {
- cwdRaw, err := os.Getwd()
- assert.NilError(t, err, "os.Getwd")
- cwd, err := fs.GetCwd(cwdRaw)
- assert.NilError(t, err, "GetCwd")
- tests := []struct {
- name string
- projectDirectory turbopath.AbsoluteSystemPath
- pkg *fs.PackageJSON
- want string
- wantErr bool
- }{
- {
- name: "finds npm from a package manager string",
- projectDirectory: cwd,
- pkg: &fs.PackageJSON{PackageManager: "npm@1.2.3"},
- want: "nodejs-npm",
- wantErr: false,
- },
- {
- name: "finds pnpm6 from a package manager string",
- projectDirectory: cwd,
- pkg: &fs.PackageJSON{PackageManager: "pnpm@1.2.3"},
- want: "nodejs-pnpm6",
- wantErr: false,
- },
- {
- name: "finds pnpm from a package manager string",
- projectDirectory: cwd,
- pkg: &fs.PackageJSON{PackageManager: "pnpm@7.8.9"},
- want: "nodejs-pnpm",
- wantErr: false,
- },
- {
- name: "finds yarn from a package manager string",
- projectDirectory: cwd,
- pkg: &fs.PackageJSON{PackageManager: "yarn@1.2.3"},
- want: "nodejs-yarn",
- wantErr: false,
- },
- {
- name: "finds berry from a package manager string",
- projectDirectory: cwd,
- pkg: &fs.PackageJSON{PackageManager: "yarn@2.3.4"},
- want: "nodejs-berry",
- wantErr: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- gotPackageManager, err := GetPackageManager(tt.projectDirectory, tt.pkg)
- if (err != nil) != tt.wantErr {
- t.Errorf("GetPackageManager() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if gotPackageManager.Name != tt.want {
- t.Errorf("GetPackageManager() = %v, want %v", gotPackageManager.Name, tt.want)
- }
- })
- }
-}
-
-func Test_readPackageManager(t *testing.T) {
- tests := []struct {
- name string
- pkg *fs.PackageJSON
- want string
- wantErr bool
- }{
- {
- name: "finds npm from a package manager string",
- pkg: &fs.PackageJSON{PackageManager: "npm@1.2.3"},
- want: "nodejs-npm",
- wantErr: false,
- },
- {
- name: "finds pnpm6 from a package manager string",
- pkg: &fs.PackageJSON{PackageManager: "pnpm@1.2.3"},
- want: "nodejs-pnpm6",
- wantErr: false,
- },
- {
- name: "finds pnpm from a package manager string",
- pkg: &fs.PackageJSON{PackageManager: "pnpm@7.8.9"},
- want: "nodejs-pnpm",
- wantErr: false,
- },
- {
- name: "finds yarn from a package manager string",
- pkg: &fs.PackageJSON{PackageManager: "yarn@1.2.3"},
- want: "nodejs-yarn",
- wantErr: false,
- },
- {
- name: "finds berry from a package manager string",
- pkg: &fs.PackageJSON{PackageManager: "yarn@2.3.4"},
- want: "nodejs-berry",
- wantErr: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- gotPackageManager, err := readPackageManager(tt.pkg)
- if (err != nil) != tt.wantErr {
- t.Errorf("readPackageManager() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if gotPackageManager.Name != tt.want {
- t.Errorf("readPackageManager() = %v, want %v", gotPackageManager.Name, tt.want)
- }
- })
- }
-}
-
-func Test_GetWorkspaces(t *testing.T) {
- type test struct {
- name string
- pm PackageManager
- rootPath turbopath.AbsoluteSystemPath
- want []string
- wantErr bool
- }
-
- cwd, _ := os.Getwd()
-
- repoRoot, err := fs.GetCwd(cwd)
- assert.NilError(t, err, "GetCwd")
- rootPath := map[string]turbopath.AbsoluteSystemPath{
- "nodejs-npm": repoRoot.UntypedJoin("../../../examples/with-yarn"),
- "nodejs-berry": repoRoot.UntypedJoin("../../../examples/with-yarn"),
- "nodejs-yarn": repoRoot.UntypedJoin("../../../examples/with-yarn"),
- "nodejs-pnpm": repoRoot.UntypedJoin("../../../examples/basic"),
- "nodejs-pnpm6": repoRoot.UntypedJoin("../../../examples/basic"),
- }
-
- want := map[string][]string{
- "nodejs-npm": {
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/docs/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/web/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/eslint-config-custom/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/tsconfig/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/ui/package.json")),
- },
- "nodejs-berry": {
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/docs/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/web/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/eslint-config-custom/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/tsconfig/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/ui/package.json")),
- },
- "nodejs-yarn": {
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/docs/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/web/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/eslint-config-custom/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/tsconfig/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/ui/package.json")),
- },
- "nodejs-pnpm": {
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/docs/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/web/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/eslint-config-custom/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/tsconfig/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/ui/package.json")),
- },
- "nodejs-pnpm6": {
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/docs/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/web/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/eslint-config-custom/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/tsconfig/package.json")),
- filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/ui/package.json")),
- },
- }
-
- tests := make([]test, len(packageManagers))
- for i, packageManager := range packageManagers {
- tests[i] = test{
- name: packageManager.Name,
- pm: packageManager,
- rootPath: rootPath[packageManager.Name],
- want: want[packageManager.Name],
- wantErr: false,
- }
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- gotWorkspaces, err := tt.pm.GetWorkspaces(tt.rootPath)
-
- gotToSlash := make([]string, len(gotWorkspaces))
- for index, workspace := range gotWorkspaces {
- gotToSlash[index] = filepath.ToSlash(workspace)
- }
-
- if (err != nil) != tt.wantErr {
- t.Errorf("GetWorkspaces() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- sort.Strings(gotToSlash)
- if !reflect.DeepEqual(gotToSlash, tt.want) {
- t.Errorf("GetWorkspaces() = %v, want %v", gotToSlash, tt.want)
- }
- })
- }
-}
-
-func Test_GetWorkspaceIgnores(t *testing.T) {
- type test struct {
- name string
- pm PackageManager
- rootPath turbopath.AbsoluteSystemPath
- want []string
- wantErr bool
- }
-
- cwdRaw, err := os.Getwd()
- assert.NilError(t, err, "os.Getwd")
- cwd, err := fs.GetCwd(cwdRaw)
- assert.NilError(t, err, "GetCwd")
- want := map[string][]string{
- "nodejs-npm": {"**/node_modules/**"},
- "nodejs-berry": {"**/node_modules", "**/.git", "**/.yarn"},
- "nodejs-yarn": {"apps/*/node_modules/**", "packages/*/node_modules/**"},
- "nodejs-pnpm": {"**/node_modules/**", "**/bower_components/**", "packages/skip"},
- "nodejs-pnpm6": {"**/node_modules/**", "**/bower_components/**", "packages/skip"},
- }
-
- tests := make([]test, len(packageManagers))
- for i, packageManager := range packageManagers {
- tests[i] = test{
- name: packageManager.Name,
- pm: packageManager,
- rootPath: cwd.UntypedJoin("fixtures"),
- want: want[packageManager.Name],
- wantErr: false,
- }
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- gotWorkspaceIgnores, err := tt.pm.GetWorkspaceIgnores(tt.rootPath)
-
- gotToSlash := make([]string, len(gotWorkspaceIgnores))
- for index, ignore := range gotWorkspaceIgnores {
- gotToSlash[index] = filepath.ToSlash(ignore)
- }
-
- if (err != nil) != tt.wantErr {
- t.Errorf("GetWorkspaceIgnores() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if !reflect.DeepEqual(gotToSlash, tt.want) {
- t.Errorf("GetWorkspaceIgnores() = %v, want %v", gotToSlash, tt.want)
- }
- })
- }
-}
-
-func Test_CanPrune(t *testing.T) {
- type test struct {
- name string
- pm PackageManager
- rootPath turbopath.AbsoluteSystemPath
- want bool
- wantErr bool
- }
-
- type want struct {
- want bool
- wantErr bool
- }
-
- cwdRaw, err := os.Getwd()
- assert.NilError(t, err, "os.Getwd")
- cwd, err := fs.GetCwd(cwdRaw)
- assert.NilError(t, err, "GetCwd")
- wants := map[string]want{
- "nodejs-npm": {true, false},
- "nodejs-berry": {false, true},
- "nodejs-yarn": {true, false},
- "nodejs-pnpm": {true, false},
- "nodejs-pnpm6": {true, false},
- }
-
- tests := make([]test, len(packageManagers))
- for i, packageManager := range packageManagers {
- tests[i] = test{
- name: packageManager.Name,
- pm: packageManager,
- rootPath: cwd.UntypedJoin("../../../examples/with-yarn"),
- want: wants[packageManager.Name].want,
- wantErr: wants[packageManager.Name].wantErr,
- }
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- canPrune, err := tt.pm.CanPrune(tt.rootPath)
-
- if (err != nil) != tt.wantErr {
- t.Errorf("CanPrune() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if canPrune != tt.want {
- t.Errorf("CanPrune() = %v, want %v", canPrune, tt.want)
- }
- })
- }
-}
diff --git a/cli/internal/packagemanager/pnpm.go b/cli/internal/packagemanager/pnpm.go
deleted file mode 100644
index e65a4dc..0000000
--- a/cli/internal/packagemanager/pnpm.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package packagemanager
-
-import (
- "fmt"
- "strings"
-
- "github.com/Masterminds/semver"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/yaml"
-)
-
-// PnpmWorkspaces is a representation of workspace package globs found
-// in pnpm-workspace.yaml
-type PnpmWorkspaces struct {
- Packages []string `yaml:"packages,omitempty"`
-}
-
-func readPnpmWorkspacePackages(workspaceFile turbopath.AbsoluteSystemPath) ([]string, error) {
- bytes, err := workspaceFile.ReadFile()
- if err != nil {
- return nil, fmt.Errorf("%v: %w", workspaceFile, err)
- }
- var pnpmWorkspaces PnpmWorkspaces
- if err := yaml.Unmarshal(bytes, &pnpmWorkspaces); err != nil {
- return nil, fmt.Errorf("%v: %w", workspaceFile, err)
- }
- return pnpmWorkspaces.Packages, nil
-}
-
-func getPnpmWorkspaceGlobs(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- pkgGlobs, err := readPnpmWorkspacePackages(rootpath.UntypedJoin("pnpm-workspace.yaml"))
- if err != nil {
- return nil, err
- }
-
- if len(pkgGlobs) == 0 {
- return nil, fmt.Errorf("pnpm-workspace.yaml: no packages found. Turborepo requires pnpm workspaces and thus packages to be defined in the root pnpm-workspace.yaml")
- }
-
- filteredPkgGlobs := []string{}
- for _, pkgGlob := range pkgGlobs {
- if !strings.HasPrefix(pkgGlob, "!") {
- filteredPkgGlobs = append(filteredPkgGlobs, pkgGlob)
- }
- }
- return filteredPkgGlobs, nil
-}
-
-func getPnpmWorkspaceIgnores(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- // Matches upstream values:
- // function: https://github.com/pnpm/pnpm/blob/d99daa902442e0c8ab945143ebaf5cdc691a91eb/packages/find-packages/src/index.ts#L27
- // key code: https://github.com/pnpm/pnpm/blob/d99daa902442e0c8ab945143ebaf5cdc691a91eb/packages/find-packages/src/index.ts#L30
- // call site: https://github.com/pnpm/pnpm/blob/d99daa902442e0c8ab945143ebaf5cdc691a91eb/packages/find-workspace-packages/src/index.ts#L32-L39
- ignores := []string{
- "**/node_modules/**",
- "**/bower_components/**",
- }
- pkgGlobs, err := readPnpmWorkspacePackages(rootpath.UntypedJoin("pnpm-workspace.yaml"))
- if err != nil {
- return nil, err
- }
- for _, pkgGlob := range pkgGlobs {
- if strings.HasPrefix(pkgGlob, "!") {
- ignores = append(ignores, pkgGlob[1:])
- }
- }
- return ignores, nil
-}
-
-var nodejsPnpm = PackageManager{
- Name: "nodejs-pnpm",
- Slug: "pnpm",
- Command: "pnpm",
- Specfile: "package.json",
- Lockfile: "pnpm-lock.yaml",
- PackageDir: "node_modules",
- // pnpm v7+ changed their handling of '--'. We no longer need to pass it to pass args to
- // the script being run, and in fact doing so will cause the '--' to be passed through verbatim,
- // potentially breaking scripts that aren't expecting it.
- // We are allowed to use nil here because ArgSeparator already has a type, so it's a typed nil,
- // This could just as easily be []string{}, but the style guide says to prefer
- // nil for empty slices.
- ArgSeparator: nil,
- WorkspaceConfigurationPath: "pnpm-workspace.yaml",
-
- getWorkspaceGlobs: getPnpmWorkspaceGlobs,
-
- getWorkspaceIgnores: getPnpmWorkspaceIgnores,
-
- Matches: func(manager string, version string) (bool, error) {
- if manager != "pnpm" {
- return false, nil
- }
-
- v, err := semver.NewVersion(version)
- if err != nil {
- return false, fmt.Errorf("could not parse pnpm version: %w", err)
- }
- c, err := semver.NewConstraint(">=7.0.0")
- if err != nil {
- return false, fmt.Errorf("could not create constraint: %w", err)
- }
-
- return c.Check(v), nil
- },
-
- detect: func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error) {
- specfileExists := projectDirectory.UntypedJoin(packageManager.Specfile).FileExists()
- lockfileExists := projectDirectory.UntypedJoin(packageManager.Lockfile).FileExists()
-
- return (specfileExists && lockfileExists), nil
- },
-
- canPrune: func(cwd turbopath.AbsoluteSystemPath) (bool, error) {
- return true, nil
- },
-
- UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) {
- return lockfile.DecodePnpmLockfile(contents)
- },
-
- prunePatches: func(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error {
- return pnpmPrunePatches(pkgJSON, patches)
- },
-}
-
-func pnpmPrunePatches(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error {
- pkgJSON.Mu.Lock()
- defer pkgJSON.Mu.Unlock()
-
- keysToDelete := []string{}
- pnpmConfig, ok := pkgJSON.RawJSON["pnpm"].(map[string]interface{})
- if !ok {
- return fmt.Errorf("Invalid structure for pnpm field in package.json")
- }
- patchedDependencies, ok := pnpmConfig["patchedDependencies"].(map[string]interface{})
- if !ok {
- return fmt.Errorf("Invalid structure for patchedDependencies field in package.json")
- }
-
- for dependency, untypedPatch := range patchedDependencies {
- patch, ok := untypedPatch.(string)
- if !ok {
- return fmt.Errorf("Expected only strings in patchedDependencies. Got %v", untypedPatch)
- }
-
- inPatches := false
-
- for _, wantedPatch := range patches {
- if wantedPatch.ToString() == patch {
- inPatches = true
- break
- }
- }
-
- if !inPatches {
- keysToDelete = append(keysToDelete, dependency)
- }
- }
-
- for _, key := range keysToDelete {
- delete(patchedDependencies, key)
- }
-
- return nil
-}
diff --git a/cli/internal/packagemanager/pnpm6.go b/cli/internal/packagemanager/pnpm6.go
deleted file mode 100644
index 6039966..0000000
--- a/cli/internal/packagemanager/pnpm6.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package packagemanager
-
-import (
- "fmt"
-
- "github.com/Masterminds/semver"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// Pnpm6Workspaces is a representation of workspace package globs found
-// in pnpm-workspace.yaml
-type Pnpm6Workspaces struct {
- Packages []string `yaml:"packages,omitempty"`
-}
-
-var nodejsPnpm6 = PackageManager{
- Name: "nodejs-pnpm6",
- Slug: "pnpm",
- Command: "pnpm",
- Specfile: "package.json",
- Lockfile: "pnpm-lock.yaml",
- PackageDir: "node_modules",
- ArgSeparator: []string{"--"},
- WorkspaceConfigurationPath: "pnpm-workspace.yaml",
-
- getWorkspaceGlobs: getPnpmWorkspaceGlobs,
-
- getWorkspaceIgnores: getPnpmWorkspaceIgnores,
-
- Matches: func(manager string, version string) (bool, error) {
- if manager != "pnpm" {
- return false, nil
- }
-
- v, err := semver.NewVersion(version)
- if err != nil {
- return false, fmt.Errorf("could not parse pnpm version: %w", err)
- }
- c, err := semver.NewConstraint("<7.0.0")
- if err != nil {
- return false, fmt.Errorf("could not create constraint: %w", err)
- }
-
- return c.Check(v), nil
- },
-
- detect: func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error) {
- specfileExists := projectDirectory.UntypedJoin(packageManager.Specfile).FileExists()
- lockfileExists := projectDirectory.UntypedJoin(packageManager.Lockfile).FileExists()
-
- return (specfileExists && lockfileExists), nil
- },
-
- canPrune: func(cwd turbopath.AbsoluteSystemPath) (bool, error) {
- return true, nil
- },
-
- UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) {
- return lockfile.DecodePnpmLockfile(contents)
- },
-}
diff --git a/cli/internal/packagemanager/pnpm_test.go b/cli/internal/packagemanager/pnpm_test.go
deleted file mode 100644
index c05bc43..0000000
--- a/cli/internal/packagemanager/pnpm_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package packagemanager
-
-import (
- "os"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "gotest.tools/v3/assert"
-)
-
-func pnpmPatchesSection(t *testing.T, pkgJSON *fs.PackageJSON) map[string]interface{} {
- t.Helper()
- pnpmSection, ok := pkgJSON.RawJSON["pnpm"].(map[string]interface{})
- assert.Assert(t, ok)
- patchesSection, ok := pnpmSection["patchedDependencies"].(map[string]interface{})
- assert.Assert(t, ok)
- return patchesSection
-}
-
-func getPnpmPackageJSON(t *testing.T) *fs.PackageJSON {
- t.Helper()
- rawCwd, err := os.Getwd()
- assert.NilError(t, err)
- cwd, err := fs.CheckedToAbsoluteSystemPath(rawCwd)
- assert.NilError(t, err)
- pkgJSONPath := cwd.Join("fixtures", "pnpm-patches.json")
- pkgJSON, err := fs.ReadPackageJSON(pkgJSONPath)
- assert.NilError(t, err)
- return pkgJSON
-}
-
-func Test_PnpmPrunePatches_KeepsNecessary(t *testing.T) {
- pkgJSON := getPnpmPackageJSON(t)
- initialPatches := pnpmPatchesSection(t, pkgJSON)
-
- assert.DeepEqual(t, initialPatches, map[string]interface{}{"is-odd@3.0.1": "patches/is-odd@3.0.1.patch"})
-
- err := pnpmPrunePatches(pkgJSON, []turbopath.AnchoredUnixPath{turbopath.AnchoredUnixPath("patches/is-odd@3.0.1.patch")})
- assert.NilError(t, err)
-
- newPatches := pnpmPatchesSection(t, pkgJSON)
- assert.DeepEqual(t, newPatches, map[string]interface{}{"is-odd@3.0.1": "patches/is-odd@3.0.1.patch"})
-}
-
-func Test_PnpmPrunePatches_RemovesExtra(t *testing.T) {
- pkgJSON := getPnpmPackageJSON(t)
- initialPatches := pnpmPatchesSection(t, pkgJSON)
-
- assert.DeepEqual(t, initialPatches, map[string]interface{}{"is-odd@3.0.1": "patches/is-odd@3.0.1.patch"})
-
- err := pnpmPrunePatches(pkgJSON, nil)
- assert.NilError(t, err)
-
- newPatches := pnpmPatchesSection(t, pkgJSON)
- assert.DeepEqual(t, newPatches, map[string]interface{}{})
-}
diff --git a/cli/internal/packagemanager/yarn.go b/cli/internal/packagemanager/yarn.go
deleted file mode 100644
index 8779c5f..0000000
--- a/cli/internal/packagemanager/yarn.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package packagemanager
-
-import (
- "errors"
- "fmt"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/Masterminds/semver"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// NoWorkspacesFoundError is a custom error used so that upstream implementations can switch on it
-type NoWorkspacesFoundError struct{}
-
-func (e *NoWorkspacesFoundError) Error() string {
- return "package.json: no workspaces found. Turborepo requires Yarn workspaces to be defined in the root package.json"
-}
-
-var nodejsYarn = PackageManager{
- Name: "nodejs-yarn",
- Slug: "yarn",
- Command: "yarn",
- Specfile: "package.json",
- Lockfile: "yarn.lock",
- PackageDir: "node_modules",
- ArgSeparator: []string{"--"},
-
- getWorkspaceGlobs: func(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- pkg, err := fs.ReadPackageJSON(rootpath.UntypedJoin("package.json"))
- if err != nil {
- return nil, fmt.Errorf("package.json: %w", err)
- }
- if len(pkg.Workspaces) == 0 {
- return nil, &NoWorkspacesFoundError{}
- }
- return pkg.Workspaces, nil
- },
-
- getWorkspaceIgnores: func(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
- // function: https://github.com/yarnpkg/yarn/blob/3119382885ea373d3c13d6a846de743eca8c914b/src/config.js#L799
-
- // Yarn is unique in ignore patterns handling.
- // The only time it does globbing is for package.json or yarn.json and it scopes the search to each workspace.
- // For example: `apps/*/node_modules/**/+(package.json|yarn.json)`
- // The `extglob` `+(package.json|yarn.json)` (from micromatch) after node_modules/** is redundant.
-
- globs, err := pm.getWorkspaceGlobs(rootpath)
- if err != nil {
- // In case of a non-monorepo, the workspaces field is empty and only node_modules in the root should be ignored
- var e *NoWorkspacesFoundError
- if errors.As(err, &e) {
- return []string{"node_modules/**"}, nil
- }
-
- return nil, err
- }
-
- ignores := make([]string, len(globs))
-
- for i, glob := range globs {
- ignores[i] = filepath.Join(glob, "/node_modules/**")
- }
-
- return ignores, nil
- },
-
- canPrune: func(cwd turbopath.AbsoluteSystemPath) (bool, error) {
- return true, nil
- },
-
- // Versions older than 2.0 are yarn, after that they become berry
- Matches: func(manager string, version string) (bool, error) {
- if manager != "yarn" {
- return false, nil
- }
-
- v, err := semver.NewVersion(version)
- if err != nil {
- return false, fmt.Errorf("could not parse yarn version: %w", err)
- }
- c, err := semver.NewConstraint("<2.0.0-0")
- if err != nil {
- return false, fmt.Errorf("could not create constraint: %w", err)
- }
-
- return c.Check(v), nil
- },
-
- // Detect for yarn needs to identify which version of yarn is running on the system.
- detect: func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error) {
- specfileExists := projectDirectory.UntypedJoin(packageManager.Specfile).FileExists()
- lockfileExists := projectDirectory.UntypedJoin(packageManager.Lockfile).FileExists()
-
- // Short-circuit, definitely not Yarn.
- if !specfileExists || !lockfileExists {
- return false, nil
- }
-
- cmd := exec.Command("yarn", "--version")
- cmd.Dir = projectDirectory.ToString()
- out, err := cmd.Output()
- if err != nil {
- return false, fmt.Errorf("could not detect yarn version: %w", err)
- }
-
- return packageManager.Matches(packageManager.Slug, strings.TrimSpace(string(out)))
- },
-
- UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) {
- return lockfile.DecodeYarnLockfile(contents)
- },
-}
diff --git a/cli/internal/process/child.go b/cli/internal/process/child.go
deleted file mode 100644
index 1c3e6e7..0000000
--- a/cli/internal/process/child.go
+++ /dev/null
@@ -1,406 +0,0 @@
-package process
-
-/**
- * Code in this file is based on the source code at
- * https://github.com/hashicorp/consul-template/tree/3ea7d99ad8eff17897e0d63dac86d74770170bb8/child/child.go
- *
- * Major changes include removing the ability to restart a child process,
- * requiring a fully-formed exec.Cmd to be passed in, and including cmd.Dir
- * in the description of a child process.
- */
-
-import (
- "errors"
- "fmt"
- "math/rand"
- "os"
- "os/exec"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "github.com/hashicorp/go-hclog"
-)
-
-func init() {
- // Seed the default rand Source with current time to produce better random
- // numbers used with splay
- rand.Seed(time.Now().UnixNano())
-}
-
-var (
- // ErrMissingCommand is the error returned when no command is specified
- // to run.
- ErrMissingCommand = errors.New("missing command")
-
- // ExitCodeOK is the default OK exit code.
- ExitCodeOK = 0
-
- // ExitCodeError is the default error code returned when the child exits with
- // an error without a more specific code.
- ExitCodeError = 127
-)
-
-// Child is a wrapper around a child process which can be used to send signals
-// and manage the processes' lifecycle.
-type Child struct {
- sync.RWMutex
-
- timeout time.Duration
-
- killSignal os.Signal
- killTimeout time.Duration
-
- splay time.Duration
-
- // cmd is the actual child process under management.
- cmd *exec.Cmd
-
- // exitCh is the channel where the processes exit will be returned.
- exitCh chan int
-
- // stopLock is the mutex to lock when stopping. stopCh is the circuit breaker
- // to force-terminate any waiting splays to kill the process now. stopped is
- // a boolean that tells us if we have previously been stopped.
- stopLock sync.RWMutex
- stopCh chan struct{}
- stopped bool
-
- // whether to set process group id or not (default on)
- setpgid bool
-
- Label string
-
- logger hclog.Logger
-}
-
-// NewInput is input to the NewChild function.
-type NewInput struct {
- // Cmd is the unstarted, preconfigured command to run
- Cmd *exec.Cmd
-
- // Timeout is the maximum amount of time to allow the command to execute. If
- // set to 0, the command is permitted to run infinitely.
- Timeout time.Duration
-
- // KillSignal is the signal to send to gracefully kill this process. This
- // value may be nil.
- KillSignal os.Signal
-
- // KillTimeout is the amount of time to wait for the process to gracefully
- // terminate before force-killing.
- KillTimeout time.Duration
-
- // Splay is the maximum random amount of time to wait before sending signals.
- // This option helps reduce the thundering herd problem by effectively
- // sleeping for a random amount of time before sending the signal. This
- // prevents multiple processes from all signaling at the same time. This value
- // may be zero (which disables the splay entirely).
- Splay time.Duration
-
- // Logger receives debug log lines about the process state and transitions
- Logger hclog.Logger
-}
-
-// New creates a new child process for management with high-level APIs for
-// sending signals to the child process, restarting the child process, and
-// gracefully terminating the child process.
-func newChild(i NewInput) (*Child, error) {
- // exec.Command prepends the command to be run to the arguments list, so
- // we only need the arguments here, it will include the command itself.
- label := fmt.Sprintf("(%v) %v", i.Cmd.Dir, strings.Join(i.Cmd.Args, " "))
- child := &Child{
- cmd: i.Cmd,
- timeout: i.Timeout,
- killSignal: i.KillSignal,
- killTimeout: i.KillTimeout,
- splay: i.Splay,
- stopCh: make(chan struct{}, 1),
- setpgid: true,
- Label: label,
- logger: i.Logger.Named(label),
- }
-
- return child, nil
-}
-
-// ExitCh returns the current exit channel for this child process. This channel
-// may change if the process is restarted, so implementers must not cache this
-// value.
-func (c *Child) ExitCh() <-chan int {
- c.RLock()
- defer c.RUnlock()
- return c.exitCh
-}
-
-// Pid returns the pid of the child process. If no child process exists, 0 is
-// returned.
-func (c *Child) Pid() int {
- c.RLock()
- defer c.RUnlock()
- return c.pid()
-}
-
-// Command returns the human-formatted command with arguments.
-func (c *Child) Command() string {
- return c.Label
-}
-
-// Start starts and begins execution of the child process. A buffered channel
-// is returned which is where the command's exit code will be returned upon
-// exit. Any errors that occur prior to starting the command will be returned
-// as the second error argument, but any errors returned by the command after
-// execution will be returned as a non-zero value over the exit code channel.
-func (c *Child) Start() error {
- // log.Printf("[INFO] (child) spawning: %s", c.Command())
- c.Lock()
- defer c.Unlock()
- return c.start()
-}
-
-// Signal sends the signal to the child process, returning any errors that
-// occur.
-func (c *Child) Signal(s os.Signal) error {
- c.logger.Debug("receiving signal %q", s.String())
- c.RLock()
- defer c.RUnlock()
- return c.signal(s)
-}
-
-// Kill sends the kill signal to the child process and waits for successful
-// termination. If no kill signal is defined, the process is killed with the
-// most aggressive kill signal. If the process does not gracefully stop within
-// the provided KillTimeout, the process is force-killed. If a splay was
-// provided, this function will sleep for a random period of time between 0 and
-// the provided splay value to reduce the thundering herd problem. This function
-// does not return any errors because it guarantees the process will be dead by
-// the return of the function call.
-func (c *Child) Kill() {
- c.logger.Debug("killing process")
- c.Lock()
- defer c.Unlock()
- c.kill(false)
-}
-
-// Stop behaves almost identical to Kill except it suppresses future processes
-// from being started by this child and it prevents the killing of the child
-// process from sending its value back up the exit channel. This is useful
-// when doing a graceful shutdown of an application.
-func (c *Child) Stop() {
- c.internalStop(false)
-}
-
-// StopImmediately behaves almost identical to Stop except it does not wait
-// for any random splay if configured. This is used for performing a fast
-// shutdown of consul-template and its children when a kill signal is received.
-func (c *Child) StopImmediately() {
- c.internalStop(true)
-}
-
-func (c *Child) internalStop(immediately bool) {
- c.Lock()
- defer c.Unlock()
-
- c.stopLock.Lock()
- defer c.stopLock.Unlock()
- if c.stopped {
- return
- }
- c.kill(immediately)
- close(c.stopCh)
- c.stopped = true
-}
-
-func (c *Child) start() error {
- setSetpgid(c.cmd, c.setpgid)
- if err := c.cmd.Start(); err != nil {
- return err
- }
-
- // Create a new exitCh so that previously invoked commands (if any) don't
- // cause us to exit, and start a goroutine to wait for that process to end.
- exitCh := make(chan int, 1)
- go func() {
- var code int
- // It's possible that kill is called before we even
- // manage to get here. Make sure we still have a valid
- // cmd before waiting on it.
- c.RLock()
- var cmd = c.cmd
- c.RUnlock()
- var err error
- if cmd != nil {
- err = cmd.Wait()
- }
- if err == nil {
- code = ExitCodeOK
- } else {
- code = ExitCodeError
- if exiterr, ok := err.(*exec.ExitError); ok {
- if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
- code = status.ExitStatus()
- }
- }
- }
-
- // If the child is in the process of killing, do not send a response back
- // down the exit channel.
- c.stopLock.RLock()
- defer c.stopLock.RUnlock()
- if !c.stopped {
- select {
- case <-c.stopCh:
- case exitCh <- code:
- }
- }
-
- close(exitCh)
- }()
-
- c.exitCh = exitCh
-
- // If a timeout was given, start the timer to wait for the child to exit
- if c.timeout != 0 {
- select {
- case code := <-exitCh:
- if code != 0 {
- return fmt.Errorf(
- "command exited with a non-zero exit status:\n"+
- "\n"+
- " %s\n"+
- "\n"+
- "This is assumed to be a failure. Please ensure the command\n"+
- "exits with a zero exit status.",
- c.Command(),
- )
- }
- case <-time.After(c.timeout):
- // Force-kill the process
- c.stopLock.Lock()
- defer c.stopLock.Unlock()
- if c.cmd != nil && c.cmd.Process != nil {
- c.cmd.Process.Kill()
- }
-
- return fmt.Errorf(
- "command did not exit within %q:\n"+
- "\n"+
- " %s\n"+
- "\n"+
- "Commands must exit in a timely manner in order for processing to\n"+
- "continue. Consider using a process supervisor or utilizing the\n"+
- "built-in exec mode instead.",
- c.timeout,
- c.Command(),
- )
- }
- }
-
- return nil
-}
-
-func (c *Child) pid() int {
- if !c.running() {
- return 0
- }
- return c.cmd.Process.Pid
-}
-
-func (c *Child) signal(s os.Signal) error {
- if !c.running() {
- return nil
- }
-
- sig, ok := s.(syscall.Signal)
- if !ok {
- return fmt.Errorf("bad signal: %s", s)
- }
- pid := c.cmd.Process.Pid
- if c.setpgid {
- // kill takes negative pid to indicate that you want to use gpid
- pid = -(pid)
- }
- // cross platform way to signal process/process group
- p, err := os.FindProcess(pid)
- if err != nil {
- return err
- }
- return p.Signal(sig)
-}
-
-// kill sends the signal to kill the process using the configured signal
-// if set, else the default system signal
-func (c *Child) kill(immediately bool) {
-
- if !c.running() {
- c.logger.Debug("Kill() called but process dead; not waiting for splay.")
- return
- } else if immediately {
- c.logger.Debug("Kill() called but performing immediate shutdown; not waiting for splay.")
- } else {
- c.logger.Debug("Kill(%v) called", immediately)
- select {
- case <-c.stopCh:
- case <-c.randomSplay():
- }
- }
-
- var exited bool
- defer func() {
- if !exited {
- c.logger.Debug("PKill")
- c.cmd.Process.Kill()
- }
- c.cmd = nil
- }()
-
- if c.killSignal == nil {
- return
- }
-
- if err := c.signal(c.killSignal); err != nil {
- c.logger.Debug("Kill failed: %s", err)
- if processNotFoundErr(err) {
- exited = true // checked in defer
- }
- return
- }
-
- killCh := make(chan struct{}, 1)
- go func() {
- defer close(killCh)
- c.cmd.Process.Wait()
- }()
-
- select {
- case <-c.stopCh:
- case <-killCh:
- exited = true
- case <-time.After(c.killTimeout):
- c.logger.Debug("timeout")
- }
-}
-
-func (c *Child) running() bool {
- select {
- case <-c.exitCh:
- return false
- default:
- }
- return c.cmd != nil && c.cmd.Process != nil
-}
-
-func (c *Child) randomSplay() <-chan time.Time {
- if c.splay == 0 {
- return time.After(0)
- }
-
- ns := c.splay.Nanoseconds()
- offset := rand.Int63n(ns)
- t := time.Duration(offset)
-
- c.logger.Debug("waiting %.2fs for random splay", t.Seconds())
-
- return time.After(t)
-}
diff --git a/cli/internal/process/child_nix_test.go b/cli/internal/process/child_nix_test.go
deleted file mode 100644
index 7311d18..0000000
--- a/cli/internal/process/child_nix_test.go
+++ /dev/null
@@ -1,190 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package process
-
-/**
- * Code in this file is based on the source code at
- * https://github.com/hashicorp/consul-template/tree/3ea7d99ad8eff17897e0d63dac86d74770170bb8/child/child_test.go
- *
- * Tests in this file use signals or pgid features not available on windows
- */
-
-import (
- "os/exec"
- "syscall"
- "testing"
- "time"
-
- "github.com/hashicorp/go-gatedio"
-)
-
-func TestSignal(t *testing.T) {
-
- c := testChild(t)
- cmd := exec.Command("sh", "-c", "trap 'echo one; exit' USR1; while true; do sleep 0.2; done")
- c.cmd = cmd
-
- out := gatedio.NewByteBuffer()
- c.cmd.Stdout = out
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- // For some reason bash doesn't start immediately
- time.Sleep(fileWaitSleepDelay)
-
- if err := c.Signal(syscall.SIGUSR1); err != nil {
- t.Fatal(err)
- }
-
- // Give time for the file to flush
- time.Sleep(fileWaitSleepDelay)
-
- expected := "one\n"
- if out.String() != expected {
- t.Errorf("expected %q to be %q", out.String(), expected)
- }
-}
-
-func TestStop_childAlreadyDead(t *testing.T) {
- c := testChild(t)
- c.cmd = exec.Command("sh", "-c", "exit 1")
- c.splay = 100 * time.Second
- c.killSignal = syscall.SIGTERM
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
-
- // For some reason bash doesn't start immediately
- time.Sleep(fileWaitSleepDelay)
-
- killStartTime := time.Now()
- c.Stop()
- killEndTime := time.Now()
-
- if killEndTime.Sub(killStartTime) > fileWaitSleepDelay {
- t.Error("expected not to wait for splay")
- }
-}
-
-func TestSignal_noProcess(t *testing.T) {
-
- c := testChild(t)
- if err := c.Signal(syscall.SIGUSR1); err != nil {
- // Just assert there is no error
- t.Fatal(err)
- }
-}
-
-func TestKill_signal(t *testing.T) {
-
- c := testChild(t)
- cmd := exec.Command("sh", "-c", "trap 'echo one; exit' USR1; while true; do sleep 0.2; done")
- c.killSignal = syscall.SIGUSR1
-
- out := gatedio.NewByteBuffer()
- cmd.Stdout = out
- c.cmd = cmd
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- // For some reason bash doesn't start immediately
- time.Sleep(fileWaitSleepDelay)
-
- c.Kill()
-
- // Give time for the file to flush
- time.Sleep(fileWaitSleepDelay)
-
- expected := "one\n"
- if out.String() != expected {
- t.Errorf("expected %q to be %q", out.String(), expected)
- }
-}
-
-func TestKill_noProcess(t *testing.T) {
- c := testChild(t)
- c.killSignal = syscall.SIGUSR1
- c.Kill()
-}
-
-func TestStop_noWaitForSplay(t *testing.T) {
- c := testChild(t)
- c.cmd = exec.Command("sh", "-c", "trap 'echo one; exit' USR1; while true; do sleep 0.2; done")
- c.splay = 100 * time.Second
- c.killSignal = syscall.SIGUSR1
-
- out := gatedio.NewByteBuffer()
- c.cmd.Stdout = out
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
-
- // For some reason bash doesn't start immediately
- time.Sleep(fileWaitSleepDelay)
-
- killStartTime := time.Now()
- c.StopImmediately()
- killEndTime := time.Now()
-
- expected := "one\n"
- if out.String() != expected {
- t.Errorf("expected %q to be %q", out.String(), expected)
- }
-
- if killEndTime.Sub(killStartTime) > fileWaitSleepDelay {
- t.Error("expected not to wait for splay")
- }
-}
-
-func TestSetpgid(t *testing.T) {
- t.Run("true", func(t *testing.T) {
- c := testChild(t)
- c.cmd = exec.Command("sh", "-c", "while true; do sleep 0.2; done")
- // default, but to be explicit for the test
- c.setpgid = true
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- // when setpgid is true, the pid and gpid should be the same
- gpid, err := syscall.Getpgid(c.Pid())
- if err != nil {
- t.Fatal("Getpgid error:", err)
- }
-
- if c.Pid() != gpid {
- t.Fatal("pid and gpid should match")
- }
- })
- t.Run("false", func(t *testing.T) {
- c := testChild(t)
- c.cmd = exec.Command("sh", "-c", "while true; do sleep 0.2; done")
- c.setpgid = false
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- // when setpgid is true, the pid and gpid should be the same
- gpid, err := syscall.Getpgid(c.Pid())
- if err != nil {
- t.Fatal("Getpgid error:", err)
- }
-
- if c.Pid() == gpid {
- t.Fatal("pid and gpid should NOT match")
- }
- })
-}
diff --git a/cli/internal/process/child_test.go b/cli/internal/process/child_test.go
deleted file mode 100644
index 63dee22..0000000
--- a/cli/internal/process/child_test.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package process
-
-/**
- * Code in this file is based on the source code at
- * https://github.com/hashicorp/consul-template/tree/3ea7d99ad8eff17897e0d63dac86d74770170bb8/child/child_test.go
- *
- * Major changes include supporting api changes in child.go and removing
- * tests for reloading, which was removed in child.go
- */
-
-import (
- "io/ioutil"
- "os"
- "os/exec"
- "strings"
- "testing"
- "time"
-
- "github.com/hashicorp/go-gatedio"
- "github.com/hashicorp/go-hclog"
-)
-
-const fileWaitSleepDelay = 150 * time.Millisecond
-
-func testChild(t *testing.T) *Child {
- cmd := exec.Command("echo", "hello", "world")
- cmd.Stdout = ioutil.Discard
- cmd.Stderr = ioutil.Discard
- c, err := newChild(NewInput{
- Cmd: cmd,
- KillSignal: os.Kill,
- KillTimeout: 2 * time.Second,
- Splay: 0 * time.Second,
- Logger: hclog.Default(),
- })
- if err != nil {
- t.Fatal(err)
- }
- return c
-}
-
-func TestNew(t *testing.T) {
-
- stdin := gatedio.NewByteBuffer()
- stdout := gatedio.NewByteBuffer()
- stderr := gatedio.NewByteBuffer()
- command := "echo"
- args := []string{"hello", "world"}
- env := []string{"a=b", "c=d"}
- killSignal := os.Kill
- killTimeout := fileWaitSleepDelay
- splay := fileWaitSleepDelay
-
- cmd := exec.Command(command, args...)
- cmd.Stdin = stdin
- cmd.Stderr = stderr
- cmd.Stdout = stdout
- cmd.Env = env
- c, err := newChild(NewInput{
- Cmd: cmd,
- KillSignal: killSignal,
- KillTimeout: killTimeout,
- Splay: splay,
- Logger: hclog.Default(),
- })
- if err != nil {
- t.Fatal(err)
- }
-
- if c.killSignal != killSignal {
- t.Errorf("expected %q to be %q", c.killSignal, killSignal)
- }
-
- if c.killTimeout != killTimeout {
- t.Errorf("expected %q to be %q", c.killTimeout, killTimeout)
- }
-
- if c.splay != splay {
- t.Errorf("expected %q to be %q", c.splay, splay)
- }
-
- if c.stopCh == nil {
- t.Errorf("expected %#v to be", c.stopCh)
- }
-}
-
-func TestExitCh_noProcess(t *testing.T) {
-
- c := testChild(t)
- ch := c.ExitCh()
- if ch != nil {
- t.Errorf("expected %#v to be nil", ch)
- }
-}
-
-func TestExitCh(t *testing.T) {
-
- c := testChild(t)
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- println("Started")
- defer c.Stop()
-
- ch := c.ExitCh()
- if ch == nil {
- t.Error("expected ch to exist")
- }
-}
-
-func TestPid_noProcess(t *testing.T) {
-
- c := testChild(t)
- pid := c.Pid()
- if pid != 0 {
- t.Errorf("expected %q to be 0", pid)
- }
-}
-
-func TestPid(t *testing.T) {
-
- c := testChild(t)
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- pid := c.Pid()
- if pid == 0 {
- t.Error("expected pid to not be 0")
- }
-}
-
-func TestStart(t *testing.T) {
-
- c := testChild(t)
-
- // Set our own reader and writer so we can verify they are wired to the child.
- stdin := gatedio.NewByteBuffer()
- stdout := gatedio.NewByteBuffer()
- stderr := gatedio.NewByteBuffer()
- // Custom env and command
- env := []string{"a=b", "c=d"}
- cmd := exec.Command("env")
- cmd.Stdin = stdin
- cmd.Stdout = stdout
- cmd.Stderr = stderr
- cmd.Env = env
- c.cmd = cmd
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- select {
- case <-c.ExitCh():
- case <-time.After(fileWaitSleepDelay):
- t.Fatal("process should have exited")
- }
-
- output := stdout.String()
- for _, envVar := range env {
- if !strings.Contains(output, envVar) {
- t.Errorf("expected to find %q in %q", envVar, output)
- }
- }
-}
-
-func TestKill_noSignal(t *testing.T) {
-
- c := testChild(t)
- c.cmd = exec.Command("sh", "-c", "while true; do sleep 0.2; done")
- c.killTimeout = 20 * time.Millisecond
- c.killSignal = nil
-
- if err := c.Start(); err != nil {
- t.Fatal(err)
- }
- defer c.Stop()
-
- // For some reason bash doesn't start immediately
- time.Sleep(fileWaitSleepDelay)
-
- c.Kill()
-
- // Give time for the file to flush
- time.Sleep(fileWaitSleepDelay)
-
- if c.cmd != nil {
- t.Errorf("expected cmd to be nil")
- }
-}
diff --git a/cli/internal/process/manager.go b/cli/internal/process/manager.go
deleted file mode 100644
index 0488a29..0000000
--- a/cli/internal/process/manager.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package process
-
-import (
- "errors"
- "fmt"
- "os"
- "os/exec"
- "sync"
- "time"
-
- "github.com/hashicorp/go-hclog"
-)
-
-// ErrClosing is returned when the process manager is in the process of closing,
-// meaning that no more child processes can be Exec'd, and existing, non-failed
-// child processes will be stopped with this error.
-var ErrClosing = errors.New("process manager is already closing")
-
-// ChildExit is returned when a child process exits with a non-zero exit code
-type ChildExit struct {
- ExitCode int
- Command string
-}
-
-func (ce *ChildExit) Error() string {
- return fmt.Sprintf("command %s exited (%d)", ce.Command, ce.ExitCode)
-}
-
-// Manager tracks all of the child processes that have been spawned
-type Manager struct {
- done bool
- children map[*Child]struct{}
- mu sync.Mutex
- doneCh chan struct{}
- logger hclog.Logger
-}
-
-// NewManager creates a new properly-initialized Manager instance
-func NewManager(logger hclog.Logger) *Manager {
- return &Manager{
- children: make(map[*Child]struct{}),
- doneCh: make(chan struct{}),
- logger: logger,
- }
-}
-
-// Exec spawns a child process to run the given command, then blocks
-// until it completes. Returns a nil error if the child process finished
-// successfully, ErrClosing if the manager closed during execution, and
-// a ChildExit error if the child process exited with a non-zero exit code.
-func (m *Manager) Exec(cmd *exec.Cmd) error {
- m.mu.Lock()
- if m.done {
- m.mu.Unlock()
- return ErrClosing
- }
-
- child, err := newChild(NewInput{
- Cmd: cmd,
- // Run forever by default
- Timeout: 0,
- // When it's time to exit, give a 10 second timeout
- KillTimeout: 10 * time.Second,
- // Send SIGINT to stop children
- KillSignal: os.Interrupt,
- Logger: m.logger,
- })
- if err != nil {
- return err
- }
-
- m.children[child] = struct{}{}
- m.mu.Unlock()
- err = child.Start()
- if err != nil {
- m.mu.Lock()
- delete(m.children, child)
- m.mu.Unlock()
- return err
- }
- err = nil
- exitCode, ok := <-child.ExitCh()
- if !ok {
- err = ErrClosing
- } else if exitCode != ExitCodeOK {
- err = &ChildExit{
- ExitCode: exitCode,
- Command: child.Command(),
- }
- }
-
- m.mu.Lock()
- delete(m.children, child)
- m.mu.Unlock()
- return err
-}
-
-// Close sends SIGINT to all child processes if it hasn't been done yet,
-// and in either case blocks until they all exit or timeout
-func (m *Manager) Close() {
- m.mu.Lock()
- if m.done {
- m.mu.Unlock()
- <-m.doneCh
- return
- }
- wg := sync.WaitGroup{}
- m.done = true
- for child := range m.children {
- child := child
- wg.Add(1)
- go func() {
- child.Stop()
- wg.Done()
- }()
- }
- m.mu.Unlock()
- wg.Wait()
- close(m.doneCh)
-}
diff --git a/cli/internal/process/manager_test.go b/cli/internal/process/manager_test.go
deleted file mode 100644
index fb40ffa..0000000
--- a/cli/internal/process/manager_test.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package process
-
-import (
- "errors"
- "os/exec"
- "sync"
- "testing"
- "time"
-
- "github.com/hashicorp/go-gatedio"
- "github.com/hashicorp/go-hclog"
-)
-
-func newManager() *Manager {
- return NewManager(hclog.Default())
-}
-
-func TestExec_simple(t *testing.T) {
- mgr := newManager()
-
- out := gatedio.NewByteBuffer()
- cmd := exec.Command("env")
- cmd.Stdout = out
-
- err := mgr.Exec(cmd)
- if err != nil {
- t.Errorf("expected %q to be nil", err)
- }
-
- output := out.String()
- if output == "" {
- t.Error("expected output from running 'env', got empty string")
- }
-}
-
-func TestClose(t *testing.T) {
- mgr := newManager()
-
- wg := sync.WaitGroup{}
- tasks := 4
- errors := make([]error, tasks)
- start := time.Now()
- for i := 0; i < tasks; i++ {
- wg.Add(1)
- go func(index int) {
- cmd := exec.Command("sleep", "0.5")
- err := mgr.Exec(cmd)
- if err != nil {
- errors[index] = err
- }
- wg.Done()
- }(i)
- }
- // let processes kick off
- time.Sleep(50 * time.Millisecond)
- mgr.Close()
- end := time.Now()
- wg.Wait()
- duration := end.Sub(start)
- if duration >= 500*time.Millisecond {
- t.Errorf("expected to close, total time was %q", duration)
- }
- for _, err := range errors {
- if err != ErrClosing {
- t.Errorf("expected manager closing error, found %q", err)
- }
- }
-}
-
-func TestClose_alreadyClosed(t *testing.T) {
- mgr := newManager()
- mgr.Close()
-
- // repeated closing does not error
- mgr.Close()
-
- err := mgr.Exec(exec.Command("sleep", "1"))
- if err != ErrClosing {
- t.Errorf("expected manager closing error, found %q", err)
- }
-}
-
-func TestExitCode(t *testing.T) {
- mgr := newManager()
-
- err := mgr.Exec(exec.Command("ls", "doesnotexist"))
- exitErr := &ChildExit{}
- if !errors.As(err, &exitErr) {
- t.Errorf("expected a ChildExit err, got %q", err)
- }
- if exitErr.ExitCode == 0 {
- t.Error("expected non-zero exit code , got 0")
- }
-}
diff --git a/cli/internal/process/sys_nix.go b/cli/internal/process/sys_nix.go
deleted file mode 100644
index 0e6c003..0000000
--- a/cli/internal/process/sys_nix.go
+++ /dev/null
@@ -1,23 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package process
-
-/**
- * Code in this file is based on the source code at
- * https://github.com/hashicorp/consul-template/tree/3ea7d99ad8eff17897e0d63dac86d74770170bb8/child/sys_nix.go
- */
-
-import (
- "os/exec"
- "syscall"
-)
-
-func setSetpgid(cmd *exec.Cmd, value bool) {
- cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: value}
-}
-
-func processNotFoundErr(err error) bool {
- // ESRCH == no such process, ie. already exited
- return err == syscall.ESRCH
-}
diff --git a/cli/internal/process/sys_windows.go b/cli/internal/process/sys_windows.go
deleted file mode 100644
index c626c22..0000000
--- a/cli/internal/process/sys_windows.go
+++ /dev/null
@@ -1,17 +0,0 @@
-//go:build windows
-// +build windows
-
-package process
-
-/**
- * Code in this file is based on the source code at
- * https://github.com/hashicorp/consul-template/tree/3ea7d99ad8eff17897e0d63dac86d74770170bb8/child/sys_windows.go
- */
-
-import "os/exec"
-
-func setSetpgid(cmd *exec.Cmd, value bool) {}
-
-func processNotFoundErr(err error) bool {
- return false
-}
diff --git a/cli/internal/prune/prune.go b/cli/internal/prune/prune.go
deleted file mode 100644
index a82023f..0000000
--- a/cli/internal/prune/prune.go
+++ /dev/null
@@ -1,314 +0,0 @@
-package prune
-
-import (
- "bufio"
- "fmt"
- "os"
- "strings"
-
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/context"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
-
- "github.com/fatih/color"
- "github.com/hashicorp/go-hclog"
- "github.com/mitchellh/cli"
- "github.com/pkg/errors"
-)
-
-type opts struct {
- scope []string
- docker bool
- outputDir string
-}
-
-// ExecutePrune executes the `prune` command.
-func ExecutePrune(helper *cmdutil.Helper, args *turbostate.ParsedArgsFromRust) error {
- base, err := helper.GetCmdBase(args)
- if err != nil {
- return err
- }
- if len(args.Command.Prune.Scope) == 0 {
- err := errors.New("at least one target must be specified")
- base.LogError(err.Error())
- return err
- }
- p := &prune{
- base,
- }
- if err := p.prune(args.Command.Prune); err != nil {
- logError(p.base.Logger, p.base.UI, err)
- return err
- }
- return nil
-}
-
-func logError(logger hclog.Logger, ui cli.Ui, err error) {
- logger.Error(fmt.Sprintf("error: %v", err))
- pref := color.New(color.Bold, color.FgRed, color.ReverseVideo).Sprint(" ERROR ")
- ui.Error(fmt.Sprintf("%s%s", pref, color.RedString(" %v", err)))
-}
-
-type prune struct {
- base *cmdutil.CmdBase
-}
-
-// Prune creates a smaller monorepo with only the required workspaces
-func (p *prune) prune(opts *turbostate.PrunePayload) error {
- rootPackageJSONPath := p.base.RepoRoot.UntypedJoin("package.json")
- rootPackageJSON, err := fs.ReadPackageJSON(rootPackageJSONPath)
- if err != nil {
- return fmt.Errorf("failed to read package.json: %w", err)
- }
- ctx, err := context.BuildPackageGraph(p.base.RepoRoot, rootPackageJSON)
- if err != nil {
- return errors.Wrap(err, "could not construct graph")
- }
- outDir := p.base.RepoRoot.UntypedJoin(opts.OutputDir)
- fullDir := outDir
- if opts.Docker {
- fullDir = fullDir.UntypedJoin("full")
- }
-
- p.base.Logger.Trace("scope", "value", strings.Join(opts.Scope, ", "))
- p.base.Logger.Trace("docker", "value", opts.Docker)
- p.base.Logger.Trace("out dir", "value", outDir.ToString())
-
- for _, scope := range opts.Scope {
- p.base.Logger.Trace("scope", "value", scope)
- target, scopeIsValid := ctx.WorkspaceInfos.PackageJSONs[scope]
- if !scopeIsValid {
- return errors.Errorf("invalid scope: package %v not found", scope)
- }
- p.base.Logger.Trace("target", "value", target.Name)
- p.base.Logger.Trace("directory", "value", target.Dir)
- p.base.Logger.Trace("external deps", "value", target.UnresolvedExternalDeps)
- p.base.Logger.Trace("internal deps", "value", target.InternalDeps)
- }
-
- canPrune, err := ctx.PackageManager.CanPrune(p.base.RepoRoot)
- if err != nil {
- return err
- }
- if !canPrune {
- return errors.Errorf("this command is not yet implemented for %s", ctx.PackageManager.Name)
- }
- if lockfile.IsNil(ctx.Lockfile) {
- return errors.New("Cannot prune without parsed lockfile")
- }
-
- p.base.UI.Output(fmt.Sprintf("Generating pruned monorepo for %v in %v", ui.Bold(strings.Join(opts.Scope, ", ")), ui.Bold(outDir.ToString())))
-
- packageJSONPath := outDir.UntypedJoin("package.json")
- if err := packageJSONPath.EnsureDir(); err != nil {
- return errors.Wrap(err, "could not create output directory")
- }
- if workspacePath := ctx.PackageManager.WorkspaceConfigurationPath; workspacePath != "" && p.base.RepoRoot.UntypedJoin(workspacePath).FileExists() {
- workspaceFile := fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin(workspacePath)}
- if err := fs.CopyFile(&workspaceFile, outDir.UntypedJoin(ctx.PackageManager.WorkspaceConfigurationPath).ToStringDuringMigration()); err != nil {
- return errors.Wrapf(err, "could not copy %s", ctx.PackageManager.WorkspaceConfigurationPath)
- }
- if err := fs.CopyFile(&workspaceFile, fullDir.UntypedJoin(ctx.PackageManager.WorkspaceConfigurationPath).ToStringDuringMigration()); err != nil {
- return errors.Wrapf(err, "could not copy %s", ctx.PackageManager.WorkspaceConfigurationPath)
- }
- if opts.Docker {
- if err := fs.CopyFile(&workspaceFile, outDir.UntypedJoin("json", ctx.PackageManager.WorkspaceConfigurationPath).ToStringDuringMigration()); err != nil {
- return errors.Wrapf(err, "could not copy %s", ctx.PackageManager.WorkspaceConfigurationPath)
- }
- }
- }
- workspaces := []turbopath.AnchoredSystemPath{}
- targets, err := ctx.InternalDependencies(append(opts.Scope, util.RootPkgName))
- if err != nil {
- return errors.Wrap(err, "could not traverse the dependency graph to find topological dependencies")
- }
- p.base.Logger.Trace("targets", "value", targets)
-
- lockfileKeys := make([]string, 0, len(rootPackageJSON.TransitiveDeps))
- for _, pkg := range rootPackageJSON.TransitiveDeps {
- lockfileKeys = append(lockfileKeys, pkg.Key)
- }
-
- for _, internalDep := range targets {
- // We skip over the pseudo root node and the root package
- if internalDep == ctx.RootNode || internalDep == util.RootPkgName {
- continue
- }
-
- workspaces = append(workspaces, ctx.WorkspaceInfos.PackageJSONs[internalDep].Dir)
- originalDir := ctx.WorkspaceInfos.PackageJSONs[internalDep].Dir.RestoreAnchor(p.base.RepoRoot)
- info, err := originalDir.Lstat()
- if err != nil {
- return errors.Wrapf(err, "failed to lstat %s", originalDir)
- }
- targetDir := ctx.WorkspaceInfos.PackageJSONs[internalDep].Dir.RestoreAnchor(fullDir)
- if err := targetDir.MkdirAllMode(info.Mode()); err != nil {
- return errors.Wrapf(err, "failed to create folder %s for %v", targetDir, internalDep)
- }
-
- if err := fs.RecursiveCopy(ctx.WorkspaceInfos.PackageJSONs[internalDep].Dir.ToStringDuringMigration(), targetDir.ToStringDuringMigration()); err != nil {
- return errors.Wrapf(err, "failed to copy %v into %v", internalDep, targetDir)
- }
- if opts.Docker {
- jsonDir := outDir.UntypedJoin("json", ctx.WorkspaceInfos.PackageJSONs[internalDep].PackageJSONPath.ToStringDuringMigration())
- if err := jsonDir.EnsureDir(); err != nil {
- return errors.Wrapf(err, "failed to create folder %v for %v", jsonDir, internalDep)
- }
- if err := fs.RecursiveCopy(ctx.WorkspaceInfos.PackageJSONs[internalDep].PackageJSONPath.ToStringDuringMigration(), jsonDir.ToStringDuringMigration()); err != nil {
- return errors.Wrapf(err, "failed to copy %v into %v", internalDep, jsonDir)
- }
- }
-
- for _, pkg := range ctx.WorkspaceInfos.PackageJSONs[internalDep].TransitiveDeps {
- lockfileKeys = append(lockfileKeys, pkg.Key)
- }
-
- p.base.UI.Output(fmt.Sprintf(" - Added %v", ctx.WorkspaceInfos.PackageJSONs[internalDep].Name))
- }
- p.base.Logger.Trace("new workspaces", "value", workspaces)
-
- lockfile, err := ctx.Lockfile.Subgraph(workspaces, lockfileKeys)
- if err != nil {
- return errors.Wrap(err, "Failed creating pruned lockfile")
- }
-
- lockfilePath := outDir.UntypedJoin(ctx.PackageManager.Lockfile)
- lockfileFile, err := lockfilePath.Create()
- if err != nil {
- return errors.Wrap(err, "Failed to create lockfile")
- }
-
- lockfileWriter := bufio.NewWriter(lockfileFile)
- if err := lockfile.Encode(lockfileWriter); err != nil {
- return errors.Wrap(err, "Failed to encode pruned lockfile")
- }
-
- if err := lockfileWriter.Flush(); err != nil {
- return errors.Wrap(err, "Failed to flush pruned lockfile")
- }
-
- if fs.FileExists(".gitignore") {
- if err := fs.CopyFile(&fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin(".gitignore")}, fullDir.UntypedJoin(".gitignore").ToStringDuringMigration()); err != nil {
- return errors.Wrap(err, "failed to copy root .gitignore")
- }
- }
-
- if fs.FileExists(".npmrc") {
- if err := fs.CopyFile(&fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin(".npmrc")}, fullDir.UntypedJoin(".npmrc").ToStringDuringMigration()); err != nil {
- return errors.Wrap(err, "failed to copy root .npmrc")
- }
- if opts.Docker {
- if err := fs.CopyFile(&fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin(".npmrc")}, outDir.UntypedJoin("json/.npmrc").ToStringDuringMigration()); err != nil {
- return errors.Wrap(err, "failed to copy root .npmrc")
- }
- }
- }
-
- turboJSON, err := fs.LoadTurboConfig(p.base.RepoRoot, rootPackageJSON, false)
- if err != nil && !errors.Is(err, os.ErrNotExist) {
- return errors.Wrap(err, "failed to read turbo.json")
- }
- if turboJSON != nil {
- // when executing a prune, it is not enough to simply copy the file, as
- // tasks may refer to scopes that no longer exist. to remedy this, we need
- // to remove from the Pipeline the TaskDefinitions that no longer apply
- for pipelineTask := range turboJSON.Pipeline {
- includeTask := false
- for _, includedPackage := range targets {
- if util.IsTaskInPackage(pipelineTask, includedPackage) {
- includeTask = true
- break
- }
- }
-
- if !includeTask {
- delete(turboJSON.Pipeline, pipelineTask)
- }
- }
-
- bytes, err := turboJSON.MarshalJSON()
-
- if err != nil {
- return errors.Wrap(err, "failed to write turbo.json")
- }
-
- if err := fullDir.UntypedJoin("turbo.json").WriteFile(bytes, 0644); err != nil {
- return errors.Wrap(err, "failed to prune workspace tasks from turbo.json")
- }
- }
-
- originalPackageJSON := fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin("package.json")}
- newPackageJSONPath := fullDir.UntypedJoin("package.json")
- // If the original lockfile uses any patches we rewrite the package.json to make sure it doesn't
- // include any patches that might have been pruned.
- if originalPatches := ctx.Lockfile.Patches(); originalPatches != nil {
- patches := lockfile.Patches()
- if err := ctx.PackageManager.PrunePatchedPackages(rootPackageJSON, patches); err != nil {
- return errors.Wrapf(err, "Unable to prune patches section of %s", rootPackageJSONPath)
- }
- packageJSONContent, err := fs.MarshalPackageJSON(rootPackageJSON)
- if err != nil {
- return err
- }
-
- info, err := originalPackageJSON.GetInfo()
- if err != nil {
- return err
- }
- newPackageJSON, err := newPackageJSONPath.Create()
- if err != nil {
- return err
- }
- if _, err := newPackageJSON.Write(packageJSONContent); err != nil {
- return err
- }
- if err := newPackageJSON.Chmod(info.Mode()); err != nil {
- return err
- }
- if err := newPackageJSON.Close(); err != nil {
- return err
- }
-
- for _, patch := range patches {
- if err := fs.CopyFile(
- &fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin(patch.ToString())},
- fullDir.UntypedJoin(patch.ToString()).ToStringDuringMigration(),
- ); err != nil {
- return errors.Wrap(err, "Failed copying patch file")
- }
- if opts.Docker {
- jsonDir := outDir.Join(turbopath.RelativeSystemPath("json"))
- if err := fs.CopyFile(
- &fs.LstatCachedFile{Path: p.base.RepoRoot.UntypedJoin(patch.ToString())},
- patch.ToSystemPath().RestoreAnchor(jsonDir).ToStringDuringMigration(),
- ); err != nil {
- return errors.Wrap(err, "Failed copying patch file")
- }
- }
- }
- } else {
- if err := fs.CopyFile(
- &originalPackageJSON,
- fullDir.UntypedJoin("package.json").ToStringDuringMigration(),
- ); err != nil {
- return errors.Wrap(err, "failed to copy root package.json")
- }
- }
-
- if opts.Docker {
- // Copy from the package.json in the full directory so we get the pruned version if needed
- if err := fs.CopyFile(
- &fs.LstatCachedFile{Path: newPackageJSONPath},
- outDir.Join(turbopath.RelativeUnixPath("json/package.json").ToSystemPath()).ToString(),
- ); err != nil {
- return errors.Wrap(err, "failed to copy root package.json")
- }
- }
-
- return nil
-}
diff --git a/cli/internal/run/dry_run.go b/cli/internal/run/dry_run.go
deleted file mode 100644
index eeee431..0000000
--- a/cli/internal/run/dry_run.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Package run implements `turbo run`
-// This file implements the logic for `turbo run --dry`
-package run
-
-import (
- gocontext "context"
- "sync"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/cache"
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/core"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/graph"
- "github.com/vercel/turbo/cli/internal/nodes"
- "github.com/vercel/turbo/cli/internal/runsummary"
- "github.com/vercel/turbo/cli/internal/taskhash"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// DryRun gets all the info needed from tasks and prints out a summary, but doesn't actually
-// execute the task.
-func DryRun(
- ctx gocontext.Context,
- g *graph.CompleteGraph,
- rs *runSpec,
- engine *core.Engine,
- _ *taskhash.Tracker, // unused, but keep here for parity with RealRun method signature
- turboCache cache.Cache,
- _ *fs.TurboJSON, // unused, but keep here for parity with RealRun method signature
- globalEnvMode util.EnvMode,
- base *cmdutil.CmdBase,
- summary runsummary.Meta,
-) error {
- defer turboCache.Shutdown()
-
- taskSummaries := []*runsummary.TaskSummary{}
-
- mu := sync.Mutex{}
- execFunc := func(ctx gocontext.Context, packageTask *nodes.PackageTask, taskSummary *runsummary.TaskSummary) error {
- // Assign some fallbacks if they were missing
- if taskSummary.Command == "" {
- taskSummary.Command = runsummary.MissingTaskLabel
- }
-
- if taskSummary.Framework == "" {
- taskSummary.Framework = runsummary.MissingFrameworkLabel
- }
-
- // This mutex is not _really_ required, since we are using Concurrency: 1 as an execution
- // option, but we add it here to match the shape of RealRuns execFunc.
- mu.Lock()
- defer mu.Unlock()
- taskSummaries = append(taskSummaries, taskSummary)
- return nil
- }
-
- // This setup mirrors a real run. We call engine.execute() with
- // a visitor function and some hardcoded execOpts.
- // Note: we do not currently attempt to parallelize the graph walking
- // (as we do in real execution)
- getArgs := func(taskID string) []string {
- return rs.ArgsForTask(taskID)
- }
-
- visitorFn := g.GetPackageTaskVisitor(ctx, engine.TaskGraph, globalEnvMode, getArgs, base.Logger, execFunc)
- execOpts := core.EngineExecutionOptions{
- Concurrency: 1,
- Parallel: false,
- }
-
- if errs := engine.Execute(visitorFn, execOpts); len(errs) > 0 {
- for _, err := range errs {
- base.UI.Error(err.Error())
- }
- return errors.New("errors occurred during dry-run graph traversal")
- }
-
- // We walk the graph with no concurrency.
- // Populating the cache state is parallelizable.
- // Do this _after_ walking the graph.
- populateCacheState(turboCache, taskSummaries)
-
- // Assign the Task Summaries to the main summary
- summary.RunSummary.Tasks = taskSummaries
-
- // The exitCode isn't really used by the Run Summary Close() method for dry runs
- // but we pass in a successful value to match Real Runs.
- return summary.Close(ctx, 0, g.WorkspaceInfos)
-}
-
-func populateCacheState(turboCache cache.Cache, taskSummaries []*runsummary.TaskSummary) {
- // We make at most 8 requests at a time for cache state.
- maxParallelRequests := 8
- taskCount := len(taskSummaries)
-
- parallelRequestCount := maxParallelRequests
- if taskCount < maxParallelRequests {
- parallelRequestCount = taskCount
- }
-
- queue := make(chan int, taskCount)
-
- wg := &sync.WaitGroup{}
- for i := 0; i < parallelRequestCount; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for index := range queue {
- task := taskSummaries[index]
- itemStatus := turboCache.Exists(task.Hash)
- task.CacheSummary = runsummary.NewTaskCacheSummary(itemStatus, nil)
- }
- }()
- }
-
- for index := range taskSummaries {
- queue <- index
- }
- close(queue)
- wg.Wait()
-}
diff --git a/cli/internal/run/global_hash.go b/cli/internal/run/global_hash.go
deleted file mode 100644
index 2ebf642..0000000
--- a/cli/internal/run/global_hash.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package run
-
-import (
- "fmt"
- "path/filepath"
- "strings"
-
- "github.com/hashicorp/go-hclog"
- "github.com/mitchellh/cli"
- "github.com/vercel/turbo/cli/internal/env"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/globby"
- "github.com/vercel/turbo/cli/internal/hashing"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/packagemanager"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-const _globalCacheKey = "Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"
-
-// Variables that we always include
-var _defaultEnvVars = []string{
- "VERCEL_ANALYTICS_ID",
-}
-
-// GlobalHashable represents all the things that we use to create the global hash
-type GlobalHashable struct {
- globalFileHashMap map[turbopath.AnchoredUnixPath]string
- rootExternalDepsHash string
- envVars env.DetailedMap
- globalCacheKey string
- pipeline fs.PristinePipeline
- envVarPassthroughs []string
- envMode util.EnvMode
-}
-
-// This exists because the global hash used to have different fields. Changing
-// to a new struct layout changes the global hash. We can remove this converter
-// when we are going to have to update the global hash for something else.
-type oldGlobalHashable struct {
- globalFileHashMap map[turbopath.AnchoredUnixPath]string
- rootExternalDepsHash string
- envVars env.EnvironmentVariablePairs
- globalCacheKey string
- pipeline fs.PristinePipeline
-}
-
-// calculateGlobalHashFromHashable returns a hash string from the globalHashable
-func calculateGlobalHashFromHashable(full GlobalHashable) (string, error) {
- switch full.envMode {
- case util.Infer:
- if full.envVarPassthroughs != nil {
- // In infer mode, if there is any passThru config (even if it is an empty array)
- // we'll hash the whole object, so we can detect changes to that config
- // Further, resolve the envMode to the concrete value.
- full.envMode = util.Strict
- return fs.HashObject(full)
- }
-
- // If we're in infer mode, and there is no global pass through config,
- // we use the old struct layout. this will be true for everyone not using the strict env
- // feature, and we don't want to break their cache.
- return fs.HashObject(oldGlobalHashable{
- globalFileHashMap: full.globalFileHashMap,
- rootExternalDepsHash: full.rootExternalDepsHash,
- envVars: full.envVars.All.ToHashable(),
- globalCacheKey: full.globalCacheKey,
- pipeline: full.pipeline,
- })
- case util.Loose:
- // Remove the passthroughs from hash consideration if we're explicitly loose.
- full.envVarPassthroughs = nil
- return fs.HashObject(full)
- case util.Strict:
- // Collapse `nil` and `[]` in strict mode.
- if full.envVarPassthroughs == nil {
- full.envVarPassthroughs = make([]string, 0)
- }
- return fs.HashObject(full)
- default:
- panic("unimplemented environment mode")
- }
-}
-
-func calculateGlobalHash(
- rootpath turbopath.AbsoluteSystemPath,
- rootPackageJSON *fs.PackageJSON,
- pipeline fs.Pipeline,
- envVarDependencies []string,
- globalFileDependencies []string,
- packageManager *packagemanager.PackageManager,
- lockFile lockfile.Lockfile,
- envVarPassthroughs []string,
- envMode util.EnvMode,
- logger hclog.Logger,
- ui cli.Ui,
- isStructuredOutput bool,
-) (GlobalHashable, error) {
- // Calculate env var dependencies
- envVars := []string{}
- envVars = append(envVars, envVarDependencies...)
- envVars = append(envVars, _defaultEnvVars...)
- globalHashableEnvVars, err := env.GetHashableEnvVars(envVars, []string{".*THASH.*"}, "")
- if err != nil {
- return GlobalHashable{}, err
- }
-
- // The only way we can add env vars into the hash via matching is via THASH,
- // so we only do a simple check here for entries in `BySource.Matching`.
- // If we enable globalEnv to accept wildcard characters, we'll need to update this
- // check.
- if !isStructuredOutput && len(globalHashableEnvVars.BySource.Matching) > 0 {
- ui.Warn(fmt.Sprintf("[DEPRECATED] Using .*THASH.* to specify an environment variable for inclusion into the hash is deprecated. You specified: %s.", strings.Join(globalHashableEnvVars.BySource.Matching.Names(), ", ")))
- }
-
- logger.Debug("global hash env vars", "vars", globalHashableEnvVars.All.Names())
-
- // Calculate global file dependencies
- globalDeps := make(util.Set)
- if len(globalFileDependencies) > 0 {
- ignores, err := packageManager.GetWorkspaceIgnores(rootpath)
- if err != nil {
- return GlobalHashable{}, err
- }
-
- f, err := globby.GlobFiles(rootpath.ToStringDuringMigration(), globalFileDependencies, ignores)
- if err != nil {
- return GlobalHashable{}, err
- }
-
- for _, val := range f {
- globalDeps.Add(val)
- }
- }
-
- if lockFile == nil {
- // If we don't have lockfile information available, add the specfile and lockfile to global deps
- globalDeps.Add(filepath.Join(rootpath.ToStringDuringMigration(), packageManager.Specfile))
- globalDeps.Add(filepath.Join(rootpath.ToStringDuringMigration(), packageManager.Lockfile))
- }
-
- // No prefix, global deps already have full paths
- globalDepsArray := globalDeps.UnsafeListOfStrings()
- globalDepsPaths := make([]turbopath.AbsoluteSystemPath, len(globalDepsArray))
- for i, path := range globalDepsArray {
- globalDepsPaths[i] = turbopath.AbsoluteSystemPathFromUpstream(path)
- }
-
- globalFileHashMap, err := hashing.GetHashableDeps(rootpath, globalDepsPaths)
- if err != nil {
- return GlobalHashable{}, fmt.Errorf("error hashing files: %w", err)
- }
-
- return GlobalHashable{
- globalFileHashMap: globalFileHashMap,
- rootExternalDepsHash: rootPackageJSON.ExternalDepsHash,
- envVars: globalHashableEnvVars,
- globalCacheKey: _globalCacheKey,
- pipeline: pipeline.Pristine(),
- envVarPassthroughs: envVarPassthroughs,
- envMode: envMode,
- }, nil
-}
diff --git a/cli/internal/run/graph_run.go b/cli/internal/run/graph_run.go
deleted file mode 100644
index 8531718..0000000
--- a/cli/internal/run/graph_run.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package run
-
-import (
- gocontext "context"
-
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/core"
- "github.com/vercel/turbo/cli/internal/graphvisualizer"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// GraphRun generates a visualization of the task graph rather than executing it.
-func GraphRun(ctx gocontext.Context, rs *runSpec, engine *core.Engine, base *cmdutil.CmdBase) error {
- graph := engine.TaskGraph
- if rs.Opts.runOpts.SinglePackage {
- graph = filterSinglePackageGraphForDisplay(engine.TaskGraph)
- }
- visualizer := graphvisualizer.New(base.RepoRoot, base.UI, graph)
-
- if rs.Opts.runOpts.GraphDot {
- visualizer.RenderDotGraph()
- } else {
- err := visualizer.GenerateGraphFile(rs.Opts.runOpts.GraphFile)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// filterSinglePackageGraphForDisplay builds an equivalent graph with package names stripped from tasks.
-// Given that this should only be used in a single-package context, all of the package names are expected
-// to be //. Also, all nodes are always connected to the root node, so we are not concerned with leaving
-// behind any unconnected nodes.
-func filterSinglePackageGraphForDisplay(originalGraph *dag.AcyclicGraph) *dag.AcyclicGraph {
- graph := &dag.AcyclicGraph{}
- for _, edge := range originalGraph.Edges() {
- src := util.StripPackageName(edge.Source().(string))
- tgt := util.StripPackageName(edge.Target().(string))
- graph.Add(src)
- graph.Add(tgt)
- graph.Connect(dag.BasicEdge(src, tgt))
- }
- return graph
-}
diff --git a/cli/internal/run/log_tag_go.go b/cli/internal/run/log_tag_go.go
deleted file mode 100644
index a3e825f..0000000
--- a/cli/internal/run/log_tag_go.go
+++ /dev/null
@@ -1,11 +0,0 @@
-//go:build go || !rust
-// +build go !rust
-
-package run
-
-import "github.com/hashicorp/go-hclog"
-
-// LogTag logs out the build tag (in this case "go") for the current build.
-func LogTag(logger hclog.Logger) {
- logger.Debug("build tag: go")
-}
diff --git a/cli/internal/run/log_tag_rust.go b/cli/internal/run/log_tag_rust.go
deleted file mode 100644
index 065f438..0000000
--- a/cli/internal/run/log_tag_rust.go
+++ /dev/null
@@ -1,11 +0,0 @@
-//go:build rust
-// +build rust
-
-package run
-
-import "github.com/hashicorp/go-hclog"
-
-// LogTag logs out the build tag (in this case "rust") for the current build.
-func LogTag(logger hclog.Logger) {
- logger.Debug("build tag: rust")
-}
diff --git a/cli/internal/run/real_run.go b/cli/internal/run/real_run.go
deleted file mode 100644
index 32c7965..0000000
--- a/cli/internal/run/real_run.go
+++ /dev/null
@@ -1,420 +0,0 @@
-package run
-
-import (
- gocontext "context"
- "fmt"
- "log"
- "os/exec"
- "strings"
- "sync"
- "time"
-
- "github.com/fatih/color"
- "github.com/hashicorp/go-hclog"
- "github.com/mitchellh/cli"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/cache"
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/colorcache"
- "github.com/vercel/turbo/cli/internal/core"
- "github.com/vercel/turbo/cli/internal/env"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/graph"
- "github.com/vercel/turbo/cli/internal/logstreamer"
- "github.com/vercel/turbo/cli/internal/nodes"
- "github.com/vercel/turbo/cli/internal/packagemanager"
- "github.com/vercel/turbo/cli/internal/process"
- "github.com/vercel/turbo/cli/internal/runcache"
- "github.com/vercel/turbo/cli/internal/runsummary"
- "github.com/vercel/turbo/cli/internal/spinner"
- "github.com/vercel/turbo/cli/internal/taskhash"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// RealRun executes a set of tasks
-func RealRun(
- ctx gocontext.Context,
- g *graph.CompleteGraph,
- rs *runSpec,
- engine *core.Engine,
- taskHashTracker *taskhash.Tracker,
- turboCache cache.Cache,
- turboJSON *fs.TurboJSON,
- globalEnvMode util.EnvMode,
- packagesInScope []string,
- base *cmdutil.CmdBase,
- runSummary runsummary.Meta,
- packageManager *packagemanager.PackageManager,
- processes *process.Manager,
-) error {
- singlePackage := rs.Opts.runOpts.SinglePackage
-
- if singlePackage {
- base.UI.Output(fmt.Sprintf("%s %s", ui.Dim("• Running"), ui.Dim(ui.Bold(strings.Join(rs.Targets, ", ")))))
- } else {
- base.UI.Output(fmt.Sprintf(ui.Dim("• Packages in scope: %v"), strings.Join(packagesInScope, ", ")))
- base.UI.Output(fmt.Sprintf("%s %s %s", ui.Dim("• Running"), ui.Dim(ui.Bold(strings.Join(rs.Targets, ", "))), ui.Dim(fmt.Sprintf("in %v packages", rs.FilteredPkgs.Len()))))
- }
-
- // Log whether remote cache is enabled
- useHTTPCache := !rs.Opts.cacheOpts.SkipRemote
- if useHTTPCache {
- base.UI.Info(ui.Dim("• Remote caching enabled"))
- } else {
- base.UI.Info(ui.Dim("• Remote caching disabled"))
- }
-
- defer func() {
- _ = spinner.WaitFor(ctx, turboCache.Shutdown, base.UI, "...writing to cache...", 1500*time.Millisecond)
- }()
- colorCache := colorcache.New()
-
- runCache := runcache.New(turboCache, base.RepoRoot, rs.Opts.runcacheOpts, colorCache)
-
- ec := &execContext{
- colorCache: colorCache,
- runSummary: runSummary,
- rs: rs,
- ui: &cli.ConcurrentUi{Ui: base.UI},
- runCache: runCache,
- env: turboJSON.GlobalEnv,
- passthroughEnv: turboJSON.GlobalPassthroughEnv,
- logger: base.Logger,
- packageManager: packageManager,
- processes: processes,
- taskHashTracker: taskHashTracker,
- repoRoot: base.RepoRoot,
- isSinglePackage: singlePackage,
- }
-
- // run the thing
- execOpts := core.EngineExecutionOptions{
- Parallel: rs.Opts.runOpts.Parallel,
- Concurrency: rs.Opts.runOpts.Concurrency,
- }
-
- mu := sync.Mutex{}
- taskSummaries := []*runsummary.TaskSummary{}
- execFunc := func(ctx gocontext.Context, packageTask *nodes.PackageTask, taskSummary *runsummary.TaskSummary) error {
- taskExecutionSummary, err := ec.exec(ctx, packageTask)
-
- // taskExecutionSummary will be nil if the task never executed
- // (i.e. if the workspace didn't implement the script corresponding to the task)
- // We don't need to collect any of the outputs or execution if the task didn't execute.
- if taskExecutionSummary != nil {
- taskSummary.ExpandedOutputs = taskHashTracker.GetExpandedOutputs(taskSummary.TaskID)
- taskSummary.Execution = taskExecutionSummary
- taskSummary.CacheSummary = taskHashTracker.GetCacheStatus(taskSummary.TaskID)
-
- // lock since multiple things to be appending to this array at the same time
- mu.Lock()
- taskSummaries = append(taskSummaries, taskSummary)
- // not using defer, just release the lock
- mu.Unlock()
- }
-
- // Return the error when there is one
- if err != nil {
- return err
- }
-
- return nil
- }
-
- getArgs := func(taskID string) []string {
- return rs.ArgsForTask(taskID)
- }
-
- visitorFn := g.GetPackageTaskVisitor(ctx, engine.TaskGraph, globalEnvMode, getArgs, base.Logger, execFunc)
- errs := engine.Execute(visitorFn, execOpts)
-
- // Track if we saw any child with a non-zero exit code
- exitCode := 0
- exitCodeErr := &process.ChildExit{}
-
- // Assign tasks after execution
- runSummary.RunSummary.Tasks = taskSummaries
-
- for _, err := range errs {
- if errors.As(err, &exitCodeErr) {
- // If a process gets killed via a signal, Go reports it's exit code as -1.
- // We take the absolute value of the exit code so we don't select '0' as
- // the greatest exit code.
- childExit := exitCodeErr.ExitCode
- if childExit < 0 {
- childExit = -childExit
- }
- if childExit > exitCode {
- exitCode = childExit
- }
- } else if exitCode == 0 {
- // We hit some error, it shouldn't be exit code 0
- exitCode = 1
- }
- base.UI.Error(err.Error())
- }
-
- // When continue on error is enabled don't register failed tasks as errors
- // and instead must inspect the task summaries.
- if ec.rs.Opts.runOpts.ContinueOnError {
- for _, summary := range runSummary.RunSummary.Tasks {
- if childExit := summary.Execution.ExitCode(); childExit != nil {
- childExit := *childExit
- if childExit < 0 {
- childExit = -childExit
- }
- if childExit > exitCode {
- exitCode = childExit
- }
- }
- }
- }
-
- if err := runSummary.Close(ctx, exitCode, g.WorkspaceInfos); err != nil {
- // We don't need to throw an error, but we can warn on this.
- // Note: this method doesn't actually return an error for Real Runs at the time of writing.
- base.UI.Info(fmt.Sprintf("Failed to close Run Summary %v", err))
- }
-
- if exitCode != 0 {
- return &process.ChildExit{
- ExitCode: exitCode,
- }
- }
- return nil
-}
-
-type execContext struct {
- colorCache *colorcache.ColorCache
- runSummary runsummary.Meta
- rs *runSpec
- ui cli.Ui
- runCache *runcache.RunCache
- env []string
- passthroughEnv []string
- logger hclog.Logger
- packageManager *packagemanager.PackageManager
- processes *process.Manager
- taskHashTracker *taskhash.Tracker
- repoRoot turbopath.AbsoluteSystemPath
- isSinglePackage bool
-}
-
-func (ec *execContext) logError(prefix string, err error) {
- ec.logger.Error(prefix, "error", err)
-
- if prefix != "" {
- prefix += ": "
- }
-
- ec.ui.Error(fmt.Sprintf("%s%s%s", ui.ERROR_PREFIX, prefix, color.RedString(" %v", err)))
-}
-
-func (ec *execContext) exec(ctx gocontext.Context, packageTask *nodes.PackageTask) (*runsummary.TaskExecutionSummary, error) {
- // Setup tracer. Every time tracer() is called the taskExecutionSummary's duration is updated
- // So make sure to call it before returning.
- tracer, taskExecutionSummary := ec.runSummary.RunSummary.TrackTask(packageTask.TaskID)
-
- progressLogger := ec.logger.Named("")
- progressLogger.Debug("start")
-
- passThroughArgs := ec.rs.ArgsForTask(packageTask.Task)
- hash := packageTask.Hash
- ec.logger.Debug("task hash", "value", hash)
- // TODO(gsoltis): if/when we fix https://github.com/vercel/turbo/issues/937
- // the following block should never get hit. In the meantime, keep it after hashing
- // so that downstream tasks can count on the hash existing
- //
- // bail if the script doesn't exist
- if packageTask.Command == "" {
- progressLogger.Debug("no task in package, skipping")
- progressLogger.Debug("done", "status", "skipped", "duration", taskExecutionSummary.Duration)
- // Return nil here because there was no execution, so there is no task execution summary
- return nil, nil
- }
-
- // Set building status now that we know it's going to run.
- tracer(runsummary.TargetBuilding, nil, &successCode)
-
- var prefix string
- var prettyPrefix string
- if ec.rs.Opts.runOpts.LogPrefix == "none" {
- prefix = ""
- } else {
- prefix = packageTask.OutputPrefix(ec.isSinglePackage)
- }
-
- prettyPrefix = ec.colorCache.PrefixWithColor(packageTask.PackageName, prefix)
-
- // Cache ---------------------------------------------
- taskCache := ec.runCache.TaskCache(packageTask, hash)
- // Create a logger for replaying
- prefixedUI := &cli.PrefixedUi{
- Ui: ec.ui,
- OutputPrefix: prettyPrefix,
- InfoPrefix: prettyPrefix,
- ErrorPrefix: prettyPrefix,
- WarnPrefix: prettyPrefix,
- }
-
- cacheStatus, timeSaved, err := taskCache.RestoreOutputs(ctx, prefixedUI, progressLogger)
-
- // It's safe to set the CacheStatus even if there's an error, because if there's
- // an error, the 0 values are actually what we want. We save cacheStatus and timeSaved
- // for the task, so that even if there's an error, we have those values for the taskSummary.
- ec.taskHashTracker.SetCacheStatus(
- packageTask.TaskID,
- runsummary.NewTaskCacheSummary(cacheStatus, &timeSaved),
- )
-
- if err != nil {
- prefixedUI.Error(fmt.Sprintf("error fetching from cache: %s", err))
- } else if cacheStatus.Local || cacheStatus.Remote { // If there was a cache hit
- ec.taskHashTracker.SetExpandedOutputs(packageTask.TaskID, taskCache.ExpandedOutputs)
- // We only cache successful executions, so we can assume this is a successCode exit.
- tracer(runsummary.TargetCached, nil, &successCode)
- return taskExecutionSummary, nil
- }
-
- // Setup command execution
- argsactual := append([]string{"run"}, packageTask.Task)
- if len(passThroughArgs) > 0 {
- // This will be either '--' or a typed nil
- argsactual = append(argsactual, ec.packageManager.ArgSeparator...)
- argsactual = append(argsactual, passThroughArgs...)
- }
-
- cmd := exec.Command(ec.packageManager.Command, argsactual...)
- cmd.Dir = packageTask.Pkg.Dir.ToSystemPath().RestoreAnchor(ec.repoRoot).ToString()
-
- currentState := env.GetEnvMap()
- passthroughEnv := env.EnvironmentVariableMap{}
-
- if packageTask.EnvMode == util.Strict {
- defaultPassthrough := []string{
- "PATH",
- "SHELL",
- "SYSTEMROOT", // Go will always include this on Windows, but we're being explicit here
- }
-
- passthroughEnv.Merge(env.FromKeys(currentState, defaultPassthrough))
- passthroughEnv.Merge(env.FromKeys(currentState, ec.env))
- passthroughEnv.Merge(env.FromKeys(currentState, ec.passthroughEnv))
- passthroughEnv.Merge(env.FromKeys(currentState, packageTask.TaskDefinition.EnvVarDependencies))
- passthroughEnv.Merge(env.FromKeys(currentState, packageTask.TaskDefinition.PassthroughEnv))
- } else {
- passthroughEnv.Merge(currentState)
- }
-
- // Always last to make sure it clobbers.
- passthroughEnv.Add("TURBO_HASH", hash)
-
- cmd.Env = passthroughEnv.ToHashable()
-
- // Setup stdout/stderr
- // If we are not caching anything, then we don't need to write logs to disk
- // be careful about this conditional given the default of cache = true
- writer, err := taskCache.OutputWriter(prettyPrefix)
- if err != nil {
- tracer(runsummary.TargetBuildFailed, err, nil)
-
- ec.logError(prettyPrefix, err)
- if !ec.rs.Opts.runOpts.ContinueOnError {
- return nil, errors.Wrapf(err, "failed to capture outputs for \"%v\"", packageTask.TaskID)
- }
- }
-
- // Create a logger
- logger := log.New(writer, "", 0)
- // Setup a streamer that we'll pipe cmd.Stdout to
- logStreamerOut := logstreamer.NewLogstreamer(logger, prettyPrefix, false)
- // Setup a streamer that we'll pipe cmd.Stderr to.
- logStreamerErr := logstreamer.NewLogstreamer(logger, prettyPrefix, false)
- cmd.Stderr = logStreamerErr
- cmd.Stdout = logStreamerOut
- // Flush/Reset any error we recorded
- logStreamerErr.FlushRecord()
- logStreamerOut.FlushRecord()
-
- closeOutputs := func() error {
- var closeErrors []error
-
- if err := logStreamerOut.Close(); err != nil {
- closeErrors = append(closeErrors, errors.Wrap(err, "log stdout"))
- }
- if err := logStreamerErr.Close(); err != nil {
- closeErrors = append(closeErrors, errors.Wrap(err, "log stderr"))
- }
-
- if err := writer.Close(); err != nil {
- closeErrors = append(closeErrors, errors.Wrap(err, "log file"))
- }
- if len(closeErrors) > 0 {
- msgs := make([]string, len(closeErrors))
- for i, err := range closeErrors {
- msgs[i] = err.Error()
- }
- return fmt.Errorf("could not flush log output: %v", strings.Join(msgs, ", "))
- }
- return nil
- }
-
- // Run the command
- if err := ec.processes.Exec(cmd); err != nil {
- // close off our outputs. We errored, so we mostly don't care if we fail to close
- _ = closeOutputs()
- // if we already know we're in the process of exiting,
- // we don't need to record an error to that effect.
- if errors.Is(err, process.ErrClosing) {
- return taskExecutionSummary, nil
- }
-
- // If the error we got is a ChildExit, it will have an ExitCode field
- // Pass that along into the tracer.
- var e *process.ChildExit
- if errors.As(err, &e) {
- tracer(runsummary.TargetBuildFailed, err, &e.ExitCode)
- } else {
- // If it wasn't a ChildExit, and something else went wrong, we don't have an exitCode
- tracer(runsummary.TargetBuildFailed, err, nil)
- }
-
- progressLogger.Error(fmt.Sprintf("Error: command finished with error: %v", err))
- if !ec.rs.Opts.runOpts.ContinueOnError {
- prefixedUI.Error(fmt.Sprintf("ERROR: command finished with error: %s", err))
- ec.processes.Close()
- } else {
- prefixedUI.Warn("command finished with error, but continuing...")
- // Set to nil so we don't short-circuit any other execution
- err = nil
- }
-
- // If there was an error, flush the buffered output
- taskCache.OnError(prefixedUI, progressLogger)
-
- return taskExecutionSummary, err
- }
-
- // Add another timestamp into the tracer, so we have an accurate timestamp for how long the task took.
- tracer(runsummary.TargetExecuted, nil, nil)
-
- // Close off our outputs and cache them
- if err := closeOutputs(); err != nil {
- ec.logError("", err)
- } else {
- if err = taskCache.SaveOutputs(ctx, progressLogger, prefixedUI, int(taskExecutionSummary.Duration.Milliseconds())); err != nil {
- ec.logError("", fmt.Errorf("error caching output: %w", err))
- } else {
- ec.taskHashTracker.SetExpandedOutputs(packageTask.TaskID, taskCache.ExpandedOutputs)
- }
- }
-
- // Clean up tracing
- tracer(runsummary.TargetBuilt, nil, &successCode)
- progressLogger.Debug("done", "status", "complete", "duration", taskExecutionSummary.Duration)
- return taskExecutionSummary, nil
-}
-
-var successCode = 0
diff --git a/cli/internal/run/run.go b/cli/internal/run/run.go
deleted file mode 100644
index 2ac1141..0000000
--- a/cli/internal/run/run.go
+++ /dev/null
@@ -1,487 +0,0 @@
-package run
-
-import (
- gocontext "context"
- "fmt"
- "os"
- "sort"
- "sync"
- "time"
-
- "github.com/vercel/turbo/cli/internal/analytics"
- "github.com/vercel/turbo/cli/internal/cache"
- "github.com/vercel/turbo/cli/internal/cmdutil"
- "github.com/vercel/turbo/cli/internal/context"
- "github.com/vercel/turbo/cli/internal/core"
- "github.com/vercel/turbo/cli/internal/daemon"
- "github.com/vercel/turbo/cli/internal/daemonclient"
- "github.com/vercel/turbo/cli/internal/env"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/graph"
- "github.com/vercel/turbo/cli/internal/process"
- "github.com/vercel/turbo/cli/internal/runsummary"
- "github.com/vercel/turbo/cli/internal/scm"
- "github.com/vercel/turbo/cli/internal/scope"
- "github.com/vercel/turbo/cli/internal/signals"
- "github.com/vercel/turbo/cli/internal/taskhash"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
-
- "github.com/pkg/errors"
-)
-
-// ExecuteRun executes the run command
-func ExecuteRun(ctx gocontext.Context, helper *cmdutil.Helper, signalWatcher *signals.Watcher, args *turbostate.ParsedArgsFromRust) error {
- base, err := helper.GetCmdBase(args)
- LogTag(base.Logger)
- if err != nil {
- return err
- }
- tasks := args.Command.Run.Tasks
- passThroughArgs := args.Command.Run.PassThroughArgs
- if len(tasks) == 0 {
- return errors.New("at least one task must be specified")
- }
- opts, err := optsFromArgs(args)
- if err != nil {
- return err
- }
-
- opts.runOpts.PassThroughArgs = passThroughArgs
- run := configureRun(base, opts, signalWatcher)
- if err := run.run(ctx, tasks); err != nil {
- base.LogError("run failed: %v", err)
- return err
- }
- return nil
-}
-
-func optsFromArgs(args *turbostate.ParsedArgsFromRust) (*Opts, error) {
- runPayload := args.Command.Run
-
- opts := getDefaultOptions()
- // aliases := make(map[string]string)
- if err := scope.OptsFromArgs(&opts.scopeOpts, args); err != nil {
- return nil, err
- }
-
- // Cache flags
- opts.clientOpts.Timeout = args.RemoteCacheTimeout
- opts.cacheOpts.SkipFilesystem = runPayload.RemoteOnly
- opts.cacheOpts.OverrideDir = runPayload.CacheDir
- opts.cacheOpts.Workers = runPayload.CacheWorkers
-
- // Run flags
- opts.runOpts.LogPrefix = runPayload.LogPrefix
- opts.runOpts.Summarize = runPayload.Summarize
- opts.runOpts.ExperimentalSpaceID = runPayload.ExperimentalSpaceID
- opts.runOpts.EnvMode = runPayload.EnvMode
-
- // Runcache flags
- opts.runcacheOpts.SkipReads = runPayload.Force
- opts.runcacheOpts.SkipWrites = runPayload.NoCache
-
- if runPayload.OutputLogs != "" {
- err := opts.runcacheOpts.SetTaskOutputMode(runPayload.OutputLogs)
- if err != nil {
- return nil, err
- }
- }
-
- // Run flags
- if runPayload.Concurrency != "" {
- concurrency, err := util.ParseConcurrency(runPayload.Concurrency)
- if err != nil {
- return nil, err
- }
- opts.runOpts.Concurrency = concurrency
- }
- opts.runOpts.Parallel = runPayload.Parallel
- opts.runOpts.Profile = runPayload.Profile
- opts.runOpts.ContinueOnError = runPayload.ContinueExecution
- opts.runOpts.Only = runPayload.Only
- opts.runOpts.NoDaemon = runPayload.NoDaemon
- opts.runOpts.SinglePackage = args.Command.Run.SinglePackage
-
- // See comment on Graph in turbostate.go for an explanation on Graph's representation.
- // If flag is passed...
- if runPayload.Graph != nil {
- // If no value is attached, we print to stdout
- if *runPayload.Graph == "" {
- opts.runOpts.GraphDot = true
- } else {
- // Otherwise, we emit to the file name attached as value
- opts.runOpts.GraphDot = false
- opts.runOpts.GraphFile = *runPayload.Graph
- }
- }
-
- if runPayload.DryRun != "" {
- opts.runOpts.DryRunJSON = runPayload.DryRun == _dryRunJSONValue
-
- if runPayload.DryRun == _dryRunTextValue || runPayload.DryRun == _dryRunJSONValue {
- opts.runOpts.DryRun = true
- } else {
- return nil, fmt.Errorf("invalid dry-run mode: %v", runPayload.DryRun)
- }
- }
-
- return opts, nil
-}
-
-func configureRun(base *cmdutil.CmdBase, opts *Opts, signalWatcher *signals.Watcher) *run {
- if os.Getenv("TURBO_FORCE") == "true" {
- opts.runcacheOpts.SkipReads = true
- }
-
- if os.Getenv("TURBO_REMOTE_ONLY") == "true" {
- opts.cacheOpts.SkipFilesystem = true
- }
-
- processes := process.NewManager(base.Logger.Named("processes"))
- signalWatcher.AddOnClose(processes.Close)
- return &run{
- base: base,
- opts: opts,
- processes: processes,
- }
-}
-
-type run struct {
- base *cmdutil.CmdBase
- opts *Opts
- processes *process.Manager
-}
-
-func (r *run) run(ctx gocontext.Context, targets []string) error {
- startAt := time.Now()
- packageJSONPath := r.base.RepoRoot.UntypedJoin("package.json")
- rootPackageJSON, err := fs.ReadPackageJSON(packageJSONPath)
- if err != nil {
- return fmt.Errorf("failed to read package.json: %w", err)
- }
-
- isStructuredOutput := r.opts.runOpts.GraphDot || r.opts.runOpts.DryRunJSON
-
- var pkgDepGraph *context.Context
- if r.opts.runOpts.SinglePackage {
- pkgDepGraph, err = context.SinglePackageGraph(r.base.RepoRoot, rootPackageJSON)
- } else {
- pkgDepGraph, err = context.BuildPackageGraph(r.base.RepoRoot, rootPackageJSON)
- }
- if err != nil {
- var warnings *context.Warnings
- if errors.As(err, &warnings) {
- r.base.LogWarning("Issues occurred when constructing package graph. Turbo will function, but some features may not be available", err)
- } else {
- return err
- }
- }
-
- if ui.IsCI && !r.opts.runOpts.NoDaemon {
- r.base.Logger.Info("skipping turbod since we appear to be in a non-interactive context")
- } else if !r.opts.runOpts.NoDaemon {
- turbodClient, err := daemon.GetClient(ctx, r.base.RepoRoot, r.base.Logger, r.base.TurboVersion, daemon.ClientOpts{})
- if err != nil {
- r.base.LogWarning("", errors.Wrap(err, "failed to contact turbod. Continuing in standalone mode"))
- } else {
- defer func() { _ = turbodClient.Close() }()
- r.base.Logger.Debug("running in daemon mode")
- daemonClient := daemonclient.New(turbodClient)
- r.opts.runcacheOpts.OutputWatcher = daemonClient
- }
- }
-
- if err := util.ValidateGraph(&pkgDepGraph.WorkspaceGraph); err != nil {
- return errors.Wrap(err, "Invalid package dependency graph")
- }
-
- // TODO: consolidate some of these arguments
- // Note: not all properties are set here. GlobalHash and Pipeline keys are set later
- g := &graph.CompleteGraph{
- WorkspaceGraph: pkgDepGraph.WorkspaceGraph,
- WorkspaceInfos: pkgDepGraph.WorkspaceInfos,
- RootNode: pkgDepGraph.RootNode,
- TaskDefinitions: map[string]*fs.TaskDefinition{},
- RepoRoot: r.base.RepoRoot,
- }
-
- turboJSON, err := g.GetTurboConfigFromWorkspace(util.RootPkgName, r.opts.runOpts.SinglePackage)
- if err != nil {
- return err
- }
-
- // TODO: these values come from a config file, hopefully viper can help us merge these
- r.opts.cacheOpts.RemoteCacheOpts = turboJSON.RemoteCacheOptions
-
- pipeline := turboJSON.Pipeline
- g.Pipeline = pipeline
- scmInstance, err := scm.FromInRepo(r.base.RepoRoot)
- if err != nil {
- if errors.Is(err, scm.ErrFallback) {
- r.base.Logger.Debug("", err)
- } else {
- return errors.Wrap(err, "failed to create SCM")
- }
- }
- filteredPkgs, isAllPackages, err := scope.ResolvePackages(&r.opts.scopeOpts, r.base.RepoRoot, scmInstance, pkgDepGraph, r.base.UI, r.base.Logger)
- if err != nil {
- return errors.Wrap(err, "failed to resolve packages to run")
- }
- if isAllPackages {
- // if there is a root task for any of our targets, we need to add it
- for _, target := range targets {
- key := util.RootTaskID(target)
- if _, ok := pipeline[key]; ok {
- filteredPkgs.Add(util.RootPkgName)
- // we only need to know we're running a root task once to add it for consideration
- break
- }
- }
- }
-
- globalHashable, err := calculateGlobalHash(
- r.base.RepoRoot,
- rootPackageJSON,
- pipeline,
- turboJSON.GlobalEnv,
- turboJSON.GlobalDeps,
- pkgDepGraph.PackageManager,
- pkgDepGraph.Lockfile,
- turboJSON.GlobalPassthroughEnv,
- r.opts.runOpts.EnvMode,
- r.base.Logger,
- r.base.UI,
- isStructuredOutput,
- )
-
- if err != nil {
- return fmt.Errorf("failed to collect global hash inputs: %v", err)
- }
-
- if globalHash, err := calculateGlobalHashFromHashable(globalHashable); err == nil {
- r.base.Logger.Debug("global hash", "value", globalHash)
- g.GlobalHash = globalHash
- } else {
- return fmt.Errorf("failed to calculate global hash: %v", err)
- }
-
- r.base.Logger.Debug("local cache folder", "path", r.opts.cacheOpts.OverrideDir)
-
- rs := &runSpec{
- Targets: targets,
- FilteredPkgs: filteredPkgs,
- Opts: r.opts,
- }
- packageManager := pkgDepGraph.PackageManager
-
- engine, err := buildTaskGraphEngine(
- g,
- rs,
- r.opts.runOpts.SinglePackage,
- )
-
- if err != nil {
- return errors.Wrap(err, "error preparing engine")
- }
-
- taskHashTracker := taskhash.NewTracker(
- g.RootNode,
- g.GlobalHash,
- // TODO(mehulkar): remove g,Pipeline, because we need to get task definitions from CompleteGaph instead
- g.Pipeline,
- )
-
- g.TaskHashTracker = taskHashTracker
-
- // CalculateFileHashes assigns PackageInputsExpandedHashes as a side-effect
- err = taskHashTracker.CalculateFileHashes(
- engine.TaskGraph.Vertices(),
- rs.Opts.runOpts.Concurrency,
- g.WorkspaceInfos,
- g.TaskDefinitions,
- r.base.RepoRoot,
- )
-
- if err != nil {
- return errors.Wrap(err, "error hashing package files")
- }
-
- // If we are running in parallel, then we remove all the edges in the graph
- // except for the root. Rebuild the task graph for backwards compatibility.
- // We still use dependencies specified by the pipeline configuration.
- if rs.Opts.runOpts.Parallel {
- for _, edge := range g.WorkspaceGraph.Edges() {
- if edge.Target() != g.RootNode {
- g.WorkspaceGraph.RemoveEdge(edge)
- }
- }
- engine, err = buildTaskGraphEngine(
- g,
- rs,
- r.opts.runOpts.SinglePackage,
- )
- if err != nil {
- return errors.Wrap(err, "error preparing engine")
- }
- }
-
- // Graph Run
- if rs.Opts.runOpts.GraphFile != "" || rs.Opts.runOpts.GraphDot {
- return GraphRun(ctx, rs, engine, r.base)
- }
-
- packagesInScope := rs.FilteredPkgs.UnsafeListOfStrings()
- sort.Strings(packagesInScope)
- // Initiate analytics and cache
- analyticsClient := r.initAnalyticsClient(ctx)
- defer analyticsClient.CloseWithTimeout(50 * time.Millisecond)
- turboCache, err := r.initCache(ctx, rs, analyticsClient)
-
- if err != nil {
- if errors.Is(err, cache.ErrNoCachesEnabled) {
- r.base.UI.Warn("No caches are enabled. You can try \"turbo login\", \"turbo link\", or ensuring you are not passing --remote-only to enable caching")
- } else {
- return errors.Wrap(err, "failed to set up caching")
- }
- }
-
- var envVarPassthroughMap env.EnvironmentVariableMap
- if globalHashable.envVarPassthroughs != nil {
- if envVarPassthroughDetailedMap, err := env.GetHashableEnvVars(globalHashable.envVarPassthroughs, nil, ""); err == nil {
- envVarPassthroughMap = envVarPassthroughDetailedMap.BySource.Explicit
- }
- }
-
- globalEnvMode := rs.Opts.runOpts.EnvMode
- if globalEnvMode == util.Infer && turboJSON.GlobalPassthroughEnv != nil {
- globalEnvMode = util.Strict
- }
-
- // RunSummary contains information that is statically analyzable about
- // the tasks that we expect to run based on the user command.
- summary := runsummary.NewRunSummary(
- startAt,
- r.base.UI,
- r.base.RepoRoot,
- rs.Opts.scopeOpts.PackageInferenceRoot,
- r.base.TurboVersion,
- r.base.APIClient,
- rs.Opts.runOpts,
- packagesInScope,
- globalEnvMode,
- runsummary.NewGlobalHashSummary(
- globalHashable.globalFileHashMap,
- globalHashable.rootExternalDepsHash,
- globalHashable.envVars,
- envVarPassthroughMap,
- globalHashable.globalCacheKey,
- globalHashable.pipeline,
- ),
- rs.Opts.SynthesizeCommand(rs.Targets),
- )
-
- // Dry Run
- if rs.Opts.runOpts.DryRun {
- return DryRun(
- ctx,
- g,
- rs,
- engine,
- taskHashTracker,
- turboCache,
- turboJSON,
- globalEnvMode,
- r.base,
- summary,
- )
- }
-
- // Regular run
- return RealRun(
- ctx,
- g,
- rs,
- engine,
- taskHashTracker,
- turboCache,
- turboJSON,
- globalEnvMode,
- packagesInScope,
- r.base,
- summary,
- // Extra arg only for regular runs, dry-run doesn't get this
- packageManager,
- r.processes,
- )
-}
-
-func (r *run) initAnalyticsClient(ctx gocontext.Context) analytics.Client {
- apiClient := r.base.APIClient
- var analyticsSink analytics.Sink
- if apiClient.IsLinked() {
- analyticsSink = apiClient
- } else {
- r.opts.cacheOpts.SkipRemote = true
- analyticsSink = analytics.NullSink
- }
- analyticsClient := analytics.NewClient(ctx, analyticsSink, r.base.Logger.Named("analytics"))
- return analyticsClient
-}
-
-func (r *run) initCache(ctx gocontext.Context, rs *runSpec, analyticsClient analytics.Client) (cache.Cache, error) {
- apiClient := r.base.APIClient
- // Theoretically this is overkill, but bias towards not spamming the console
- once := &sync.Once{}
-
- return cache.New(rs.Opts.cacheOpts, r.base.RepoRoot, apiClient, analyticsClient, func(_cache cache.Cache, err error) {
- // Currently the HTTP Cache is the only one that can be disabled.
- // With a cache system refactor, we might consider giving names to the caches so
- // we can accurately report them here.
- once.Do(func() {
- r.base.LogWarning("Remote Caching is unavailable", err)
- })
- })
-}
-
-func buildTaskGraphEngine(
- g *graph.CompleteGraph,
- rs *runSpec,
- isSinglePackage bool,
-) (*core.Engine, error) {
- engine := core.NewEngine(g, isSinglePackage)
-
- // Note: g.Pipeline is a map, but this for loop only cares about the keys
- for taskName := range g.Pipeline {
- engine.AddTask(taskName)
- }
-
- if err := engine.Prepare(&core.EngineBuildingOptions{
- Packages: rs.FilteredPkgs.UnsafeListOfStrings(),
- TaskNames: rs.Targets,
- TasksOnly: rs.Opts.runOpts.Only,
- }); err != nil {
- return nil, err
- }
-
- // Check for cycles in the DAG.
- if err := util.ValidateGraph(engine.TaskGraph); err != nil {
- return nil, fmt.Errorf("Invalid task dependency graph:\n%v", err)
- }
-
- // Check that no tasks would be blocked by a persistent task
- if err := engine.ValidatePersistentDependencies(g, rs.Opts.runOpts.Concurrency); err != nil {
- return nil, fmt.Errorf("Invalid persistent task configuration:\n%v", err)
- }
-
- return engine, nil
-}
-
-// dry run custom flag
-// NOTE: These *must* be kept in sync with the corresponding Rust
-// enum definitions in shim/src/commands/mod.rs
-const (
- _dryRunJSONValue = "Json"
- _dryRunTextValue = "Text"
-)
diff --git a/cli/internal/run/run_spec.go b/cli/internal/run/run_spec.go
deleted file mode 100644
index 14402d3..0000000
--- a/cli/internal/run/run_spec.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Package run implements `turbo run`
-// This file implements some structs for options
-package run
-
-import (
- "strings"
-
- "github.com/vercel/turbo/cli/internal/cache"
- "github.com/vercel/turbo/cli/internal/client"
- "github.com/vercel/turbo/cli/internal/runcache"
- "github.com/vercel/turbo/cli/internal/scope"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// runSpec contains the run-specific configuration elements that come from a particular
-// invocation of turbo.
-type runSpec struct {
- // Target is a list of task that are going to run this time
- // E.g. in `turbo run build lint` Targets will be ["build", "lint"]
- Targets []string
-
- // FilteredPkgs is the list of packages that are relevant for this run.
- FilteredPkgs util.Set
-
- // Opts contains various opts, gathered from CLI flags,
- // but bucketed in smaller structs based on what they mean.
- Opts *Opts
-}
-
-// ArgsForTask returns the set of args that need to be passed through to the task
-func (rs *runSpec) ArgsForTask(task string) []string {
- passThroughArgs := make([]string, 0, len(rs.Opts.runOpts.PassThroughArgs))
- for _, target := range rs.Targets {
- if target == task {
- passThroughArgs = append(passThroughArgs, rs.Opts.runOpts.PassThroughArgs...)
- }
- }
- return passThroughArgs
-}
-
-// Opts holds the current run operations configuration
-type Opts struct {
- runOpts util.RunOpts
- cacheOpts cache.Opts
- clientOpts client.Opts
- runcacheOpts runcache.Opts
- scopeOpts scope.Opts
-}
-
-// SynthesizeCommand produces a command that produces an equivalent set of packages, tasks,
-// and task arguments to what the current set of opts selects.
-func (o *Opts) SynthesizeCommand(tasks []string) string {
- cmd := "turbo run"
- cmd += " " + strings.Join(tasks, " ")
- for _, filterPattern := range o.scopeOpts.FilterPatterns {
- cmd += " --filter=" + filterPattern
- }
- for _, filterPattern := range o.scopeOpts.LegacyFilter.AsFilterPatterns() {
- cmd += " --filter=" + filterPattern
- }
- if o.runOpts.Parallel {
- cmd += " --parallel"
- }
- if o.runOpts.ContinueOnError {
- cmd += " --continue"
- }
- if o.runOpts.DryRun {
- if o.runOpts.DryRunJSON {
- cmd += " --dry=json"
- } else {
- cmd += " --dry"
- }
- }
- if len(o.runOpts.PassThroughArgs) > 0 {
- cmd += " -- " + strings.Join(o.runOpts.PassThroughArgs, " ")
- }
- return cmd
-}
-
-// getDefaultOptions returns the default set of Opts for every run
-func getDefaultOptions() *Opts {
- return &Opts{
- runOpts: util.RunOpts{
- Concurrency: 10,
- },
- clientOpts: client.Opts{
- Timeout: client.ClientTimeout,
- },
- }
-}
diff --git a/cli/internal/run/run_spec_test.go b/cli/internal/run/run_spec_test.go
deleted file mode 100644
index 2bcfe2b..0000000
--- a/cli/internal/run/run_spec_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package run
-
-import (
- "testing"
-
- "github.com/vercel/turbo/cli/internal/scope"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-func TestSynthesizeCommand(t *testing.T) {
- testCases := []struct {
- filterPatterns []string
- legacyFilter scope.LegacyFilter
- passThroughArgs []string
- parallel bool
- continueOnError bool
- dryRun bool
- dryRunJSON bool
- tasks []string
- expected string
- }{
- {
- filterPatterns: []string{"my-app"},
- tasks: []string{"build"},
- expected: "turbo run build --filter=my-app",
- },
- {
- filterPatterns: []string{"my-app"},
- tasks: []string{"build"},
- passThroughArgs: []string{"-v", "--foo=bar"},
- expected: "turbo run build --filter=my-app -- -v --foo=bar",
- },
- {
- legacyFilter: scope.LegacyFilter{
- Entrypoints: []string{"my-app"},
- SkipDependents: true,
- },
- tasks: []string{"build"},
- passThroughArgs: []string{"-v", "--foo=bar"},
- expected: "turbo run build --filter=my-app -- -v --foo=bar",
- },
- {
- legacyFilter: scope.LegacyFilter{
- Entrypoints: []string{"my-app"},
- SkipDependents: true,
- },
- filterPatterns: []string{"other-app"},
- tasks: []string{"build"},
- passThroughArgs: []string{"-v", "--foo=bar"},
- expected: "turbo run build --filter=other-app --filter=my-app -- -v --foo=bar",
- },
- {
- legacyFilter: scope.LegacyFilter{
- Entrypoints: []string{"my-app"},
- IncludeDependencies: true,
- Since: "some-ref",
- },
- filterPatterns: []string{"other-app"},
- tasks: []string{"build"},
- expected: "turbo run build --filter=other-app --filter=...my-app...[some-ref]...",
- },
- {
- filterPatterns: []string{"my-app"},
- tasks: []string{"build"},
- parallel: true,
- continueOnError: true,
- expected: "turbo run build --filter=my-app --parallel --continue",
- },
- {
- filterPatterns: []string{"my-app"},
- tasks: []string{"build"},
- dryRun: true,
- expected: "turbo run build --filter=my-app --dry",
- },
- {
- filterPatterns: []string{"my-app"},
- tasks: []string{"build"},
- dryRun: true,
- dryRunJSON: true,
- expected: "turbo run build --filter=my-app --dry=json",
- },
- }
-
- for _, testCase := range testCases {
- testCase := testCase
- t.Run(testCase.expected, func(t *testing.T) {
- o := Opts{
- scopeOpts: scope.Opts{
- FilterPatterns: testCase.filterPatterns,
- LegacyFilter: testCase.legacyFilter,
- },
- runOpts: util.RunOpts{
- PassThroughArgs: testCase.passThroughArgs,
- Parallel: testCase.parallel,
- ContinueOnError: testCase.continueOnError,
- DryRun: testCase.dryRun,
- DryRunJSON: testCase.dryRunJSON,
- },
- }
- cmd := o.SynthesizeCommand(testCase.tasks)
- if cmd != testCase.expected {
- t.Errorf("SynthesizeCommand() got %v, want %v", cmd, testCase.expected)
- }
- })
- }
-
-}
diff --git a/cli/internal/runcache/output_watcher.go b/cli/internal/runcache/output_watcher.go
deleted file mode 100644
index 5f90f0e..0000000
--- a/cli/internal/runcache/output_watcher.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package runcache
-
-import (
- "context"
-
- "github.com/vercel/turbo/cli/internal/fs"
-)
-
-// OutputWatcher instances are responsible for tracking changes to task outputs
-type OutputWatcher interface {
- // GetChangedOutputs returns which of the given globs have changed since the specified hash was last run
- GetChangedOutputs(ctx context.Context, hash string, repoRelativeOutputGlobs []string) ([]string, error)
- // NotifyOutputsWritten tells the watcher that the given globs have been cached with the specified hash
- NotifyOutputsWritten(ctx context.Context, hash string, repoRelativeOutputGlobs fs.TaskOutputs) error
-}
-
-// NoOpOutputWatcher implements OutputWatcher, but always considers every glob to have changed
-type NoOpOutputWatcher struct{}
-
-var _ OutputWatcher = (*NoOpOutputWatcher)(nil)
-
-// GetChangedOutputs implements OutputWatcher.GetChangedOutputs.
-// Since this is a no-op watcher, no tracking is done.
-func (NoOpOutputWatcher) GetChangedOutputs(ctx context.Context, hash string, repoRelativeOutputGlobs []string) ([]string, error) {
- return repoRelativeOutputGlobs, nil
-}
-
-// NotifyOutputsWritten implements OutputWatcher.NotifyOutputsWritten.
-// Since this is a no-op watcher, consider all globs to have changed
-func (NoOpOutputWatcher) NotifyOutputsWritten(ctx context.Context, hash string, repoRelativeOutputGlobs fs.TaskOutputs) error {
- return nil
-}
diff --git a/cli/internal/runcache/runcache.go b/cli/internal/runcache/runcache.go
deleted file mode 100644
index ba6145b..0000000
--- a/cli/internal/runcache/runcache.go
+++ /dev/null
@@ -1,354 +0,0 @@
-package runcache
-
-import (
- "bufio"
- "context"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/fatih/color"
- "github.com/hashicorp/go-hclog"
- "github.com/mitchellh/cli"
- "github.com/vercel/turbo/cli/internal/cache"
- "github.com/vercel/turbo/cli/internal/colorcache"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/globby"
- "github.com/vercel/turbo/cli/internal/logstreamer"
- "github.com/vercel/turbo/cli/internal/nodes"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// LogReplayer is a function that is responsible for replaying the contents of a given log file
-type LogReplayer = func(logger hclog.Logger, output *cli.PrefixedUi, logFile turbopath.AbsoluteSystemPath)
-
-// Opts holds the configurable options for a RunCache instance
-type Opts struct {
- SkipReads bool
- SkipWrites bool
- TaskOutputModeOverride *util.TaskOutputMode
- LogReplayer LogReplayer
- OutputWatcher OutputWatcher
-}
-
-// SetTaskOutputMode parses the task output mode from string and then sets it in opts
-func (opts *Opts) SetTaskOutputMode(value string) error {
- outputMode, err := util.FromTaskOutputModeString(value)
- if err != nil {
- return fmt.Errorf("must be one of \"%v\"", TaskOutputModes())
- }
- opts.TaskOutputModeOverride = &outputMode
- return nil
-}
-
-// TaskOutputModes creates the description string for task outputs
-func TaskOutputModes() string {
- var builder strings.Builder
-
- first := true
- for _, mode := range util.TaskOutputModeStrings {
- if !first {
- builder.WriteString("|")
- }
- first = false
- builder.WriteString(string(mode))
- }
- return builder.String()
-}
-
-// RunCache represents the interface to the cache for a single `turbo run`
-type RunCache struct {
- taskOutputModeOverride *util.TaskOutputMode
- cache cache.Cache
- readsDisabled bool
- writesDisabled bool
- repoRoot turbopath.AbsoluteSystemPath
- logReplayer LogReplayer
- outputWatcher OutputWatcher
- colorCache *colorcache.ColorCache
-}
-
-// New returns a new instance of RunCache, wrapping the given cache
-func New(cache cache.Cache, repoRoot turbopath.AbsoluteSystemPath, opts Opts, colorCache *colorcache.ColorCache) *RunCache {
- rc := &RunCache{
- taskOutputModeOverride: opts.TaskOutputModeOverride,
- cache: cache,
- readsDisabled: opts.SkipReads,
- writesDisabled: opts.SkipWrites,
- repoRoot: repoRoot,
- logReplayer: opts.LogReplayer,
- outputWatcher: opts.OutputWatcher,
- colorCache: colorCache,
- }
-
- if rc.logReplayer == nil {
- rc.logReplayer = defaultLogReplayer
- }
- if rc.outputWatcher == nil {
- rc.outputWatcher = &NoOpOutputWatcher{}
- }
- return rc
-}
-
-// TaskCache represents a single task's (package-task?) interface to the RunCache
-// and controls access to the task's outputs
-type TaskCache struct {
- ExpandedOutputs []turbopath.AnchoredSystemPath
- rc *RunCache
- repoRelativeGlobs fs.TaskOutputs
- hash string
- pt *nodes.PackageTask
- taskOutputMode util.TaskOutputMode
- cachingDisabled bool
- LogFileName turbopath.AbsoluteSystemPath
-}
-
-// RestoreOutputs attempts to restore output for the corresponding task from the cache.
-// Returns the cacheStatus, the timeSaved, and error values, so the consumer can understand
-// what happened in here.
-func (tc *TaskCache) RestoreOutputs(ctx context.Context, prefixedUI *cli.PrefixedUi, progressLogger hclog.Logger) (cache.ItemStatus, int, error) {
- if tc.cachingDisabled || tc.rc.readsDisabled {
- if tc.taskOutputMode != util.NoTaskOutput && tc.taskOutputMode != util.ErrorTaskOutput {
- prefixedUI.Output(fmt.Sprintf("cache bypass, force executing %s", ui.Dim(tc.hash)))
- }
- return cache.ItemStatus{Local: false, Remote: false}, 0, nil
- }
-
- changedOutputGlobs, err := tc.rc.outputWatcher.GetChangedOutputs(ctx, tc.hash, tc.repoRelativeGlobs.Inclusions)
- if err != nil {
- progressLogger.Warn(fmt.Sprintf("Failed to check if we can skip restoring outputs for %v: %v. Proceeding to check cache", tc.pt.TaskID, err))
- prefixedUI.Warn(ui.Dim(fmt.Sprintf("Failed to check if we can skip restoring outputs for %v: %v. Proceeding to check cache", tc.pt.TaskID, err)))
- changedOutputGlobs = tc.repoRelativeGlobs.Inclusions
- }
-
- hasChangedOutputs := len(changedOutputGlobs) > 0
- var cacheStatus cache.ItemStatus
- var timeSaved int
- if hasChangedOutputs {
- // Note that we currently don't use the output globs when restoring, but we could in the
- // future to avoid doing unnecessary file I/O. We also need to pass along the exclusion
- // globs as well.
- itemStatus, restoredFiles, duration, err := tc.rc.cache.Fetch(tc.rc.repoRoot, tc.hash, nil)
- hit := itemStatus.Local || itemStatus.Remote
- timeSaved = duration
- tc.ExpandedOutputs = restoredFiles
- // Assign to this variable outside this closure so we can return at the end of the function
- cacheStatus = itemStatus
- if err != nil {
- // If there was an error fetching from cache, we'll say there was no cache hit
- return cache.ItemStatus{Local: false, Remote: false}, 0, err
- } else if !hit {
- if tc.taskOutputMode != util.NoTaskOutput && tc.taskOutputMode != util.ErrorTaskOutput {
- prefixedUI.Output(fmt.Sprintf("cache miss, executing %s", ui.Dim(tc.hash)))
- }
- // If there was no hit, we can also say there was no hit
- return cache.ItemStatus{Local: false, Remote: false}, 0, nil
- }
-
- if err := tc.rc.outputWatcher.NotifyOutputsWritten(ctx, tc.hash, tc.repoRelativeGlobs); err != nil {
- // Don't fail the whole operation just because we failed to watch the outputs
- prefixedUI.Warn(ui.Dim(fmt.Sprintf("Failed to mark outputs as cached for %v: %v", tc.pt.TaskID, err)))
- }
- } else {
- // If no outputs have changed, that means we have a local cache hit.
- cacheStatus.Local = true
- prefixedUI.Warn(fmt.Sprintf("Skipping cache check for %v, outputs have not changed since previous run.", tc.pt.TaskID))
- }
-
- switch tc.taskOutputMode {
- // When only showing new task output, cached output should only show the computed hash
- case util.NewTaskOutput:
- fallthrough
- case util.HashTaskOutput:
- prefixedUI.Info(fmt.Sprintf("cache hit, suppressing output %s", ui.Dim(tc.hash)))
- case util.FullTaskOutput:
- progressLogger.Debug("log file", "path", tc.LogFileName)
- prefixedUI.Info(fmt.Sprintf("cache hit, replaying output %s", ui.Dim(tc.hash)))
- tc.ReplayLogFile(prefixedUI, progressLogger)
- case util.ErrorTaskOutput:
- // The task succeeded, so we don't output anything in this case
- default:
- // NoLogs, do not output anything
- }
- // TODO: timeSaved could be part of cacheStatus, so we don't have to make a new struct
- // downstream, but this would be a more invasive change right now.
- return cacheStatus, timeSaved, nil
-}
-
-// ReplayLogFile writes out the stored logfile to the terminal
-func (tc TaskCache) ReplayLogFile(prefixedUI *cli.PrefixedUi, progressLogger hclog.Logger) {
- if tc.LogFileName.FileExists() {
- tc.rc.logReplayer(progressLogger, prefixedUI, tc.LogFileName)
- }
-}
-
-// OnError replays the logfile if --output-mode=errors-only.
-// This is called if the task exited with an non-zero error code.
-func (tc TaskCache) OnError(terminal *cli.PrefixedUi, logger hclog.Logger) {
- if tc.taskOutputMode == util.ErrorTaskOutput {
- tc.ReplayLogFile(terminal, logger)
- }
-}
-
-// nopWriteCloser is modeled after io.NopCloser, which is for Readers
-type nopWriteCloser struct {
- io.Writer
-}
-
-func (nopWriteCloser) Close() error { return nil }
-
-type fileWriterCloser struct {
- io.Writer
- file *os.File
- bufio *bufio.Writer
-}
-
-func (fwc *fileWriterCloser) Close() error {
- if err := fwc.bufio.Flush(); err != nil {
- return err
- }
- return fwc.file.Close()
-}
-
-// OutputWriter creates a sink suitable for handling the output of the command associated
-// with this task.
-func (tc TaskCache) OutputWriter(prefix string) (io.WriteCloser, error) {
- // an os.Stdout wrapper that will add prefixes before printing to stdout
- stdoutWriter := logstreamer.NewPrettyStdoutWriter(prefix)
-
- if tc.cachingDisabled || tc.rc.writesDisabled {
- return nopWriteCloser{stdoutWriter}, nil
- }
- // Setup log file
- if err := tc.LogFileName.EnsureDir(); err != nil {
- return nil, err
- }
-
- output, err := tc.LogFileName.Create()
- if err != nil {
- return nil, err
- }
-
- bufWriter := bufio.NewWriter(output)
- fwc := &fileWriterCloser{
- file: output,
- bufio: bufWriter,
- }
- if tc.taskOutputMode == util.NoTaskOutput || tc.taskOutputMode == util.HashTaskOutput || tc.taskOutputMode == util.ErrorTaskOutput {
- // only write to log file, not to stdout
- fwc.Writer = bufWriter
- } else {
- fwc.Writer = io.MultiWriter(stdoutWriter, bufWriter)
- }
-
- return fwc, nil
-}
-
-var _emptyIgnore []string
-
-// SaveOutputs is responsible for saving the outputs of task to the cache, after the task has completed
-func (tc *TaskCache) SaveOutputs(ctx context.Context, logger hclog.Logger, terminal cli.Ui, duration int) error {
- if tc.cachingDisabled || tc.rc.writesDisabled {
- return nil
- }
-
- logger.Debug("caching output", "outputs", tc.repoRelativeGlobs)
-
- filesToBeCached, err := globby.GlobAll(tc.rc.repoRoot.ToStringDuringMigration(), tc.repoRelativeGlobs.Inclusions, tc.repoRelativeGlobs.Exclusions)
- if err != nil {
- return err
- }
-
- relativePaths := make([]turbopath.AnchoredSystemPath, len(filesToBeCached))
-
- for index, value := range filesToBeCached {
- relativePath, err := tc.rc.repoRoot.RelativePathString(value)
- if err != nil {
- logger.Error(fmt.Sprintf("error: %v", err))
- terminal.Error(fmt.Sprintf("%s%s", ui.ERROR_PREFIX, color.RedString(" %v", fmt.Errorf("File path cannot be made relative: %w", err))))
- continue
- }
- relativePaths[index] = fs.UnsafeToAnchoredSystemPath(relativePath)
- }
-
- if err = tc.rc.cache.Put(tc.rc.repoRoot, tc.hash, duration, relativePaths); err != nil {
- return err
- }
- err = tc.rc.outputWatcher.NotifyOutputsWritten(ctx, tc.hash, tc.repoRelativeGlobs)
- if err != nil {
- // Don't fail the cache write because we also failed to record it, we will just do
- // extra I/O in the future restoring files that haven't changed from cache
- logger.Warn(fmt.Sprintf("Failed to mark outputs as cached for %v: %v", tc.pt.TaskID, err))
- terminal.Warn(ui.Dim(fmt.Sprintf("Failed to mark outputs as cached for %v: %v", tc.pt.TaskID, err)))
- }
-
- tc.ExpandedOutputs = relativePaths
-
- return nil
-}
-
-// TaskCache returns a TaskCache instance, providing an interface to the underlying cache specific
-// to this run and the given PackageTask
-func (rc *RunCache) TaskCache(pt *nodes.PackageTask, hash string) TaskCache {
- logFileName := rc.repoRoot.UntypedJoin(pt.LogFile)
- hashableOutputs := pt.HashableOutputs()
- repoRelativeGlobs := fs.TaskOutputs{
- Inclusions: make([]string, len(hashableOutputs.Inclusions)),
- Exclusions: make([]string, len(hashableOutputs.Exclusions)),
- }
-
- for index, output := range hashableOutputs.Inclusions {
- repoRelativeGlobs.Inclusions[index] = filepath.Join(pt.Pkg.Dir.ToStringDuringMigration(), output)
- }
- for index, output := range hashableOutputs.Exclusions {
- repoRelativeGlobs.Exclusions[index] = filepath.Join(pt.Pkg.Dir.ToStringDuringMigration(), output)
- }
-
- taskOutputMode := pt.TaskDefinition.OutputMode
- if rc.taskOutputModeOverride != nil {
- taskOutputMode = *rc.taskOutputModeOverride
- }
-
- return TaskCache{
- ExpandedOutputs: []turbopath.AnchoredSystemPath{},
- rc: rc,
- repoRelativeGlobs: repoRelativeGlobs,
- hash: hash,
- pt: pt,
- taskOutputMode: taskOutputMode,
- cachingDisabled: !pt.TaskDefinition.ShouldCache,
- LogFileName: logFileName,
- }
-}
-
-// defaultLogReplayer will try to replay logs back to the given Ui instance
-func defaultLogReplayer(logger hclog.Logger, output *cli.PrefixedUi, logFileName turbopath.AbsoluteSystemPath) {
- logger.Debug("start replaying logs")
- f, err := logFileName.Open()
- if err != nil {
- output.Warn(fmt.Sprintf("error reading logs: %v", err))
- logger.Error(fmt.Sprintf("error reading logs: %v", err.Error()))
- }
- defer func() { _ = f.Close() }()
- scan := bufio.NewScanner(f)
- for scan.Scan() {
- str := string(scan.Bytes())
- // cli.PrefixedUi won't prefix empty strings (it'll just print them as empty strings).
- // So if we have a blank string, we'll just output the string here, instead of passing
- // it onto the PrefixedUi.
- if str == "" {
- // Just output the prefix if the current line is a blank string
- // Note: output.OutputPrefix is also a colored prefix already
- output.Ui.Output(output.OutputPrefix)
- } else {
- // Writing to Stdout
- output.Output(str)
- }
-
- }
- logger.Debug("finish replaying logs")
-}
diff --git a/cli/internal/runsummary/execution_summary.go b/cli/internal/runsummary/execution_summary.go
deleted file mode 100644
index fabb690..0000000
--- a/cli/internal/runsummary/execution_summary.go
+++ /dev/null
@@ -1,282 +0,0 @@
-package runsummary
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "sync"
- "time"
-
- "github.com/vercel/turbo/cli/internal/chrometracing"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-
- "github.com/mitchellh/cli"
-)
-
-// executionEvent represents a single event in the build process, i.e. a target starting or finishing
-// building, or reaching some milestone within those steps.
-type executionEvent struct {
- // Timestamp of this event
- Time time.Time
- // Duration of this event
- Duration time.Duration
- // Target which has just changed
- Label string
- // Its current status
- Status executionEventName
- // Error, only populated for failure statuses
- Err string
-
- exitCode *int
-}
-
-// executionEventName represents the status of a target when we log a build result.
-type executionEventName int
-
-// The collection of expected build result statuses.
-const (
- targetInitialized executionEventName = iota
- TargetBuilding
- TargetBuildStopped
- TargetExecuted
- TargetBuilt
- TargetCached
- TargetBuildFailed
-)
-
-func (en executionEventName) toString() string {
- switch en {
- case targetInitialized:
- return "initialized"
- case TargetBuilding:
- return "building"
- case TargetBuildStopped:
- return "buildStopped"
- case TargetExecuted:
- return "executed"
- case TargetBuilt:
- return "built"
- case TargetCached:
- return "cached"
- case TargetBuildFailed:
- return "buildFailed"
- }
-
- return ""
-}
-
-// TaskExecutionSummary contains data about the state of a single task in a turbo run.
-// Some fields are updated over time as the task prepares to execute and finishes execution.
-type TaskExecutionSummary struct {
- startAt time.Time // set once
- status executionEventName // current status, updated during execution
- err string // only populated for failure statuses
- Duration time.Duration // updated during the task execution
- exitCode *int // pointer so we can distinguish between 0 and unknown.
-}
-
-func (ts *TaskExecutionSummary) endTime() time.Time {
- return ts.startAt.Add(ts.Duration)
-}
-
-// MarshalJSON munges the TaskExecutionSummary into a format we want
-// We'll use an anonmyous, private struct for this, so it's not confusingly duplicated
-func (ts *TaskExecutionSummary) MarshalJSON() ([]byte, error) {
- serializable := struct {
- Start int64 `json:"startTime"`
- End int64 `json:"endTime"`
- Err string `json:"error,omitempty"`
- ExitCode *int `json:"exitCode"`
- }{
- Start: ts.startAt.UnixMilli(),
- End: ts.endTime().UnixMilli(),
- Err: ts.err,
- ExitCode: ts.exitCode,
- }
-
- return json.Marshal(&serializable)
-}
-
-// ExitCode access exit code nil means no exit code was received
-func (ts *TaskExecutionSummary) ExitCode() *int {
- var exitCode int
- if ts.exitCode == nil {
- return nil
- }
- exitCode = *ts.exitCode
- return &exitCode
-}
-
-// executionSummary is the state of the entire `turbo run`. Individual task state in `Tasks` field
-type executionSummary struct {
- // mu guards reads/writes to the `state` field
- mu sync.Mutex
- tasks map[string]*TaskExecutionSummary // key is a taskID
- profileFilename string
-
- // These get serialized to JSON
- command string // a synthesized turbo command to produce this invocation
- repoPath turbopath.RelativeSystemPath // the (possibly empty) path from the turborepo root to where the command was run
- success int // number of tasks that exited successfully (does not include cache hits)
- failure int // number of tasks that exited with failure
- cached int // number of tasks that had a cache hit
- attempted int // number of tasks that started
- startedAt time.Time
- endedAt time.Time
- exitCode int
-}
-
-// MarshalJSON munges the executionSummary into a format we want
-// We'll use an anonmyous, private struct for this, so it's not confusingly duplicated.
-func (es *executionSummary) MarshalJSON() ([]byte, error) {
- serializable := struct {
- Command string `json:"command"`
- RepoPath string `json:"repoPath"`
- Success int `json:"success"`
- Failure int `json:"failed"`
- Cached int `json:"cached"`
- Attempted int `json:"attempted"`
- StartTime int64 `json:"startTime"`
- EndTime int64 `json:"endTime"`
- ExitCode int `json:"exitCode"`
- }{
- Command: es.command,
- RepoPath: es.repoPath.ToString(),
- StartTime: es.startedAt.UnixMilli(),
- EndTime: es.endedAt.UnixMilli(),
- Success: es.success,
- Failure: es.failure,
- Cached: es.cached,
- Attempted: es.attempted,
- ExitCode: es.exitCode,
- }
-
- return json.Marshal(&serializable)
-}
-
-// newExecutionSummary creates a executionSummary instance to track events in a `turbo run`.`
-func newExecutionSummary(command string, repoPath turbopath.RelativeSystemPath, start time.Time, tracingProfile string) *executionSummary {
- if tracingProfile != "" {
- chrometracing.EnableTracing()
- }
-
- return &executionSummary{
- command: command,
- repoPath: repoPath,
- success: 0,
- failure: 0,
- cached: 0,
- attempted: 0,
- tasks: make(map[string]*TaskExecutionSummary),
- startedAt: start,
- profileFilename: tracingProfile,
- }
-}
-
-// Run starts the Execution of a single task. It returns a function that can
-// be used to update the state of a given taskID with the executionEventName enum
-func (es *executionSummary) run(taskID string) (func(outcome executionEventName, err error, exitCode *int), *TaskExecutionSummary) {
- start := time.Now()
- taskExecutionSummary := es.add(&executionEvent{
- Time: start,
- Label: taskID,
- Status: targetInitialized,
- })
-
- tracer := chrometracing.Event(taskID)
-
- // This function can be called with an enum and an optional error to update
- // the state of a given taskID.
- tracerFn := func(outcome executionEventName, err error, exitCode *int) {
- defer tracer.Done()
- now := time.Now()
- result := &executionEvent{
- Time: now,
- Duration: now.Sub(start),
- Label: taskID,
- Status: outcome,
- // We'll assign this here regardless of whether it is nil, but we'll check for nil
- // when we assign it to the taskExecutionSummary.
- exitCode: exitCode,
- }
-
- if err != nil {
- result.Err = err.Error()
- }
-
- // Ignore the return value here
- es.add(result)
- }
-
- return tracerFn, taskExecutionSummary
-}
-
-func (es *executionSummary) add(event *executionEvent) *TaskExecutionSummary {
- es.mu.Lock()
- defer es.mu.Unlock()
-
- var taskExecSummary *TaskExecutionSummary
- if ts, ok := es.tasks[event.Label]; ok {
- // If we already know about this task, we'll update it with the new event
- taskExecSummary = ts
- } else {
- // If we don't know about it yet, init and add it into the parent struct
- // (event.Status should always be `targetBuilding` here.)
- taskExecSummary = &TaskExecutionSummary{startAt: event.Time}
- es.tasks[event.Label] = taskExecSummary
- }
-
- // Update the Status, Duration, and Err fields
- taskExecSummary.status = event.Status
- taskExecSummary.err = event.Err
- taskExecSummary.Duration = event.Duration
-
- if event.exitCode != nil {
- taskExecSummary.exitCode = event.exitCode
- }
-
- switch {
- case event.Status == TargetBuilding:
- es.attempted++
- case event.Status == TargetBuildFailed:
- es.failure++
- case event.Status == TargetCached:
- es.cached++
- case event.Status == TargetBuilt:
- es.success++
- }
-
- return es.tasks[event.Label]
-}
-
-// writeChromeTracing writes to a profile name if the `--profile` flag was passed to turbo run
-func writeChrometracing(filename string, terminal cli.Ui) error {
- outputPath := chrometracing.Path()
- if outputPath == "" {
- // tracing wasn't enabled
- return nil
- }
-
- name := fmt.Sprintf("turbo-%s.trace", time.Now().Format(time.RFC3339))
- if filename != "" {
- name = filename
- }
- if err := chrometracing.Close(); err != nil {
- terminal.Warn(fmt.Sprintf("Failed to flush tracing data: %v", err))
- }
- cwdRaw, err := os.Getwd()
- if err != nil {
- return err
- }
- root, err := fs.GetCwd(cwdRaw)
- if err != nil {
- return err
- }
- // chrometracing.Path() is absolute by default, but can still be relative if overriden via $CHROMETRACING_DIR
- // so we have to account for that before converting to turbopath.AbsoluteSystemPath
- if err := fs.CopyFile(&fs.LstatCachedFile{Path: fs.ResolveUnknownPath(root, outputPath)}, name); err != nil {
- return err
- }
- return nil
-}
diff --git a/cli/internal/runsummary/format_execution_summary.go b/cli/internal/runsummary/format_execution_summary.go
deleted file mode 100644
index 37092be..0000000
--- a/cli/internal/runsummary/format_execution_summary.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package runsummary
-
-import (
- "os"
- "time"
-
- "github.com/fatih/color"
- internalUI "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-func (rsm *Meta) printExecutionSummary() {
- maybeFullTurbo := ""
- summary := rsm.RunSummary
- ui := rsm.ui
-
- attempted := summary.ExecutionSummary.attempted
- successful := summary.ExecutionSummary.cached + summary.ExecutionSummary.success
- cached := summary.ExecutionSummary.cached
- // TODO: can we use a method on ExecutionSummary here?
- duration := time.Since(summary.ExecutionSummary.startedAt).Truncate(time.Millisecond)
-
- if cached == attempted && attempted > 0 {
- terminalProgram := os.Getenv("TERM_PROGRAM")
- // On the macOS Terminal, the rainbow colors show up as a magenta background
- // with a gray background on a single letter. Instead, we print in bold magenta
- if terminalProgram == "Apple_Terminal" {
- fallbackTurboColor := color.New(color.FgHiMagenta, color.Bold).SprintFunc()
- maybeFullTurbo = fallbackTurboColor(">>> FULL TURBO")
- } else {
- maybeFullTurbo = internalUI.Rainbow(">>> FULL TURBO")
- }
- }
-
- if attempted == 0 {
- ui.Output("") // Clear the line
- ui.Warn("No tasks were executed as part of this run.")
- }
-
- ui.Output("") // Clear the line
- spacer := " " // 4 chars
-
- var lines []string
-
- // The only difference between these two branches is that when there is a run summary
- // we print the path to that file and we adjust the whitespace in the printed text so it aligns.
- // We could just always align to account for the summary line, but that would require a whole
- // bunch of test output assertions to change.
- if rsm.getPath().FileExists() {
- lines = []string{
- util.Sprintf("${BOLD} Tasks:${BOLD_GREEN}%s%v successful${RESET}${GRAY}, %v total${RESET}", spacer, successful, attempted),
- util.Sprintf("${BOLD} Cached:%s%v cached${RESET}${GRAY}, %v total${RESET}", spacer, cached, attempted),
- util.Sprintf("${BOLD} Time:%s%v${RESET} %v${RESET}", spacer, duration, maybeFullTurbo),
- util.Sprintf("${BOLD}Summary:%s%s${RESET}", spacer, rsm.getPath()),
- }
- } else {
- lines = []string{
- util.Sprintf("${BOLD} Tasks:${BOLD_GREEN}%s%v successful${RESET}${GRAY}, %v total${RESET}", spacer, successful, attempted),
- util.Sprintf("${BOLD}Cached:%s%v cached${RESET}${GRAY}, %v total${RESET}", spacer, cached, attempted),
- util.Sprintf("${BOLD} Time:%s%v${RESET} %v${RESET}", spacer, duration, maybeFullTurbo),
- }
- }
-
- // Print the real thing
- for _, line := range lines {
- ui.Output(line)
- }
-
- ui.Output("")
-}
diff --git a/cli/internal/runsummary/format_json.go b/cli/internal/runsummary/format_json.go
deleted file mode 100644
index 76a0a40..0000000
--- a/cli/internal/runsummary/format_json.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package runsummary
-
-import (
- "encoding/json"
-
- "github.com/pkg/errors"
- "github.com/segmentio/ksuid"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// FormatJSON returns a json string representing a RunSummary
-func (rsm *Meta) FormatJSON() ([]byte, error) {
- rsm.normalize() // normalize data
-
- var bytes []byte
- var err error
-
- if rsm.singlePackage {
- bytes, err = json.MarshalIndent(nonMonorepoRunSummary(*rsm.RunSummary), "", " ")
- } else {
- bytes, err = json.MarshalIndent(rsm.RunSummary, "", " ")
- }
-
- if err != nil {
- return nil, errors.Wrap(err, "failed to render JSON")
- }
- return bytes, nil
-}
-
-func (rsm *Meta) normalize() {
- for _, t := range rsm.RunSummary.Tasks {
- t.EnvVars.Global = rsm.RunSummary.GlobalHashSummary.envVars
- t.EnvVars.GlobalPassthrough = rsm.RunSummary.GlobalHashSummary.passthroughEnvVars
- }
-
- // Remove execution summary for dry runs
- if rsm.runType == runTypeDryJSON {
- rsm.RunSummary.ExecutionSummary = nil
- }
-
- // For single packages, we don't need the Packages
- // and each task summary needs some cleaning.
- if rsm.singlePackage {
- rsm.RunSummary.Packages = []string{}
-
- for _, task := range rsm.RunSummary.Tasks {
- task.cleanForSinglePackage()
- }
- }
-}
-
-// nonMonorepoRunSummary is an exact copy of RunSummary, but the JSON tags are structured
-// for rendering a single-package run of turbo. Notably, we want to always omit packages
-// since there is no concept of packages in a single-workspace repo.
-// This struct exists solely for the purpose of serializing to JSON and should not be
-// used anywhere else.
-type nonMonorepoRunSummary struct {
- ID ksuid.KSUID `json:"id"`
- Version string `json:"version"`
- TurboVersion string `json:"turboVersion"`
- GlobalHashSummary *GlobalHashSummary `json:"globalCacheInputs"`
- Packages []string `json:"-"`
- EnvMode util.EnvMode `json:"envMode"`
- ExecutionSummary *executionSummary `json:"execution,omitempty"`
- Tasks []*TaskSummary `json:"tasks"`
-}
diff --git a/cli/internal/runsummary/format_text.go b/cli/internal/runsummary/format_text.go
deleted file mode 100644
index 28b1638..0000000
--- a/cli/internal/runsummary/format_text.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package runsummary
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "strconv"
- "strings"
- "text/tabwriter"
-
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-// FormatAndPrintText prints a Run Summary to the Terminal UI
-func (rsm Meta) FormatAndPrintText(workspaceInfos workspace.Catalog) error {
- ui := rsm.ui
- summary := rsm.RunSummary
-
- rsm.normalize() // normalize data
-
- if !rsm.singlePackage {
- ui.Output("")
- ui.Info(util.Sprintf("${CYAN}${BOLD}Packages in Scope${RESET}"))
- p := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
- fmt.Fprintln(p, "Name\tPath\t")
- for _, pkg := range summary.Packages {
- fmt.Fprintf(p, "%s\t%s\t\n", pkg, workspaceInfos.PackageJSONs[pkg].Dir)
- }
- if err := p.Flush(); err != nil {
- return err
- }
- }
-
- fileCount := 0
- for range summary.GlobalHashSummary.GlobalFileHashMap {
- fileCount = fileCount + 1
- }
- w1 := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
- ui.Output("")
- ui.Info(util.Sprintf("${CYAN}${BOLD}Global Hash Inputs${RESET}"))
- fmt.Fprintln(w1, util.Sprintf(" ${GREY}Global Files\t=\t%d${RESET}", fileCount))
- fmt.Fprintln(w1, util.Sprintf(" ${GREY}External Dependencies Hash\t=\t%s${RESET}", summary.GlobalHashSummary.RootExternalDepsHash))
- fmt.Fprintln(w1, util.Sprintf(" ${GREY}Global Cache Key\t=\t%s${RESET}", summary.GlobalHashSummary.GlobalCacheKey))
- if bytes, err := json.Marshal(summary.GlobalHashSummary.Pipeline); err == nil {
- fmt.Fprintln(w1, util.Sprintf(" ${GREY}Root pipeline\t=\t%s${RESET}", bytes))
- }
- if err := w1.Flush(); err != nil {
- return err
- }
-
- ui.Output("")
- ui.Info(util.Sprintf("${CYAN}${BOLD}Tasks to Run${RESET}"))
-
- for _, task := range summary.Tasks {
- taskName := task.TaskID
-
- if rsm.singlePackage {
- taskName = task.Task
- }
-
- ui.Info(util.Sprintf("${BOLD}%s${RESET}", taskName))
- w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Task\t=\t%s\t${RESET}", task.Task))
-
- if !rsm.singlePackage {
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Package\t=\t%s\t${RESET}", task.Package))
- }
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Hash\t=\t%s\t${RESET}", task.Hash))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Cached (Local)\t=\t%s\t${RESET}", strconv.FormatBool(task.CacheSummary.Local)))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Cached (Remote)\t=\t%s\t${RESET}", strconv.FormatBool(task.CacheSummary.Remote)))
-
- if !rsm.singlePackage {
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Directory\t=\t%s\t${RESET}", task.Dir))
- }
-
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Command\t=\t%s\t${RESET}", task.Command))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Outputs\t=\t%s\t${RESET}", strings.Join(task.Outputs, ", ")))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Log File\t=\t%s\t${RESET}", task.LogFile))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Dependencies\t=\t%s\t${RESET}", strings.Join(task.Dependencies, ", ")))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Dependendents\t=\t%s\t${RESET}", strings.Join(task.Dependents, ", ")))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Inputs Files Considered\t=\t%d\t${RESET}", len(task.ExpandedInputs)))
-
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Configured Environment Variables\t=\t%s\t${RESET}", strings.Join(task.EnvVars.Configured, ", ")))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Inferred Environment Variables\t=\t%s\t${RESET}", strings.Join(task.EnvVars.Inferred, ", ")))
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Global Environment Variables\t=\t%s\t${RESET}", strings.Join(task.EnvVars.Global, ", ")))
-
- bytes, err := json.Marshal(task.ResolvedTaskDefinition)
- // If there's an error, we can silently ignore it, we don't need to block the entire print.
- if err == nil {
- fmt.Fprintln(w, util.Sprintf(" ${GREY}ResolvedTaskDefinition\t=\t%s\t${RESET}", string(bytes)))
- }
-
- fmt.Fprintln(w, util.Sprintf(" ${GREY}Framework\t=\t%s\t${RESET}", task.Framework))
- if err := w.Flush(); err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/cli/internal/runsummary/globalhash_summary.go b/cli/internal/runsummary/globalhash_summary.go
deleted file mode 100644
index e24976d5..0000000
--- a/cli/internal/runsummary/globalhash_summary.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package runsummary
-
-import (
- "github.com/vercel/turbo/cli/internal/env"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// GlobalHashSummary contains the pieces of data that impacted the global hash (then then impacted the task hash)
-type GlobalHashSummary struct {
- GlobalCacheKey string `json:"rootKey"`
- GlobalFileHashMap map[turbopath.AnchoredUnixPath]string `json:"files"`
- RootExternalDepsHash string `json:"hashOfExternalDependencies"`
- Pipeline fs.PristinePipeline `json:"rootPipeline"`
-
- // This is a private field because and not in JSON, because we'll add it to each task
- envVars env.EnvironmentVariablePairs
- passthroughEnvVars env.EnvironmentVariablePairs
-}
-
-// NewGlobalHashSummary creates a GlobalHashSummary struct from a set of fields.
-func NewGlobalHashSummary(
- fileHashMap map[turbopath.AnchoredUnixPath]string,
- rootExternalDepsHash string,
- envVars env.DetailedMap,
- passthroughEnvVars env.EnvironmentVariableMap,
- globalCacheKey string,
- pipeline fs.PristinePipeline,
-) *GlobalHashSummary {
- return &GlobalHashSummary{
- envVars: envVars.All.ToSecretHashable(),
- passthroughEnvVars: passthroughEnvVars.ToSecretHashable(),
- GlobalFileHashMap: fileHashMap,
- RootExternalDepsHash: rootExternalDepsHash,
- GlobalCacheKey: globalCacheKey,
- Pipeline: pipeline,
- }
-}
diff --git a/cli/internal/runsummary/run_summary.go b/cli/internal/runsummary/run_summary.go
deleted file mode 100644
index a297114..0000000
--- a/cli/internal/runsummary/run_summary.go
+++ /dev/null
@@ -1,320 +0,0 @@
-// Package runsummary implements structs that report on a `turbo run` and `turbo run --dry`
-package runsummary
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "path/filepath"
- "sync"
- "time"
-
- "github.com/mitchellh/cli"
- "github.com/segmentio/ksuid"
- "github.com/vercel/turbo/cli/internal/client"
- "github.com/vercel/turbo/cli/internal/spinner"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-// MissingTaskLabel is printed when a package is missing a definition for a task that is supposed to run
-// E.g. if `turbo run build --dry` is run, and package-a doesn't define a `build` script in package.json,
-// the RunSummary will print this, instead of the script (e.g. `next build`).
-const MissingTaskLabel = "<NONEXISTENT>"
-
-// MissingFrameworkLabel is a string to identify when a workspace doesn't detect a framework
-const MissingFrameworkLabel = "<NO FRAMEWORK DETECTED>"
-
-const runSummarySchemaVersion = "0"
-const runsEndpoint = "/v0/spaces/%s/runs"
-const runsPatchEndpoint = "/v0/spaces/%s/runs/%s"
-const tasksEndpoint = "/v0/spaces/%s/runs/%s/tasks"
-
-type runType int
-
-const (
- runTypeReal runType = iota
- runTypeDryText
- runTypeDryJSON
-)
-
-// Meta is a wrapper around the serializable RunSummary, with some extra information
-// about the Run and references to other things that we need.
-type Meta struct {
- RunSummary *RunSummary
- ui cli.Ui
- repoRoot turbopath.AbsoluteSystemPath // used to write run summary
- repoPath turbopath.RelativeSystemPath
- singlePackage bool
- shouldSave bool
- apiClient *client.APIClient
- spaceID string
- runType runType
- synthesizedCommand string
-}
-
-// RunSummary contains a summary of what happens in the `turbo run` command and why.
-type RunSummary struct {
- ID ksuid.KSUID `json:"id"`
- Version string `json:"version"`
- TurboVersion string `json:"turboVersion"`
- GlobalHashSummary *GlobalHashSummary `json:"globalCacheInputs"`
- Packages []string `json:"packages"`
- EnvMode util.EnvMode `json:"envMode"`
- ExecutionSummary *executionSummary `json:"execution,omitempty"`
- Tasks []*TaskSummary `json:"tasks"`
-}
-
-// NewRunSummary returns a RunSummary instance
-func NewRunSummary(
- startAt time.Time,
- ui cli.Ui,
- repoRoot turbopath.AbsoluteSystemPath,
- repoPath turbopath.RelativeSystemPath,
- turboVersion string,
- apiClient *client.APIClient,
- runOpts util.RunOpts,
- packages []string,
- globalEnvMode util.EnvMode,
- globalHashSummary *GlobalHashSummary,
- synthesizedCommand string,
-) Meta {
- singlePackage := runOpts.SinglePackage
- profile := runOpts.Profile
- shouldSave := runOpts.Summarize
- spaceID := runOpts.ExperimentalSpaceID
-
- runType := runTypeReal
- if runOpts.DryRun {
- runType = runTypeDryText
- if runOpts.DryRunJSON {
- runType = runTypeDryJSON
- }
- }
-
- executionSummary := newExecutionSummary(synthesizedCommand, repoPath, startAt, profile)
-
- return Meta{
- RunSummary: &RunSummary{
- ID: ksuid.New(),
- Version: runSummarySchemaVersion,
- ExecutionSummary: executionSummary,
- TurboVersion: turboVersion,
- Packages: packages,
- EnvMode: globalEnvMode,
- Tasks: []*TaskSummary{},
- GlobalHashSummary: globalHashSummary,
- },
- ui: ui,
- runType: runType,
- repoRoot: repoRoot,
- singlePackage: singlePackage,
- shouldSave: shouldSave,
- apiClient: apiClient,
- spaceID: spaceID,
- synthesizedCommand: synthesizedCommand,
- }
-}
-
-// getPath returns a path to where the runSummary is written.
-// The returned path will always be relative to the dir passsed in.
-// We don't do a lot of validation, so `../../` paths are allowed.
-func (rsm *Meta) getPath() turbopath.AbsoluteSystemPath {
- filename := fmt.Sprintf("%s.json", rsm.RunSummary.ID)
- return rsm.repoRoot.UntypedJoin(filepath.Join(".turbo", "runs"), filename)
-}
-
-// Close wraps up the RunSummary at the end of a `turbo run`.
-func (rsm *Meta) Close(ctx context.Context, exitCode int, workspaceInfos workspace.Catalog) error {
- if rsm.runType == runTypeDryJSON || rsm.runType == runTypeDryText {
- return rsm.closeDryRun(workspaceInfos)
- }
-
- rsm.RunSummary.ExecutionSummary.exitCode = exitCode
- rsm.RunSummary.ExecutionSummary.endedAt = time.Now()
-
- summary := rsm.RunSummary
- if err := writeChrometracing(summary.ExecutionSummary.profileFilename, rsm.ui); err != nil {
- rsm.ui.Error(fmt.Sprintf("Error writing tracing data: %v", err))
- }
-
- // TODO: printing summary to local, writing to disk, and sending to API
- // are all the same thng, we should use a strategy similar to cache save/upload to
- // do this in parallel.
-
- // Otherwise, attempt to save the summary
- // Warn on the error, but we don't need to throw an error
- if rsm.shouldSave {
- if err := rsm.save(); err != nil {
- rsm.ui.Warn(fmt.Sprintf("Error writing run summary: %v", err))
- }
- }
-
- rsm.printExecutionSummary()
-
- // If we're not supposed to save or if there's no spaceID
- if !rsm.shouldSave || rsm.spaceID == "" {
- return nil
- }
-
- if !rsm.apiClient.IsLinked() {
- rsm.ui.Warn("Failed to post to space because repo is not linked to a Space. Run `turbo link` first.")
- return nil
- }
-
- // Wrap the record function so we can hoist out url/errors but keep
- // the function signature/type the spinner.WaitFor expects.
- var url string
- var errs []error
- record := func() {
- url, errs = rsm.record()
- }
-
- func() {
- _ = spinner.WaitFor(ctx, record, rsm.ui, "...sending run summary...", 1000*time.Millisecond)
- }()
-
- // After the spinner is done, print any errors and the url
- if len(errs) > 0 {
- rsm.ui.Warn("Errors recording run to Spaces")
- for _, err := range errs {
- rsm.ui.Warn(fmt.Sprintf("%v", err))
- }
- }
-
- if url != "" {
- rsm.ui.Output(fmt.Sprintf("Run: %s", url))
- rsm.ui.Output("")
- }
-
- return nil
-}
-
-// closeDryRun wraps up the Run Summary at the end of `turbo run --dry`.
-// Ideally this should be inlined into Close(), but RunSummary doesn't currently
-// have context about whether a run was real or dry.
-func (rsm *Meta) closeDryRun(workspaceInfos workspace.Catalog) error {
- // Render the dry run as json
- if rsm.runType == runTypeDryJSON {
- rendered, err := rsm.FormatJSON()
- if err != nil {
- return err
- }
-
- rsm.ui.Output(string(rendered))
- return nil
- }
-
- return rsm.FormatAndPrintText(workspaceInfos)
-}
-
-// TrackTask makes it possible for the consumer to send information about the execution of a task.
-func (summary *RunSummary) TrackTask(taskID string) (func(outcome executionEventName, err error, exitCode *int), *TaskExecutionSummary) {
- return summary.ExecutionSummary.run(taskID)
-}
-
-// Save saves the run summary to a file
-func (rsm *Meta) save() error {
- json, err := rsm.FormatJSON()
- if err != nil {
- return err
- }
-
- // summaryPath will always be relative to the dir passsed in.
- // We don't do a lot of validation, so `../../` paths are allowed
- summaryPath := rsm.getPath()
-
- if err := summaryPath.EnsureDir(); err != nil {
- return err
- }
-
- return summaryPath.WriteFile(json, 0644)
-}
-
-// record sends the summary to the API
-func (rsm *Meta) record() (string, []error) {
- errs := []error{}
-
- // Right now we'll send the POST to create the Run and the subsequent task payloads
- // after all execution is done, but in the future, this first POST request
- // can happen when the Run actually starts, so we can send updates to the associated Space
- // as tasks complete.
- createRunEndpoint := fmt.Sprintf(runsEndpoint, rsm.spaceID)
- response := &spacesRunResponse{}
-
- payload := rsm.newSpacesRunCreatePayload()
- if startPayload, err := json.Marshal(payload); err == nil {
- if resp, err := rsm.apiClient.JSONPost(createRunEndpoint, startPayload); err != nil {
- errs = append(errs, fmt.Errorf("POST %s: %w", createRunEndpoint, err))
- } else {
- if err := json.Unmarshal(resp, response); err != nil {
- errs = append(errs, fmt.Errorf("Error unmarshaling response: %w", err))
- }
- }
- }
-
- if response.ID != "" {
- if taskErrs := rsm.postTaskSummaries(response.ID); len(taskErrs) > 0 {
- errs = append(errs, taskErrs...)
- }
-
- if donePayload, err := json.Marshal(newSpacesDonePayload(rsm.RunSummary)); err == nil {
- patchURL := fmt.Sprintf(runsPatchEndpoint, rsm.spaceID, response.ID)
- if _, err := rsm.apiClient.JSONPatch(patchURL, donePayload); err != nil {
- errs = append(errs, fmt.Errorf("PATCH %s: %w", patchURL, err))
- }
- }
- }
-
- if len(errs) > 0 {
- return response.URL, errs
- }
-
- return response.URL, nil
-}
-
-func (rsm *Meta) postTaskSummaries(runID string) []error {
- errs := []error{}
- // We make at most 8 requests at a time.
- maxParallelRequests := 8
- taskSummaries := rsm.RunSummary.Tasks
- taskCount := len(taskSummaries)
- taskURL := fmt.Sprintf(tasksEndpoint, rsm.spaceID, runID)
-
- parallelRequestCount := maxParallelRequests
- if taskCount < maxParallelRequests {
- parallelRequestCount = taskCount
- }
-
- queue := make(chan int, taskCount)
-
- wg := &sync.WaitGroup{}
- for i := 0; i < parallelRequestCount; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for index := range queue {
- task := taskSummaries[index]
- payload := newSpacesTaskPayload(task)
- if taskPayload, err := json.Marshal(payload); err == nil {
- if _, err := rsm.apiClient.JSONPost(taskURL, taskPayload); err != nil {
- errs = append(errs, fmt.Errorf("Error sending %s summary to space: %w", task.TaskID, err))
- }
- }
- }
- }()
- }
-
- for index := range taskSummaries {
- queue <- index
- }
- close(queue)
- wg.Wait()
-
- if len(errs) > 0 {
- return errs
- }
-
- return nil
-}
diff --git a/cli/internal/runsummary/spaces.go b/cli/internal/runsummary/spaces.go
deleted file mode 100644
index bf19941..0000000
--- a/cli/internal/runsummary/spaces.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package runsummary
-
-import (
- "github.com/vercel/turbo/cli/internal/ci"
-)
-
-// spacesRunResponse deserialized the response from POST Run endpoint
-type spacesRunResponse struct {
- ID string
- URL string
-}
-
-type spacesRunPayload struct {
- StartTime int64 `json:"startTime,omitempty"` // when the run was started
- EndTime int64 `json:"endTime,omitempty"` // when the run ended. we should never submit start and end at the same time.
- Status string `json:"status,omitempty"` // Status is "running" or "completed"
- Type string `json:"type,omitempty"` // hardcoded to "TURBO"
- ExitCode int `json:"exitCode,omitempty"` // exit code for the full run
- Command string `json:"command,omitempty"` // the thing that kicked off the turbo run
- RepositoryPath string `json:"repositoryPath,omitempty"` // where the command was invoked from
- Context string `json:"context,omitempty"` // the host on which this Run was executed (e.g. Github Action, Vercel, etc)
-
- // TODO: we need to add these in
- // originationUser string
- // gitBranch string
- // gitSha string
-}
-
-// spacesCacheStatus is the same as TaskCacheSummary so we can convert
-// spacesCacheStatus(cacheSummary), but change the json tags, to omit local and remote fields
-type spacesCacheStatus struct {
- // omitted fields, but here so we can convert from TaskCacheSummary easily
- Local bool `json:"-"`
- Remote bool `json:"-"`
- Status string `json:"status"` // should always be there
- Source string `json:"source,omitempty"`
- TimeSaved int `json:"timeSaved"`
-}
-
-type spacesTask struct {
- Key string `json:"key,omitempty"`
- Name string `json:"name,omitempty"`
- Workspace string `json:"workspace,omitempty"`
- Hash string `json:"hash,omitempty"`
- StartTime int64 `json:"startTime,omitempty"`
- EndTime int64 `json:"endTime,omitempty"`
- Cache spacesCacheStatus `json:"cache,omitempty"`
- ExitCode int `json:"exitCode,omitempty"`
- Dependencies []string `json:"dependencies,omitempty"`
- Dependents []string `json:"dependents,omitempty"`
- Logs string `json:"log"`
-}
-
-func (rsm *Meta) newSpacesRunCreatePayload() *spacesRunPayload {
- startTime := rsm.RunSummary.ExecutionSummary.startedAt.UnixMilli()
- context := "LOCAL"
- if name := ci.Constant(); name != "" {
- context = name
- }
- return &spacesRunPayload{
- StartTime: startTime,
- Status: "running",
- Command: rsm.synthesizedCommand,
- RepositoryPath: rsm.repoPath.ToString(),
- Type: "TURBO",
- Context: context,
- }
-}
-
-func newSpacesDonePayload(runsummary *RunSummary) *spacesRunPayload {
- endTime := runsummary.ExecutionSummary.endedAt.UnixMilli()
- return &spacesRunPayload{
- Status: "completed",
- EndTime: endTime,
- ExitCode: runsummary.ExecutionSummary.exitCode,
- }
-}
-
-func newSpacesTaskPayload(taskSummary *TaskSummary) *spacesTask {
- startTime := taskSummary.Execution.startAt.UnixMilli()
- endTime := taskSummary.Execution.endTime().UnixMilli()
-
- return &spacesTask{
- Key: taskSummary.TaskID,
- Name: taskSummary.Task,
- Workspace: taskSummary.Package,
- Hash: taskSummary.Hash,
- StartTime: startTime,
- EndTime: endTime,
- Cache: spacesCacheStatus(taskSummary.CacheSummary), // wrapped so we can remove fields
- ExitCode: *taskSummary.Execution.exitCode,
- Dependencies: taskSummary.Dependencies,
- Dependents: taskSummary.Dependents,
- Logs: string(taskSummary.GetLogs()),
- }
-}
diff --git a/cli/internal/runsummary/task_summary.go b/cli/internal/runsummary/task_summary.go
deleted file mode 100644
index fb0cb30..0000000
--- a/cli/internal/runsummary/task_summary.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package runsummary
-
-import (
- "os"
-
- "github.com/vercel/turbo/cli/internal/cache"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// TaskCacheSummary is an extended version of cache.ItemStatus
-// that includes TimeSaved and some better data.
-type TaskCacheSummary struct {
- Local bool `json:"local"` // Deprecated, but keeping around for --dry=json
- Remote bool `json:"remote"` // Deprecated, but keeping around for --dry=json
- Status string `json:"status"` // should always be there
- Source string `json:"source,omitempty"` // can be empty on status:miss
- TimeSaved int `json:"timeSaved"` // always include, but can be 0
-}
-
-// NewTaskCacheSummary decorates a cache.ItemStatus into a TaskCacheSummary
-// Importantly, it adds the derived keys of `source` and `status` based on
-// the local/remote booleans. It would be nice if these were just included
-// from upstream, but that is a more invasive change.
-func NewTaskCacheSummary(itemStatus cache.ItemStatus, timeSaved *int) TaskCacheSummary {
- status := cache.CacheEventMiss
- if itemStatus.Local || itemStatus.Remote {
- status = cache.CacheEventHit
- }
-
- var source string
- if itemStatus.Local {
- source = cache.CacheSourceFS
- } else if itemStatus.Remote {
- source = cache.CacheSourceRemote
- }
-
- cs := TaskCacheSummary{
- // copy these over
- Local: itemStatus.Local,
- Remote: itemStatus.Remote,
- Status: status,
- Source: source,
- }
- // add in a dereferences timeSaved, should be 0 if nil
- if timeSaved != nil {
- cs.TimeSaved = *timeSaved
- }
- return cs
-}
-
-// TaskSummary contains information about the task that was about to run
-// TODO(mehulkar): `Outputs` and `ExcludedOutputs` are slightly redundant
-// as the information is also available in ResolvedTaskDefinition. We could remove them
-// and favor a version of Outputs that is the fully expanded list of files.
-type TaskSummary struct {
- TaskID string `json:"taskId,omitempty"`
- Task string `json:"task"`
- Package string `json:"package,omitempty"`
- Hash string `json:"hash"`
- ExpandedInputs map[turbopath.AnchoredUnixPath]string `json:"inputs"`
- ExternalDepsHash string `json:"hashOfExternalDependencies"`
- CacheSummary TaskCacheSummary `json:"cache"`
- Command string `json:"command"`
- CommandArguments []string `json:"cliArguments"`
- Outputs []string `json:"outputs"`
- ExcludedOutputs []string `json:"excludedOutputs"`
- LogFile string `json:"logFile"`
- Dir string `json:"directory,omitempty"`
- Dependencies []string `json:"dependencies"`
- Dependents []string `json:"dependents"`
- ResolvedTaskDefinition *fs.TaskDefinition `json:"resolvedTaskDefinition"`
- ExpandedOutputs []turbopath.AnchoredSystemPath `json:"expandedOutputs"`
- Framework string `json:"framework"`
- EnvMode util.EnvMode `json:"envMode"`
- EnvVars TaskEnvVarSummary `json:"environmentVariables"`
- Execution *TaskExecutionSummary `json:"execution,omitempty"` // omit when it's not set
-}
-
-// GetLogs reads the Logfile and returns the data
-func (ts *TaskSummary) GetLogs() []byte {
- bytes, err := os.ReadFile(ts.LogFile)
- if err != nil {
- return []byte{}
- }
- return bytes
-}
-
-// TaskEnvVarSummary contains the environment variables that impacted a task's hash
-type TaskEnvVarSummary struct {
- Configured []string `json:"configured"`
- Inferred []string `json:"inferred"`
- Global []string `json:"global"`
- Passthrough []string `json:"passthrough"`
- GlobalPassthrough []string `json:"globalPassthrough"`
-}
-
-// cleanForSinglePackage converts a TaskSummary to remove references to workspaces
-func (ts *TaskSummary) cleanForSinglePackage() {
- dependencies := make([]string, len(ts.Dependencies))
- for i, dependency := range ts.Dependencies {
- dependencies[i] = util.StripPackageName(dependency)
- }
- dependents := make([]string, len(ts.Dependents))
- for i, dependent := range ts.Dependents {
- dependents[i] = util.StripPackageName(dependent)
- }
- task := util.StripPackageName(ts.TaskID)
-
- ts.TaskID = task
- ts.Task = task
- ts.Dependencies = dependencies
- ts.Dependents = dependents
- ts.Dir = ""
- ts.Package = ""
-}
diff --git a/cli/internal/scm/git_go.go b/cli/internal/scm/git_go.go
deleted file mode 100644
index 0dac2bf..0000000
--- a/cli/internal/scm/git_go.go
+++ /dev/null
@@ -1,111 +0,0 @@
-//go:build go || !rust
-// +build go !rust
-
-// Package scm abstracts operations on various tools like git
-// Currently, only git is supported.
-//
-// Adapted from https://github.com/thought-machine/please/tree/master/src/scm
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package scm
-
-import (
- "fmt"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/pkg/errors"
-)
-
-// git implements operations on a git repository.
-type git struct {
- repoRoot turbopath.AbsoluteSystemPath
-}
-
-// ChangedFiles returns a list of modified files since the given commit, optionally including untracked files.
-func (g *git) ChangedFiles(fromCommit string, toCommit string, relativeTo string) ([]string, error) {
- if relativeTo == "" {
- relativeTo = g.repoRoot.ToString()
- }
- relSuffix := []string{"--", relativeTo}
- command := []string{"diff", "--name-only", toCommit}
-
- out, err := exec.Command("git", append(command, relSuffix...)...).CombinedOutput()
- if err != nil {
- return nil, errors.Wrapf(err, "finding changes relative to %v", relativeTo)
- }
- files := strings.Split(string(out), "\n")
-
- if fromCommit != "" {
- // Grab the diff from the merge-base to HEAD using ... syntax. This ensures we have just
- // the changes that have occurred on the current branch.
- command = []string{"diff", "--name-only", fromCommit + "..." + toCommit}
- out, err = exec.Command("git", append(command, relSuffix...)...).CombinedOutput()
- if err != nil {
- // Check if we can provide a better error message for non-existent commits.
- // If we error on the check or can't find it, fall back to whatever error git
- // reported.
- if exists, err := commitExists(fromCommit); err == nil && !exists {
- return nil, fmt.Errorf("commit %v does not exist", fromCommit)
- }
- return nil, errors.Wrapf(err, "git comparing with %v", fromCommit)
- }
- committedChanges := strings.Split(string(out), "\n")
- files = append(files, committedChanges...)
- }
- command = []string{"ls-files", "--other", "--exclude-standard"}
- out, err = exec.Command("git", append(command, relSuffix...)...).CombinedOutput()
- if err != nil {
- return nil, errors.Wrap(err, "finding untracked files")
- }
- untracked := strings.Split(string(out), "\n")
- files = append(files, untracked...)
- // git will report changed files relative to the worktree: re-relativize to relativeTo
- normalized := make([]string, 0)
- for _, f := range files {
- if f == "" {
- continue
- }
- normalizedFile, err := g.fixGitRelativePath(strings.TrimSpace(f), relativeTo)
- if err != nil {
- return nil, err
- }
- normalized = append(normalized, normalizedFile)
- }
- return normalized, nil
-}
-
-func (g *git) PreviousContent(fromCommit string, filePath string) ([]byte, error) {
- if fromCommit == "" {
- return nil, fmt.Errorf("Need commit sha to inspect file contents")
- }
-
- out, err := exec.Command("git", "show", fmt.Sprintf("%s:%s", fromCommit, filePath)).CombinedOutput()
- if err != nil {
- return nil, errors.Wrapf(err, "unable to get contents of %s", filePath)
- }
-
- return out, nil
-}
-
-func commitExists(commit string) (bool, error) {
- err := exec.Command("git", "cat-file", "-t", commit).Run()
- if err != nil {
- exitErr := &exec.ExitError{}
- if errors.As(err, &exitErr) && exitErr.ExitCode() == 128 {
- return false, nil
- }
- return false, err
- }
- return true, nil
-}
-
-func (g *git) fixGitRelativePath(worktreePath, relativeTo string) (string, error) {
- p, err := filepath.Rel(relativeTo, filepath.Join(g.repoRoot, worktreePath))
- if err != nil {
- return "", errors.Wrapf(err, "unable to determine relative path for %s and %s", g.repoRoot, relativeTo)
- }
- return p, nil
-}
diff --git a/cli/internal/scm/git_rust.go b/cli/internal/scm/git_rust.go
deleted file mode 100644
index 4b4cd2d..0000000
--- a/cli/internal/scm/git_rust.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Package scm abstracts operations on various tools like git
-// Currently, only git is supported.
-//
-// Adapted from https://github.com/thought-machine/please/tree/master/src/scm
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-//go:build rust
-// +build rust
-
-package scm
-
-import (
- "fmt"
- "github.com/vercel/turbo/cli/internal/ffi"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// git implements operations on a git repository.
-type git struct {
- repoRoot turbopath.AbsoluteSystemPath
-}
-
-// ChangedFiles returns a list of modified files since the given commit, optionally including untracked files.
-func (g *git) ChangedFiles(fromCommit string, toCommit string, monorepoRoot string) ([]string, error) {
- return ffi.ChangedFiles(g.repoRoot.ToString(), monorepoRoot, fromCommit, toCommit)
-}
-
-func (g *git) PreviousContent(fromCommit string, filePath string) ([]byte, error) {
- if fromCommit == "" {
- return nil, fmt.Errorf("Need commit sha to inspect file contents")
- }
-
- return ffi.PreviousContent(g.repoRoot.ToString(), fromCommit, filePath)
-}
diff --git a/cli/internal/scm/scm.go b/cli/internal/scm/scm.go
deleted file mode 100644
index e7f17c8..0000000
--- a/cli/internal/scm/scm.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Package scm abstracts operations on various tools like git
-// Currently, only git is supported.
-//
-// Adapted from https://github.com/thought-machine/please/tree/master/src/scm
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package scm
-
-import (
- "github.com/pkg/errors"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-var ErrFallback = errors.New("cannot find a .git folder. Falling back to manual file hashing (which may be slower). If you are running this build in a pruned directory, you can ignore this message. Otherwise, please initialize a git repository in the root of your monorepo")
-
-// An SCM represents an SCM implementation that we can ask for various things.
-type SCM interface {
- // ChangedFiles returns a list of modified files since the given commit, including untracked files
- ChangedFiles(fromCommit string, toCommit string, relativeTo string) ([]string, error)
- // PreviousContent Returns the content of the file at fromCommit
- PreviousContent(fromCommit string, filePath string) ([]byte, error)
-}
-
-// newGitSCM returns a new SCM instance for this repo root.
-// It returns nil if there is no known implementation there.
-func newGitSCM(repoRoot turbopath.AbsoluteSystemPath) SCM {
- if repoRoot.UntypedJoin(".git").Exists() {
- return &git{repoRoot: repoRoot}
- }
- return nil
-}
-
-// newFallback returns a new SCM instance for this repo root.
-// If there is no known implementation it returns a stub.
-func newFallback(repoRoot turbopath.AbsoluteSystemPath) (SCM, error) {
- if scm := newGitSCM(repoRoot); scm != nil {
- return scm, nil
- }
-
- return &stub{}, ErrFallback
-}
-
-// FromInRepo produces an SCM instance, given a path within a
-// repository. It does not need to be a git repository, and if
-// it is not, the given path is assumed to be the root.
-func FromInRepo(repoRoot turbopath.AbsoluteSystemPath) (SCM, error) {
- dotGitDir, err := repoRoot.Findup(".git")
- if err != nil {
- return nil, err
- }
- return newFallback(dotGitDir.Dir())
-}
diff --git a/cli/internal/scm/stub.go b/cli/internal/scm/stub.go
deleted file mode 100644
index 2e356c5..0000000
--- a/cli/internal/scm/stub.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Adapted from https://github.com/thought-machine/please/tree/master/src/scm
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package scm
-
-type stub struct{}
-
-func (s *stub) ChangedFiles(fromCommit string, toCommit string, relativeTo string) ([]string, error) {
- return nil, nil
-}
-
-func (s *stub) PreviousContent(fromCommit string, filePath string) ([]byte, error) {
- return nil, nil
-}
diff --git a/cli/internal/scope/filter/filter.go b/cli/internal/scope/filter/filter.go
deleted file mode 100644
index 60aaf1d..0000000
--- a/cli/internal/scope/filter/filter.go
+++ /dev/null
@@ -1,421 +0,0 @@
-package filter
-
-import (
- "fmt"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-type SelectedPackages struct {
- pkgs util.Set
- unusedFilters []*TargetSelector
-}
-
-// PackagesChangedInRange is the signature of a function to provide the set of
-// packages that have changed in a particular range of git refs.
-type PackagesChangedInRange = func(fromRef string, toRef string) (util.Set, error)
-
-// PackageInference holds the information we have inferred from the working-directory
-// (really --infer-filter-root flag) about which packages are of interest.
-type PackageInference struct {
- // PackageName, if set, means that we have determined that filters without a package-specifier
- // should get this package name
- PackageName string
- // DirectoryRoot is used to infer a "parentDir" for the filter in the event that we haven't
- // identified a specific package. If the filter already contains a parentDir, this acts as
- // a prefix. If the filter does not contain a parentDir, we consider this to be a glob for
- // all subdirectories
- DirectoryRoot turbopath.RelativeSystemPath
-}
-
-type Resolver struct {
- Graph *dag.AcyclicGraph
- WorkspaceInfos workspace.Catalog
- Cwd turbopath.AbsoluteSystemPath
- Inference *PackageInference
- PackagesChangedInRange PackagesChangedInRange
-}
-
-// GetPackagesFromPatterns compiles filter patterns and applies them, returning
-// the selected packages
-func (r *Resolver) GetPackagesFromPatterns(patterns []string) (util.Set, error) {
- selectors := []*TargetSelector{}
- for _, pattern := range patterns {
- selector, err := ParseTargetSelector(pattern)
- if err != nil {
- return nil, err
- }
- selectors = append(selectors, selector)
- }
- selected, err := r.getFilteredPackages(selectors)
- if err != nil {
- return nil, err
- }
- return selected.pkgs, nil
-}
-
-func (pi *PackageInference) apply(selector *TargetSelector) error {
- if selector.namePattern != "" {
- // The selector references a package name, don't apply inference
- return nil
- }
- if pi.PackageName != "" {
- selector.namePattern = pi.PackageName
- }
- if selector.parentDir != "" {
- parentDir := pi.DirectoryRoot.Join(selector.parentDir)
- selector.parentDir = parentDir
- } else if pi.PackageName == "" {
- // The user didn't set a parent directory and we didn't find a single package,
- // so use the directory we inferred and select all subdirectories
- selector.parentDir = pi.DirectoryRoot.Join("**")
- }
- return nil
-}
-
-func (r *Resolver) applyInference(selectors []*TargetSelector) ([]*TargetSelector, error) {
- if r.Inference == nil {
- return selectors, nil
- }
- // If there are existing patterns, use inference on those. If there are no
- // patterns, but there is a directory supplied, synthesize a selector
- if len(selectors) == 0 {
- selectors = append(selectors, &TargetSelector{})
- }
- for _, selector := range selectors {
- if err := r.Inference.apply(selector); err != nil {
- return nil, err
- }
- }
- return selectors, nil
-}
-
-func (r *Resolver) getFilteredPackages(selectors []*TargetSelector) (*SelectedPackages, error) {
- selectors, err := r.applyInference(selectors)
- if err != nil {
- return nil, err
- }
- prodPackageSelectors := []*TargetSelector{}
- allPackageSelectors := []*TargetSelector{}
- for _, selector := range selectors {
- if selector.followProdDepsOnly {
- prodPackageSelectors = append(prodPackageSelectors, selector)
- } else {
- allPackageSelectors = append(allPackageSelectors, selector)
- }
- }
- if len(allPackageSelectors) > 0 || len(prodPackageSelectors) > 0 {
- if len(allPackageSelectors) > 0 {
- selected, err := r.filterGraph(allPackageSelectors)
- if err != nil {
- return nil, err
- }
- return selected, nil
- }
- }
- return &SelectedPackages{
- pkgs: make(util.Set),
- }, nil
-}
-
-func (r *Resolver) filterGraph(selectors []*TargetSelector) (*SelectedPackages, error) {
- includeSelectors := []*TargetSelector{}
- excludeSelectors := []*TargetSelector{}
- for _, selector := range selectors {
- if selector.exclude {
- excludeSelectors = append(excludeSelectors, selector)
- } else {
- includeSelectors = append(includeSelectors, selector)
- }
- }
- var include *SelectedPackages
- if len(includeSelectors) > 0 {
- found, err := r.filterGraphWithSelectors(includeSelectors)
- if err != nil {
- return nil, err
- }
- include = found
- } else {
- vertexSet := make(util.Set)
- for _, v := range r.Graph.Vertices() {
- vertexSet.Add(v)
- }
- include = &SelectedPackages{
- pkgs: vertexSet,
- }
- }
- exclude, err := r.filterGraphWithSelectors(excludeSelectors)
- if err != nil {
- return nil, err
- }
- return &SelectedPackages{
- pkgs: include.pkgs.Difference(exclude.pkgs),
- unusedFilters: append(include.unusedFilters, exclude.unusedFilters...),
- }, nil
-}
-
-func (r *Resolver) filterGraphWithSelectors(selectors []*TargetSelector) (*SelectedPackages, error) {
- unmatchedSelectors := []*TargetSelector{}
-
- cherryPickedPackages := make(dag.Set)
- walkedDependencies := make(dag.Set)
- walkedDependents := make(dag.Set)
- walkedDependentsDependencies := make(dag.Set)
-
- for _, selector := range selectors {
- // TODO(gsoltis): this should be a list?
- entryPackages, err := r.filterGraphWithSelector(selector)
- if err != nil {
- return nil, err
- }
- if entryPackages.Len() == 0 {
- unmatchedSelectors = append(unmatchedSelectors, selector)
- }
- for _, pkg := range entryPackages {
- if selector.includeDependencies {
- dependencies, err := r.Graph.Ancestors(pkg)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to get dependencies of package %v", pkg)
- }
- for dep := range dependencies {
- walkedDependencies.Add(dep)
- }
- if !selector.excludeSelf {
- walkedDependencies.Add(pkg)
- }
- }
- if selector.includeDependents {
- dependents, err := r.Graph.Descendents(pkg)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to get dependents of package %v", pkg)
- }
- for dep := range dependents {
- walkedDependents.Add(dep)
- if selector.includeDependencies {
- dependentDeps, err := r.Graph.Ancestors(dep)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to get dependencies of dependent %v", dep)
- }
- for dependentDep := range dependentDeps {
- walkedDependentsDependencies.Add(dependentDep)
- }
- }
- }
- if !selector.excludeSelf {
- walkedDependents.Add(pkg)
- }
- }
- if !selector.includeDependencies && !selector.includeDependents {
- cherryPickedPackages.Add(pkg)
- }
- }
- }
- allPkgs := make(util.Set)
- for pkg := range cherryPickedPackages {
- allPkgs.Add(pkg)
- }
- for pkg := range walkedDependencies {
- allPkgs.Add(pkg)
- }
- for pkg := range walkedDependents {
- allPkgs.Add(pkg)
- }
- for pkg := range walkedDependentsDependencies {
- allPkgs.Add(pkg)
- }
- return &SelectedPackages{
- pkgs: allPkgs,
- unusedFilters: unmatchedSelectors,
- }, nil
-}
-
-func (r *Resolver) filterGraphWithSelector(selector *TargetSelector) (util.Set, error) {
- if selector.matchDependencies {
- return r.filterSubtreesWithSelector(selector)
- }
- return r.filterNodesWithSelector(selector)
-}
-
-// filterNodesWithSelector returns the set of nodes that match a given selector
-func (r *Resolver) filterNodesWithSelector(selector *TargetSelector) (util.Set, error) {
- entryPackages := make(util.Set)
- selectorWasUsed := false
- if selector.fromRef != "" {
- // get changed packaged
- selectorWasUsed = true
- changedPkgs, err := r.PackagesChangedInRange(selector.fromRef, selector.getToRef())
- if err != nil {
- return nil, err
- }
- parentDir := selector.parentDir
- for pkgName := range changedPkgs {
- if parentDir != "" {
- // Type assert/coerce to string here because we want to use
- // this value in a map that has string keys.
- // TODO(mehulkar) `changedPkgs` is a util.Set, we could make a `util.PackageNamesSet``
- // or something similar that is all strings.
- pkgNameStr := pkgName.(string)
- if pkgName == util.RootPkgName {
- // The root package changed, only add it if
- // the parentDir is equivalent to the root
- if matches, err := doublestar.PathMatch(r.Cwd.Join(parentDir).ToString(), r.Cwd.ToString()); err != nil {
- return nil, fmt.Errorf("failed to resolve directory relationship %v contains %v: %v", parentDir, r.Cwd, err)
- } else if matches {
- entryPackages.Add(pkgName)
- }
- } else if pkg, ok := r.WorkspaceInfos.PackageJSONs[pkgNameStr]; !ok {
- return nil, fmt.Errorf("missing info for package %v", pkgName)
- } else if matches, err := doublestar.PathMatch(r.Cwd.Join(parentDir).ToString(), pkg.Dir.RestoreAnchor(r.Cwd).ToString()); err != nil {
- return nil, fmt.Errorf("failed to resolve directory relationship %v contains %v: %v", selector.parentDir, pkg.Dir, err)
- } else if matches {
- entryPackages.Add(pkgName)
- }
- } else {
- entryPackages.Add(pkgName)
- }
- }
- } else if selector.parentDir != "" {
- // get packages by path
- selectorWasUsed = true
- parentDir := selector.parentDir
- if parentDir == "." {
- entryPackages.Add(util.RootPkgName)
- } else {
- for name, pkg := range r.WorkspaceInfos.PackageJSONs {
- if matches, err := doublestar.PathMatch(r.Cwd.Join(parentDir).ToString(), pkg.Dir.RestoreAnchor(r.Cwd).ToString()); err != nil {
- return nil, fmt.Errorf("failed to resolve directory relationship %v contains %v: %v", selector.parentDir, pkg.Dir, err)
- } else if matches {
- entryPackages.Add(name)
- }
- }
- }
- }
- if selector.namePattern != "" {
- // find packages that match name
- if !selectorWasUsed {
- matched, err := matchPackageNamesToVertices(selector.namePattern, r.Graph.Vertices())
- if err != nil {
- return nil, err
- }
- entryPackages = matched
- selectorWasUsed = true
- } else {
- matched, err := matchPackageNames(selector.namePattern, entryPackages)
- if err != nil {
- return nil, err
- }
- entryPackages = matched
- }
- }
- // TODO(gsoltis): we can do this earlier
- // Check if the selector specified anything
- if !selectorWasUsed {
- return nil, fmt.Errorf("invalid selector: %v", selector.raw)
- }
- return entryPackages, nil
-}
-
-// filterSubtreesWithSelector returns the set of nodes where the node or any of its dependencies
-// match a selector
-func (r *Resolver) filterSubtreesWithSelector(selector *TargetSelector) (util.Set, error) {
- // foreach package that matches parentDir && namePattern, check if any dependency is in changed packages
- changedPkgs, err := r.PackagesChangedInRange(selector.fromRef, selector.getToRef())
- if err != nil {
- return nil, err
- }
-
- parentDir := selector.parentDir
- entryPackages := make(util.Set)
- for name, pkg := range r.WorkspaceInfos.PackageJSONs {
- if parentDir == "" {
- entryPackages.Add(name)
- } else if matches, err := doublestar.PathMatch(parentDir.ToString(), pkg.Dir.RestoreAnchor(r.Cwd).ToString()); err != nil {
- return nil, fmt.Errorf("failed to resolve directory relationship %v contains %v: %v", selector.parentDir, pkg.Dir, err)
- } else if matches {
- entryPackages.Add(name)
- }
- }
- if selector.namePattern != "" {
- matched, err := matchPackageNames(selector.namePattern, entryPackages)
- if err != nil {
- return nil, err
- }
- entryPackages = matched
- }
- roots := make(util.Set)
- matched := make(util.Set)
- for pkg := range entryPackages {
- if matched.Includes(pkg) {
- roots.Add(pkg)
- continue
- }
- deps, err := r.Graph.Ancestors(pkg)
- if err != nil {
- return nil, err
- }
- for changedPkg := range changedPkgs {
- if !selector.excludeSelf && pkg == changedPkg {
- roots.Add(pkg)
- break
- }
- if deps.Include(changedPkg) {
- roots.Add(pkg)
- matched.Add(changedPkg)
- break
- }
- }
- }
- return roots, nil
-}
-
-func matchPackageNamesToVertices(pattern string, vertices []dag.Vertex) (util.Set, error) {
- packages := make(util.Set)
- for _, v := range vertices {
- packages.Add(v)
- }
- packages.Add(util.RootPkgName)
- return matchPackageNames(pattern, packages)
-}
-
-func matchPackageNames(pattern string, packages util.Set) (util.Set, error) {
- matcher, err := matcherFromPattern(pattern)
- if err != nil {
- return nil, err
- }
- matched := make(util.Set)
- for _, pkg := range packages {
- pkg := pkg.(string)
- if matcher(pkg) {
- matched.Add(pkg)
- }
- }
- if matched.Len() == 0 && !strings.HasPrefix(pattern, "@") && !strings.Contains(pattern, "/") {
- // we got no matches and the pattern isn't a scoped package.
- // Check if we have exactly one scoped package that does match
- scopedPattern := fmt.Sprintf("@*/%v", pattern)
- matcher, err = matcherFromPattern(scopedPattern)
- if err != nil {
- return nil, err
- }
- foundScopedPkg := false
- for _, pkg := range packages {
- pkg := pkg.(string)
- if matcher(pkg) {
- if foundScopedPkg {
- // we found a second scoped package. Return the empty set, we can't
- // disambiguate
- return make(util.Set), nil
- }
- foundScopedPkg = true
- matched.Add(pkg)
- }
- }
- }
- return matched, nil
-}
diff --git a/cli/internal/scope/filter/filter_test.go b/cli/internal/scope/filter/filter_test.go
deleted file mode 100644
index a23ae1d..0000000
--- a/cli/internal/scope/filter/filter_test.go
+++ /dev/null
@@ -1,614 +0,0 @@
-package filter
-
-import (
- "fmt"
- "os"
- "strings"
- "testing"
-
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-func setMatches(t *testing.T, name string, s util.Set, expected []string) {
- expectedSet := make(util.Set)
- for _, item := range expected {
- expectedSet.Add(item)
- }
- missing := s.Difference(expectedSet)
- if missing.Len() > 0 {
- t.Errorf("%v set has extra elements: %v", name, strings.Join(missing.UnsafeListOfStrings(), ", "))
- }
- extra := expectedSet.Difference(s)
- if extra.Len() > 0 {
- t.Errorf("%v set missing elements: %v", name, strings.Join(extra.UnsafeListOfStrings(), ", "))
- }
-}
-
-func Test_filter(t *testing.T) {
- rawCwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- root, err := fs.GetCwd(rawCwd)
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- workspaceInfos := workspace.Catalog{
- PackageJSONs: make(map[string]*fs.PackageJSON),
- }
- packageJSONs := workspaceInfos.PackageJSONs
- graph := &dag.AcyclicGraph{}
- graph.Add("project-0")
- packageJSONs["project-0"] = &fs.PackageJSON{
- Name: "project-0",
- Dir: turbopath.AnchoredUnixPath("packages/project-0").ToSystemPath(),
- }
- graph.Add("project-1")
- packageJSONs["project-1"] = &fs.PackageJSON{
- Name: "project-1",
- Dir: turbopath.AnchoredUnixPath("packages/project-1").ToSystemPath(),
- }
- graph.Add("project-2")
- packageJSONs["project-2"] = &fs.PackageJSON{
- Name: "project-2",
- Dir: "project-2",
- }
- graph.Add("project-3")
- packageJSONs["project-3"] = &fs.PackageJSON{
- Name: "project-3",
- Dir: "project-3",
- }
- graph.Add("project-4")
- packageJSONs["project-4"] = &fs.PackageJSON{
- Name: "project-4",
- Dir: "project-4",
- }
- graph.Add("project-5")
- packageJSONs["project-5"] = &fs.PackageJSON{
- Name: "project-5",
- Dir: "project-5",
- }
- // Note: inside project-5
- graph.Add("project-6")
- packageJSONs["project-6"] = &fs.PackageJSON{
- Name: "project-6",
- Dir: turbopath.AnchoredUnixPath("project-5/packages/project-6").ToSystemPath(),
- }
- // Add dependencies
- graph.Connect(dag.BasicEdge("project-0", "project-1"))
- graph.Connect(dag.BasicEdge("project-0", "project-5"))
- graph.Connect(dag.BasicEdge("project-1", "project-2"))
- graph.Connect(dag.BasicEdge("project-1", "project-4"))
-
- testCases := []struct {
- Name string
- Selectors []*TargetSelector
- PackageInference *PackageInference
- Expected []string
- }{
- {
- "select root package",
- []*TargetSelector{
- {
- namePattern: util.RootPkgName,
- },
- },
- nil,
- []string{util.RootPkgName},
- },
- {
- "select only package dependencies (excluding the package itself)",
- []*TargetSelector{
- {
- excludeSelf: true,
- includeDependencies: true,
- namePattern: "project-1",
- },
- },
- nil,
- []string{"project-2", "project-4"},
- },
- {
- "select package with dependencies",
- []*TargetSelector{
- {
- excludeSelf: false,
- includeDependencies: true,
- namePattern: "project-1",
- },
- },
- nil,
- []string{"project-1", "project-2", "project-4"},
- },
- {
- "select package with dependencies and dependents, including dependent dependencies",
- []*TargetSelector{
- {
- excludeSelf: true,
- includeDependencies: true,
- includeDependents: true,
- namePattern: "project-1",
- },
- },
- nil,
- []string{"project-0", "project-1", "project-2", "project-4", "project-5"},
- },
- {
- "select package with dependents",
- []*TargetSelector{
- {
- includeDependents: true,
- namePattern: "project-2",
- },
- },
- nil,
- []string{"project-1", "project-2", "project-0"},
- },
- {
- "select dependents excluding package itself",
- []*TargetSelector{
- {
- excludeSelf: true,
- includeDependents: true,
- namePattern: "project-2",
- },
- },
- nil,
- []string{"project-0", "project-1"},
- },
- {
- "filter using two selectors: one selects dependencies another selects dependents",
- []*TargetSelector{
- {
- excludeSelf: true,
- includeDependents: true,
- namePattern: "project-2",
- },
- {
- excludeSelf: true,
- includeDependencies: true,
- namePattern: "project-1",
- },
- },
- nil,
- []string{"project-0", "project-1", "project-2", "project-4"},
- },
- {
- "select just a package by name",
- []*TargetSelector{
- {
- namePattern: "project-2",
- },
- },
- nil,
- []string{"project-2"},
- },
- // Note: we don't support the option to switch path prefix mode
- // {
- // "select by parentDir",
- // []*TargetSelector{
- // {
- // parentDir: "/packages",
- // },
- // },
- // []string{"project-0", "project-1"},
- // },
- {
- "select by parentDir using glob",
- []*TargetSelector{
- {
- parentDir: turbopath.MakeRelativeSystemPath("packages", "*"),
- },
- },
- nil,
- []string{"project-0", "project-1"},
- },
- {
- "select by parentDir using globstar",
- []*TargetSelector{
- {
- parentDir: turbopath.MakeRelativeSystemPath("project-5", "**"),
- },
- },
- nil,
- []string{"project-5", "project-6"},
- },
- {
- "select by parentDir with no glob",
- []*TargetSelector{
- {
- parentDir: turbopath.MakeRelativeSystemPath("project-5"),
- },
- },
- nil,
- []string{"project-5"},
- },
- {
- "select all packages except one",
- []*TargetSelector{
- {
- exclude: true,
- namePattern: "project-1",
- },
- },
- nil,
- []string{"project-0", "project-2", "project-3", "project-4", "project-5", "project-6"},
- },
- {
- "select by parentDir and exclude one package by pattern",
- []*TargetSelector{
- {
- parentDir: turbopath.MakeRelativeSystemPath("packages", "*"),
- },
- {
- exclude: true,
- namePattern: "*-1",
- },
- },
- nil,
- []string{"project-0"},
- },
- {
- "select root package by directory",
- []*TargetSelector{
- {
- parentDir: turbopath.MakeRelativeSystemPath("."), // input . gets cleaned to ""
- },
- },
- nil,
- []string{util.RootPkgName},
- },
- {
- "select packages directory",
- []*TargetSelector{},
- &PackageInference{
- DirectoryRoot: turbopath.MakeRelativeSystemPath("packages"),
- },
- []string{"project-0", "project-1"},
- },
- {
- "infer single package",
- []*TargetSelector{},
- &PackageInference{
- DirectoryRoot: turbopath.MakeRelativeSystemPath("packages", "project-0"),
- PackageName: "project-0",
- },
- []string{"project-0"},
- },
- {
- "infer single package from subdirectory",
- []*TargetSelector{},
- &PackageInference{
- DirectoryRoot: turbopath.MakeRelativeSystemPath("packages", "project-0", "src"),
- PackageName: "project-0",
- },
- []string{"project-0"},
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.Name, func(t *testing.T) {
- r := &Resolver{
- Graph: graph,
- WorkspaceInfos: workspaceInfos,
- Cwd: root,
- Inference: tc.PackageInference,
- }
- pkgs, err := r.getFilteredPackages(tc.Selectors)
- if err != nil {
- t.Fatalf("%v failed to filter packages: %v", tc.Name, err)
- }
- setMatches(t, tc.Name, pkgs.pkgs, tc.Expected)
- })
- }
-
- t.Run("report unmatched filters", func(t *testing.T) {
- r := &Resolver{
- Graph: graph,
- WorkspaceInfos: workspaceInfos,
- Cwd: root,
- }
- pkgs, err := r.getFilteredPackages([]*TargetSelector{
- {
- excludeSelf: true,
- includeDependencies: true,
- namePattern: "project-7",
- },
- })
- if err != nil {
- t.Fatalf("unmatched filter failed to filter packages: %v", err)
- }
- if pkgs.pkgs.Len() != 0 {
- t.Errorf("unmatched filter expected no packages, got %v", strings.Join(pkgs.pkgs.UnsafeListOfStrings(), ", "))
- }
- if len(pkgs.unusedFilters) != 1 {
- t.Errorf("unmatched filter expected to report one unused filter, got %v", len(pkgs.unusedFilters))
- }
- })
-}
-
-func Test_matchScopedPackage(t *testing.T) {
- rawCwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- root, err := fs.GetCwd(rawCwd)
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
-
- workspaceInfos := workspace.Catalog{
- PackageJSONs: make(map[string]*fs.PackageJSON),
- }
- packageJSONs := workspaceInfos.PackageJSONs
- graph := &dag.AcyclicGraph{}
- graph.Add("@foo/bar")
- packageJSONs["@foo/bar"] = &fs.PackageJSON{
- Name: "@foo/bar",
- Dir: turbopath.AnchoredUnixPath("packages/bar").ToSystemPath(),
- }
- r := &Resolver{
- Graph: graph,
- WorkspaceInfos: workspaceInfos,
- Cwd: root,
- }
- pkgs, err := r.getFilteredPackages([]*TargetSelector{
- {
- namePattern: "bar",
- },
- })
- if err != nil {
- t.Fatalf("failed to filter packages: %v", err)
- }
- setMatches(t, "match scoped package", pkgs.pkgs, []string{"@foo/bar"})
-}
-
-func Test_matchExactPackages(t *testing.T) {
- rawCwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- root, err := fs.GetCwd(rawCwd)
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
-
- workspaceInfos := workspace.Catalog{
- PackageJSONs: make(map[string]*fs.PackageJSON),
- }
- packageJSONs := workspaceInfos.PackageJSONs
- graph := &dag.AcyclicGraph{}
- graph.Add("@foo/bar")
- packageJSONs["@foo/bar"] = &fs.PackageJSON{
- Name: "@foo/bar",
- Dir: turbopath.AnchoredUnixPath("packages/@foo/bar").ToSystemPath(),
- }
- graph.Add("bar")
- packageJSONs["bar"] = &fs.PackageJSON{
- Name: "bar",
- Dir: turbopath.AnchoredUnixPath("packages/bar").ToSystemPath(),
- }
- r := &Resolver{
- Graph: graph,
- WorkspaceInfos: workspaceInfos,
- Cwd: root,
- }
- pkgs, err := r.getFilteredPackages([]*TargetSelector{
- {
- namePattern: "bar",
- },
- })
- if err != nil {
- t.Fatalf("failed to filter packages: %v", err)
- }
- setMatches(t, "match exact package", pkgs.pkgs, []string{"bar"})
-}
-
-func Test_matchMultipleScopedPackages(t *testing.T) {
- rawCwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- root, err := fs.GetCwd(rawCwd)
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
-
- workspaceInfos := workspace.Catalog{
- PackageJSONs: make(map[string]*fs.PackageJSON),
- }
- packageJSONs := workspaceInfos.PackageJSONs
- graph := &dag.AcyclicGraph{}
- graph.Add("@foo/bar")
- packageJSONs["@foo/bar"] = &fs.PackageJSON{
- Name: "@foo/bar",
- Dir: turbopath.AnchoredUnixPath("packages/@foo/bar").ToSystemPath(),
- }
- graph.Add("@types/bar")
- packageJSONs["@types/bar"] = &fs.PackageJSON{
- Name: "@types/bar",
- Dir: turbopath.AnchoredUnixPath("packages/@types/bar").ToSystemPath(),
- }
- r := &Resolver{
- Graph: graph,
- WorkspaceInfos: workspaceInfos,
- Cwd: root,
- }
- pkgs, err := r.getFilteredPackages([]*TargetSelector{
- {
- namePattern: "bar",
- },
- })
- if err != nil {
- t.Fatalf("failed to filter packages: %v", err)
- }
- setMatches(t, "match nothing with multiple scoped packages", pkgs.pkgs, []string{})
-}
-
-func Test_SCM(t *testing.T) {
- rawCwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- root, err := fs.GetCwd(rawCwd)
- if err != nil {
- t.Fatalf("failed to get working directory: %v", err)
- }
- head1Changed := make(util.Set)
- head1Changed.Add("package-1")
- head1Changed.Add("package-2")
- head1Changed.Add(util.RootPkgName)
- head2Changed := make(util.Set)
- head2Changed.Add("package-3")
- workspaceInfos := workspace.Catalog{
- PackageJSONs: make(map[string]*fs.PackageJSON),
- }
- packageJSONs := workspaceInfos.PackageJSONs
- graph := &dag.AcyclicGraph{}
- graph.Add("package-1")
- packageJSONs["package-1"] = &fs.PackageJSON{
- Name: "package-1",
- Dir: "package-1",
- }
- graph.Add("package-2")
- packageJSONs["package-2"] = &fs.PackageJSON{
- Name: "package-2",
- Dir: "package-2",
- }
- graph.Add("package-3")
- packageJSONs["package-3"] = &fs.PackageJSON{
- Name: "package-3",
- Dir: "package-3",
- }
- graph.Add("package-20")
- packageJSONs["package-20"] = &fs.PackageJSON{
- Name: "package-20",
- Dir: "package-20",
- }
-
- graph.Connect(dag.BasicEdge("package-3", "package-20"))
-
- r := &Resolver{
- Graph: graph,
- WorkspaceInfos: workspaceInfos,
- Cwd: root,
- PackagesChangedInRange: func(fromRef string, toRef string) (util.Set, error) {
- if fromRef == "HEAD~1" && toRef == "HEAD" {
- return head1Changed, nil
- } else if fromRef == "HEAD~2" && toRef == "HEAD" {
- union := head1Changed.Copy()
- for val := range head2Changed {
- union.Add(val)
- }
- return union, nil
- } else if fromRef == "HEAD~2" && toRef == "HEAD~1" {
- return head2Changed, nil
- }
- panic(fmt.Sprintf("unsupported commit range %v...%v", fromRef, toRef))
- },
- }
-
- testCases := []struct {
- Name string
- Selectors []*TargetSelector
- Expected []string
- }{
- {
- "all changed packages",
- []*TargetSelector{
- {
- fromRef: "HEAD~1",
- },
- },
- []string{"package-1", "package-2", util.RootPkgName},
- },
- {
- "all changed packages with parent dir exact match",
- []*TargetSelector{
- {
- fromRef: "HEAD~1",
- parentDir: ".",
- },
- },
- []string{util.RootPkgName},
- },
- {
- "changed packages in directory",
- []*TargetSelector{
- {
- fromRef: "HEAD~1",
- parentDir: "package-2",
- },
- },
- []string{"package-2"},
- },
- {
- "changed packages matching pattern",
- []*TargetSelector{
- {
- fromRef: "HEAD~1",
- namePattern: "package-2*",
- },
- },
- []string{"package-2"},
- },
- {
- "changed packages matching pattern",
- []*TargetSelector{
- {
- fromRef: "HEAD~1",
- namePattern: "package-2*",
- },
- },
- []string{"package-2"},
- },
- // Note: missing test here that takes advantage of automatically exempting
- // test-only changes from pulling in dependents
- //
- // turbo-specific tests below here
- {
- "changed package was requested scope, and we're matching dependencies",
- []*TargetSelector{
- {
- fromRef: "HEAD~1",
- namePattern: "package-1",
- matchDependencies: true,
- },
- },
- []string{"package-1"},
- },
- {
- "older commit",
- []*TargetSelector{
- {
- fromRef: "HEAD~2",
- },
- },
- []string{"package-1", "package-2", "package-3", util.RootPkgName},
- },
- {
- "commit range",
- []*TargetSelector{
- {
- fromRef: "HEAD~2",
- toRefOverride: "HEAD~1",
- },
- },
- []string{"package-3"},
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.Name, func(t *testing.T) {
- pkgs, err := r.getFilteredPackages(tc.Selectors)
- if err != nil {
- t.Fatalf("%v failed to filter packages: %v", tc.Name, err)
- }
- setMatches(t, tc.Name, pkgs.pkgs, tc.Expected)
- })
- }
-}
diff --git a/cli/internal/scope/filter/matcher.go b/cli/internal/scope/filter/matcher.go
deleted file mode 100644
index 2460326..0000000
--- a/cli/internal/scope/filter/matcher.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package filter
-
-import (
- "regexp"
- "strings"
-
- "github.com/pkg/errors"
-)
-
-type Matcher = func(pkgName string) bool
-
-func matchAll(pkgName string) bool {
- return true
-}
-
-func matcherFromPattern(pattern string) (Matcher, error) {
- if pattern == "*" {
- return matchAll, nil
- }
-
- escaped := regexp.QuoteMeta(pattern)
- // replace escaped '*' with regex '.*'
- normalized := strings.ReplaceAll(escaped, "\\*", ".*")
- if normalized == pattern {
- return func(pkgName string) bool { return pkgName == pattern }, nil
- }
- regex, err := regexp.Compile("^" + normalized + "$")
- if err != nil {
- return nil, errors.Wrapf(err, "failed to compile filter pattern to regex: %v", pattern)
- }
- return func(pkgName string) bool { return regex.Match([]byte(pkgName)) }, nil
-}
diff --git a/cli/internal/scope/filter/matcher_test.go b/cli/internal/scope/filter/matcher_test.go
deleted file mode 100644
index 966be2b..0000000
--- a/cli/internal/scope/filter/matcher_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package filter
-
-import "testing"
-
-func TestMatcher(t *testing.T) {
- testCases := map[string][]struct {
- test string
- want bool
- }{
- "*": {
- {
- test: "@eslint/plugin-foo",
- want: true,
- },
- {
- test: "express",
- want: true,
- },
- },
- "eslint-*": {
- {
- test: "eslint-plugin-foo",
- want: true,
- },
- {
- test: "express",
- want: false,
- },
- },
- "*plugin*": {
- {
- test: "@eslint/plugin-foo",
- want: true,
- },
- {
- test: "express",
- want: false,
- },
- },
- "a*c": {
- {
- test: "abc",
- want: true,
- },
- },
- "*-positive": {
- {
- test: "is-positive",
- want: true,
- },
- },
- }
- for pattern, tests := range testCases {
- matcher, err := matcherFromPattern(pattern)
- if err != nil {
- t.Fatalf("failed to compile match pattern %v, %v", pattern, err)
- }
- for _, testCase := range tests {
- got := matcher(testCase.test)
- if got != testCase.want {
- t.Errorf("%v.match(%v) got %v, want %v", pattern, testCase.test, got, testCase.want)
- }
- }
- }
-}
diff --git a/cli/internal/scope/filter/parse_target_selector.go b/cli/internal/scope/filter/parse_target_selector.go
deleted file mode 100644
index 4f5c90f..0000000
--- a/cli/internal/scope/filter/parse_target_selector.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package filter
-
-import (
- "regexp"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-type TargetSelector struct {
- includeDependencies bool
- matchDependencies bool
- includeDependents bool
- exclude bool
- excludeSelf bool
- followProdDepsOnly bool
- parentDir turbopath.RelativeSystemPath
- namePattern string
- fromRef string
- toRefOverride string
- raw string
-}
-
-func (ts *TargetSelector) IsValid() bool {
- return ts.fromRef != "" || ts.parentDir != "" || ts.namePattern != ""
-}
-
-// getToRef returns the git ref to use for upper bound of the comparison when finding changed
-// packages.
-func (ts *TargetSelector) getToRef() string {
- if ts.toRefOverride == "" {
- return "HEAD"
- }
- return ts.toRefOverride
-}
-
-var errCantMatchDependencies = errors.New("cannot use match dependencies without specifying either a directory or package")
-
-var targetSelectorRegex = regexp.MustCompile(`^(?P<name>[^.](?:[^{}[\]]*[^{}[\].])?)?(?P<directory>\{[^}]*\})?(?P<commits>(?:\.{3})?\[[^\]]+\])?$`)
-
-// ParseTargetSelector is a function that returns pnpm compatible --filter command line flags
-func ParseTargetSelector(rawSelector string) (*TargetSelector, error) {
- exclude := false
- firstChar := rawSelector[0]
- selector := rawSelector
- if firstChar == '!' {
- selector = selector[1:]
- exclude = true
- }
- excludeSelf := false
- includeDependencies := strings.HasSuffix(selector, "...")
- if includeDependencies {
- selector = selector[:len(selector)-3]
- if strings.HasSuffix(selector, "^") {
- excludeSelf = true
- selector = selector[:len(selector)-1]
- }
- }
- includeDependents := strings.HasPrefix(selector, "...")
- if includeDependents {
- selector = selector[3:]
- if strings.HasPrefix(selector, "^") {
- excludeSelf = true
- selector = selector[1:]
- }
- }
-
- matches := targetSelectorRegex.FindAllStringSubmatch(selector, -1)
-
- if len(matches) == 0 {
- if relativePath, ok := isSelectorByLocation(selector); ok {
- return &TargetSelector{
- exclude: exclude,
- includeDependencies: includeDependencies,
- includeDependents: includeDependents,
- parentDir: relativePath,
- raw: rawSelector,
- }, nil
- }
- return &TargetSelector{
- exclude: exclude,
- excludeSelf: excludeSelf,
- includeDependencies: includeDependencies,
- includeDependents: includeDependents,
- namePattern: selector,
- raw: rawSelector,
- }, nil
- }
-
- fromRef := ""
- toRefOverride := ""
- var parentDir turbopath.RelativeSystemPath
- namePattern := ""
- preAddDepdencies := false
- if len(matches) > 0 && len(matches[0]) > 0 {
- match := matches[0]
- namePattern = match[targetSelectorRegex.SubexpIndex("name")]
- rawParentDir := match[targetSelectorRegex.SubexpIndex("directory")]
- if len(rawParentDir) > 0 {
- // trim {}
- rawParentDir = rawParentDir[1 : len(rawParentDir)-1]
- if rawParentDir == "" {
- return nil, errors.New("empty path specification")
- } else if relPath, err := turbopath.CheckedToRelativeSystemPath(rawParentDir); err == nil {
- parentDir = relPath
- } else {
- return nil, errors.Wrapf(err, "invalid path specification: %v", rawParentDir)
- }
- }
- rawCommits := match[targetSelectorRegex.SubexpIndex("commits")]
- if len(rawCommits) > 0 {
- fromRef = rawCommits
- if strings.HasPrefix(fromRef, "...") {
- if parentDir == "" && namePattern == "" {
- return &TargetSelector{}, errCantMatchDependencies
- }
- preAddDepdencies = true
- fromRef = fromRef[3:]
- }
- // strip []
- fromRef = fromRef[1 : len(fromRef)-1]
- refs := strings.Split(fromRef, "...")
- if len(refs) == 2 {
- fromRef = refs[0]
- toRefOverride = refs[1]
- }
- }
- }
-
- return &TargetSelector{
- fromRef: fromRef,
- toRefOverride: toRefOverride,
- exclude: exclude,
- excludeSelf: excludeSelf,
- includeDependencies: includeDependencies,
- matchDependencies: preAddDepdencies,
- includeDependents: includeDependents,
- namePattern: namePattern,
- parentDir: parentDir,
- raw: rawSelector,
- }, nil
-}
-
-// isSelectorByLocation returns true if the selector is by filesystem location
-func isSelectorByLocation(rawSelector string) (turbopath.RelativeSystemPath, bool) {
- if rawSelector[0:1] != "." {
- return "", false
- }
-
- // . or ./ or .\
- if len(rawSelector) == 1 || rawSelector[1:2] == "/" || rawSelector[1:2] == "\\" {
- return turbopath.MakeRelativeSystemPath(rawSelector), true
- }
-
- if rawSelector[1:2] != "." {
- return "", false
- }
-
- // .. or ../ or ..\
- if len(rawSelector) == 2 || rawSelector[2:3] == "/" || rawSelector[2:3] == "\\" {
- return turbopath.MakeRelativeSystemPath(rawSelector), true
- }
- return "", false
-}
diff --git a/cli/internal/scope/filter/parse_target_selector_test.go b/cli/internal/scope/filter/parse_target_selector_test.go
deleted file mode 100644
index 2973a61..0000000
--- a/cli/internal/scope/filter/parse_target_selector_test.go
+++ /dev/null
@@ -1,311 +0,0 @@
-package filter
-
-import (
- "reflect"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-func TestParseTargetSelector(t *testing.T) {
- tests := []struct {
- rawSelector string
- want *TargetSelector
- wantErr bool
- }{
- {
- "{}",
- &TargetSelector{},
- true,
- },
- {
- "foo",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "foo",
- parentDir: "",
- },
- false,
- },
- {
- "foo...",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: true,
- includeDependents: false,
- namePattern: "foo",
- parentDir: "",
- },
- false,
- },
- {
- "...foo",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: true,
- namePattern: "foo",
- parentDir: "",
- },
- false,
- },
- {
- "...foo...",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: true,
- includeDependents: true,
- namePattern: "foo",
- parentDir: "",
- },
- false,
- },
- {
- "foo^...",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: true,
- includeDependencies: true,
- includeDependents: false,
- namePattern: "foo",
- parentDir: "",
- },
- false,
- },
- {
- "...^foo",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: true,
- includeDependencies: false,
- includeDependents: true,
- namePattern: "foo",
- parentDir: "",
- },
- false,
- },
- {
- "./foo",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "",
- parentDir: "foo",
- },
- false,
- },
- {
- "../foo",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "",
- parentDir: turbopath.MakeRelativeSystemPath("..", "foo"),
- },
- false,
- },
- {
- "...{./foo}",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: true,
- namePattern: "",
- parentDir: "foo",
- },
- false,
- },
- {
- ".",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "",
- parentDir: ".",
- },
- false,
- },
- {
- "..",
- &TargetSelector{
- fromRef: "",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "",
- parentDir: "..",
- },
- false,
- },
- {
- "[master]",
- &TargetSelector{
- fromRef: "master",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "",
- parentDir: "",
- },
- false,
- },
- {
- "[from...to]",
- &TargetSelector{
- fromRef: "from",
- toRefOverride: "to",
- },
- false,
- },
- {
- "{foo}[master]",
- &TargetSelector{
- fromRef: "master",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "",
- parentDir: "foo",
- },
- false,
- },
- {
- "pattern{foo}[master]",
- &TargetSelector{
- fromRef: "master",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: false,
- namePattern: "pattern",
- parentDir: "foo",
- },
- false,
- },
- {
- "[master]...",
- &TargetSelector{
- fromRef: "master",
- exclude: false,
- excludeSelf: false,
- includeDependencies: true,
- includeDependents: false,
- namePattern: "",
- parentDir: "",
- },
- false,
- },
- {
- "...[master]",
- &TargetSelector{
- fromRef: "master",
- exclude: false,
- excludeSelf: false,
- includeDependencies: false,
- includeDependents: true,
- namePattern: "",
- parentDir: "",
- },
- false,
- },
- {
- "...[master]...",
- &TargetSelector{
- fromRef: "master",
- exclude: false,
- excludeSelf: false,
- includeDependencies: true,
- includeDependents: true,
- namePattern: "",
- parentDir: "",
- },
- false,
- },
- {
- "...[from...to]...",
- &TargetSelector{
- fromRef: "from",
- toRefOverride: "to",
- includeDependencies: true,
- includeDependents: true,
- },
- false,
- },
- {
- "foo...[master]",
- &TargetSelector{
- fromRef: "master",
- namePattern: "foo",
- matchDependencies: true,
- },
- false,
- },
- {
- "foo...[master]...",
- &TargetSelector{
- fromRef: "master",
- namePattern: "foo",
- matchDependencies: true,
- includeDependencies: true,
- },
- false,
- },
- {
- "{foo}...[master]",
- &TargetSelector{
- fromRef: "master",
- parentDir: "foo",
- matchDependencies: true,
- },
- false,
- },
- {
- "......[master]",
- &TargetSelector{},
- true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.rawSelector, func(t *testing.T) {
- got, err := ParseTargetSelector(tt.rawSelector)
- if tt.wantErr {
- if err == nil {
- t.Errorf("ParseTargetSelector() error = %#v, wantErr %#v", err, tt.wantErr)
- }
- } else {
- // copy the raw selector from the args into what we want. This value is used
- // for reporting errors in the case of a malformed selector
- tt.want.raw = tt.rawSelector
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("ParseTargetSelector() = %#v, want %#v", got, tt.want)
- }
- }
- })
- }
-}
diff --git a/cli/internal/scope/scope.go b/cli/internal/scope/scope.go
deleted file mode 100644
index b5ed4e7..0000000
--- a/cli/internal/scope/scope.go
+++ /dev/null
@@ -1,380 +0,0 @@
-package scope
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "sort"
- "strings"
-
- "github.com/hashicorp/go-hclog"
- "github.com/mitchellh/cli"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/context"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/scm"
- scope_filter "github.com/vercel/turbo/cli/internal/scope/filter"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/turbostate"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/util/filter"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-// LegacyFilter holds the options in use before the filter syntax. They have their own rules
-// for how they are compiled into filter expressions.
-type LegacyFilter struct {
- // IncludeDependencies is whether to include pkg.dependencies in execution (defaults to false)
- IncludeDependencies bool
- // SkipDependents is whether to skip dependent impacted consumers in execution (defaults to false)
- SkipDependents bool
- // Entrypoints is a list of package entrypoints
- Entrypoints []string
- // Since is the git ref used to calculate changed packages
- Since string
-}
-
-var _sinceHelp = `Limit/Set scope to changed packages since a
-mergebase. This uses the git diff ${target_branch}...
-mechanism to identify which packages have changed.`
-
-func addLegacyFlagsFromArgs(opts *LegacyFilter, args *turbostate.ParsedArgsFromRust) {
- opts.IncludeDependencies = args.Command.Run.IncludeDependencies
- opts.SkipDependents = args.Command.Run.NoDeps
- opts.Entrypoints = args.Command.Run.Scope
- opts.Since = args.Command.Run.Since
-}
-
-// Opts holds the options for how to select the entrypoint packages for a turbo run
-type Opts struct {
- LegacyFilter LegacyFilter
- // IgnorePatterns is the list of globs of file paths to ignore from execution scope calculation
- IgnorePatterns []string
- // GlobalDepPatterns is a list of globs to global files whose contents will be included in the global hash calculation
- GlobalDepPatterns []string
- // Patterns are the filter patterns supplied to --filter on the commandline
- FilterPatterns []string
-
- PackageInferenceRoot turbopath.RelativeSystemPath
-}
-
-var (
- _filterHelp = `Use the given selector to specify package(s) to act as
-entry points. The syntax mirrors pnpm's syntax, and
-additional documentation and examples can be found in
-turbo's documentation https://turbo.build/repo/docs/reference/command-line-reference#--filter
---filter can be specified multiple times. Packages that
-match any filter will be included.`
- _ignoreHelp = `Files to ignore when calculating changed files (i.e. --since). Supports globs.`
- _globalDepHelp = `Specify glob of global filesystem dependencies to be hashed. Useful for .env and files
-in the root directory. Includes turbo.json, root package.json, and the root lockfile by default.`
-)
-
-// normalize package inference path. We compare against "" in several places, so maintain
-// that behavior. In a post-rust-port world, this should more properly be an Option
-func resolvePackageInferencePath(raw string) (turbopath.RelativeSystemPath, error) {
- pkgInferenceRoot, err := turbopath.CheckedToRelativeSystemPath(raw)
- if err != nil {
- return "", errors.Wrapf(err, "invalid package inference root %v", raw)
- }
- if pkgInferenceRoot == "." {
- return "", nil
- }
- return pkgInferenceRoot, nil
-}
-
-// OptsFromArgs adds the settings relevant to this package to the given Opts
-func OptsFromArgs(opts *Opts, args *turbostate.ParsedArgsFromRust) error {
- opts.FilterPatterns = args.Command.Run.Filter
- opts.IgnorePatterns = args.Command.Run.Ignore
- opts.GlobalDepPatterns = args.Command.Run.GlobalDeps
- pkgInferenceRoot, err := resolvePackageInferencePath(args.Command.Run.PkgInferenceRoot)
- if err != nil {
- return err
- }
- opts.PackageInferenceRoot = pkgInferenceRoot
- addLegacyFlagsFromArgs(&opts.LegacyFilter, args)
- return nil
-}
-
-// AsFilterPatterns normalizes legacy selectors to filter syntax
-func (l *LegacyFilter) AsFilterPatterns() []string {
- var patterns []string
- prefix := ""
- if !l.SkipDependents {
- prefix = "..."
- }
- suffix := ""
- if l.IncludeDependencies {
- suffix = "..."
- }
- since := ""
- if l.Since != "" {
- since = fmt.Sprintf("[%v]", l.Since)
- }
- if len(l.Entrypoints) > 0 {
- // --scope implies our tweaked syntax to see if any dependency matches
- if since != "" {
- since = "..." + since
- }
- for _, pattern := range l.Entrypoints {
- if strings.HasPrefix(pattern, "!") {
- patterns = append(patterns, pattern)
- } else {
- filterPattern := fmt.Sprintf("%v%v%v%v", prefix, pattern, since, suffix)
- patterns = append(patterns, filterPattern)
- }
- }
- } else if since != "" {
- // no scopes specified, but --since was provided
- filterPattern := fmt.Sprintf("%v%v%v", prefix, since, suffix)
- patterns = append(patterns, filterPattern)
- }
- return patterns
-}
-
-// ResolvePackages translates specified flags to a set of entry point packages for
-// the selected tasks. Returns the selected packages and whether or not the selected
-// packages represents a default "all packages".
-func ResolvePackages(opts *Opts, repoRoot turbopath.AbsoluteSystemPath, scm scm.SCM, ctx *context.Context, tui cli.Ui, logger hclog.Logger) (util.Set, bool, error) {
- inferenceBase, err := calculateInference(repoRoot, opts.PackageInferenceRoot, ctx.WorkspaceInfos, logger)
- if err != nil {
- return nil, false, err
- }
- filterResolver := &scope_filter.Resolver{
- Graph: &ctx.WorkspaceGraph,
- WorkspaceInfos: ctx.WorkspaceInfos,
- Cwd: repoRoot,
- Inference: inferenceBase,
- PackagesChangedInRange: opts.getPackageChangeFunc(scm, repoRoot, ctx),
- }
- filterPatterns := opts.FilterPatterns
- legacyFilterPatterns := opts.LegacyFilter.AsFilterPatterns()
- filterPatterns = append(filterPatterns, legacyFilterPatterns...)
- isAllPackages := len(filterPatterns) == 0 && opts.PackageInferenceRoot == ""
- filteredPkgs, err := filterResolver.GetPackagesFromPatterns(filterPatterns)
- if err != nil {
- return nil, false, err
- }
-
- if isAllPackages {
- // no filters specified, run every package
- for _, f := range ctx.WorkspaceNames {
- filteredPkgs.Add(f)
- }
- }
- filteredPkgs.Delete(ctx.RootNode)
- return filteredPkgs, isAllPackages, nil
-}
-
-func calculateInference(repoRoot turbopath.AbsoluteSystemPath, pkgInferencePath turbopath.RelativeSystemPath, packageInfos workspace.Catalog, logger hclog.Logger) (*scope_filter.PackageInference, error) {
- if pkgInferencePath == "" {
- // No inference specified, no need to calculate anything
- return nil, nil
- }
- logger.Debug(fmt.Sprintf("Using %v as a basis for selecting packages", pkgInferencePath))
- fullInferencePath := repoRoot.Join(pkgInferencePath)
- for _, pkgInfo := range packageInfos.PackageJSONs {
- pkgPath := pkgInfo.Dir.RestoreAnchor(repoRoot)
- inferredPathIsBelow, err := pkgPath.ContainsPath(fullInferencePath)
- if err != nil {
- return nil, err
- }
- // We skip over the root package as the inferred path will always be below it
- if inferredPathIsBelow && pkgPath != repoRoot {
- // set both. The user might have set a parent directory filter,
- // in which case we *should* fail to find any packages, but we should
- // do so in a consistent manner
- return &scope_filter.PackageInference{
- PackageName: pkgInfo.Name,
- DirectoryRoot: pkgInferencePath,
- }, nil
- }
- inferredPathIsBetweenRootAndPkg, err := fullInferencePath.ContainsPath(pkgPath)
- if err != nil {
- return nil, err
- }
- if inferredPathIsBetweenRootAndPkg {
- // we've found *some* package below our inference directory. We can stop now and conclude
- // that we're looking for all packages in a subdirectory
- break
- }
- }
- return &scope_filter.PackageInference{
- DirectoryRoot: pkgInferencePath,
- }, nil
-}
-
-func (o *Opts) getPackageChangeFunc(scm scm.SCM, cwd turbopath.AbsoluteSystemPath, ctx *context.Context) scope_filter.PackagesChangedInRange {
- return func(fromRef string, toRef string) (util.Set, error) {
- // We could filter changed files at the git level, since it's possible
- // that the changes we're interested in are scoped, but we need to handle
- // global dependencies changing as well. A future optimization might be to
- // scope changed files more deeply if we know there are no global dependencies.
- var changedFiles []string
- if fromRef != "" {
- scmChangedFiles, err := scm.ChangedFiles(fromRef, toRef, cwd.ToStringDuringMigration())
- if err != nil {
- return nil, err
- }
- sort.Strings(scmChangedFiles)
- changedFiles = scmChangedFiles
- }
- makeAllPkgs := func() util.Set {
- allPkgs := make(util.Set)
- for pkg := range ctx.WorkspaceInfos.PackageJSONs {
- allPkgs.Add(pkg)
- }
- return allPkgs
- }
- if hasRepoGlobalFileChanged, err := repoGlobalFileHasChanged(o, getDefaultGlobalDeps(), changedFiles); err != nil {
- return nil, err
- } else if hasRepoGlobalFileChanged {
- return makeAllPkgs(), nil
- }
-
- filteredChangedFiles, err := filterIgnoredFiles(o, changedFiles)
- if err != nil {
- return nil, err
- }
- changedPkgs := getChangedPackages(filteredChangedFiles, ctx.WorkspaceInfos)
-
- if lockfileChanges, fullChanges := getChangesFromLockfile(scm, ctx, changedFiles, fromRef); !fullChanges {
- for _, pkg := range lockfileChanges {
- changedPkgs.Add(pkg)
- }
- } else {
- return makeAllPkgs(), nil
- }
-
- return changedPkgs, nil
- }
-}
-
-func getChangesFromLockfile(scm scm.SCM, ctx *context.Context, changedFiles []string, fromRef string) ([]string, bool) {
- lockfileFilter, err := filter.Compile([]string{ctx.PackageManager.Lockfile})
- if err != nil {
- panic(fmt.Sprintf("Lockfile is invalid glob: %v", err))
- }
- match := false
- for _, file := range changedFiles {
- if lockfileFilter.Match(file) {
- match = true
- break
- }
- }
- if !match {
- return nil, false
- }
-
- if lockfile.IsNil(ctx.Lockfile) {
- return nil, true
- }
-
- prevContents, err := scm.PreviousContent(fromRef, ctx.PackageManager.Lockfile)
- if err != nil {
- // unable to reconstruct old lockfile, assume everything changed
- return nil, true
- }
- prevLockfile, err := ctx.PackageManager.UnmarshalLockfile(ctx.WorkspaceInfos.PackageJSONs[util.RootPkgName], prevContents)
- if err != nil {
- // unable to parse old lockfile, assume everything changed
- return nil, true
- }
- additionalPkgs, err := ctx.ChangedPackages(prevLockfile)
- if err != nil {
- // missing at least one lockfile, assume everything changed
- return nil, true
- }
-
- return additionalPkgs, false
-}
-
-func getDefaultGlobalDeps() []string {
- // include turbo.json and root package.json as implicit global dependencies
- defaultGlobalDeps := []string{
- "turbo.json",
- "package.json",
- }
- return defaultGlobalDeps
-}
-
-func repoGlobalFileHasChanged(opts *Opts, defaultGlobalDeps []string, changedFiles []string) (bool, error) {
- globalDepsGlob, err := filter.Compile(append(opts.GlobalDepPatterns, defaultGlobalDeps...))
- if err != nil {
- return false, errors.Wrap(err, "invalid global deps glob")
- }
-
- if globalDepsGlob != nil {
- for _, file := range changedFiles {
- if globalDepsGlob.Match(filepath.ToSlash(file)) {
- return true, nil
- }
- }
- }
- return false, nil
-}
-
-func filterIgnoredFiles(opts *Opts, changedFiles []string) ([]string, error) {
- // changedFiles is an array of repo-relative system paths.
- // opts.IgnorePatterns is an array of unix-separator glob paths.
- ignoreGlob, err := filter.Compile(opts.IgnorePatterns)
- if err != nil {
- return nil, errors.Wrap(err, "invalid ignore globs")
- }
- filteredChanges := []string{}
- for _, file := range changedFiles {
- // If we don't have anything to ignore, or if this file doesn't match the ignore pattern,
- // keep it as a changed file.
- if ignoreGlob == nil || !ignoreGlob.Match(filepath.ToSlash(file)) {
- filteredChanges = append(filteredChanges, file)
- }
- }
- return filteredChanges, nil
-}
-
-func fileInPackage(changedFile string, packagePath string) bool {
- // This whole method is basically this regex: /^.*\/?$/
- // The regex is more-expensive, so we don't do it.
-
- // If it has the prefix, it might be in the package.
- if strings.HasPrefix(changedFile, packagePath) {
- // Now we need to see if the prefix stopped at a reasonable boundary.
- prefixLen := len(packagePath)
- changedFileLen := len(changedFile)
-
- // Same path.
- if prefixLen == changedFileLen {
- return true
- }
-
- // We know changedFile is longer than packagePath.
- // We can safely directly index into it.
- // Look ahead one byte and see if it's the separator.
- if changedFile[prefixLen] == os.PathSeparator {
- return true
- }
- }
-
- // If it does not have the prefix, it's definitely not in the package.
- return false
-}
-
-func getChangedPackages(changedFiles []string, packageInfos workspace.Catalog) util.Set {
- changedPackages := make(util.Set)
- for _, changedFile := range changedFiles {
- found := false
- for pkgName, pkgInfo := range packageInfos.PackageJSONs {
- if pkgName != util.RootPkgName && fileInPackage(changedFile, pkgInfo.Dir.ToStringDuringMigration()) {
- changedPackages.Add(pkgName)
- found = true
- break
- }
- }
- if !found {
- // Consider the root package to have changed
- changedPackages.Add(util.RootPkgName)
- }
- }
- return changedPackages
-}
diff --git a/cli/internal/scope/scope_test.go b/cli/internal/scope/scope_test.go
deleted file mode 100644
index 216984d..0000000
--- a/cli/internal/scope/scope_test.go
+++ /dev/null
@@ -1,550 +0,0 @@
-package scope
-
-import (
- "fmt"
- "io"
- "os"
- "path/filepath"
- "reflect"
- "testing"
-
- "github.com/hashicorp/go-hclog"
- "github.com/pyr-sh/dag"
- "github.com/vercel/turbo/cli/internal/context"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/lockfile"
- "github.com/vercel/turbo/cli/internal/packagemanager"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/ui"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
-)
-
-type mockSCM struct {
- changed []string
- contents map[string][]byte
-}
-
-func (m *mockSCM) ChangedFiles(_fromCommit string, _toCommit string, _relativeTo string) ([]string, error) {
- return m.changed, nil
-}
-
-func (m *mockSCM) PreviousContent(fromCommit string, filePath string) ([]byte, error) {
- contents, ok := m.contents[filePath]
- if !ok {
- return nil, fmt.Errorf("No contents found")
- }
- return contents, nil
-}
-
-type mockLockfile struct {
- globalChange bool
- versions map[string]string
- allDeps map[string]map[string]string
-}
-
-func (m *mockLockfile) ResolvePackage(workspacePath turbopath.AnchoredUnixPath, name string, version string) (lockfile.Package, error) {
- resolvedVersion, ok := m.versions[name]
- if ok {
- key := fmt.Sprintf("%s%s", name, version)
- return lockfile.Package{Key: key, Version: resolvedVersion, Found: true}, nil
- }
- return lockfile.Package{Found: false}, nil
-}
-
-func (m *mockLockfile) AllDependencies(key string) (map[string]string, bool) {
- deps, ok := m.allDeps[key]
- return deps, ok
-}
-
-func (m *mockLockfile) Encode(w io.Writer) error {
- return nil
-}
-
-func (m *mockLockfile) GlobalChange(other lockfile.Lockfile) bool {
- return m.globalChange || (other != nil && other.(*mockLockfile).globalChange)
-}
-
-func (m *mockLockfile) Patches() []turbopath.AnchoredUnixPath {
- return nil
-}
-
-func (m *mockLockfile) Subgraph(workspaces []turbopath.AnchoredSystemPath, packages []string) (lockfile.Lockfile, error) {
- return nil, nil
-}
-
-var _ (lockfile.Lockfile) = (*mockLockfile)(nil)
-
-func TestResolvePackages(t *testing.T) {
- cwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("cwd: %v", err)
- }
- root, err := fs.GetCwd(cwd)
- if err != nil {
- t.Fatalf("cwd: %v", err)
- }
- tui := ui.Default()
- logger := hclog.Default()
- // Dependency graph:
- //
- // app0 -
- // \
- // app1 -> libA
- // \
- // > libB -> libD
- // /
- // app2 <
- // \
- // > libC
- // /
- // app2-a <
- //
- // Filesystem layout:
- //
- // app/
- // app0
- // app1
- // app2
- // app2-a
- // libs/
- // libA
- // libB
- // libC
- // libD
- graph := dag.AcyclicGraph{}
- graph.Add("app0")
- graph.Add("app1")
- graph.Add("app2")
- graph.Add("app2-a")
- graph.Add("libA")
- graph.Add("libB")
- graph.Add("libC")
- graph.Add("libD")
- graph.Connect(dag.BasicEdge("libA", "libB"))
- graph.Connect(dag.BasicEdge("libB", "libD"))
- graph.Connect(dag.BasicEdge("app0", "libA"))
- graph.Connect(dag.BasicEdge("app1", "libA"))
- graph.Connect(dag.BasicEdge("app2", "libB"))
- graph.Connect(dag.BasicEdge("app2", "libC"))
- graph.Connect(dag.BasicEdge("app2-a", "libC"))
- workspaceInfos := workspace.Catalog{
- PackageJSONs: map[string]*fs.PackageJSON{
- "//": {
- Dir: turbopath.AnchoredSystemPath("").ToSystemPath(),
- UnresolvedExternalDeps: map[string]string{"global": "2"},
- TransitiveDeps: []lockfile.Package{{Key: "global2", Version: "2", Found: true}},
- },
- "app0": {
- Dir: turbopath.AnchoredUnixPath("app/app0").ToSystemPath(),
- Name: "app0",
- UnresolvedExternalDeps: map[string]string{"app0-dep": "2"},
- TransitiveDeps: []lockfile.Package{
- {Key: "app0-dep2", Version: "2", Found: true},
- {Key: "app0-util2", Version: "2", Found: true},
- },
- },
- "app1": {
- Dir: turbopath.AnchoredUnixPath("app/app1").ToSystemPath(),
- Name: "app1",
- },
- "app2": {
- Dir: turbopath.AnchoredUnixPath("app/app2").ToSystemPath(),
- Name: "app2",
- },
- "app2-a": {
- Dir: turbopath.AnchoredUnixPath("app/app2-a").ToSystemPath(),
- Name: "app2-a",
- },
- "libA": {
- Dir: turbopath.AnchoredUnixPath("libs/libA").ToSystemPath(),
- Name: "libA",
- },
- "libB": {
- Dir: turbopath.AnchoredUnixPath("libs/libB").ToSystemPath(),
- Name: "libB",
- UnresolvedExternalDeps: map[string]string{"external": "1"},
- TransitiveDeps: []lockfile.Package{
- {Key: "external-dep-a1", Version: "1", Found: true},
- {Key: "external-dep-b1", Version: "1", Found: true},
- {Key: "external1", Version: "1", Found: true},
- },
- },
- "libC": {
- Dir: turbopath.AnchoredUnixPath("libs/libC").ToSystemPath(),
- Name: "libC",
- },
- "libD": {
- Dir: turbopath.AnchoredUnixPath("libs/libD").ToSystemPath(),
- Name: "libD",
- },
- },
- }
- packageNames := []string{}
- for name := range workspaceInfos.PackageJSONs {
- packageNames = append(packageNames, name)
- }
-
- // global -> globalDep
- // app0-dep -> app0-dep :)
-
- makeLockfile := func(f func(*mockLockfile)) *mockLockfile {
- l := mockLockfile{
- globalChange: false,
- versions: map[string]string{
- "global": "2",
- "app0-dep": "2",
- "app0-util": "2",
- "external": "1",
- "external-dep-a": "1",
- "external-dep-b": "1",
- },
- allDeps: map[string]map[string]string{
- "global2": map[string]string{},
- "app0-dep2": map[string]string{
- "app0-util": "2",
- },
- "app0-util2": map[string]string{},
- "external1": map[string]string{
- "external-dep-a": "1",
- "external-dep-b": "1",
- },
- "external-dep-a1": map[string]string{},
- "external-dep-b1": map[string]string{},
- },
- }
- if f != nil {
- f(&l)
- }
- return &l
- }
-
- testCases := []struct {
- name string
- changed []string
- expected []string
- expectAllPackages bool
- scope []string
- since string
- ignore string
- globalDeps []string
- includeDependencies bool
- includeDependents bool
- lockfile string
- currLockfile *mockLockfile
- prevLockfile *mockLockfile
- inferPkgPath string
- }{
- {
- name: "Just scope and dependencies",
- changed: []string{},
- includeDependencies: true,
- scope: []string{"app2"},
- expected: []string{"app2", "libB", "libC", "libD"},
- },
- {
- name: "Only turbo.json changed",
- changed: []string{"turbo.json"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- since: "dummy",
- includeDependencies: true,
- },
- {
- name: "Only root package.json changed",
- changed: []string{"package.json"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- since: "dummy",
- includeDependencies: true,
- },
- {
- name: "Only package-lock.json changed",
- changed: []string{"package-lock.json"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- since: "dummy",
- includeDependencies: true,
- lockfile: "package-lock.json",
- },
- {
- name: "Only yarn.lock changed",
- changed: []string{"yarn.lock"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- since: "dummy",
- includeDependencies: true,
- lockfile: "yarn.lock",
- },
- {
- name: "Only pnpm-lock.yaml changed",
- changed: []string{"pnpm-lock.yaml"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- since: "dummy",
- includeDependencies: true,
- lockfile: "pnpm-lock.yaml",
- },
- {
- name: "One package changed",
- changed: []string{"libs/libB/src/index.ts"},
- expected: []string{"libB"},
- since: "dummy",
- },
- {
- name: "One package manifest changed",
- changed: []string{"libs/libB/package.json"},
- expected: []string{"libB"},
- since: "dummy",
- },
- {
- name: "An ignored package changed",
- changed: []string{"libs/libB/src/index.ts"},
- expected: []string{},
- since: "dummy",
- ignore: "libs/libB/**/*.ts",
- },
- {
- // nothing in scope depends on the change
- name: "unrelated library changed",
- changed: []string{"libs/libC/src/index.ts"},
- expected: []string{},
- since: "dummy",
- scope: []string{"app1"},
- includeDependencies: true, // scope implies include-dependencies
- },
- {
- // a dependent lib changed, scope implies include-dependencies,
- // so all deps of app1 get built
- name: "dependency of scope changed",
- changed: []string{"libs/libA/src/index.ts"},
- expected: []string{"libA", "libB", "libD", "app1"},
- since: "dummy",
- scope: []string{"app1"},
- includeDependencies: true, // scope implies include-dependencies
- },
- {
- // a dependent lib changed, user explicitly asked to not build dependencies.
- // Since the package matching the scope had a changed dependency, we run it.
- // We don't include its dependencies because the user asked for no dependencies.
- // note: this is not yet supported by the CLI, as you cannot specify --include-dependencies=false
- name: "dependency of scope changed, user asked to not include depedencies",
- changed: []string{"libs/libA/src/index.ts"},
- expected: []string{"app1"},
- since: "dummy",
- scope: []string{"app1"},
- includeDependencies: false,
- },
- {
- // a nested dependent lib changed, user explicitly asked to not build dependencies
- // note: this is not yet supported by the CLI, as you cannot specify --include-dependencies=false
- name: "nested dependency of scope changed, user asked to not include dependencies",
- changed: []string{"libs/libB/src/index.ts"},
- expected: []string{"app1"},
- since: "dummy",
- scope: []string{"app1"},
- includeDependencies: false,
- },
- {
- name: "global dependency changed, even though it was ignored, forcing a build of everything",
- changed: []string{"libs/libB/src/index.ts"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- since: "dummy",
- ignore: "libs/libB/**/*.ts",
- globalDeps: []string{"libs/**/*.ts"},
- },
- {
- name: "an app changed, user asked for dependencies to build",
- changed: []string{"app/app2/src/index.ts"},
- since: "dummy",
- includeDependencies: true,
- expected: []string{"app2", "libB", "libC", "libD"},
- },
- {
- name: "a library changed, user asked for dependents to be built",
- changed: []string{"libs/libB"},
- since: "dummy",
- includeDependents: true,
- expected: []string{"app0", "app1", "app2", "libA", "libB"},
- },
- {
- // no changes, no base to compare against, defaults to everything
- name: "no changes or scope specified, build everything",
- since: "",
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- expectAllPackages: true,
- },
- {
- // a dependent library changed, no deps beyond the scope are build
- // "libB" is still built because it is a dependent within the scope, but libB's dependents
- // are skipped
- name: "a dependent library changed, build up to scope",
- changed: []string{"libs/libD/src/index.ts"},
- since: "dummy",
- scope: []string{"libB"},
- expected: []string{"libB", "libD"},
- includeDependencies: true, // scope implies include-dependencies
- },
- {
- name: "library change, no scope",
- changed: []string{"libs/libA/src/index.ts"},
- expected: []string{"libA", "app0", "app1"},
- includeDependents: true,
- since: "dummy",
- },
- {
- // make sure multiple apps with the same prefix are handled separately.
- // prevents this issue: https://github.com/vercel/turbo/issues/1528
- name: "Two apps with an overlapping prefix changed",
- changed: []string{"app/app2/src/index.js", "app/app2-a/src/index.js"},
- expected: []string{"app2", "app2-a"},
- since: "dummy",
- },
- {
- name: "Global lockfile change invalidates all packages",
- changed: []string{"dummy.lock"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- lockfile: "dummy.lock",
- currLockfile: makeLockfile(nil),
- prevLockfile: makeLockfile(func(ml *mockLockfile) {
- ml.globalChange = true
- }),
- since: "dummy",
- },
- {
- name: "Dependency of workspace root change invalidates all packages",
- changed: []string{"dummy.lock"},
- expected: []string{"//", "app0", "app1", "app2", "app2-a", "libA", "libB", "libC", "libD"},
- lockfile: "dummy.lock",
- currLockfile: makeLockfile(nil),
- prevLockfile: makeLockfile(func(ml *mockLockfile) {
- ml.versions["global"] = "3"
- ml.allDeps["global3"] = map[string]string{}
- }),
- since: "dummy",
- },
- {
- name: "Version change invalidates package",
- changed: []string{"dummy.lock"},
- expected: []string{"//", "app0"},
- lockfile: "dummy.lock",
- currLockfile: makeLockfile(nil),
- prevLockfile: makeLockfile(func(ml *mockLockfile) {
- ml.versions["app0-util"] = "3"
- ml.allDeps["app0-dep2"] = map[string]string{"app0-util": "3"}
- ml.allDeps["app0-util3"] = map[string]string{}
- }),
- since: "dummy",
- },
- {
- name: "Transitive dep invalidates package",
- changed: []string{"dummy.lock"},
- expected: []string{"//", "libB"},
- lockfile: "dummy.lock",
- currLockfile: makeLockfile(nil),
- prevLockfile: makeLockfile(func(ml *mockLockfile) {
- ml.versions["external-dep-a"] = "2"
- ml.allDeps["external1"] = map[string]string{"external-dep-a": "2", "external-dep-b": "1"}
- ml.allDeps["external-dep-a2"] = map[string]string{}
- }),
- since: "dummy",
- },
- {
- name: "Transitive dep invalidates package and dependents",
- changed: []string{"dummy.lock"},
- expected: []string{"//", "app0", "app1", "app2", "libA", "libB"},
- lockfile: "dummy.lock",
- includeDependents: true,
- currLockfile: makeLockfile(nil),
- prevLockfile: makeLockfile(func(ml *mockLockfile) {
- ml.versions["external-dep-a"] = "2"
- ml.allDeps["external1"] = map[string]string{"external-dep-a": "2", "external-dep-b": "1"}
- ml.allDeps["external-dep-a2"] = map[string]string{}
- }),
- since: "dummy",
- },
- {
- name: "Infer app2 from directory",
- inferPkgPath: "app/app2",
- expected: []string{"app2"},
- },
- {
- name: "Infer app2 from a subdirectory",
- inferPkgPath: "app/app2/src",
- expected: []string{"app2"},
- },
- {
- name: "Infer from a directory with no packages",
- inferPkgPath: "wrong",
- expected: []string{},
- },
- {
- name: "Infer from a parent directory",
- inferPkgPath: "app",
- expected: []string{"app0", "app1", "app2", "app2-a"},
- },
- {
- name: "library change, no scope, inferred libs",
- changed: []string{"libs/libA/src/index.ts"},
- expected: []string{"libA"},
- since: "dummy",
- inferPkgPath: "libs",
- },
- {
- name: "library change, no scope, inferred app",
- changed: []string{"libs/libA/src/index.ts"},
- expected: []string{},
- since: "dummy",
- inferPkgPath: "app",
- },
- }
- for i, tc := range testCases {
- t.Run(fmt.Sprintf("test #%v %v", i, tc.name), func(t *testing.T) {
- // Convert test data to system separators.
- systemSeparatorChanged := make([]string, len(tc.changed))
- for index, path := range tc.changed {
- systemSeparatorChanged[index] = filepath.FromSlash(path)
- }
- scm := &mockSCM{
- changed: systemSeparatorChanged,
- contents: make(map[string][]byte, len(systemSeparatorChanged)),
- }
- for _, path := range systemSeparatorChanged {
- scm.contents[path] = nil
- }
- readLockfile := func(_rootPackageJSON *fs.PackageJSON, content []byte) (lockfile.Lockfile, error) {
- return tc.prevLockfile, nil
- }
- pkgInferenceRoot, err := resolvePackageInferencePath(tc.inferPkgPath)
- if err != nil {
- t.Errorf("bad inference path (%v): %v", tc.inferPkgPath, err)
- }
- pkgs, isAllPackages, err := ResolvePackages(&Opts{
- LegacyFilter: LegacyFilter{
- Entrypoints: tc.scope,
- Since: tc.since,
- IncludeDependencies: tc.includeDependencies,
- SkipDependents: !tc.includeDependents,
- },
- IgnorePatterns: []string{tc.ignore},
- GlobalDepPatterns: tc.globalDeps,
- PackageInferenceRoot: pkgInferenceRoot,
- }, root, scm, &context.Context{
- WorkspaceInfos: workspaceInfos,
- WorkspaceNames: packageNames,
- PackageManager: &packagemanager.PackageManager{Lockfile: tc.lockfile, UnmarshalLockfile: readLockfile},
- WorkspaceGraph: graph,
- RootNode: "root",
- Lockfile: tc.currLockfile,
- }, tui, logger)
- if err != nil {
- t.Errorf("expected no error, got %v", err)
- }
- expected := make(util.Set)
- for _, pkg := range tc.expected {
- expected.Add(pkg)
- }
- if !reflect.DeepEqual(pkgs, expected) {
- t.Errorf("ResolvePackages got %v, want %v", pkgs, expected)
- }
- if isAllPackages != tc.expectAllPackages {
- t.Errorf("isAllPackages got %v, want %v", isAllPackages, tc.expectAllPackages)
- }
- })
- }
-}
diff --git a/cli/internal/server/server.go b/cli/internal/server/server.go
deleted file mode 100644
index 5e738cc..0000000
--- a/cli/internal/server/server.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package server
-
-import (
- "context"
- "sync"
- "time"
-
- "github.com/hashicorp/go-hclog"
- "github.com/pkg/errors"
- "github.com/vercel/turbo/cli/internal/filewatcher"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/globwatcher"
- "github.com/vercel/turbo/cli/internal/turbodprotocol"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
-)
-
-// Server implements the GRPC serverside of TurbodServer
-// Note for the future: we don't yet make use of turbo.json
-// or the package graph in the server. Once we do, we may need a
-// layer of indirection between "the thing that responds to grpc requests"
-// and "the thing that holds our persistent data structures" to handle
-// changes in the underlying configuration.
-type Server struct {
- turbodprotocol.UnimplementedTurbodServer
- watcher *filewatcher.FileWatcher
- globWatcher *globwatcher.GlobWatcher
- turboVersion string
- started time.Time
- logFilePath turbopath.AbsoluteSystemPath
- repoRoot turbopath.AbsoluteSystemPath
- closerMu sync.Mutex
- closer *closer
-}
-
-// GRPCServer is the interface that the turbo server needs to the underlying
-// GRPC server. This lets the turbo server register itself, as well as provides
-// a hook for shutting down the server.
-type GRPCServer interface {
- grpc.ServiceRegistrar
- GracefulStop()
-}
-
-type closer struct {
- grpcServer GRPCServer
- once sync.Once
-}
-
-func (c *closer) close() {
- // This can get triggered from a request handler (Shutdown). Since
- // calling GracefulStop blocks until all request handlers complete,
- // we need to run it in a goroutine to let the Shutdown handler complete
- // and avoid deadlocking.
- c.once.Do(func() {
- go func() {
- c.grpcServer.GracefulStop()
- }()
- })
-}
-
-var _defaultCookieTimeout = 500 * time.Millisecond
-
-// New returns a new instance of Server
-func New(serverName string, logger hclog.Logger, repoRoot turbopath.AbsoluteSystemPath, turboVersion string, logFilePath turbopath.AbsoluteSystemPath) (*Server, error) {
- cookieDir := fs.GetTurboDataDir().UntypedJoin("cookies", serverName)
- cookieJar, err := filewatcher.NewCookieJar(cookieDir, _defaultCookieTimeout)
- if err != nil {
- return nil, err
- }
- watcher, err := filewatcher.GetPlatformSpecificBackend(logger)
- if err != nil {
- return nil, err
- }
- fileWatcher := filewatcher.New(logger.Named("FileWatcher"), repoRoot, watcher)
- globWatcher := globwatcher.New(logger.Named("GlobWatcher"), repoRoot, cookieJar)
- server := &Server{
- watcher: fileWatcher,
- globWatcher: globWatcher,
- turboVersion: turboVersion,
- started: time.Now(),
- logFilePath: logFilePath,
- repoRoot: repoRoot,
- }
- server.watcher.AddClient(cookieJar)
- server.watcher.AddClient(globWatcher)
- server.watcher.AddClient(server)
- if err := server.watcher.Start(); err != nil {
- return nil, errors.Wrapf(err, "watching %v", repoRoot)
- }
- if err := server.watcher.AddRoot(cookieDir); err != nil {
- _ = server.watcher.Close()
- return nil, errors.Wrapf(err, "failed to watch cookie directory: %v", cookieDir)
- }
- return server, nil
-}
-
-func (s *Server) tryClose() bool {
- s.closerMu.Lock()
- defer s.closerMu.Unlock()
- if s.closer != nil {
- s.closer.close()
- return true
- }
- return false
-}
-
-// OnFileWatchEvent implements filewatcher.FileWatchClient.OnFileWatchEvent
-// In the event that the root of the monorepo is deleted, shut down the server.
-func (s *Server) OnFileWatchEvent(ev filewatcher.Event) {
- if ev.EventType == filewatcher.FileDeleted && ev.Path == s.repoRoot {
- _ = s.tryClose()
- }
-}
-
-// OnFileWatchError implements filewatcher.FileWatchClient.OnFileWatchError
-func (s *Server) OnFileWatchError(err error) {}
-
-// OnFileWatchClosed implements filewatcher.FileWatchClient.OnFileWatchClosed
-func (s *Server) OnFileWatchClosed() {}
-
-// Close is used for shutting down this copy of the server
-func (s *Server) Close() error {
- return s.watcher.Close()
-}
-
-// Register registers this server to respond to GRPC requests
-func (s *Server) Register(grpcServer GRPCServer) {
- s.closerMu.Lock()
- s.closer = &closer{
- grpcServer: grpcServer,
- }
- s.closerMu.Unlock()
- turbodprotocol.RegisterTurbodServer(grpcServer, s)
-}
-
-// NotifyOutputsWritten implements the NotifyOutputsWritten rpc from turbo.proto
-func (s *Server) NotifyOutputsWritten(ctx context.Context, req *turbodprotocol.NotifyOutputsWrittenRequest) (*turbodprotocol.NotifyOutputsWrittenResponse, error) {
- outputs := fs.TaskOutputs{
- Inclusions: req.OutputGlobs,
- Exclusions: req.OutputExclusionGlobs,
- }
-
- err := s.globWatcher.WatchGlobs(req.Hash, outputs)
- if err != nil {
- return nil, err
- }
- return &turbodprotocol.NotifyOutputsWrittenResponse{}, nil
-}
-
-// GetChangedOutputs implements the GetChangedOutputs rpc from turbo.proto
-func (s *Server) GetChangedOutputs(ctx context.Context, req *turbodprotocol.GetChangedOutputsRequest) (*turbodprotocol.GetChangedOutputsResponse, error) {
-
- changedGlobs, err := s.globWatcher.GetChangedGlobs(req.Hash, req.OutputGlobs)
- if err != nil {
- return nil, err
- }
- return &turbodprotocol.GetChangedOutputsResponse{
- ChangedOutputGlobs: changedGlobs,
- }, nil
-}
-
-// Hello implements the Hello rpc from turbo.proto
-func (s *Server) Hello(ctx context.Context, req *turbodprotocol.HelloRequest) (*turbodprotocol.HelloResponse, error) {
- clientVersion := req.Version
- if clientVersion != s.turboVersion {
- err := status.Errorf(codes.FailedPrecondition, "version mismatch. Client %v Server %v", clientVersion, s.turboVersion)
- return nil, err
- }
- return &turbodprotocol.HelloResponse{}, nil
-}
-
-// Shutdown implements the Shutdown rpc from turbo.proto
-func (s *Server) Shutdown(ctx context.Context, req *turbodprotocol.ShutdownRequest) (*turbodprotocol.ShutdownResponse, error) {
- if s.tryClose() {
- return &turbodprotocol.ShutdownResponse{}, nil
- }
- err := status.Error(codes.NotFound, "shutdown mechanism not found")
- return nil, err
-}
-
-// Status implements the Status rpc from turbo.proto
-func (s *Server) Status(ctx context.Context, req *turbodprotocol.StatusRequest) (*turbodprotocol.StatusResponse, error) {
- uptime := uint64(time.Since(s.started).Milliseconds())
- return &turbodprotocol.StatusResponse{
- DaemonStatus: &turbodprotocol.DaemonStatus{
- LogFile: s.logFilePath.ToString(),
- UptimeMsec: uptime,
- },
- }, nil
-}
diff --git a/cli/internal/server/server_test.go b/cli/internal/server/server_test.go
deleted file mode 100644
index b7dcf3a..0000000
--- a/cli/internal/server/server_test.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package server
-
-import (
- "context"
- "testing"
- "time"
-
- "github.com/hashicorp/go-hclog"
- "google.golang.org/grpc"
- "gotest.tools/v3/assert"
-
- turbofs "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbodprotocol"
-)
-
-type mockGrpc struct {
- stopped chan struct{}
-}
-
-func (m *mockGrpc) GracefulStop() {
- close(m.stopped)
-}
-
-func (m *mockGrpc) RegisterService(desc *grpc.ServiceDesc, impl interface{}) {}
-
-func TestDeleteRepoRoot(t *testing.T) {
- logger := hclog.Default()
- logger.SetLevel(hclog.Debug)
- repoRootRaw := t.TempDir()
- repoRoot := turbofs.AbsoluteSystemPathFromUpstream(repoRootRaw)
-
- grpcServer := &mockGrpc{
- stopped: make(chan struct{}),
- }
-
- s, err := New("testServer", logger, repoRoot, "some-version", "/log/file/path")
- assert.NilError(t, err, "New")
- s.Register(grpcServer)
-
- // Delete the repo root, ensure that GracefulStop got called
- err = repoRoot.Remove()
- assert.NilError(t, err, "Remove")
-
- select {
- case <-grpcServer.stopped:
- case <-time.After(2 * time.Second):
- t.Error("timed out waiting for graceful stop to be called")
- }
-}
-
-func TestShutdown(t *testing.T) {
- logger := hclog.Default()
- repoRootRaw := t.TempDir()
- repoRoot := turbofs.AbsoluteSystemPathFromUpstream(repoRootRaw)
-
- grpcServer := &mockGrpc{
- stopped: make(chan struct{}),
- }
-
- s, err := New("testServer", logger, repoRoot, "some-version", "/log/file/path")
- assert.NilError(t, err, "New")
- s.Register(grpcServer)
-
- ctx := context.Background()
- _, err = s.Shutdown(ctx, &turbodprotocol.ShutdownRequest{})
- assert.NilError(t, err, "Shutdown")
- // Ensure that graceful stop gets called
- select {
- case <-grpcServer.stopped:
- case <-time.After(2 * time.Second):
- t.Error("timed out waiting for graceful stop to be called")
- }
-}
diff --git a/cli/internal/signals/signals.go b/cli/internal/signals/signals.go
deleted file mode 100644
index 8634144..0000000
--- a/cli/internal/signals/signals.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package signals
-
-import (
- "os"
- "os/signal"
- "sync"
- "syscall"
-)
-
-// Watcher watches for signals delivered to this process and provides
-// the opportunity for turbo to run cleanup
-type Watcher struct {
- doneCh chan struct{}
- closed bool
- mu sync.Mutex
- closers []func()
-}
-
-// AddOnClose registers a cleanup handler to run when a signal is received
-func (w *Watcher) AddOnClose(closer func()) {
- w.mu.Lock()
- defer w.mu.Unlock()
- w.closers = append(w.closers, closer)
-}
-
-// Close runs the cleanup handlers registered with this watcher
-func (w *Watcher) Close() {
- w.mu.Lock()
- defer w.mu.Unlock()
- if w.closed {
- return
- }
- w.closed = true
- for _, closer := range w.closers {
- closer()
- }
- w.closers = nil
- close(w.doneCh)
-}
-
-// Done returns a channel that will be closed after all of the cleanup
-// handlers have been run.
-func (w *Watcher) Done() <-chan struct{} {
- return w.doneCh
-}
-
-// NewWatcher returns a new Watcher instance for watching signals.
-func NewWatcher() *Watcher {
- // TODO: platform specific signals to watch for?
- signalCh := make(chan os.Signal, 1)
- signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
- w := &Watcher{
- doneCh: make(chan struct{}),
- }
- go func() {
- <-signalCh
- w.Close()
- }()
- return w
-}
diff --git a/cli/internal/spinner/spinner.go b/cli/internal/spinner/spinner.go
deleted file mode 100644
index 8ce6b4a..0000000
--- a/cli/internal/spinner/spinner.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package spinner
-
-import (
- "context"
- "fmt"
- "io"
- "time"
-
- "github.com/mitchellh/cli"
- progressbar "github.com/schollz/progressbar/v3"
- "github.com/vercel/turbo/cli/internal/ui"
-)
-
-// getWriterAndColor unwraps cli.Ui instances until it gets to a BasicUi.
-// If it happens to spot a ColoredUi along the way, it marks that color is
-// enabled.
-func getWriterAndColor(terminal cli.Ui, useColor bool) (io.Writer, bool) {
- switch terminal := terminal.(type) {
- case *cli.BasicUi:
- return terminal.Writer, useColor
- case *cli.ColoredUi:
- return getWriterAndColor(terminal.Ui, true)
- case *cli.ConcurrentUi:
- return getWriterAndColor(terminal.Ui, useColor)
- case *cli.PrefixedUi:
- return getWriterAndColor(terminal.Ui, useColor)
- case *cli.MockUi:
- return terminal.OutputWriter, false
- default:
- panic(fmt.Sprintf("unknown Ui: %v", terminal))
- }
-}
-
-// WaitFor runs fn, and prints msg to the terminal if it takes longer
-// than initialDelay to complete. Depending on the terminal configuration, it may
-// display a single instance of msg, or an infinite spinner, updated every 250ms.
-func WaitFor(ctx context.Context, fn func(), terminal cli.Ui, msg string, initialDelay time.Duration) error {
- doneCh := make(chan struct{})
- go func() {
- fn()
- close(doneCh)
- }()
- if ui.IsTTY {
- select {
- case <-ctx.Done():
- return nil
- case <-time.After(initialDelay):
- writer, useColor := getWriterAndColor(terminal, false)
- bar := progressbar.NewOptions(
- -1,
- progressbar.OptionEnableColorCodes(useColor),
- progressbar.OptionSetDescription(fmt.Sprintf("[yellow]%v[reset]", msg)),
- progressbar.OptionSpinnerType(14),
- progressbar.OptionSetWriter(writer),
- )
- for {
- select {
- case <-doneCh:
- err := bar.Finish()
- terminal.Output("")
- return err
- case <-time.After(250 * time.Millisecond):
- if err := bar.Add(1); err != nil {
- return err
- }
- case <-ctx.Done():
- return nil
- }
- }
- case <-doneCh:
- return nil
- }
- } else {
- // wait for the timeout before displaying a message, even with no tty
- select {
- case <-ctx.Done():
- return nil
- case <-doneCh:
- return nil
- case <-time.After(initialDelay):
- terminal.Output(msg)
- }
- select {
- case <-ctx.Done():
- case <-doneCh:
- }
- return nil
- }
-}
diff --git a/cli/internal/tarpatch/tar.go b/cli/internal/tarpatch/tar.go
deleted file mode 100644
index a4dab23..0000000
--- a/cli/internal/tarpatch/tar.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Adapted from https://github.com/moby/moby/blob/924edb948c2731df3b77697a8fcc85da3f6eef57/pkg/archive/archive.go
-// Copyright Docker, Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-// Package tarpatch addresses an issue with stdlib throwing an error in some environments.
-package tarpatch
-
-import (
- "archive/tar"
- "io/fs"
- "os"
- "strings"
- "time"
-
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-// nosysFileInfo hides the system-dependent info of the wrapped FileInfo to
-// prevent tar.FileInfoHeader from introspecting it and potentially calling into
-// glibc.
-type nosysFileInfo struct {
- os.FileInfo
-}
-
-func (fi nosysFileInfo) Sys() interface{} {
- // A Sys value of type *tar.Header is safe as it is system-independent.
- // The tar.FileInfoHeader function copies the fields into the returned
- // header without performing any OS lookups.
- if sys, ok := fi.FileInfo.Sys().(*tar.Header); ok {
- return sys
- }
- return nil
-}
-
-// FileInfoHeaderNoLookups creates a partially-populated tar.Header from fi.
-//
-// Compared to the archive/tar.FileInfoHeader function, this function is safe to
-// call from a chrooted process as it does not populate fields which would
-// require operating system lookups. It behaves identically to
-// tar.FileInfoHeader when fi is a FileInfo value returned from
-// tar.Header.FileInfo().
-//
-// When fi is a FileInfo for a native file, such as returned from os.Stat() and
-// os.Lstat(), the returned Header value differs from one returned from
-// tar.FileInfoHeader in the following ways. The Uname and Gname fields are not
-// set as OS lookups would be required to populate them. The AccessTime and
-// ChangeTime fields are not currently set (not yet implemented) although that
-// is subject to change. Callers which require the AccessTime or ChangeTime
-// fields to be zeroed should explicitly zero them out in the returned Header
-// value to avoid any compatibility issues in the future.
-func FileInfoHeaderNoLookups(fi fs.FileInfo, link string) (*tar.Header, error) {
- hdr, err := tar.FileInfoHeader(nosysFileInfo{fi}, link)
- if err != nil {
- return nil, err
- }
- return hdr, sysStat(fi, hdr)
-}
-
-// FileInfoHeader creates a populated Header from fi.
-//
-// Compared to the archive/tar package, this function fills in less information
-// but is safe to call from a chrooted process. The AccessTime and ChangeTime
-// fields are not set in the returned header, ModTime is truncated to one-second
-// precision, and the Uname and Gname fields are only set when fi is a FileInfo
-// value returned from tar.Header.FileInfo().
-func FileInfoHeader(fullPath turbopath.AnchoredUnixPath, fileInfo fs.FileInfo, link string) (*tar.Header, error) {
- hdr, err := FileInfoHeaderNoLookups(fileInfo, link)
- if err != nil {
- return nil, err
- }
- hdr.Format = tar.FormatPAX
- hdr.ModTime = hdr.ModTime.Truncate(time.Second)
- hdr.AccessTime = time.Time{}
- hdr.ChangeTime = time.Time{}
- hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
- hdr.Name = canonicalTarName(fullPath, fileInfo.IsDir())
- return hdr, nil
-}
-
-// canonicalTarName provides a platform-independent and consistent posix-style
-// path for files and directories to be archived regardless of the platform.
-func canonicalTarName(fullPath turbopath.AnchoredUnixPath, isDir bool) string {
- nameString := fullPath.ToString()
- if isDir {
- // Append '/' if not already present.
- if !strings.HasSuffix(nameString, "/") {
- nameString += "/"
- }
- }
-
- return nameString
-}
diff --git a/cli/internal/tarpatch/tar_unix.go b/cli/internal/tarpatch/tar_unix.go
deleted file mode 100644
index 3020c0e..0000000
--- a/cli/internal/tarpatch/tar_unix.go
+++ /dev/null
@@ -1,42 +0,0 @@
-//go:build !windows
-// +build !windows
-
-// Adapted from https://github.com/moby/moby/blob/924edb948c2731df3b77697a8fcc85da3f6eef57/pkg/archive/archive_unix.go
-// Copyright Docker, Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-package tarpatch
-
-import (
- "archive/tar"
- "os"
- "syscall"
-
- "golang.org/x/sys/unix"
-)
-
-// chmodTarEntry is used to adjust the file permissions used in tar header based
-// on the platform the archival is done.
-func chmodTarEntry(perm os.FileMode) os.FileMode {
- return perm // noop for unix as golang APIs provide perm bits correctly
-}
-
-// sysStat populates hdr from system-dependent fields of fi without performing
-// any OS lookups.
-func sysStat(fi os.FileInfo, hdr *tar.Header) error {
- s, ok := fi.Sys().(*syscall.Stat_t)
- if !ok {
- return nil
- }
-
- hdr.Uid = int(s.Uid)
- hdr.Gid = int(s.Gid)
-
- if s.Mode&unix.S_IFBLK != 0 ||
- s.Mode&unix.S_IFCHR != 0 {
- hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert
- hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert
- }
-
- return nil
-}
diff --git a/cli/internal/tarpatch/tar_windows.go b/cli/internal/tarpatch/tar_windows.go
deleted file mode 100644
index 486e6fd..0000000
--- a/cli/internal/tarpatch/tar_windows.go
+++ /dev/null
@@ -1,27 +0,0 @@
-//go:build windows
-// +build windows
-
-// Adapted from https://github.com/moby/moby/blob/924edb948c2731df3b77697a8fcc85da3f6eef57/pkg/archive/archive_windows.go
-// Copyright Docker, Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-package tarpatch
-
-import (
- "archive/tar"
- "os"
-)
-
-// chmodTarEntry is used to adjust the file permissions used in tar header based
-// on the platform the archival is done.
-func chmodTarEntry(perm os.FileMode) os.FileMode {
- // Remove group- and world-writable bits.
- perm &= 0o755
-
- // Add the x bit: make everything +x on Windows
- return perm | 0o111
-}
-
-func sysStat(fi os.FileInfo, hdr *tar.Header) error {
- return nil
-}
diff --git a/cli/internal/taskhash/taskhash.go b/cli/internal/taskhash/taskhash.go
deleted file mode 100644
index a912ad9..0000000
--- a/cli/internal/taskhash/taskhash.go
+++ /dev/null
@@ -1,497 +0,0 @@
-// Package taskhash handles calculating dependency hashes for nodes in the task execution graph.
-package taskhash
-
-import (
- "fmt"
- "sort"
- "strings"
- "sync"
-
- "github.com/hashicorp/go-hclog"
- "github.com/pyr-sh/dag"
- gitignore "github.com/sabhiram/go-gitignore"
- "github.com/vercel/turbo/cli/internal/doublestar"
- "github.com/vercel/turbo/cli/internal/env"
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/hashing"
- "github.com/vercel/turbo/cli/internal/inference"
- "github.com/vercel/turbo/cli/internal/nodes"
- "github.com/vercel/turbo/cli/internal/runsummary"
- "github.com/vercel/turbo/cli/internal/turbopath"
- "github.com/vercel/turbo/cli/internal/util"
- "github.com/vercel/turbo/cli/internal/workspace"
- "golang.org/x/sync/errgroup"
-)
-
-// Tracker caches package-inputs hashes, as well as package-task hashes.
-// package-inputs hashes must be calculated before package-task hashes,
-// and package-task hashes must be calculated in topographical order.
-// package-task hashing is threadsafe, provided topographical order is
-// respected.
-type Tracker struct {
- rootNode string
- globalHash string
- pipeline fs.Pipeline
-
- packageInputsHashes packageFileHashes
-
- // packageInputsExpandedHashes is a map of a hashkey to a list of files that are inputs to the task.
- // Writes to this map happen during CalculateFileHash(). Since this happens synchronously
- // before walking the task graph, it does not need to be protected by a mutex.
- packageInputsExpandedHashes map[packageFileHashKey]map[turbopath.AnchoredUnixPath]string
-
- // mu is a mutex that we can lock/unlock to read/write from maps
- // the fields below should be protected by the mutex.
- mu sync.RWMutex
- packageTaskEnvVars map[string]env.DetailedMap // taskId -> envvar pairs that affect the hash.
- packageTaskHashes map[string]string // taskID -> hash
- packageTaskFramework map[string]string // taskID -> inferred framework for package
- packageTaskOutputs map[string][]turbopath.AnchoredSystemPath
- packageTaskCacheStatus map[string]runsummary.TaskCacheSummary
-}
-
-// NewTracker creates a tracker for package-inputs combinations and package-task combinations.
-func NewTracker(rootNode string, globalHash string, pipeline fs.Pipeline) *Tracker {
- return &Tracker{
- rootNode: rootNode,
- globalHash: globalHash,
- pipeline: pipeline,
- packageTaskHashes: make(map[string]string),
- packageTaskFramework: make(map[string]string),
- packageTaskEnvVars: make(map[string]env.DetailedMap),
- packageTaskOutputs: make(map[string][]turbopath.AnchoredSystemPath),
- packageTaskCacheStatus: make(map[string]runsummary.TaskCacheSummary),
- }
-}
-
-// packageFileSpec defines a combination of a package and optional set of input globs
-type packageFileSpec struct {
- pkg string
- inputs []string
-}
-
-func specFromPackageTask(packageTask *nodes.PackageTask) packageFileSpec {
- return packageFileSpec{
- pkg: packageTask.PackageName,
- inputs: packageTask.TaskDefinition.Inputs,
- }
-}
-
-// packageFileHashKey is a hashable representation of a packageFileSpec.
-type packageFileHashKey string
-
-// hashes the inputs for a packageTask
-func (pfs packageFileSpec) ToKey() packageFileHashKey {
- sort.Strings(pfs.inputs)
- return packageFileHashKey(fmt.Sprintf("%v#%v", pfs.pkg, strings.Join(pfs.inputs, "!")))
-}
-
-func safeCompileIgnoreFile(filepath string) (*gitignore.GitIgnore, error) {
- if fs.FileExists(filepath) {
- return gitignore.CompileIgnoreFile(filepath)
- }
- // no op
- return gitignore.CompileIgnoreLines([]string{}...), nil
-}
-
-func (pfs *packageFileSpec) getHashObject(pkg *fs.PackageJSON, repoRoot turbopath.AbsoluteSystemPath) map[turbopath.AnchoredUnixPath]string {
- hashObject, pkgDepsErr := hashing.GetPackageDeps(repoRoot, &hashing.PackageDepsOptions{
- PackagePath: pkg.Dir,
- InputPatterns: pfs.inputs,
- })
- if pkgDepsErr != nil {
- manualHashObject, err := manuallyHashPackage(pkg, pfs.inputs, repoRoot)
- if err != nil {
- return make(map[turbopath.AnchoredUnixPath]string)
- }
- hashObject = manualHashObject
- }
-
- return hashObject
-}
-
-func (pfs *packageFileSpec) hash(hashObject map[turbopath.AnchoredUnixPath]string) (string, error) {
- hashOfFiles, otherErr := fs.HashObject(hashObject)
- if otherErr != nil {
- return "", otherErr
- }
- return hashOfFiles, nil
-}
-
-func manuallyHashPackage(pkg *fs.PackageJSON, inputs []string, rootPath turbopath.AbsoluteSystemPath) (map[turbopath.AnchoredUnixPath]string, error) {
- hashObject := make(map[turbopath.AnchoredUnixPath]string)
- // Instead of implementing all gitignore properly, we hack it. We only respect .gitignore in the root and in
- // the directory of a package.
- ignore, err := safeCompileIgnoreFile(rootPath.UntypedJoin(".gitignore").ToString())
- if err != nil {
- return nil, err
- }
-
- ignorePkg, err := safeCompileIgnoreFile(rootPath.UntypedJoin(pkg.Dir.ToStringDuringMigration(), ".gitignore").ToString())
- if err != nil {
- return nil, err
- }
-
- pathPrefix := rootPath.UntypedJoin(pkg.Dir.ToStringDuringMigration())
- includePattern := ""
- excludePattern := ""
- if len(inputs) > 0 {
- var includePatterns []string
- var excludePatterns []string
- for _, pattern := range inputs {
- if len(pattern) > 0 && pattern[0] == '!' {
- excludePatterns = append(excludePatterns, pathPrefix.UntypedJoin(pattern[1:]).ToString())
- } else {
- includePatterns = append(includePatterns, pathPrefix.UntypedJoin(pattern).ToString())
- }
- }
- if len(includePatterns) > 0 {
- includePattern = "{" + strings.Join(includePatterns, ",") + "}"
- }
- if len(excludePatterns) > 0 {
- excludePattern = "{" + strings.Join(excludePatterns, ",") + "}"
- }
- }
-
- err = fs.Walk(pathPrefix.ToStringDuringMigration(), func(name string, isDir bool) error {
- convertedName := turbopath.AbsoluteSystemPathFromUpstream(name)
- rootMatch := ignore.MatchesPath(convertedName.ToString())
- otherMatch := ignorePkg.MatchesPath(convertedName.ToString())
- if !rootMatch && !otherMatch {
- if !isDir {
- if includePattern != "" {
- val, err := doublestar.PathMatch(includePattern, convertedName.ToString())
- if err != nil {
- return err
- }
- if !val {
- return nil
- }
- }
- if excludePattern != "" {
- val, err := doublestar.PathMatch(excludePattern, convertedName.ToString())
- if err != nil {
- return err
- }
- if val {
- return nil
- }
- }
- hash, err := fs.GitLikeHashFile(convertedName.ToString())
- if err != nil {
- return fmt.Errorf("could not hash file %v. \n%w", convertedName.ToString(), err)
- }
-
- relativePath, err := convertedName.RelativeTo(pathPrefix)
- if err != nil {
- return fmt.Errorf("File path cannot be made relative: %w", err)
- }
- hashObject[relativePath.ToUnixPath()] = hash
- }
- }
- return nil
- })
- if err != nil {
- return nil, err
- }
- return hashObject, nil
-}
-
-// packageFileHashes is a map from a package and optional input globs to the hash of
-// the matched files in the package.
-type packageFileHashes map[packageFileHashKey]string
-
-// CalculateFileHashes hashes each unique package-inputs combination that is present
-// in the task graph. Must be called before calculating task hashes.
-func (th *Tracker) CalculateFileHashes(
- allTasks []dag.Vertex,
- workerCount int,
- workspaceInfos workspace.Catalog,
- taskDefinitions map[string]*fs.TaskDefinition,
- repoRoot turbopath.AbsoluteSystemPath,
-) error {
- hashTasks := make(util.Set)
-
- for _, v := range allTasks {
- taskID, ok := v.(string)
- if !ok {
- return fmt.Errorf("unknown task %v", taskID)
- }
- if taskID == th.rootNode {
- continue
- }
- pkgName, _ := util.GetPackageTaskFromId(taskID)
- if pkgName == th.rootNode {
- continue
- }
-
- taskDefinition, ok := taskDefinitions[taskID]
- if !ok {
- return fmt.Errorf("missing pipeline entry %v", taskID)
- }
-
- pfs := &packageFileSpec{
- pkg: pkgName,
- inputs: taskDefinition.Inputs,
- }
-
- hashTasks.Add(pfs)
- }
-
- hashes := make(map[packageFileHashKey]string, len(hashTasks))
- hashObjects := make(map[packageFileHashKey]map[turbopath.AnchoredUnixPath]string, len(hashTasks))
- hashQueue := make(chan *packageFileSpec, workerCount)
- hashErrs := &errgroup.Group{}
-
- for i := 0; i < workerCount; i++ {
- hashErrs.Go(func() error {
- for packageFileSpec := range hashQueue {
- pkg, ok := workspaceInfos.PackageJSONs[packageFileSpec.pkg]
- if !ok {
- return fmt.Errorf("cannot find package %v", packageFileSpec.pkg)
- }
- hashObject := packageFileSpec.getHashObject(pkg, repoRoot)
- hash, err := packageFileSpec.hash(hashObject)
- if err != nil {
- return err
- }
- th.mu.Lock()
- pfsKey := packageFileSpec.ToKey()
- hashes[pfsKey] = hash
- hashObjects[pfsKey] = hashObject
- th.mu.Unlock()
- }
- return nil
- })
- }
- for ht := range hashTasks {
- hashQueue <- ht.(*packageFileSpec)
- }
- close(hashQueue)
- err := hashErrs.Wait()
- if err != nil {
- return err
- }
- th.packageInputsHashes = hashes
- th.packageInputsExpandedHashes = hashObjects
- return nil
-}
-
-type taskHashable struct {
- packageDir turbopath.AnchoredUnixPath
- hashOfFiles string
- externalDepsHash string
- task string
- outputs fs.TaskOutputs
- passThruArgs []string
- envMode util.EnvMode
- passthroughEnv []string
- hashableEnvPairs []string
- globalHash string
- taskDependencyHashes []string
-}
-
-type oldTaskHashable struct {
- packageDir turbopath.AnchoredUnixPath
- hashOfFiles string
- externalDepsHash string
- task string
- outputs fs.TaskOutputs
- passThruArgs []string
- hashableEnvPairs []string
- globalHash string
- taskDependencyHashes []string
-}
-
-// calculateTaskHashFromHashable returns a hash string from the taskHashable
-func calculateTaskHashFromHashable(full *taskHashable, useOldTaskHashable bool) (string, error) {
- // The user is not using the strict environment variables feature.
- if useOldTaskHashable {
- return fs.HashObject(&oldTaskHashable{
- packageDir: full.packageDir,
- hashOfFiles: full.hashOfFiles,
- externalDepsHash: full.externalDepsHash,
- task: full.task,
- outputs: full.outputs,
- passThruArgs: full.passThruArgs,
- hashableEnvPairs: full.hashableEnvPairs,
- globalHash: full.globalHash,
- taskDependencyHashes: full.taskDependencyHashes,
- })
- }
-
- switch full.envMode {
- case util.Loose:
- // Remove the passthroughs from hash consideration if we're explicitly loose.
- full.passthroughEnv = nil
- return fs.HashObject(full)
- case util.Strict:
- // Collapse `nil` and `[]` in strict mode.
- if full.passthroughEnv == nil {
- full.passthroughEnv = make([]string, 0)
- }
- return fs.HashObject(full)
- case util.Infer:
- panic("task inferred status should have already been resolved")
- default:
- panic("unimplemented environment mode")
- }
-}
-
-func (th *Tracker) calculateDependencyHashes(dependencySet dag.Set) ([]string, error) {
- dependencyHashSet := make(util.Set)
-
- rootPrefix := th.rootNode + util.TaskDelimiter
- th.mu.RLock()
- defer th.mu.RUnlock()
- for _, dependency := range dependencySet {
- if dependency == th.rootNode {
- continue
- }
- dependencyTask, ok := dependency.(string)
- if !ok {
- return nil, fmt.Errorf("unknown task: %v", dependency)
- }
- if strings.HasPrefix(dependencyTask, rootPrefix) {
- continue
- }
- dependencyHash, ok := th.packageTaskHashes[dependencyTask]
- if !ok {
- return nil, fmt.Errorf("missing hash for dependent task: %v", dependencyTask)
- }
- dependencyHashSet.Add(dependencyHash)
- }
- dependenciesHashList := dependencyHashSet.UnsafeListOfStrings()
- sort.Strings(dependenciesHashList)
- return dependenciesHashList, nil
-}
-
-// CalculateTaskHash calculates the hash for package-task combination. It is threadsafe, provided
-// that it has previously been called on its task-graph dependencies. File hashes must be calculated
-// first.
-func (th *Tracker) CalculateTaskHash(packageTask *nodes.PackageTask, dependencySet dag.Set, logger hclog.Logger, args []string, useOldTaskHashable bool) (string, error) {
- pfs := specFromPackageTask(packageTask)
- pkgFileHashKey := pfs.ToKey()
-
- hashOfFiles, ok := th.packageInputsHashes[pkgFileHashKey]
- if !ok {
- return "", fmt.Errorf("cannot find package-file hash for %v", pkgFileHashKey)
- }
-
- var keyMatchers []string
- framework := inference.InferFramework(packageTask.Pkg)
- if framework != nil && framework.EnvMatcher != "" {
- // log auto detected framework and env prefix
- logger.Debug(fmt.Sprintf("auto detected framework for %s", packageTask.PackageName), "framework", framework.Slug, "env_prefix", framework.EnvMatcher)
- keyMatchers = append(keyMatchers, framework.EnvMatcher)
- }
-
- envVars, err := env.GetHashableEnvVars(
- packageTask.TaskDefinition.EnvVarDependencies,
- keyMatchers,
- "TURBO_CI_VENDOR_ENV_KEY",
- )
- if err != nil {
- return "", err
- }
- hashableEnvPairs := envVars.All.ToHashable()
- outputs := packageTask.HashableOutputs()
- taskDependencyHashes, err := th.calculateDependencyHashes(dependencySet)
- if err != nil {
- return "", err
- }
- // log any auto detected env vars
- logger.Debug(fmt.Sprintf("task hash env vars for %s:%s", packageTask.PackageName, packageTask.Task), "vars", hashableEnvPairs)
-
- hash, err := calculateTaskHashFromHashable(&taskHashable{
- packageDir: packageTask.Pkg.Dir.ToUnixPath(),
- hashOfFiles: hashOfFiles,
- externalDepsHash: packageTask.Pkg.ExternalDepsHash,
- task: packageTask.Task,
- outputs: outputs.Sort(),
- passThruArgs: args,
- envMode: packageTask.EnvMode,
- passthroughEnv: packageTask.TaskDefinition.PassthroughEnv,
- hashableEnvPairs: hashableEnvPairs,
- globalHash: th.globalHash,
- taskDependencyHashes: taskDependencyHashes,
- }, useOldTaskHashable)
- if err != nil {
- return "", fmt.Errorf("failed to hash task %v: %v", packageTask.TaskID, hash)
- }
- th.mu.Lock()
- th.packageTaskEnvVars[packageTask.TaskID] = envVars
- th.packageTaskHashes[packageTask.TaskID] = hash
- if framework != nil {
- th.packageTaskFramework[packageTask.TaskID] = framework.Slug
- }
- th.mu.Unlock()
- return hash, nil
-}
-
-// GetExpandedInputs gets the expanded set of inputs for a given PackageTask
-func (th *Tracker) GetExpandedInputs(packageTask *nodes.PackageTask) map[turbopath.AnchoredUnixPath]string {
- pfs := specFromPackageTask(packageTask)
- expandedInputs := th.packageInputsExpandedHashes[pfs.ToKey()]
- inputsCopy := make(map[turbopath.AnchoredUnixPath]string, len(expandedInputs))
-
- for path, hash := range expandedInputs {
- inputsCopy[path] = hash
- }
-
- return inputsCopy
-}
-
-// GetEnvVars returns the hashed env vars for a given taskID
-func (th *Tracker) GetEnvVars(taskID string) env.DetailedMap {
- th.mu.RLock()
- defer th.mu.RUnlock()
- return th.packageTaskEnvVars[taskID]
-}
-
-// GetFramework returns the inferred framework for a given taskID
-func (th *Tracker) GetFramework(taskID string) string {
- th.mu.RLock()
- defer th.mu.RUnlock()
- return th.packageTaskFramework[taskID]
-}
-
-// GetExpandedOutputs returns a list of outputs for a given taskID
-func (th *Tracker) GetExpandedOutputs(taskID string) []turbopath.AnchoredSystemPath {
- th.mu.RLock()
- defer th.mu.RUnlock()
- outputs, ok := th.packageTaskOutputs[taskID]
-
- if !ok {
- return []turbopath.AnchoredSystemPath{}
- }
-
- return outputs
-}
-
-// SetExpandedOutputs a list of outputs for a given taskID so it can be read later
-func (th *Tracker) SetExpandedOutputs(taskID string, outputs []turbopath.AnchoredSystemPath) {
- th.mu.Lock()
- defer th.mu.Unlock()
- th.packageTaskOutputs[taskID] = outputs
-}
-
-// SetCacheStatus records the task status for the given taskID
-func (th *Tracker) SetCacheStatus(taskID string, cacheSummary runsummary.TaskCacheSummary) {
- th.mu.Lock()
- defer th.mu.Unlock()
- th.packageTaskCacheStatus[taskID] = cacheSummary
-}
-
-// GetCacheStatus records the task status for the given taskID
-func (th *Tracker) GetCacheStatus(taskID string) runsummary.TaskCacheSummary {
- th.mu.Lock()
- defer th.mu.Unlock()
-
- if status, ok := th.packageTaskCacheStatus[taskID]; ok {
- return status
- }
-
- // Return an empty one, all the fields will be false and 0
- return runsummary.TaskCacheSummary{}
-}
diff --git a/cli/internal/taskhash/taskhash_test.go b/cli/internal/taskhash/taskhash_test.go
deleted file mode 100644
index dea0010..0000000
--- a/cli/internal/taskhash/taskhash_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package taskhash
-
-import (
- "path/filepath"
- "strings"
- "testing"
-
- "github.com/vercel/turbo/cli/internal/fs"
- "github.com/vercel/turbo/cli/internal/turbopath"
-)
-
-func Test_manuallyHashPackage(t *testing.T) {
- rootIgnore := strings.Join([]string{
- "ignoreme",
- "ignorethisdir/",
- }, "\n")
- pkgIgnore := strings.Join([]string{
- "pkgignoreme",
- "pkgignorethisdir/",
- }, "\n")
- root := t.TempDir()
- repoRoot := turbopath.AbsoluteSystemPathFromUpstream(root)
- pkgName := turbopath.AnchoredUnixPath("child-dir/libA").ToSystemPath()
- type fileHash struct {
- contents string
- hash string
- }
- files := map[turbopath.AnchoredUnixPath]fileHash{
- "top-level-file": {"top-level-file-contents", ""},
- "other-dir/other-dir-file": {"other-dir-file-contents", ""},
- "ignoreme": {"anything", ""},
- "child-dir/libA/some-file": {"some-file-contents", "7e59c6a6ea9098c6d3beb00e753e2c54ea502311"},
- "child-dir/libA/some-dir/other-file": {"some-file-contents", "7e59c6a6ea9098c6d3beb00e753e2c54ea502311"},
- "child-dir/libA/some-dir/another-one": {"some-file-contents", "7e59c6a6ea9098c6d3beb00e753e2c54ea502311"},
- "child-dir/libA/some-dir/excluded-file": {"some-file-contents", "7e59c6a6ea9098c6d3beb00e753e2c54ea502311"},
- "child-dir/libA/ignoreme": {"anything", ""},
- "child-dir/libA/ignorethisdir/anything": {"anything", ""},
- "child-dir/libA/pkgignoreme": {"anything", ""},
- "child-dir/libA/pkgignorethisdir/file": {"anything", ""},
- }
-
- rootIgnoreFile, err := repoRoot.Join(".gitignore").Create()
- if err != nil {
- t.Fatalf("failed to create .gitignore: %v", err)
- }
- _, err = rootIgnoreFile.WriteString(rootIgnore)
- if err != nil {
- t.Fatalf("failed to write contents to .gitignore: %v", err)
- }
- rootIgnoreFile.Close()
- pkgIgnoreFilename := pkgName.RestoreAnchor(repoRoot).Join(".gitignore")
- err = pkgIgnoreFilename.EnsureDir()
- if err != nil {
- t.Fatalf("failed to ensure directories for %v: %v", pkgIgnoreFilename, err)
- }
- pkgIgnoreFile, err := pkgIgnoreFilename.Create()
- if err != nil {
- t.Fatalf("failed to create libA/.gitignore: %v", err)
- }
- _, err = pkgIgnoreFile.WriteString(pkgIgnore)
- if err != nil {
- t.Fatalf("failed to write contents to libA/.gitignore: %v", err)
- }
- pkgIgnoreFile.Close()
- for path, spec := range files {
- filename := path.ToSystemPath().RestoreAnchor(repoRoot)
- err = filename.EnsureDir()
- if err != nil {
- t.Fatalf("failed to ensure directories for %v: %v", filename, err)
- }
- f, err := filename.Create()
- if err != nil {
- t.Fatalf("failed to create file: %v: %v", filename, err)
- }
- _, err = f.WriteString(spec.contents)
- if err != nil {
- t.Fatalf("failed to write contents to %v: %v", filename, err)
- }
- f.Close()
- }
- // now that we've created the repo, expect our .gitignore file too
- files[turbopath.AnchoredUnixPath("child-dir/libA/.gitignore")] = fileHash{contents: "", hash: "3237694bc3312ded18386964a855074af7b066af"}
-
- pkg := &fs.PackageJSON{
- Dir: pkgName,
- }
- hashes, err := manuallyHashPackage(pkg, []string{}, repoRoot)
- if err != nil {
- t.Fatalf("failed to calculate manual hashes: %v", err)
- }
-
- count := 0
- for path, spec := range files {
- systemPath := path.ToSystemPath()
- if systemPath.HasPrefix(pkgName) {
- relPath := systemPath[len(pkgName)+1:]
- got, ok := hashes[relPath.ToUnixPath()]
- if !ok {
- if spec.hash != "" {
- t.Errorf("did not find hash for %v, but wanted one", path)
- }
- } else if got != spec.hash {
- t.Errorf("hash of %v, got %v want %v", path, got, spec.hash)
- } else {
- count++
- }
- }
- }
- if count != len(hashes) {
- t.Errorf("found extra hashes in %v", hashes)
- }
-
- count = 0
- justFileHashes, err := manuallyHashPackage(pkg, []string{filepath.FromSlash("**/*file"), "!" + filepath.FromSlash("some-dir/excluded-file")}, repoRoot)
- if err != nil {
- t.Fatalf("failed to calculate manual hashes: %v", err)
- }
- for path, spec := range files {
- systemPath := path.ToSystemPath()
- if systemPath.HasPrefix(pkgName) {
- shouldInclude := strings.HasSuffix(systemPath.ToString(), "file") && !strings.HasSuffix(systemPath.ToString(), "excluded-file")
- relPath := systemPath[len(pkgName)+1:]
- got, ok := justFileHashes[relPath.ToUnixPath()]
- if !ok && shouldInclude {
- if spec.hash != "" {
- t.Errorf("did not find hash for %v, but wanted one", path)
- }
- } else if shouldInclude && got != spec.hash {
- t.Errorf("hash of %v, got %v want %v", path, got, spec.hash)
- } else if shouldInclude {
- count++
- }
- }
- }
- if count != len(justFileHashes) {
- t.Errorf("found extra hashes in %v", hashes)
- }
-}
diff --git a/cli/internal/turbodprotocol/turbod.proto b/cli/internal/turbodprotocol/turbod.proto
deleted file mode 100644
index cf7c554..0000000
--- a/cli/internal/turbodprotocol/turbod.proto
+++ /dev/null
@@ -1,53 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/vercel/turbo/cli/internal/turbodprotocol";
-
-package turbodprotocol;
-
-service Turbod {
- rpc Hello (HelloRequest) returns (HelloResponse);
- rpc Shutdown (ShutdownRequest) returns (ShutdownResponse);
- rpc Status (StatusRequest) returns (StatusResponse);
- // Implement cache watching
- rpc NotifyOutputsWritten (NotifyOutputsWrittenRequest) returns (NotifyOutputsWrittenResponse);
- rpc GetChangedOutputs (GetChangedOutputsRequest) returns (GetChangedOutputsResponse);
-}
-
-message HelloRequest {
- string version = 1;
- string session_id = 2;
-}
-
-message HelloResponse {}
-
-message ShutdownRequest {}
-
-message ShutdownResponse {}
-
-message StatusRequest {}
-
-message StatusResponse {
- DaemonStatus daemonStatus = 1;
-}
-
-message NotifyOutputsWrittenRequest {
- repeated string output_globs = 1;
- string hash = 2;
- repeated string output_exclusion_globs = 3;
-}
-
-message NotifyOutputsWrittenResponse {}
-
-message GetChangedOutputsRequest {
- repeated string output_globs = 1;
- string hash = 2;
-}
-
-message GetChangedOutputsResponse {
- repeated string changed_output_globs = 1;
-}
-
-message DaemonStatus {
- string log_file = 1;
- uint64 uptime_msec = 2;
-}
diff --git a/cli/internal/turbopath/absolute_system_path.go b/cli/internal/turbopath/absolute_system_path.go
deleted file mode 100644
index df65827..0000000
--- a/cli/internal/turbopath/absolute_system_path.go
+++ /dev/null
@@ -1,258 +0,0 @@
-package turbopath
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-)
-
-// AbsoluteSystemPath is a root-relative path using system separators.
-type AbsoluteSystemPath string
-
-// _dirPermissions are the default permission bits we apply to directories.
-const _dirPermissions = os.ModeDir | 0775
-
-// _nonRelativeSentinel is the leading sentinel that indicates traversal.
-const _nonRelativeSentinel = ".."
-
-// ToString returns a string represenation of this Path.
-// Used for interfacing with APIs that require a string.
-func (p AbsoluteSystemPath) ToString() string {
- return string(p)
-}
-
-// RelativeTo calculates the relative path between two `AbsoluteSystemPath`s.
-func (p AbsoluteSystemPath) RelativeTo(basePath AbsoluteSystemPath) (AnchoredSystemPath, error) {
- processed, err := filepath.Rel(basePath.ToString(), p.ToString())
- return AnchoredSystemPath(processed), err
-}
-
-// Join appends relative path segments to this AbsoluteSystemPath.
-func (p AbsoluteSystemPath) Join(additional ...RelativeSystemPath) AbsoluteSystemPath {
- cast := RelativeSystemPathArray(additional)
- return AbsoluteSystemPath(filepath.Join(p.ToString(), filepath.Join(cast.ToStringArray()...)))
-}
-
-// ToStringDuringMigration returns a string representation of this path.
-// These instances should eventually be removed.
-func (p AbsoluteSystemPath) ToStringDuringMigration() string {
- return p.ToString()
-}
-
-// UntypedJoin is a Join that does not constrain the type of the arguments.
-// This enables you to pass in strings, but does not protect you from garbage in.
-func (p AbsoluteSystemPath) UntypedJoin(args ...string) AbsoluteSystemPath {
- return AbsoluteSystemPath(filepath.Join(p.ToString(), filepath.Join(args...)))
-}
-
-// Dir implements filepath.Dir() for an AbsoluteSystemPath
-func (p AbsoluteSystemPath) Dir() AbsoluteSystemPath {
- return AbsoluteSystemPath(filepath.Dir(p.ToString()))
-}
-
-// Mkdir implements os.Mkdir(p, perm)
-func (p AbsoluteSystemPath) Mkdir(perm os.FileMode) error {
- return os.Mkdir(p.ToString(), perm)
-}
-
-// MkdirAll implements os.MkdirAll(p, perm)
-func (p AbsoluteSystemPath) MkdirAll(perm os.FileMode) error {
- return os.MkdirAll(p.ToString(), perm)
-}
-
-// Open implements os.Open(p) for an AbsoluteSystemPath
-func (p AbsoluteSystemPath) Open() (*os.File, error) {
- return os.Open(p.ToString())
-}
-
-// OpenFile implements os.OpenFile for an absolute path
-func (p AbsoluteSystemPath) OpenFile(flags int, mode os.FileMode) (*os.File, error) {
- return os.OpenFile(p.ToString(), flags, mode)
-}
-
-// Lstat implements os.Lstat for absolute path
-func (p AbsoluteSystemPath) Lstat() (os.FileInfo, error) {
- return os.Lstat(p.ToString())
-}
-
-// Stat implements os.Stat for absolute path
-func (p AbsoluteSystemPath) Stat() (os.FileInfo, error) {
- return os.Stat(p.ToString())
-}
-
-// Findup checks all parent directories for a file.
-func (p AbsoluteSystemPath) Findup(name RelativeSystemPath) (AbsoluteSystemPath, error) {
- path, err := FindupFrom(name.ToString(), p.ToString())
-
- return AbsoluteSystemPath(path), err
-
-}
-
-// Exists returns true if the given path exists.
-func (p AbsoluteSystemPath) Exists() bool {
- _, err := p.Lstat()
- return err == nil
-}
-
-// DirExists returns true if the given path exists and is a directory.
-func (p AbsoluteSystemPath) DirExists() bool {
- info, err := p.Lstat()
- return err == nil && info.IsDir()
-}
-
-// FileExists returns true if the given path exists and is a file.
-func (p AbsoluteSystemPath) FileExists() bool {
- info, err := os.Lstat(p.ToString())
- return err == nil && !info.IsDir()
-}
-
-// ContainsPath returns true if this absolute path is a parent of the
-// argument.
-func (p AbsoluteSystemPath) ContainsPath(other AbsoluteSystemPath) (bool, error) {
- // In Go, filepath.Rel can return a path that starts with "../" or equivalent.
- // Checking filesystem-level contains can get extremely complicated
- // (see https://github.com/golang/dep/blob/f13583b555deaa6742f141a9c1185af947720d60/internal/fs/fs.go#L33)
- // As a compromise, rely on the stdlib to generate a relative path and then check
- // if the first step is "../".
- rel, err := filepath.Rel(p.ToString(), other.ToString())
- if err != nil {
- return false, err
- }
- return !strings.HasPrefix(rel, _nonRelativeSentinel), nil
-}
-
-// ReadFile reads the contents of the specified file
-func (p AbsoluteSystemPath) ReadFile() ([]byte, error) {
- return ioutil.ReadFile(p.ToString())
-}
-
-// VolumeName returns the volume of the specified path
-func (p AbsoluteSystemPath) VolumeName() string {
- return filepath.VolumeName(p.ToString())
-}
-
-// WriteFile writes the contents of the specified file
-func (p AbsoluteSystemPath) WriteFile(contents []byte, mode os.FileMode) error {
- return ioutil.WriteFile(p.ToString(), contents, mode)
-}
-
-// EnsureDir ensures that the directory containing this file exists
-func (p AbsoluteSystemPath) EnsureDir() error {
- dir := p.Dir()
- err := os.MkdirAll(dir.ToString(), _dirPermissions)
- if err != nil && dir.FileExists() {
- // It looks like this is a file and not a directory. Attempt to remove it; this can
- // happen in some cases if you change a rule from outputting a file to a directory.
- if err2 := dir.Remove(); err2 == nil {
- err = os.MkdirAll(dir.ToString(), _dirPermissions)
- } else {
- return err
- }
- }
- return err
-}
-
-// MkdirAllMode Create directory at path and all necessary parents ensuring that path has the correct mode set
-func (p AbsoluteSystemPath) MkdirAllMode(mode os.FileMode) error {
- info, err := p.Lstat()
- if err == nil {
- if info.IsDir() && info.Mode() == mode {
- // Dir exists with the correct mode
- return nil
- } else if info.IsDir() {
- // Dir exists with incorrect mode
- return os.Chmod(p.ToString(), mode)
- } else {
- // Path exists as file, remove it
- if err := p.Remove(); err != nil {
- return err
- }
- }
- }
- if err := os.MkdirAll(p.ToString(), mode); err != nil {
- return err
- }
- // This is necessary only when umask results in creating a directory with permissions different than the one passed by the user
- return os.Chmod(p.ToString(), mode)
-}
-
-// Create is the AbsoluteSystemPath wrapper for os.Create
-func (p AbsoluteSystemPath) Create() (*os.File, error) {
- return os.Create(p.ToString())
-}
-
-// Ext implements filepath.Ext(p) for an absolute path
-func (p AbsoluteSystemPath) Ext() string {
- return filepath.Ext(p.ToString())
-}
-
-// RelativePathString returns the relative path from this AbsoluteSystemPath to another absolute path in string form as a string
-func (p AbsoluteSystemPath) RelativePathString(path string) (string, error) {
- return filepath.Rel(p.ToString(), path)
-}
-
-// PathTo returns the relative path between two absolute paths
-// This should likely eventually return an AnchoredSystemPath
-func (p AbsoluteSystemPath) PathTo(other AbsoluteSystemPath) (string, error) {
- return p.RelativePathString(other.ToString())
-}
-
-// Symlink implements os.Symlink(target, p) for absolute path
-func (p AbsoluteSystemPath) Symlink(target string) error {
- return os.Symlink(target, p.ToString())
-}
-
-// Readlink implements os.Readlink(p) for an absolute path
-func (p AbsoluteSystemPath) Readlink() (string, error) {
- return os.Readlink(p.ToString())
-}
-
-// Remove removes the file or (empty) directory at the given path
-func (p AbsoluteSystemPath) Remove() error {
- return os.Remove(p.ToString())
-}
-
-// RemoveAll implements os.RemoveAll for absolute paths.
-func (p AbsoluteSystemPath) RemoveAll() error {
- return os.RemoveAll(p.ToString())
-}
-
-// Base implements filepath.Base for an absolute path
-func (p AbsoluteSystemPath) Base() string {
- return filepath.Base(p.ToString())
-}
-
-// Rename implements os.Rename(p, dest) for absolute paths
-func (p AbsoluteSystemPath) Rename(dest AbsoluteSystemPath) error {
- return os.Rename(p.ToString(), dest.ToString())
-}
-
-// EvalSymlinks implements filepath.EvalSymlinks for absolute path
-func (p AbsoluteSystemPath) EvalSymlinks() (AbsoluteSystemPath, error) {
- result, err := filepath.EvalSymlinks(p.ToString())
- if err != nil {
- return "", err
- }
- return AbsoluteSystemPath(result), nil
-}
-
-// HasPrefix is strings.HasPrefix for paths, ensuring that it matches on separator boundaries.
-// This does NOT perform Clean in advance.
-func (p AbsoluteSystemPath) HasPrefix(prefix AbsoluteSystemPath) bool {
- prefixLen := len(prefix)
- pathLen := len(p)
-
- if prefixLen > pathLen {
- // Can't be a prefix if longer.
- return false
- } else if prefixLen == pathLen {
- // Can be a prefix if they're equal, but otherwise no.
- return p == prefix
- }
-
- // otherPath is definitely shorter than p.
- // We need to confirm that p[len(otherPath)] is a system separator.
-
- return strings.HasPrefix(p.ToString(), prefix.ToString()) && os.IsPathSeparator(p[prefixLen])
-}
diff --git a/cli/internal/turbopath/absolute_system_path_darwin.go b/cli/internal/turbopath/absolute_system_path_darwin.go
deleted file mode 100644
index e2c3bff..0000000
--- a/cli/internal/turbopath/absolute_system_path_darwin.go
+++ /dev/null
@@ -1,23 +0,0 @@
-//go:build darwin
-// +build darwin
-
-// Adapted from https://github.com/containerd/continuity/blob/b4ca35286886296377de39e6eafd1affae019fc3/driver/lchmod_unix.go
-// Copyright The containerd Authors
-// SPDX-License-Identifier: Apache-2.0
-
-package turbopath
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-// Lchmod changes the mode of a file not following symlinks.
-func (p AbsoluteSystemPath) Lchmod(mode os.FileMode) error {
- err := unix.Fchmodat(unix.AT_FDCWD, p.ToString(), uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
- if err != nil {
- err = &os.PathError{Op: "lchmod", Path: p.ToString(), Err: err}
- }
- return err
-}
diff --git a/cli/internal/turbopath/absolute_system_path_notdarwin.go b/cli/internal/turbopath/absolute_system_path_notdarwin.go
deleted file mode 100644
index 1195888..0000000
--- a/cli/internal/turbopath/absolute_system_path_notdarwin.go
+++ /dev/null
@@ -1,13 +0,0 @@
-//go:build !darwin
-// +build !darwin
-
-package turbopath
-
-import (
- "os"
-)
-
-// Lchmod changes the mode of a file not following symlinks.
-func (p AbsoluteSystemPath) Lchmod(mode os.FileMode) error {
- return nil
-}
diff --git a/cli/internal/turbopath/absolute_system_path_test.go b/cli/internal/turbopath/absolute_system_path_test.go
deleted file mode 100644
index 4ca36f9..0000000
--- a/cli/internal/turbopath/absolute_system_path_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package turbopath
-
-import (
- "os"
- "runtime"
- "testing"
-
- "gotest.tools/v3/assert"
- "gotest.tools/v3/fs"
-)
-
-func Test_Mkdir(t *testing.T) {
- type Case struct {
- name string
- isDir bool
- exists bool
- mode os.FileMode
- expectedMode os.FileMode
- }
-
- cases := []Case{
- {
- name: "dir doesn't exist",
- exists: false,
- expectedMode: os.ModeDir | 0777,
- },
- {
- name: "path exists as file",
- exists: true,
- isDir: false,
- mode: 0666,
- expectedMode: os.ModeDir | 0755,
- },
- {
- name: "dir exists with incorrect mode",
- exists: true,
- isDir: false,
- mode: os.ModeDir | 0755,
- expectedMode: os.ModeDir | 0655,
- },
- {
- name: "dir exists with correct mode",
- exists: true,
- isDir: false,
- mode: os.ModeDir | 0755,
- expectedMode: os.ModeDir | 0755,
- },
- }
-
- for _, testCase := range cases {
- testDir := fs.NewDir(t, "system-path-mkdir-test")
- testName := testCase.name
- path := testDir.Join("foo")
- if testCase.isDir {
- err := os.Mkdir(path, testCase.mode)
- assert.NilError(t, err, "%s: Mkdir", testName)
- } else if testCase.exists {
- file, err := os.Create(path)
- assert.NilError(t, err, "%s: Create", testName)
- err = file.Chmod(testCase.mode)
- assert.NilError(t, err, "%s: Chmod", testName)
- err = file.Close()
- assert.NilError(t, err, "%s: Close", testName)
- }
-
- testPath := AbsoluteSystemPath(path)
- err := testPath.MkdirAllMode(testCase.expectedMode)
- assert.NilError(t, err, "%s: Mkdir", testName)
-
- stat, err := testPath.Lstat()
- assert.NilError(t, err, "%s: Lstat", testName)
- assert.Assert(t, stat.IsDir(), testName)
-
- assert.Assert(t, stat.IsDir(), testName)
-
- if runtime.GOOS == "windows" {
- // For windows os.Chmod will only change the writable bit so that's all we check
- assert.Equal(t, stat.Mode().Perm()&0200, testCase.expectedMode.Perm()&0200, testName)
- } else {
- assert.Equal(t, stat.Mode(), testCase.expectedMode, testName)
- }
-
- }
-}
-
-func TestAbsoluteSystemPath_Findup(t *testing.T) {
- tests := []struct {
- name string
- fs []AnchoredSystemPath
- executionDirectory AnchoredSystemPath
- fileName RelativeSystemPath
- want AnchoredSystemPath
- wantErr bool
- }{
- {
- name: "hello world",
- fs: []AnchoredSystemPath{
- AnchoredUnixPath("one/two/three/four/.file").ToSystemPath(),
- AnchoredUnixPath("one/two/three/four/.target").ToSystemPath(),
- },
- executionDirectory: AnchoredUnixPath("one/two/three/four").ToSystemPath(),
- fileName: RelativeUnixPath(".target").ToSystemPath(),
- want: AnchoredUnixPath("one/two/three/four/.target").ToSystemPath(),
- },
- {
- name: "parent",
- fs: []AnchoredSystemPath{
- AnchoredUnixPath("one/two/three/four/.file").ToSystemPath(),
- AnchoredUnixPath("one/two/three/.target").ToSystemPath(),
- },
- executionDirectory: AnchoredUnixPath("one/two/three/four").ToSystemPath(),
- fileName: RelativeUnixPath(".target").ToSystemPath(),
- want: AnchoredUnixPath("one/two/three/.target").ToSystemPath(),
- },
- {
- name: "gets the closest",
- fs: []AnchoredSystemPath{
- AnchoredUnixPath("one/two/three/four/.file").ToSystemPath(),
- AnchoredUnixPath("one/two/three/.target").ToSystemPath(),
- AnchoredUnixPath("one/two/.target").ToSystemPath(),
- },
- executionDirectory: AnchoredUnixPath("one/two/three/four").ToSystemPath(),
- fileName: RelativeUnixPath(".target").ToSystemPath(),
- want: AnchoredUnixPath("one/two/three/.target").ToSystemPath(),
- },
- {
- name: "nonexistent",
- fs: []AnchoredSystemPath{
- AnchoredUnixPath("one/two/three/four/.file").ToSystemPath(),
- },
- executionDirectory: AnchoredUnixPath("one/two/three/four").ToSystemPath(),
- fileName: RelativeUnixPath(".nonexistent").ToSystemPath(),
- want: "",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- fsRoot := AbsoluteSystemPath(t.TempDir())
- for _, file := range tt.fs {
- path := file.RestoreAnchor(fsRoot)
- assert.NilError(t, path.Dir().MkdirAll(0777))
- assert.NilError(t, path.WriteFile(nil, 0777))
- }
-
- got, err := tt.executionDirectory.RestoreAnchor(fsRoot).Findup(tt.fileName)
- if tt.wantErr {
- assert.ErrorIs(t, err, os.ErrNotExist)
- return
- }
- if got != "" && got != tt.want.RestoreAnchor(fsRoot) {
- t.Errorf("AbsoluteSystemPath.Findup() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestJoin(t *testing.T) {
- rawRoot, err := os.Getwd()
- if err != nil {
- t.Fatalf("cwd %v", err)
- }
- root := AbsoluteSystemPathFromUpstream(rawRoot)
- testRoot := root.Join("a", "b", "c")
- dot := testRoot.Join(".")
- if dot != testRoot {
- t.Errorf(". path got %v, want %v", dot, testRoot)
- }
-
- doubleDot := testRoot.Join("..")
- expectedDoubleDot := root.Join("a", "b")
- if doubleDot != expectedDoubleDot {
- t.Errorf(".. path got %v, want %v", doubleDot, expectedDoubleDot)
- }
-}
diff --git a/cli/internal/turbopath/anchored_system_path.go b/cli/internal/turbopath/anchored_system_path.go
deleted file mode 100644
index 0957ead..0000000
--- a/cli/internal/turbopath/anchored_system_path.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package turbopath
-
-import (
- "os"
- "path/filepath"
- "strings"
-)
-
-// AnchoredSystemPath is a path stemming from a specified root using system separators.
-type AnchoredSystemPath string
-
-// ToString returns a string represenation of this Path.
-// Used for interfacing with APIs that require a string.
-func (p AnchoredSystemPath) ToString() string {
- return string(p)
-}
-
-// ToStringDuringMigration returns the string representation of this path, and is for
-// use in situations where we expect a future path migration to remove the need for the
-// string representation
-func (p AnchoredSystemPath) ToStringDuringMigration() string {
- return string(p)
-}
-
-// ToSystemPath returns itself.
-func (p AnchoredSystemPath) ToSystemPath() AnchoredSystemPath {
- return p
-}
-
-// ToUnixPath converts a AnchoredSystemPath to a AnchoredUnixPath.
-func (p AnchoredSystemPath) ToUnixPath() AnchoredUnixPath {
- return AnchoredUnixPath(filepath.ToSlash(p.ToString()))
-}
-
-// RelativeTo calculates the relative path between two AnchoredSystemPath`s.
-func (p AnchoredSystemPath) RelativeTo(basePath AnchoredSystemPath) (AnchoredSystemPath, error) {
- processed, err := filepath.Rel(basePath.ToString(), p.ToString())
- return AnchoredSystemPath(processed), err
-}
-
-// RestoreAnchor prefixes the AnchoredSystemPath with its anchor to return an AbsoluteSystemPath.
-func (p AnchoredSystemPath) RestoreAnchor(anchor AbsoluteSystemPath) AbsoluteSystemPath {
- return AbsoluteSystemPath(filepath.Join(anchor.ToString(), p.ToString()))
-}
-
-// Dir returns filepath.Dir for the path.
-func (p AnchoredSystemPath) Dir() AnchoredSystemPath {
- return AnchoredSystemPath(filepath.Dir(p.ToString()))
-}
-
-// Join appends relative path segments to this AnchoredSystemPath.
-func (p AnchoredSystemPath) Join(additional ...RelativeSystemPath) AnchoredSystemPath {
- cast := RelativeSystemPathArray(additional)
- return AnchoredSystemPath(filepath.Join(p.ToString(), filepath.Join(cast.ToStringArray()...)))
-}
-
-// HasPrefix is strings.HasPrefix for paths, ensuring that it matches on separator boundaries.
-// This does NOT perform Clean in advance.
-func (p AnchoredSystemPath) HasPrefix(prefix AnchoredSystemPath) bool {
- prefixLen := len(prefix)
- pathLen := len(p)
-
- if prefixLen > pathLen {
- // Can't be a prefix if longer.
- return false
- } else if prefixLen == pathLen {
- // Can be a prefix if they're equal, but otherwise no.
- return p == prefix
- }
-
- // otherPath is definitely shorter than p.
- // We need to confirm that p[len(otherPath)] is a system separator.
-
- return strings.HasPrefix(p.ToString(), prefix.ToString()) && os.IsPathSeparator(p[prefixLen])
-}
diff --git a/cli/internal/turbopath/anchored_unix_path.go b/cli/internal/turbopath/anchored_unix_path.go
deleted file mode 100644
index 23e371a..0000000
--- a/cli/internal/turbopath/anchored_unix_path.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package turbopath
-
-import (
- "path"
- "path/filepath"
-)
-
-// AnchoredUnixPath is a path stemming from a specified root using Unix `/` separators.
-type AnchoredUnixPath string
-
-// ToString returns a string represenation of this Path.
-// Used for interfacing with APIs that require a string.
-func (p AnchoredUnixPath) ToString() string {
- return string(p)
-}
-
-// ToSystemPath converts a AnchoredUnixPath to a AnchoredSystemPath.
-func (p AnchoredUnixPath) ToSystemPath() AnchoredSystemPath {
- return AnchoredSystemPath(filepath.FromSlash(p.ToString()))
-}
-
-// ToUnixPath returns itself.
-func (p AnchoredUnixPath) ToUnixPath() AnchoredUnixPath {
- return p
-}
-
-// Join appends relative path segments to this RelativeUnixPath.
-func (p AnchoredUnixPath) Join(additional ...RelativeUnixPath) AnchoredUnixPath {
- cast := RelativeUnixPathArray(additional)
- return AnchoredUnixPath(path.Join(p.ToString(), path.Join(cast.ToStringArray()...)))
-}
diff --git a/cli/internal/turbopath/find_up.go b/cli/internal/turbopath/find_up.go
deleted file mode 100644
index bf7c39c..0000000
--- a/cli/internal/turbopath/find_up.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package turbopath
-
-import (
- "os"
- "path/filepath"
-)
-
-func hasFile(name, dir string) (bool, error) {
- files, err := os.ReadDir(dir)
-
- if err != nil {
- return false, err
- }
-
- for _, f := range files {
- if name == f.Name() {
- return true, nil
- }
- }
-
- return false, nil
-}
-
-func findupFrom(name, dir string) (string, error) {
- for {
- found, err := hasFile(name, dir)
-
- if err != nil {
- return "", err
- }
-
- if found {
- return filepath.Join(dir, name), nil
- }
-
- parent := filepath.Dir(dir)
-
- if parent == dir {
- return "", nil
- }
-
- dir = parent
- }
-}
-
-// FindupFrom Recursively finds a file by walking up parents in the file tree
-// starting from a specific directory.
-func FindupFrom(name, dir string) (string, error) {
- return findupFrom(name, dir)
-}
diff --git a/cli/internal/turbopath/relative_system_path.go b/cli/internal/turbopath/relative_system_path.go
deleted file mode 100644
index d6115db..0000000
--- a/cli/internal/turbopath/relative_system_path.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package turbopath
-
-import (
- "fmt"
- "path/filepath"
-)
-
-// RelativeSystemPath is a relative path using system separators.
-type RelativeSystemPath string
-
-// CheckedToRelativeSystemPath inspects a string and determines if it is a relative path.
-func CheckedToRelativeSystemPath(s string) (RelativeSystemPath, error) {
- if filepath.IsAbs(s) {
- return "", fmt.Errorf("%v is not a relative path", s)
- }
- return RelativeSystemPath(filepath.Clean(s)), nil
-}
-
-// MakeRelativeSystemPath joins the given segments in a system-appropriate way
-func MakeRelativeSystemPath(segments ...string) RelativeSystemPath {
- return RelativeSystemPath(filepath.Join(segments...))
-}
-
-// ToString returns a string represenation of this Path.
-// Used for interfacing with APIs that require a string.
-func (p RelativeSystemPath) ToString() string {
- return string(p)
-}
-
-// ToSystemPath returns itself.
-func (p RelativeSystemPath) ToSystemPath() RelativeSystemPath {
- return p
-}
-
-// ToUnixPath converts from RelativeSystemPath to RelativeUnixPath.
-func (p RelativeSystemPath) ToUnixPath() RelativeUnixPath {
- return RelativeUnixPath(filepath.ToSlash(p.ToString()))
-}
-
-// Join appends relative path segments to this RelativeSystemPath.
-func (p RelativeSystemPath) Join(additional ...RelativeSystemPath) RelativeSystemPath {
- cast := RelativeSystemPathArray(additional)
- return RelativeSystemPath(filepath.Join(p.ToString(), filepath.Join(cast.ToStringArray()...)))
-}
diff --git a/cli/internal/turbopath/relative_unix_path.go b/cli/internal/turbopath/relative_unix_path.go
deleted file mode 100644
index 05829e2..0000000
--- a/cli/internal/turbopath/relative_unix_path.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package turbopath
-
-import (
- "path"
- "path/filepath"
-)
-
-// RelativeUnixPath is a relative path using Unix `/` separators.
-type RelativeUnixPath string
-
-// ToString returns a string represenation of this Path.
-// Used for interfacing with APIs that require a string.
-func (p RelativeUnixPath) ToString() string {
- return string(p)
-}
-
-// ToSystemPath converts a RelativeUnixPath to a RelativeSystemPath.
-func (p RelativeUnixPath) ToSystemPath() RelativeSystemPath {
- return RelativeSystemPath(filepath.FromSlash(p.ToString()))
-}
-
-// ToUnixPath converts a RelativeUnixPath to a RelativeSystemPath.
-func (p RelativeUnixPath) ToUnixPath() RelativeUnixPath {
- return p
-}
-
-// Join appends relative path segments to this RelativeUnixPath.
-func (p RelativeUnixPath) Join(additional ...RelativeUnixPath) RelativeUnixPath {
- cast := RelativeUnixPathArray(additional)
- return RelativeUnixPath(path.Join(p.ToString(), path.Join(cast.ToStringArray()...)))
-}
diff --git a/cli/internal/turbopath/turbopath.go b/cli/internal/turbopath/turbopath.go
deleted file mode 100644
index f50b75f..0000000
--- a/cli/internal/turbopath/turbopath.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Package turbopath teaches the Go type system about six
-// different types of paths:
-// - AbsoluteSystemPath
-// - RelativeSystemPath
-// - AnchoredSystemPath
-// - AbsoluteUnixPath
-// - RelativeUnixPath
-// - AnchoredUnixPath
-//
-// Between these two things it is assumed that we will be able to
-// reasonably describe file paths being used within the system and
-// have the type system enforce correctness instead of relying upon
-// runtime code to accomplish the task.
-//
-// Absolute paths are, "absolute, including volume root." They are not
-// portable between System and Unix.
-//
-// Relative paths are simply arbitrary path segments using a particular
-// path delimiter. They are portable between System and Unix.
-//
-// Anchored paths are, "absolute, starting at a particular root."
-// They are not aware of *what* their anchor is. It could be a repository,
-// an `os.dirFS`, a package, `cwd`, or more. They are stored *without*
-// a preceding delimiter for compatibility with `io/fs`. They are portable
-// between System and Unix.
-//
-// In some future world everything in here can be optimized out at compile time.
-// Everything is either `string` or `[]string`
-//
-// Much of this is dreadfully repetitive because of intentional
-// limitations in the Go type system.
-package turbopath
-
-// AnchoredUnixPathArray is a type used to enable transform operations on arrays of paths.
-type AnchoredUnixPathArray []AnchoredUnixPath
-
-// RelativeSystemPathArray is a type used to enable transform operations on arrays of paths.
-type RelativeSystemPathArray []RelativeSystemPath
-
-// RelativeUnixPathArray is a type used to enable transform operations on arrays of paths.
-type RelativeUnixPathArray []RelativeUnixPath
-
-// ToStringArray enables ergonomic operations on arrays of RelativeSystemPath
-func (source RelativeSystemPathArray) ToStringArray() []string {
- output := make([]string, len(source))
- for index, path := range source {
- output[index] = path.ToString()
- }
- return output
-}
-
-// ToStringArray enables ergonomic operations on arrays of RelativeUnixPath
-func (source RelativeUnixPathArray) ToStringArray() []string {
- output := make([]string, len(source))
- for index, path := range source {
- output[index] = path.ToString()
- }
- return output
-}
-
-// ToSystemPathArray enables ergonomic operations on arrays of AnchoredUnixPath
-func (source AnchoredUnixPathArray) ToSystemPathArray() []AnchoredSystemPath {
- output := make([]AnchoredSystemPath, len(source))
- for index, path := range source {
- output[index] = path.ToSystemPath()
- }
- return output
-}
-
-// The following methods exist to import a path string and cast it to the appropriate
-// type. They exist to communicate intent and make it explicit that this is an
-// intentional action, not a "helpful" insertion by the IDE.
-//
-// This is intended to map closely to the `unsafe` keyword, without the denotative
-// meaning of `unsafe` in English. These are "trust me, I've checkex it" places, and
-// intend to mark the places where we smuggle paths from outside the world of safe
-// path handling into the world where we carefully consider the path to ensure safety.
-
-// AbsoluteSystemPathFromUpstream takes a path string and casts it to an
-// AbsoluteSystemPath without checking. If the input to this function is
-// not an AbsoluteSystemPath it will result in downstream errors.
-func AbsoluteSystemPathFromUpstream(path string) AbsoluteSystemPath {
- return AbsoluteSystemPath(path)
-}
-
-// AnchoredSystemPathFromUpstream takes a path string and casts it to an
-// AnchoredSystemPath without checking. If the input to this function is
-// not an AnchoredSystemPath it will result in downstream errors.
-func AnchoredSystemPathFromUpstream(path string) AnchoredSystemPath {
- return AnchoredSystemPath(path)
-}
-
-// AnchoredUnixPathFromUpstream takes a path string and casts it to an
-// AnchoredUnixPath without checking. If the input to this function is
-// not an AnchoredUnixPath it will result in downstream errors.
-func AnchoredUnixPathFromUpstream(path string) AnchoredUnixPath {
- return AnchoredUnixPath(path)
-}
-
-// RelativeSystemPathFromUpstream takes a path string and casts it to an
-// RelativeSystemPath without checking. If the input to this function is
-// not an RelativeSystemPath it will result in downstream errors.
-func RelativeSystemPathFromUpstream(path string) RelativeSystemPath {
- return RelativeSystemPath(path)
-}
-
-// RelativeUnixPathFromUpstream takes a path string and casts it to an
-// RelativeUnixPath without checking. If the input to this function is
-// not an RelativeUnixPath it will result in downstream errors.
-func RelativeUnixPathFromUpstream(path string) RelativeUnixPath {
- return RelativeUnixPath(path)
-}
diff --git a/cli/internal/turbostate/turbostate.go b/cli/internal/turbostate/turbostate.go
deleted file mode 100644
index dad5b47..0000000
--- a/cli/internal/turbostate/turbostate.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Package turbostate holds all of the state given from the Rust CLI
-// that is necessary to execute turbo. We transfer this state from Rust
-// to Go via a JSON payload.
-package turbostate
-
-import (
- "fmt"
-
- "github.com/vercel/turbo/cli/internal/util"
-)
-
-// RepoState is the state for repository. Consists of the root for the repo
-// along with the mode (single package or multi package)
-type RepoState struct {
- Root string `json:"root"`
- Mode string `json:"mode"`
-}
-
-// DaemonPayload is the extra flags and command that are
-// passed for the `daemon` subcommand
-type DaemonPayload struct {
- IdleTimeout string `json:"idle_time"`
- JSON bool `json:"json"`
-}
-
-// PrunePayload is the extra flags passed for the `prune` subcommand
-type PrunePayload struct {
- Scope []string `json:"scope"`
- Docker bool `json:"docker"`
- OutputDir string `json:"output_dir"`
-}
-
-// RunPayload is the extra flags passed for the `run` subcommand
-type RunPayload struct {
- CacheDir string `json:"cache_dir"`
- CacheWorkers int `json:"cache_workers"`
- Concurrency string `json:"concurrency"`
- ContinueExecution bool `json:"continue_execution"`
- DryRun string `json:"dry_run"`
- Filter []string `json:"filter"`
- Force bool `json:"force"`
- GlobalDeps []string `json:"global_deps"`
- EnvMode util.EnvMode `json:"env_mode"`
- // NOTE: Graph has three effective states that is modeled using a *string:
- // nil -> no flag passed
- // "" -> flag passed but no file name attached: print to stdout
- // "foo" -> flag passed and file name attached: emit to file
- // The mirror for this in Rust is `Option<String>` with the default value
- // for the flag being `Some("")`.
- Graph *string `json:"graph"`
- Ignore []string `json:"ignore"`
- IncludeDependencies bool `json:"include_dependencies"`
- NoCache bool `json:"no_cache"`
- NoDaemon bool `json:"no_daemon"`
- NoDeps bool `json:"no_deps"`
- Only bool `json:"only"`
- OutputLogs string `json:"output_logs"`
- PassThroughArgs []string `json:"pass_through_args"`
- Parallel bool `json:"parallel"`
- Profile string `json:"profile"`
- RemoteOnly bool `json:"remote_only"`
- Scope []string `json:"scope"`
- Since string `json:"since"`
- SinglePackage bool `json:"single_package"`
- Summarize bool `json:"summarize"`
- Tasks []string `json:"tasks"`
- PkgInferenceRoot string `json:"pkg_inference_root"`
- LogPrefix string `json:"log_prefix"`
- ExperimentalSpaceID string `json:"experimental_space_id"`
-}
-
-// Command consists of the data necessary to run a command.
-// Only one of these fields should be initialized at a time.
-type Command struct {
- Daemon *DaemonPayload `json:"daemon"`
- Prune *PrunePayload `json:"prune"`
- Run *RunPayload `json:"run"`
-}
-
-// ParsedArgsFromRust are the parsed command line arguments passed
-// from the Rust shim
-type ParsedArgsFromRust struct {
- API string `json:"api"`
- Color bool `json:"color"`
- CPUProfile string `json:"cpu_profile"`
- CWD string `json:"cwd"`
- Heap string `json:"heap"`
- Login string `json:"login"`
- NoColor bool `json:"no_color"`
- Preflight bool `json:"preflight"`
- RemoteCacheTimeout uint64 `json:"remote_cache_timeout"`
- Team string `json:"team"`
- Token string `json:"token"`
- Trace string `json:"trace"`
- Verbosity int `json:"verbosity"`
- TestRun bool `json:"test_run"`
- Command Command `json:"command"`
-}
-
-// GetColor returns the value of the `color` flag.
-func (a ParsedArgsFromRust) GetColor() bool {
- return a.Color
-}
-
-// GetNoColor returns the value of the `token` flag.
-func (a ParsedArgsFromRust) GetNoColor() bool {
- return a.NoColor
-}
-
-// GetLogin returns the value of the `login` flag.
-func (a ParsedArgsFromRust) GetLogin() (string, error) {
- return a.Login, nil
-}
-
-// GetAPI returns the value of the `api` flag.
-func (a ParsedArgsFromRust) GetAPI() (string, error) {
- return a.API, nil
-}
-
-// GetTeam returns the value of the `team` flag.
-func (a ParsedArgsFromRust) GetTeam() (string, error) {
- return a.Team, nil
-}
-
-// GetToken returns the value of the `token` flag.
-func (a ParsedArgsFromRust) GetToken() (string, error) {
- return a.Token, nil
-}
-
-// GetCwd returns the value of the `cwd` flag.
-func (a ParsedArgsFromRust) GetCwd() (string, error) {
- return a.CWD, nil
-}
-
-// GetRemoteCacheTimeout returns the value of the `remote-cache-timeout` flag.
-func (a ParsedArgsFromRust) GetRemoteCacheTimeout() (uint64, error) {
- if a.RemoteCacheTimeout != 0 {
- return a.RemoteCacheTimeout, nil
- }
- return 0, fmt.Errorf("no remote cache timeout provided")
-}
diff --git a/cli/internal/ui/charset.go b/cli/internal/ui/charset.go
deleted file mode 100644
index 0207c10..0000000
--- a/cli/internal/ui/charset.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package ui
-
-var charset = []string{" ", "> ", ">> ", ">>>"}
diff --git a/cli/internal/ui/colors.go b/cli/internal/ui/colors.go
deleted file mode 100644
index 4b2eccd..0000000
--- a/cli/internal/ui/colors.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package ui
-
-import (
- "os"
-
- "github.com/fatih/color"
-)
-
-type ColorMode int
-
-const (
- ColorModeUndefined ColorMode = iota + 1
- ColorModeSuppressed
- ColorModeForced
-)
-
-func GetColorModeFromEnv() ColorMode {
- // The FORCED_COLOR behavior and accepted values are taken from the supports-color NodeJS Package:
- // The accepted values as documented are "0" to disable, and "1", "2", or "3" to force-enable color
- // at the specified support level (1 = 16 colors, 2 = 256 colors, 3 = 16M colors).
- // We don't currently use the level for anything specific, and just treat things as on and off.
- //
- // Note: while "false" and "true" aren't documented, the library coerces these values to 0 and 1
- // respectively, so that behavior is reproduced here as well.
- // https://www.npmjs.com/package/supports-color
-
- switch forceColor := os.Getenv("FORCE_COLOR"); {
- case forceColor == "false" || forceColor == "0":
- return ColorModeSuppressed
- case forceColor == "true" || forceColor == "1" || forceColor == "2" || forceColor == "3":
- return ColorModeForced
- default:
- return ColorModeUndefined
- }
-}
-
-func applyColorMode(colorMode ColorMode) ColorMode {
- switch colorMode {
- case ColorModeForced:
- color.NoColor = false
- case ColorModeSuppressed:
- color.NoColor = true
- case ColorModeUndefined:
- default:
- // color.NoColor already gets its default value based on
- // isTTY and/or the presence of the NO_COLOR env variable.
- }
-
- if color.NoColor {
- return ColorModeSuppressed
- } else {
- return ColorModeForced
- }
-}
diff --git a/cli/internal/ui/spinner.go b/cli/internal/ui/spinner.go
deleted file mode 100644
index 6e47d2d..0000000
--- a/cli/internal/ui/spinner.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package ui
-
-import (
- "fmt"
- "io"
- "os"
- "time"
-
- "github.com/briandowns/spinner"
-)
-
-// startStopper is the interface to interact with the spinner.
-type startStopper interface {
- Start()
- Stop()
-}
-
-// Spinner represents an indicator that an asynchronous operation is taking place.
-//
-// For short operations, less than 4 seconds, display only the spinner with the Start and Stop methods.
-// For longer operations, display intermediate progress events using the Events method.
-type Spinner struct {
- spin startStopper
-}
-
-// NewSpinner returns a spinner that outputs to w.
-func NewSpinner(w io.Writer) *Spinner {
- interval := 125 * time.Millisecond
- if os.Getenv("CI") == "true" {
- interval = 30 * time.Second
- }
- s := spinner.New(charset, interval, spinner.WithHiddenCursor(true))
- s.Writer = w
- s.Color("faint")
- return &Spinner{
- spin: s,
- }
-}
-
-// Start starts the spinner suffixed with a label.
-func (s *Spinner) Start(label string) {
- s.suffix(fmt.Sprintf(" %s", label))
- s.spin.Start()
-}
-
-// Stop stops the spinner and replaces it with a label.
-func (s *Spinner) Stop(label string) {
- s.finalMSG(fmt.Sprint(label))
- s.spin.Stop()
-}
-
-func (s *Spinner) lock() {
- if spinner, ok := s.spin.(*spinner.Spinner); ok {
- spinner.Lock()
- }
-}
-
-func (s *Spinner) unlock() {
- if spinner, ok := s.spin.(*spinner.Spinner); ok {
- spinner.Unlock()
- }
-}
-
-func (s *Spinner) suffix(label string) {
- s.lock()
- defer s.unlock()
- if spinner, ok := s.spin.(*spinner.Spinner); ok {
- spinner.Suffix = label
- }
-}
-
-func (s *Spinner) finalMSG(label string) {
- s.lock()
- defer s.unlock()
- if spinner, ok := s.spin.(*spinner.Spinner); ok {
- spinner.FinalMSG = label
- }
-}
diff --git a/cli/internal/ui/term/cursor.go b/cli/internal/ui/term/cursor.go
deleted file mode 100644
index 253f043..0000000
--- a/cli/internal/ui/term/cursor.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-// Package cursor provides functionality to interact with the terminal cursor.
-package cursor
-
-import (
- "io"
- "os"
-
- "github.com/AlecAivazis/survey/v2/terminal"
-)
-
-type cursor interface {
- Up(n int) error
- Down(n int) error
- Hide() error
- Show() error
-}
-
-// fakeFileWriter is a terminal.FileWriter.
-// If the underlying writer w does not implement Fd() then a dummy value is returned.
-type fakeFileWriter struct {
- w io.Writer
-}
-
-// Write delegates to the internal writer.
-func (w *fakeFileWriter) Write(p []byte) (int, error) {
- return w.w.Write(p)
-}
-
-// Fd is required to be implemented to satisfy the terminal.FileWriter interface.
-// If the underlying writer is a file, like os.Stdout, then invoke it. Otherwise, this method allows us to create
-// a Cursor that can write to any io.Writer like a bytes.Buffer by returning a dummy value.
-func (w *fakeFileWriter) Fd() uintptr {
- if v, ok := w.w.(terminal.FileWriter); ok {
- return v.Fd()
- }
- return 0
-}
-
-// Cursor represents the terminal's cursor.
-type Cursor struct {
- c cursor
-}
-
-// New creates a new cursor that writes to stderr.
-func New() *Cursor {
- return &Cursor{
- c: &terminal.Cursor{
- Out: os.Stderr,
- },
- }
-}
-
-// EraseLine erases a line from a FileWriter.
-func EraseLine(fw terminal.FileWriter) {
- terminal.EraseLine(fw, terminal.ERASE_LINE_ALL)
-}
-
-// EraseLinesAbove erases a line and moves the cursor up from fw, repeated n times.
-func EraseLinesAbove(fw terminal.FileWriter, n int) {
- c := Cursor{
- c: &terminal.Cursor{
- Out: fw,
- },
- }
- for i := 0; i < n; i += 1 {
- EraseLine(fw)
- c.c.Up(1)
- }
- EraseLine(fw) // Erase the nth line as well.
-}
diff --git a/cli/internal/ui/term/cursor_test.go b/cli/internal/ui/term/cursor_test.go
deleted file mode 100644
index 270ebe8..0000000
--- a/cli/internal/ui/term/cursor_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-//go:build !windows
-// +build !windows
-
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package cursor
-
-import (
- "io"
- "strings"
- "testing"
-
- "github.com/AlecAivazis/survey/v2/terminal"
- "github.com/stretchr/testify/require"
-)
-
-func TestEraseLine(t *testing.T) {
- testCases := map[string]struct {
- inWriter func(writer io.Writer) terminal.FileWriter
- shouldErase bool
- }{
- "should erase a line if the writer is a file": {
- inWriter: func(writer io.Writer) terminal.FileWriter {
- return &fakeFileWriter{w: writer}
- },
- shouldErase: true,
- },
- }
-
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- // GIVEN
- buf := new(strings.Builder)
-
- // WHEN
- EraseLine(tc.inWriter(buf))
-
- // THEN
- isErased := buf.String() != ""
- require.Equal(t, tc.shouldErase, isErased)
- })
- }
-}
diff --git a/cli/internal/ui/ui.go b/cli/internal/ui/ui.go
deleted file mode 100644
index 9084c76..0000000
--- a/cli/internal/ui/ui.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package ui
-
-import (
- "fmt"
- "io"
- "math"
- "os"
- "regexp"
- "strings"
-
- "github.com/fatih/color"
- "github.com/mattn/go-isatty"
- "github.com/mitchellh/cli"
- "github.com/vercel/turbo/cli/internal/ci"
-)
-
-const ansiEscapeStr = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
-
-// IsTTY is true when stdout appears to be a tty
-var IsTTY = isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
-
-// IsCI is true when we appear to be running in a non-interactive context.
-var IsCI = !IsTTY || ci.IsCi()
-var gray = color.New(color.Faint)
-var bold = color.New(color.Bold)
-var ERROR_PREFIX = color.New(color.Bold, color.FgRed, color.ReverseVideo).Sprint(" ERROR ")
-var WARNING_PREFIX = color.New(color.Bold, color.FgYellow, color.ReverseVideo).Sprint(" WARNING ")
-
-// InfoPrefix is a colored string for warning level log messages
-var InfoPrefix = color.New(color.Bold, color.FgWhite, color.ReverseVideo).Sprint(" INFO ")
-
-var ansiRegex = regexp.MustCompile(ansiEscapeStr)
-
-// Dim prints out dimmed text
-func Dim(str string) string {
- return gray.Sprint(str)
-}
-
-func Bold(str string) string {
- return bold.Sprint(str)
-}
-
-// Adapted from go-rainbow
-// Copyright (c) 2017 Raphael Amorim
-// Source: https://github.com/raphamorim/go-rainbow
-// SPDX-License-Identifier: MIT
-func rgb(i int) (int, int, int) {
- var f = 0.275
-
- return int(math.Sin(f*float64(i)+4*math.Pi/3)*127 + 128),
- // int(math.Sin(f*float64(i)+2*math.Pi/3)*127 + 128),
- int(45),
- int(math.Sin(f*float64(i)+0)*127 + 128)
-}
-
-// Rainbow function returns a formated colorized string ready to print it to the shell/terminal
-//
-// Adapted from go-rainbow
-// Copyright (c) 2017 Raphael Amorim
-// Source: https://github.com/raphamorim/go-rainbow
-// SPDX-License-Identifier: MIT
-func Rainbow(text string) string {
- var rainbowStr []string
- for index, value := range text {
- r, g, b := rgb(index)
- str := fmt.Sprintf("\033[1m\033[38;2;%d;%d;%dm%c\033[0m\033[0;1m", r, g, b, value)
- rainbowStr = append(rainbowStr, str)
- }
-
- return strings.Join(rainbowStr, "")
-}
-
-type stripAnsiWriter struct {
- wrappedWriter io.Writer
-}
-
-func (into *stripAnsiWriter) Write(p []byte) (int, error) {
- n, err := into.wrappedWriter.Write(ansiRegex.ReplaceAll(p, []byte{}))
- if err != nil {
- // The number of bytes returned here isn't directly related to the input bytes
- // if ansi color codes were being stripped out, but we are counting on Stdout.Write
- // not failing under typical operation as well.
- return n, err
- }
-
- // Write must return a non-nil error if it returns n < len(p). Consequently, if the
- // wrappedWrite.Write call succeeded we will return len(p) as the number of bytes
- // written.
- return len(p), nil
-}
-
-// Default returns the default colored ui
-func Default() *cli.ColoredUi {
- return BuildColoredUi(ColorModeUndefined)
-}
-
-func BuildColoredUi(colorMode ColorMode) *cli.ColoredUi {
- colorMode = applyColorMode(colorMode)
-
- var outWriter, errWriter io.Writer
-
- if colorMode == ColorModeSuppressed {
- outWriter = &stripAnsiWriter{wrappedWriter: os.Stdout}
- errWriter = &stripAnsiWriter{wrappedWriter: os.Stderr}
- } else {
- outWriter = os.Stdout
- errWriter = os.Stderr
- }
-
- return &cli.ColoredUi{
- Ui: &cli.BasicUi{
- Reader: os.Stdin,
- Writer: outWriter,
- ErrorWriter: errWriter,
- },
- OutputColor: cli.UiColorNone,
- InfoColor: cli.UiColorNone,
- WarnColor: cli.UiColor{Code: int(color.FgYellow), Bold: false},
- ErrorColor: cli.UiColorRed,
- }
-}
diff --git a/cli/internal/util/backends.go b/cli/internal/util/backends.go
deleted file mode 100644
index 66941ad..0000000
--- a/cli/internal/util/backends.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package util
-
-import (
- "fmt"
- "io/ioutil"
- "path/filepath"
-
- "github.com/vercel/turbo/cli/internal/yaml"
-)
-
-// YarnRC Represents contents of .yarnrc.yml
-type YarnRC struct {
- NodeLinker string `yaml:"nodeLinker"`
-}
-
-// IsNMLinker Checks that Yarn is set to use the node-modules linker style
-func IsNMLinker(cwd string) (bool, error) {
- yarnRC := &YarnRC{}
-
- bytes, err := ioutil.ReadFile(filepath.Join(cwd, ".yarnrc.yml"))
- if err != nil {
- return false, fmt.Errorf(".yarnrc.yml: %w", err)
- }
-
- if yaml.Unmarshal(bytes, yarnRC) != nil {
- return false, fmt.Errorf(".yarnrc.yml: %w", err)
- }
-
- return yarnRC.NodeLinker == "node-modules", nil
-}
diff --git a/cli/internal/util/browser/open.go b/cli/internal/util/browser/open.go
deleted file mode 100644
index a6171e9..0000000
--- a/cli/internal/util/browser/open.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package browser
-
-import (
- "fmt"
- "os/exec"
- "runtime"
-)
-
-// OpenBrowser attempts to interactively open a browser window at the given URL
-func OpenBrowser(url string) error {
- var err error
-
- switch runtime.GOOS {
- case "linux":
- if posixBinExists("wslview") {
- err = exec.Command("wslview", url).Start()
- } else {
- err = exec.Command("xdg-open", url).Start()
- }
- case "windows":
- err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
- case "darwin":
- err = exec.Command("open", url).Start()
- default:
- err = fmt.Errorf("unsupported platform")
- }
- if err != nil {
- return err
- }
- return nil
-}
-
-func posixBinExists(bin string) bool {
- err := exec.Command("which", bin).Run()
- // we mostly don't care what the error is, it suggests the binary is not usable
- return err == nil
-}
diff --git a/cli/internal/util/closer.go b/cli/internal/util/closer.go
deleted file mode 100644
index 996760b..0000000
--- a/cli/internal/util/closer.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package util
-
-// CloseAndIgnoreError is a utility to tell our linter that we explicitly deem it okay
-// to not check a particular error on closing of a resource.
-//
-// We use `errcheck` as a linter, which is super-opinionated about checking errors,
-// even in places where we don't necessarily care to check the error.
-//
-// `golangci-lint` has a default ignore list for this lint problem (EXC0001) which
-// can be used to sidestep this problem but it's possibly a little too-heavy-handed
-// in exclusion. At the expense of discoverability, this utility function forces
-// opt-in to ignoring errors on closing of things that can be `Close`d.
-func CloseAndIgnoreError(closer interface{ Close() error }) {
- _ = closer.Close()
-}
diff --git a/cli/internal/util/cmd.go b/cli/internal/util/cmd.go
deleted file mode 100644
index ae79aa0..0000000
--- a/cli/internal/util/cmd.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package util
-
-import (
- "bytes"
-
- "github.com/spf13/cobra"
-)
-
-// ExitCodeError is a specific error that is returned by the command to specify the exit code
-type ExitCodeError struct {
- ExitCode int
-}
-
-func (e *ExitCodeError) Error() string { return "exit code error" }
-
-// HelpForCobraCmd returns the help string for a given command
-// Note that this overwrites the output for the command
-func HelpForCobraCmd(cmd *cobra.Command) string {
- f := cmd.HelpFunc()
- buf := bytes.NewBufferString("")
- cmd.SetOut(buf)
- f(cmd, []string{})
- return buf.String()
-}
diff --git a/cli/internal/util/filter/filter.go b/cli/internal/util/filter/filter.go
deleted file mode 100644
index fbc475d..0000000
--- a/cli/internal/util/filter/filter.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2015-2020 InfluxData Inc. MIT License (MIT)
-// https://github.com/influxdata/telegraf
-package filter
-
-import (
- "strings"
-
- "github.com/gobwas/glob"
-)
-
-type Filter interface {
- Match(string) bool
-}
-
-// Compile takes a list of string filters and returns a Filter interface
-// for matching a given string against the filter list. The filter list
-// supports glob matching too, ie:
-//
-// f, _ := Compile([]string{"cpu", "mem", "net*"})
-// f.Match("cpu") // true
-// f.Match("network") // true
-// f.Match("memory") // false
-func Compile(filters []string) (Filter, error) {
- // return if there is nothing to compile
- if len(filters) == 0 {
- return nil, nil
- }
-
- // check if we can compile a non-glob filter
- noGlob := true
- for _, filter := range filters {
- if hasMeta(filter) {
- noGlob = false
- break
- }
- }
-
- switch {
- case noGlob:
- // return non-globbing filter if not needed.
- return compileFilterNoGlob(filters), nil
- case len(filters) == 1:
- return glob.Compile(filters[0])
- default:
- return glob.Compile("{" + strings.Join(filters, ",") + "}")
- }
-}
-
-// hasMeta reports whether path contains any magic glob characters.
-func hasMeta(s string) bool {
- return strings.ContainsAny(s, "*?[")
-}
-
-type filter struct {
- m map[string]struct{}
-}
-
-func (f *filter) Match(s string) bool {
- _, ok := f.m[s]
- return ok
-}
-
-type filtersingle struct {
- s string
-}
-
-func (f *filtersingle) Match(s string) bool {
- return f.s == s
-}
-
-func compileFilterNoGlob(filters []string) Filter {
- if len(filters) == 1 {
- return &filtersingle{s: filters[0]}
- }
- out := filter{m: make(map[string]struct{})}
- for _, filter := range filters {
- out.m[filter] = struct{}{}
- }
- return &out
-}
-
-type IncludeExcludeFilter struct {
- include Filter
- exclude Filter
- includeDefault bool
- excludeDefault bool
-}
-
-func NewIncludeExcludeFilter(
- include []string,
- exclude []string,
-) (Filter, error) {
- return NewIncludeExcludeFilterDefaults(include, exclude, true, false)
-}
-
-func NewIncludeExcludeFilterDefaults(
- include []string,
- exclude []string,
- includeDefault bool,
- excludeDefault bool,
-) (Filter, error) {
- in, err := Compile(include)
- if err != nil {
- return nil, err
- }
-
- ex, err := Compile(exclude)
- if err != nil {
- return nil, err
- }
-
- return &IncludeExcludeFilter{in, ex, includeDefault, excludeDefault}, nil
-}
-
-func (f *IncludeExcludeFilter) Match(s string) bool {
- if f.include != nil {
- if !f.include.Match(s) {
- return false
- }
- } else if !f.includeDefault {
- return false
- }
-
- if f.exclude != nil {
- if f.exclude.Match(s) {
- return false
- }
- } else if f.excludeDefault {
- return false
- }
-
- return true
-}
diff --git a/cli/internal/util/filter/filter_test.go b/cli/internal/util/filter/filter_test.go
deleted file mode 100644
index 727a4b6..0000000
--- a/cli/internal/util/filter/filter_test.go
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2015-2020 InfluxData Inc. MIT License (MIT)
-// https://github.com/influxdata/telegraf
-package filter
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCompile(t *testing.T) {
- f, err := Compile([]string{})
- assert.NoError(t, err)
- assert.Nil(t, f)
-
- f, err = Compile([]string{"cpu"})
- assert.NoError(t, err)
- assert.True(t, f.Match("cpu"))
- assert.False(t, f.Match("cpu0"))
- assert.False(t, f.Match("mem"))
-
- f, err = Compile([]string{"cpu*"})
- assert.NoError(t, err)
- assert.True(t, f.Match("cpu"))
- assert.True(t, f.Match("cpu0"))
- assert.False(t, f.Match("mem"))
-
- f, err = Compile([]string{"cpu", "mem"})
- assert.NoError(t, err)
- assert.True(t, f.Match("cpu"))
- assert.False(t, f.Match("cpu0"))
- assert.True(t, f.Match("mem"))
-
- f, err = Compile([]string{"cpu", "mem", "net*"})
- assert.NoError(t, err)
- assert.True(t, f.Match("cpu"))
- assert.False(t, f.Match("cpu0"))
- assert.True(t, f.Match("mem"))
- assert.True(t, f.Match("network"))
-}
-
-func TestIncludeExclude(t *testing.T) {
- tags := []string{}
- labels := []string{"best", "com_influxdata", "timeseries", "com_influxdata_telegraf", "ever"}
-
- filter, err := NewIncludeExcludeFilter([]string{}, []string{"com_influx*"})
- if err != nil {
- t.Fatalf("Failed to create include/exclude filter - %v", err)
- }
-
- for i := range labels {
- if filter.Match(labels[i]) {
- tags = append(tags, labels[i])
- }
- }
-
- assert.Equal(t, []string{"best", "timeseries", "ever"}, tags)
-}
-
-var benchbool bool
-
-func BenchmarkFilterSingleNoGlobFalse(b *testing.B) {
- f, _ := Compile([]string{"cpu"})
- var tmp bool
- for n := 0; n < b.N; n++ {
- tmp = f.Match("network")
- }
- benchbool = tmp
-}
-
-func BenchmarkFilterSingleNoGlobTrue(b *testing.B) {
- f, _ := Compile([]string{"cpu"})
- var tmp bool
- for n := 0; n < b.N; n++ {
- tmp = f.Match("cpu")
- }
- benchbool = tmp
-}
-
-func BenchmarkFilter(b *testing.B) {
- f, _ := Compile([]string{"cpu", "mem", "net*"})
- var tmp bool
- for n := 0; n < b.N; n++ {
- tmp = f.Match("network")
- }
- benchbool = tmp
-}
-
-func BenchmarkFilterNoGlob(b *testing.B) {
- f, _ := Compile([]string{"cpu", "mem", "net"})
- var tmp bool
- for n := 0; n < b.N; n++ {
- tmp = f.Match("net")
- }
- benchbool = tmp
-}
-
-func BenchmarkFilter2(b *testing.B) {
- f, _ := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq",
- "aw", "az", "axxx", "ab", "cpu", "mem", "net*"})
- var tmp bool
- for n := 0; n < b.N; n++ {
- tmp = f.Match("network")
- }
- benchbool = tmp
-}
-
-func BenchmarkFilter2NoGlob(b *testing.B) {
- f, _ := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq",
- "aw", "az", "axxx", "ab", "cpu", "mem", "net"})
- var tmp bool
- for n := 0; n < b.N; n++ {
- tmp = f.Match("net")
- }
- benchbool = tmp
-}
diff --git a/cli/internal/util/graph.go b/cli/internal/util/graph.go
deleted file mode 100644
index 89de18c..0000000
--- a/cli/internal/util/graph.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package util
-
-import (
- "fmt"
- "strings"
-
- "github.com/pyr-sh/dag"
-)
-
-// ValidateGraph checks that a given DAG has no cycles and no self-referential edges.
-// We differ from the underlying DAG Validate method in that we allow multiple roots.
-func ValidateGraph(graph *dag.AcyclicGraph) error {
- // We use Cycles instead of Validate because
- // our DAG has multiple roots (entrypoints).
- // Validate mandates that there is only a single root node.
- cycles := graph.Cycles()
- if len(cycles) > 0 {
- cycleLines := make([]string, len(cycles))
- for i, cycle := range cycles {
- vertices := make([]string, len(cycle))
- for j, vertex := range cycle {
- vertices[j] = vertex.(string)
- }
- cycleLines[i] = "\t" + strings.Join(vertices, ",")
- }
- return fmt.Errorf("cyclic dependency detected:\n%s", strings.Join(cycleLines, "\n"))
- }
-
- for _, e := range graph.Edges() {
- if e.Source() == e.Target() {
- return fmt.Errorf("%s depends on itself", e.Source())
- }
- }
- return nil
-}
diff --git a/cli/internal/util/modulo.go b/cli/internal/util/modulo.go
deleted file mode 100644
index ec2957a..0000000
--- a/cli/internal/util/modulo.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package util
-
-// PostitiveMod returns a modulo operator like JavaScripts
-func PositiveMod(x, d int) int {
- x = x % d
- if x >= 0 {
- return x
- }
- if d < 0 {
- return x - d
- }
- return x + d
-}
diff --git a/cli/internal/util/parse_concurrency.go b/cli/internal/util/parse_concurrency.go
deleted file mode 100644
index 6917600..0000000
--- a/cli/internal/util/parse_concurrency.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package util
-
-import (
- "fmt"
- "math"
- "runtime"
- "strconv"
- "strings"
-)
-
-var (
- // alias so we can mock in tests
- runtimeNumCPU = runtime.NumCPU
- // positive values check for +Inf
- _positiveInfinity = 1
-)
-
-// ParseConcurrency parses a concurrency value, which can be a number (e.g. 2) or a percentage (e.g. 50%).
-func ParseConcurrency(concurrencyRaw string) (int, error) {
- if strings.HasSuffix(concurrencyRaw, "%") {
- if percent, err := strconv.ParseFloat(concurrencyRaw[:len(concurrencyRaw)-1], 64); err != nil {
- return 0, fmt.Errorf("invalid value for --concurrency CLI flag. This should be a number --concurrency=4 or percentage of CPU cores --concurrency=50%% : %w", err)
- } else {
- if percent > 0 && !math.IsInf(percent, _positiveInfinity) {
- return int(math.Max(1, float64(runtimeNumCPU())*percent/100)), nil
- } else {
- return 0, fmt.Errorf("invalid percentage value for --concurrency CLI flag. This should be a percentage of CPU cores, between 1%% and 100%% : %w", err)
- }
- }
- } else if i, err := strconv.Atoi(concurrencyRaw); err != nil {
- return 0, fmt.Errorf("invalid value for --concurrency CLI flag. This should be a positive integer greater than or equal to 1: %w", err)
- } else {
- if i >= 1 {
- return i, nil
- } else {
- return 0, fmt.Errorf("invalid value %v for --concurrency CLI flag. This should be a positive integer greater than or equal to 1", i)
- }
- }
-}
diff --git a/cli/internal/util/parse_concurrency_test.go b/cli/internal/util/parse_concurrency_test.go
deleted file mode 100644
index b732724..0000000
--- a/cli/internal/util/parse_concurrency_test.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package util
-
-import (
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestParseConcurrency(t *testing.T) {
- cases := []struct {
- Input string
- Expected int
- }{
- {
- "12",
- 12,
- },
- {
- "200%",
- 20,
- },
- {
- "100%",
- 10,
- },
- {
- "50%",
- 5,
- },
- {
- "25%",
- 2,
- },
- {
- "1%",
- 1,
- },
- {
- "0644", // we parse in base 10
- 644,
- },
- }
-
- // mock runtime.NumCPU() to 10
- runtimeNumCPU = func() int {
- return 10
- }
-
- for i, tc := range cases {
- t.Run(fmt.Sprintf("%d) '%s' should be parsed at '%d'", i, tc.Input, tc.Expected), func(t *testing.T) {
- if result, err := ParseConcurrency(tc.Input); err != nil {
- t.Fatalf("invalid parse: %#v", err)
- } else {
- assert.EqualValues(t, tc.Expected, result)
- }
- })
- }
-}
-
-func TestInvalidPercents(t *testing.T) {
- inputs := []string{
- "asdf",
- "-1",
- "-l%",
- "infinity%",
- "-infinity%",
- "nan%",
- "0b01",
- "0o644",
- "0xFF",
- }
- for _, tc := range inputs {
- t.Run(tc, func(t *testing.T) {
- val, err := ParseConcurrency(tc)
- assert.Error(t, err, "input %v got %v", tc, val)
- })
- }
-}
diff --git a/cli/internal/util/printf.go b/cli/internal/util/printf.go
deleted file mode 100644
index 9cd6dce..0000000
--- a/cli/internal/util/printf.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright Thought Machine, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-package util
-
-import (
- "fmt"
- "io"
- "os"
-
- "github.com/vercel/turbo/cli/internal/ui"
-)
-
-// initPrintf sets up the replacements used by printf.
-func InitPrintf() {
- if !ui.IsTTY {
- replacements = map[string]string{}
- }
-}
-
-// printf is used throughout this package to print something to stderr with some
-// replacements for pseudo-shell variables for ANSI formatting codes.
-func Sprintf(format string, args ...interface{}) string {
- return os.Expand(fmt.Sprintf(format, args...), replace)
-}
-
-func Printf(format string, args ...interface{}) {
- fmt.Fprint(os.Stderr, os.Expand(fmt.Sprintf(format, args...), replace))
-}
-
-func Fprintf(writer io.Writer, format string, args ...interface{}) {
- fmt.Fprint(writer, os.Expand(fmt.Sprintf(format, args...), replace))
-}
-
-func replace(s string) string {
- return replacements[s]
-}
-
-// These are the standard set of replacements we use.
-var replacements = map[string]string{
- "BOLD": "\x1b[1m",
- "BOLD_GREY": "\x1b[30;1m",
- "BOLD_RED": "\x1b[31;1m",
- "BOLD_GREEN": "\x1b[32;1m",
- "BOLD_YELLOW": "\x1b[33;1m",
- "BOLD_BLUE": "\x1b[34;1m",
- "BOLD_MAGENTA": "\x1b[35;1m",
- "BOLD_CYAN": "\x1b[36;1m",
- "BOLD_WHITE": "\x1b[37;1m",
- "UNDERLINE": "\x1b[4m",
- "GREY": "\x1b[2m",
- "RED": "\x1b[31m",
- "GREEN": "\x1b[32m",
- "YELLOW": "\x1b[33m",
- "BLUE": "\x1b[34m",
- "MAGENTA": "\x1b[35m",
- "CYAN": "\x1b[36m",
- "WHITE": "\x1b[37m",
- "WHITE_ON_RED": "\x1b[37;41;1m",
- "RED_NO_BG": "\x1b[31;49;1m",
- "RESET": "\x1b[0m",
- "ERASE_AFTER": "\x1b[K",
- "CLEAR_END": "\x1b[0J",
-}
diff --git a/cli/internal/util/run_opts.go b/cli/internal/util/run_opts.go
deleted file mode 100644
index 08676a0..0000000
--- a/cli/internal/util/run_opts.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package util
-
-import "strings"
-
-// EnvMode specifies if we will be using strict env vars
-type EnvMode string
-
-const (
- // Infer - infer environment variable constraints from turbo.json
- Infer EnvMode = "Infer"
- // Loose - environment variables are unconstrained
- Loose EnvMode = "Loose"
- // Strict - environment variables are limited
- Strict EnvMode = "Strict"
-)
-
-// MarshalText implements TextMarshaler for the struct.
-func (s EnvMode) MarshalText() (text []byte, err error) {
- return []byte(strings.ToLower(string(s))), nil
-}
-
-// RunOpts holds the options that control the execution of a turbo run
-type RunOpts struct {
- // Force execution to be serially one-at-a-time
- Concurrency int
- // Whether to execute in parallel (defaults to false)
- Parallel bool
-
- EnvMode EnvMode
- // The filename to write a perf profile.
- Profile string
- // If true, continue task executions even if a task fails.
- ContinueOnError bool
- PassThroughArgs []string
- // Restrict execution to only the listed task names. Default false
- Only bool
- // Dry run flags
- DryRun bool
- DryRunJSON bool
- // Graph flags
- GraphDot bool
- GraphFile string
- NoDaemon bool
- SinglePackage bool
-
- // logPrefix controls whether we should print a prefix in task logs
- LogPrefix string
-
- // Whether turbo should create a run summary
- Summarize bool
-
- ExperimentalSpaceID string
-}
diff --git a/cli/internal/util/semaphore.go b/cli/internal/util/semaphore.go
deleted file mode 100644
index ef29df0..0000000
--- a/cli/internal/util/semaphore.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package util
-
-// Semaphore is a wrapper around a channel to provide
-// utility methods to clarify that we are treating the
-// channel as a semaphore
-type Semaphore chan struct{}
-
-// NewSemaphore creates a semaphore that allows up
-// to a given limit of simultaneous acquisitions
-func NewSemaphore(n int) Semaphore {
- if n <= 0 {
- panic("semaphore with limit <=0")
- }
- ch := make(chan struct{}, n)
- return Semaphore(ch)
-}
-
-// Acquire is used to acquire an available slot.
-// Blocks until available.
-func (s Semaphore) Acquire() {
- s <- struct{}{}
-}
-
-// TryAcquire is used to do a non-blocking acquire.
-// Returns a bool indicating success
-func (s Semaphore) TryAcquire() bool {
- select {
- case s <- struct{}{}:
- return true
- default:
- return false
- }
-}
-
-// Release is used to return a slot. Acquire must
-// be called as a pre-condition.
-func (s Semaphore) Release() {
- select {
- case <-s:
- default:
- panic("release without an acquire")
- }
-}
diff --git a/cli/internal/util/set.go b/cli/internal/util/set.go
deleted file mode 100644
index b6c5f86..0000000
--- a/cli/internal/util/set.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package util
-
-// Set is a set data structure.
-type Set map[interface{}]interface{}
-
-// SetFromStrings creates a Set containing the strings from the given slice
-func SetFromStrings(sl []string) Set {
- set := make(Set, len(sl))
- for _, item := range sl {
- set.Add(item)
- }
- return set
-}
-
-// Hashable is the interface used by set to get the hash code of a value.
-// If this isn't given, then the value of the item being added to the set
-// itself is used as the comparison value.
-type Hashable interface {
- Hashcode() interface{}
-}
-
-// hashcode returns the hashcode used for set elements.
-func hashcode(v interface{}) interface{} {
- if h, ok := v.(Hashable); ok {
- return h.Hashcode()
- }
-
- return v
-}
-
-// Add adds an item to the set
-func (s Set) Add(v interface{}) {
- s[hashcode(v)] = v
-}
-
-// Delete removes an item from the set.
-func (s Set) Delete(v interface{}) {
- delete(s, hashcode(v))
-}
-
-// Includes returns true/false of whether a value is in the set.
-func (s Set) Includes(v interface{}) bool {
- _, ok := s[hashcode(v)]
- return ok
-}
-
-// Intersection computes the set intersection with other.
-func (s Set) Intersection(other Set) Set {
- result := make(Set)
- if s == nil || other == nil {
- return result
- }
- // Iteration over a smaller set has better performance.
- if other.Len() < s.Len() {
- s, other = other, s
- }
- for _, v := range s {
- if other.Includes(v) {
- result.Add(v)
- }
- }
- return result
-}
-
-// Difference returns a set with the elements that s has but
-// other doesn't.
-func (s Set) Difference(other Set) Set {
- result := make(Set)
- for k, v := range s {
- var ok bool
- if other != nil {
- _, ok = other[k]
- }
- if !ok {
- result.Add(v)
- }
- }
-
- return result
-}
-
-// Some tests whether at least one element in the array passes the test implemented by the provided function.
-// It returns a Boolean value.
-func (s Set) Some(cb func(interface{}) bool) bool {
- for _, v := range s {
- if cb(v) {
- return true
- }
- }
- return false
-}
-
-// Filter returns a set that contains the elements from the receiver
-// where the given callback returns true.
-func (s Set) Filter(cb func(interface{}) bool) Set {
- result := make(Set)
-
- for _, v := range s {
- if cb(v) {
- result.Add(v)
- }
- }
-
- return result
-}
-
-// Len is the number of items in the set.
-func (s Set) Len() int {
- return len(s)
-}
-
-// List returns the list of set elements.
-func (s Set) List() []interface{} {
- if s == nil {
- return nil
- }
-
- r := make([]interface{}, 0, len(s))
- for _, v := range s {
- r = append(r, v)
- }
-
- return r
-}
-
-// UnsafeListOfStrings dangerously casts list to a string
-func (s Set) UnsafeListOfStrings() []string {
- if s == nil {
- return nil
- }
-
- r := make([]string, 0, len(s))
- for _, v := range s {
- r = append(r, v.(string))
- }
-
- return r
-}
-
-// Copy returns a shallow copy of the set.
-func (s Set) Copy() Set {
- c := make(Set)
- for k, v := range s {
- c[k] = v
- }
- return c
-}
diff --git a/cli/internal/util/set_test.go b/cli/internal/util/set_test.go
deleted file mode 100644
index 52736b4..0000000
--- a/cli/internal/util/set_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package util
-
-import (
- "fmt"
- "testing"
-)
-
-func TestSetDifference(t *testing.T) {
- cases := []struct {
- Name string
- A, B []interface{}
- Expected []interface{}
- }{
- {
- "same",
- []interface{}{1, 2, 3},
- []interface{}{3, 1, 2},
- []interface{}{},
- },
-
- {
- "A has extra elements",
- []interface{}{1, 2, 3},
- []interface{}{3, 2},
- []interface{}{1},
- },
-
- {
- "B has extra elements",
- []interface{}{1, 2, 3},
- []interface{}{3, 2, 1, 4},
- []interface{}{},
- },
- }
-
- for i, tc := range cases {
- t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
- one := make(Set)
- two := make(Set)
- expected := make(Set)
- for _, v := range tc.A {
- one.Add(v)
- }
- for _, v := range tc.B {
- two.Add(v)
- }
- for _, v := range tc.Expected {
- expected.Add(v)
- }
-
- actual := one.Difference(two)
- match := actual.Intersection(expected)
- if match.Len() != expected.Len() {
- t.Fatalf("bad: %#v", actual.List())
- }
- })
- }
-}
-
-func TestSetFilter(t *testing.T) {
- cases := []struct {
- Input []interface{}
- Expected []interface{}
- }{
- {
- []interface{}{1, 2, 3},
- []interface{}{1, 2, 3},
- },
-
- {
- []interface{}{4, 5, 6},
- []interface{}{4},
- },
-
- {
- []interface{}{7, 8, 9},
- []interface{}{},
- },
- }
-
- for i, tc := range cases {
- t.Run(fmt.Sprintf("%d-%#v", i, tc.Input), func(t *testing.T) {
- input := make(Set)
- expected := make(Set)
- for _, v := range tc.Input {
- input.Add(v)
- }
- for _, v := range tc.Expected {
- expected.Add(v)
- }
-
- actual := input.Filter(func(v interface{}) bool {
- return v.(int) < 5
- })
- match := actual.Intersection(expected)
- if match.Len() != expected.Len() {
- t.Fatalf("bad: %#v", actual.List())
- }
- })
- }
-}
-
-func TestSetCopy(t *testing.T) {
- a := make(Set)
- a.Add(1)
- a.Add(2)
-
- b := a.Copy()
- b.Add(3)
-
- diff := b.Difference(a)
-
- if diff.Len() != 1 {
- t.Fatalf("expected single diff value, got %#v", diff)
- }
-
- if !diff.Includes(3) {
- t.Fatalf("diff does not contain 3, got %#v", diff)
- }
-
-}
-
-func makeSet(n int) Set {
- ret := make(Set, n)
- for i := 0; i < n; i++ {
- ret.Add(i)
- }
- return ret
-}
-
-func BenchmarkSetIntersection_100_100000(b *testing.B) {
- small := makeSet(100)
- large := makeSet(100000)
-
- b.ResetTimer()
- for n := 0; n < b.N; n++ {
- small.Intersection(large)
- }
-}
-
-func BenchmarkSetIntersection_100000_100(b *testing.B) {
- small := makeSet(100)
- large := makeSet(100000)
-
- b.ResetTimer()
- for n := 0; n < b.N; n++ {
- large.Intersection(small)
- }
-}
diff --git a/cli/internal/util/status.go b/cli/internal/util/status.go
deleted file mode 100644
index 23ae165..0000000
--- a/cli/internal/util/status.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package util
-
-import "fmt"
-
-// CachingStatus represents the api server's perspective
-// on whether remote caching should be allowed
-type CachingStatus int
-
-const (
- // CachingStatusDisabled indicates that the server will not accept or serve artifacts
- CachingStatusDisabled CachingStatus = iota
- // CachingStatusEnabled indicates that the server will accept and serve artifacts
- CachingStatusEnabled
- // CachingStatusOverLimit indicates that a usage limit has been hit and the
- // server will temporarily not accept or serve artifacts
- CachingStatusOverLimit
- // CachingStatusPaused indicates that a customer's spending has been paused and the
- // server will temporarily not accept or serve artifacts
- CachingStatusPaused
-)
-
-// CachingStatusFromString parses a raw string to a caching status enum value
-func CachingStatusFromString(raw string) (CachingStatus, error) {
- switch raw {
- case "disabled":
- return CachingStatusDisabled, nil
- case "enabled":
- return CachingStatusEnabled, nil
- case "over_limit":
- return CachingStatusOverLimit, nil
- case "paused":
- return CachingStatusPaused, nil
- default:
- return CachingStatusDisabled, fmt.Errorf("unknown caching status: %v", raw)
- }
-}
-
-// CacheDisabledError is an error used to indicate that remote caching
-// is not available.
-type CacheDisabledError struct {
- Status CachingStatus
- Message string
-}
-
-func (cd *CacheDisabledError) Error() string {
- return cd.Message
-}
diff --git a/cli/internal/util/task_id.go b/cli/internal/util/task_id.go
deleted file mode 100644
index e4415b6..0000000
--- a/cli/internal/util/task_id.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package util
-
-import (
- "fmt"
- "strings"
-)
-
-const (
- // TaskDelimiter separates a package name from a task name in a task id
- TaskDelimiter = "#"
- // RootPkgName is the reserved name that specifies the root package
- RootPkgName = "//"
-)
-
-// GetTaskId returns a package-task identifier (e.g @feed/thing#build).
-func GetTaskId(pkgName interface{}, target string) string {
- if IsPackageTask(target) {
- return target
- }
- return fmt.Sprintf("%v%v%v", pkgName, TaskDelimiter, target)
-}
-
-// RootTaskID returns the task id for running the given task in the root package
-func RootTaskID(target string) string {
- return GetTaskId(RootPkgName, target)
-}
-
-// GetPackageTaskFromId returns a tuple of the package name and target task
-func GetPackageTaskFromId(taskId string) (packageName string, task string) {
- arr := strings.Split(taskId, TaskDelimiter)
- return arr[0], arr[1]
-}
-
-// RootTaskTaskName returns the task portion of a root task taskID
-func RootTaskTaskName(taskID string) string {
- return strings.TrimPrefix(taskID, RootPkgName+TaskDelimiter)
-}
-
-// IsPackageTask returns true if input is a package-specific task
-// whose name has a length greater than 0.
-//
-// Accepted: myapp#build
-// Rejected: #build, build
-func IsPackageTask(task string) bool {
- return strings.Index(task, TaskDelimiter) > 0
-}
-
-// IsTaskInPackage returns true if the task does not belong to a different package
-// note that this means unscoped tasks will always return true
-func IsTaskInPackage(task string, packageName string) bool {
- if !IsPackageTask(task) {
- return true
- }
- packageNameExpected, _ := GetPackageTaskFromId(task)
- return packageNameExpected == packageName
-}
-
-// StripPackageName removes the package portion of a taskID if it
-// is a package task. Non-package tasks are returned unmodified
-func StripPackageName(taskID string) string {
- if IsPackageTask(taskID) {
- _, task := GetPackageTaskFromId(taskID)
- return task
- }
- return taskID
-}
diff --git a/cli/internal/util/task_output_mode.go b/cli/internal/util/task_output_mode.go
deleted file mode 100644
index eee42e0..0000000
--- a/cli/internal/util/task_output_mode.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package util
-
-import (
- "encoding/json"
- "fmt"
-)
-
-// TaskOutputMode defines the ways turbo can display task output during a run
-type TaskOutputMode int
-
-const (
- // FullTaskOutput will show all task output
- FullTaskOutput TaskOutputMode = iota
- // NoTaskOutput will hide all task output
- NoTaskOutput
- // HashTaskOutput will display turbo-computed task hashes
- HashTaskOutput
- // NewTaskOutput will show all new task output and turbo-computed task hashes for cached output
- NewTaskOutput
- // ErrorTaskOutput will show task output for failures only; no cache miss/hit messages are emitted
- ErrorTaskOutput
-)
-
-const (
- fullTaskOutputString = "full"
- noTaskOutputString = "none"
- hashTaskOutputString = "hash-only"
- newTaskOutputString = "new-only"
- errorTaskOutputString = "errors-only"
-)
-
-// TaskOutputModeStrings is an array containing the string representations for task output modes
-var TaskOutputModeStrings = []string{
- fullTaskOutputString,
- noTaskOutputString,
- hashTaskOutputString,
- newTaskOutputString,
- errorTaskOutputString,
-}
-
-// FromTaskOutputModeString converts a task output mode's string representation into the enum value
-func FromTaskOutputModeString(value string) (TaskOutputMode, error) {
- switch value {
- case fullTaskOutputString:
- return FullTaskOutput, nil
- case noTaskOutputString:
- return NoTaskOutput, nil
- case hashTaskOutputString:
- return HashTaskOutput, nil
- case newTaskOutputString:
- return NewTaskOutput, nil
- case errorTaskOutputString:
- return ErrorTaskOutput, nil
- }
-
- return FullTaskOutput, fmt.Errorf("invalid task output mode: %v", value)
-}
-
-// ToTaskOutputModeString converts a task output mode enum value into the string representation
-func ToTaskOutputModeString(value TaskOutputMode) (string, error) {
- switch value {
- case FullTaskOutput:
- return fullTaskOutputString, nil
- case NoTaskOutput:
- return noTaskOutputString, nil
- case HashTaskOutput:
- return hashTaskOutputString, nil
- case NewTaskOutput:
- return newTaskOutputString, nil
- case ErrorTaskOutput:
- return errorTaskOutputString, nil
- }
-
- return "", fmt.Errorf("invalid task output mode: %v", value)
-}
-
-// UnmarshalJSON converts a task output mode string representation into an enum
-func (c *TaskOutputMode) UnmarshalJSON(data []byte) error {
- var rawTaskOutputMode string
- if err := json.Unmarshal(data, &rawTaskOutputMode); err != nil {
- return err
- }
-
- taskOutputMode, err := FromTaskOutputModeString(rawTaskOutputMode)
- if err != nil {
- return err
- }
-
- *c = taskOutputMode
- return nil
-}
-
-// MarshalJSON converts a task output mode to its string representation
-func (c TaskOutputMode) MarshalJSON() ([]byte, error) {
- outputModeString, err := ToTaskOutputModeString(c)
- if err != nil {
- return nil, err
- }
- return json.Marshal(outputModeString)
-}
diff --git a/cli/internal/workspace/workspace.go b/cli/internal/workspace/workspace.go
deleted file mode 100644
index fcd1eb8..0000000
--- a/cli/internal/workspace/workspace.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// Package workspace contains some utilities around managing workspaces
-package workspace
-
-import "github.com/vercel/turbo/cli/internal/fs"
-
-// Catalog holds information about each workspace in the monorepo.
-type Catalog struct {
- PackageJSONs map[string]*fs.PackageJSON
- TurboConfigs map[string]*fs.TurboJSON
-}
diff --git a/cli/internal/xxhash/xxhash.go b/cli/internal/xxhash/xxhash.go
deleted file mode 100644
index 642ac73..0000000
--- a/cli/internal/xxhash/xxhash.go
+++ /dev/null
@@ -1,202 +0,0 @@
-// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
-// at http://cyan4973.github.io/xxHash/.
-
-// Adapted from https://cs.github.com/evanw/esbuild/blob/0c9ced59c8b3ea3bd8dd5feebafed1f47ed279dd/internal/xxhash
-// Copyright (c) 2016 Caleb Spare. All rights reserved.
-// SPDX-License-Identifier: MIT
-package xxhash
-
-import (
- "encoding/binary"
- "math/bits"
-)
-
-const (
- prime1 uint64 = 11400714785074694791
- prime2 uint64 = 14029467366897019727
- prime3 uint64 = 1609587929392839161
- prime4 uint64 = 9650029242287828579
- prime5 uint64 = 2870177450012600261
-)
-
-// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
-// possible in the Go code is worth a small (but measurable) performance boost
-// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
-// convenience in the Go code in a few places where we need to intentionally
-// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
-// result overflows a uint64).
-var prime1v = prime1
-
-// Digest implements hash.Hash64.
-type Digest struct {
- v1 uint64
- v2 uint64
- v3 uint64
- v4 uint64
- total uint64
- mem [32]byte
- n int // how much of mem is used
-}
-
-// New creates a new Digest that computes the 64-bit xxHash algorithm.
-func New() *Digest {
- var d Digest
- d.Reset()
- return &d
-}
-
-// Reset clears the Digest's state so that it can be reused.
-func (d *Digest) Reset() {
- d.v1 = prime1v + prime2
- d.v2 = prime2
- d.v3 = 0
- d.v4 = -prime1v
- d.total = 0
- d.n = 0
-}
-
-// Size always returns 8 bytes.
-func (d *Digest) Size() int { return 8 }
-
-// BlockSize always returns 32 bytes.
-func (d *Digest) BlockSize() int { return 32 }
-
-// Write adds more data to d. It always returns len(b), nil.
-func (d *Digest) Write(b []byte) (n int, err error) {
- n = len(b)
- d.total += uint64(n)
-
- if d.n+n < 32 {
- // This new data doesn't even fill the current block.
- copy(d.mem[d.n:], b)
- d.n += n
- return
- }
-
- if d.n > 0 {
- // Finish off the partial block.
- copy(d.mem[d.n:], b)
- d.v1 = round(d.v1, u64(d.mem[0:8]))
- d.v2 = round(d.v2, u64(d.mem[8:16]))
- d.v3 = round(d.v3, u64(d.mem[16:24]))
- d.v4 = round(d.v4, u64(d.mem[24:32]))
- b = b[32-d.n:]
- d.n = 0
- }
-
- if len(b) >= 32 {
- // One or more full blocks left.
- nw := writeBlocks(d, b)
- b = b[nw:]
- }
-
- // Store any remaining partial block.
- copy(d.mem[:], b)
- d.n = len(b)
-
- return
-}
-
-// Sum appends the current hash to b and returns the resulting slice.
-func (d *Digest) Sum(b []byte) []byte {
- s := d.Sum64()
- return append(
- b,
- byte(s>>56),
- byte(s>>48),
- byte(s>>40),
- byte(s>>32),
- byte(s>>24),
- byte(s>>16),
- byte(s>>8),
- byte(s),
- )
-}
-
-// Sum64 returns the current hash.
-func (d *Digest) Sum64() uint64 {
- var h uint64
-
- if d.total >= 32 {
- v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
- h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
- h = mergeRound(h, v1)
- h = mergeRound(h, v2)
- h = mergeRound(h, v3)
- h = mergeRound(h, v4)
- } else {
- h = d.v3 + prime5
- }
-
- h += d.total
-
- i, end := 0, d.n
- for ; i+8 <= end; i += 8 {
- k1 := round(0, u64(d.mem[i:i+8]))
- h ^= k1
- h = rol27(h)*prime1 + prime4
- }
- if i+4 <= end {
- h ^= uint64(u32(d.mem[i:i+4])) * prime1
- h = rol23(h)*prime2 + prime3
- i += 4
- }
- for i < end {
- h ^= uint64(d.mem[i]) * prime5
- h = rol11(h) * prime1
- i++
- }
-
- h ^= h >> 33
- h *= prime2
- h ^= h >> 29
- h *= prime3
- h ^= h >> 32
-
- return h
-}
-
-const (
- magic = "xxh\x06"
- marshaledSize = len(magic) + 8*5 + 32
-)
-
-func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
-func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
-
-func round(acc, input uint64) uint64 {
- acc += input * prime2
- acc = rol31(acc)
- acc *= prime1
- return acc
-}
-
-func mergeRound(acc, val uint64) uint64 {
- val = round(0, val)
- acc ^= val
- acc = acc*prime1 + prime4
- return acc
-}
-
-func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) }
-func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) }
-func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
-func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
-func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
-func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
-func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
-func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }
-
-func writeBlocks(d *Digest, b []byte) int {
- v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
- n := len(b)
- for len(b) >= 32 {
- v1 = round(v1, u64(b[0:8:len(b)]))
- v2 = round(v2, u64(b[8:16:len(b)]))
- v3 = round(v3, u64(b[16:24:len(b)]))
- v4 = round(v4, u64(b[24:32:len(b)]))
- b = b[32:len(b):len(b)]
- }
- d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
- return n - len(b)
-}
diff --git a/cli/internal/yaml/apic.go b/cli/internal/yaml/apic.go
deleted file mode 100644
index 05fd305..0000000
--- a/cli/internal/yaml/apic.go
+++ /dev/null
@@ -1,747 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
- "io"
-)
-
-func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
- //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
-
- // Check if we can move the queue at the beginning of the buffer.
- if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
- if parser.tokens_head != len(parser.tokens) {
- copy(parser.tokens, parser.tokens[parser.tokens_head:])
- }
- parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
- parser.tokens_head = 0
- }
- parser.tokens = append(parser.tokens, *token)
- if pos < 0 {
- return
- }
- copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
- parser.tokens[parser.tokens_head+pos] = *token
-}
-
-// Create a new parser object.
-func yaml_parser_initialize(parser *yaml_parser_t) bool {
- *parser = yaml_parser_t{
- raw_buffer: make([]byte, 0, input_raw_buffer_size),
- buffer: make([]byte, 0, input_buffer_size),
- }
- return true
-}
-
-// Destroy a parser object.
-func yaml_parser_delete(parser *yaml_parser_t) {
- *parser = yaml_parser_t{}
-}
-
-// String read handler.
-func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
- if parser.input_pos == len(parser.input) {
- return 0, io.EOF
- }
- n = copy(buffer, parser.input[parser.input_pos:])
- parser.input_pos += n
- return n, nil
-}
-
-// Reader read handler.
-func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
- return parser.input_reader.Read(buffer)
-}
-
-// Set a string input.
-func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
- if parser.read_handler != nil {
- panic("must set the input source only once")
- }
- parser.read_handler = yaml_string_read_handler
- parser.input = input
- parser.input_pos = 0
-}
-
-// Set a file input.
-func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
- if parser.read_handler != nil {
- panic("must set the input source only once")
- }
- parser.read_handler = yaml_reader_read_handler
- parser.input_reader = r
-}
-
-// Set the source encoding.
-func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
- if parser.encoding != yaml_ANY_ENCODING {
- panic("must set the encoding only once")
- }
- parser.encoding = encoding
-}
-
-// Create a new emitter object.
-func yaml_emitter_initialize(emitter *yaml_emitter_t) {
- *emitter = yaml_emitter_t{
- buffer: make([]byte, output_buffer_size),
- raw_buffer: make([]byte, 0, output_raw_buffer_size),
- states: make([]yaml_emitter_state_t, 0, initial_stack_size),
- events: make([]yaml_event_t, 0, initial_queue_size),
- best_width: -1,
- }
-}
-
-// Destroy an emitter object.
-func yaml_emitter_delete(emitter *yaml_emitter_t) {
- *emitter = yaml_emitter_t{}
-}
-
-// String write handler.
-func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
- *emitter.output_buffer = append(*emitter.output_buffer, buffer...)
- return nil
-}
-
-// yaml_writer_write_handler uses emitter.output_writer to write the
-// emitted text.
-func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
- _, err := emitter.output_writer.Write(buffer)
- return err
-}
-
-// Set a string output.
-func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
- if emitter.write_handler != nil {
- panic("must set the output target only once")
- }
- emitter.write_handler = yaml_string_write_handler
- emitter.output_buffer = output_buffer
-}
-
-// Set a file output.
-func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
- if emitter.write_handler != nil {
- panic("must set the output target only once")
- }
- emitter.write_handler = yaml_writer_write_handler
- emitter.output_writer = w
-}
-
-// Set the output encoding.
-func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
- if emitter.encoding != yaml_ANY_ENCODING {
- panic("must set the output encoding only once")
- }
- emitter.encoding = encoding
-}
-
-// Set the canonical output style.
-func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
- emitter.canonical = canonical
-}
-
-// Set the indentation increment.
-func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
- if indent < 2 || indent > 9 {
- indent = 2
- }
- emitter.best_indent = indent
-}
-
-// Set the preferred line width.
-func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
- if width < 0 {
- width = -1
- }
- emitter.best_width = width
-}
-
-// Set if unescaped non-ASCII characters are allowed.
-func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
- emitter.unicode = unicode
-}
-
-// Set the preferred line break character.
-func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
- emitter.line_break = line_break
-}
-
-///*
-// * Destroy a token object.
-// */
-//
-//YAML_DECLARE(void)
-//yaml_token_delete(yaml_token_t *token)
-//{
-// assert(token); // Non-NULL token object expected.
-//
-// switch (token.type)
-// {
-// case YAML_TAG_DIRECTIVE_TOKEN:
-// yaml_free(token.data.tag_directive.handle);
-// yaml_free(token.data.tag_directive.prefix);
-// break;
-//
-// case YAML_ALIAS_TOKEN:
-// yaml_free(token.data.alias.value);
-// break;
-//
-// case YAML_ANCHOR_TOKEN:
-// yaml_free(token.data.anchor.value);
-// break;
-//
-// case YAML_TAG_TOKEN:
-// yaml_free(token.data.tag.handle);
-// yaml_free(token.data.tag.suffix);
-// break;
-//
-// case YAML_SCALAR_TOKEN:
-// yaml_free(token.data.scalar.value);
-// break;
-//
-// default:
-// break;
-// }
-//
-// memset(token, 0, sizeof(yaml_token_t));
-//}
-//
-///*
-// * Check if a string is a valid UTF-8 sequence.
-// *
-// * Check 'reader.c' for more details on UTF-8 encoding.
-// */
-//
-//static int
-//yaml_check_utf8(yaml_char_t *start, size_t length)
-//{
-// yaml_char_t *end = start+length;
-// yaml_char_t *pointer = start;
-//
-// while (pointer < end) {
-// unsigned char octet;
-// unsigned int width;
-// unsigned int value;
-// size_t k;
-//
-// octet = pointer[0];
-// width = (octet & 0x80) == 0x00 ? 1 :
-// (octet & 0xE0) == 0xC0 ? 2 :
-// (octet & 0xF0) == 0xE0 ? 3 :
-// (octet & 0xF8) == 0xF0 ? 4 : 0;
-// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
-// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
-// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
-// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
-// if (!width) return 0;
-// if (pointer+width > end) return 0;
-// for (k = 1; k < width; k ++) {
-// octet = pointer[k];
-// if ((octet & 0xC0) != 0x80) return 0;
-// value = (value << 6) + (octet & 0x3F);
-// }
-// if (!((width == 1) ||
-// (width == 2 && value >= 0x80) ||
-// (width == 3 && value >= 0x800) ||
-// (width == 4 && value >= 0x10000))) return 0;
-//
-// pointer += width;
-// }
-//
-// return 1;
-//}
-//
-
-// Create STREAM-START.
-func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
- *event = yaml_event_t{
- typ: yaml_STREAM_START_EVENT,
- encoding: encoding,
- }
-}
-
-// Create STREAM-END.
-func yaml_stream_end_event_initialize(event *yaml_event_t) {
- *event = yaml_event_t{
- typ: yaml_STREAM_END_EVENT,
- }
-}
-
-// Create DOCUMENT-START.
-func yaml_document_start_event_initialize(
- event *yaml_event_t,
- version_directive *yaml_version_directive_t,
- tag_directives []yaml_tag_directive_t,
- implicit bool,
-) {
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_START_EVENT,
- version_directive: version_directive,
- tag_directives: tag_directives,
- implicit: implicit,
- }
-}
-
-// Create DOCUMENT-END.
-func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_END_EVENT,
- implicit: implicit,
- }
-}
-
-// Create ALIAS.
-func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool {
- *event = yaml_event_t{
- typ: yaml_ALIAS_EVENT,
- anchor: anchor,
- }
- return true
-}
-
-// Create SCALAR.
-func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- anchor: anchor,
- tag: tag,
- value: value,
- implicit: plain_implicit,
- quoted_implicit: quoted_implicit,
- style: yaml_style_t(style),
- }
- return true
-}
-
-// Create SEQUENCE-START.
-func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(style),
- }
- return true
-}
-
-// Create SEQUENCE-END.
-func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- }
- return true
-}
-
-// Create MAPPING-START.
-func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(style),
- }
-}
-
-// Create MAPPING-END.
-func yaml_mapping_end_event_initialize(event *yaml_event_t) {
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- }
-}
-
-// Destroy an event object.
-func yaml_event_delete(event *yaml_event_t) {
- *event = yaml_event_t{}
-}
-
-///*
-// * Create a document object.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_initialize(document *yaml_document_t,
-// version_directive *yaml_version_directive_t,
-// tag_directives_start *yaml_tag_directive_t,
-// tag_directives_end *yaml_tag_directive_t,
-// start_implicit int, end_implicit int)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// struct {
-// start *yaml_node_t
-// end *yaml_node_t
-// top *yaml_node_t
-// } nodes = { NULL, NULL, NULL }
-// version_directive_copy *yaml_version_directive_t = NULL
-// struct {
-// start *yaml_tag_directive_t
-// end *yaml_tag_directive_t
-// top *yaml_tag_directive_t
-// } tag_directives_copy = { NULL, NULL, NULL }
-// value yaml_tag_directive_t = { NULL, NULL }
-// mark yaml_mark_t = { 0, 0, 0 }
-//
-// assert(document) // Non-NULL document object is expected.
-// assert((tag_directives_start && tag_directives_end) ||
-// (tag_directives_start == tag_directives_end))
-// // Valid tag directives are expected.
-//
-// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
-//
-// if (version_directive) {
-// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
-// if (!version_directive_copy) goto error
-// version_directive_copy.major = version_directive.major
-// version_directive_copy.minor = version_directive.minor
-// }
-//
-// if (tag_directives_start != tag_directives_end) {
-// tag_directive *yaml_tag_directive_t
-// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
-// goto error
-// for (tag_directive = tag_directives_start
-// tag_directive != tag_directives_end; tag_directive ++) {
-// assert(tag_directive.handle)
-// assert(tag_directive.prefix)
-// if (!yaml_check_utf8(tag_directive.handle,
-// strlen((char *)tag_directive.handle)))
-// goto error
-// if (!yaml_check_utf8(tag_directive.prefix,
-// strlen((char *)tag_directive.prefix)))
-// goto error
-// value.handle = yaml_strdup(tag_directive.handle)
-// value.prefix = yaml_strdup(tag_directive.prefix)
-// if (!value.handle || !value.prefix) goto error
-// if (!PUSH(&context, tag_directives_copy, value))
-// goto error
-// value.handle = NULL
-// value.prefix = NULL
-// }
-// }
-//
-// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
-// tag_directives_copy.start, tag_directives_copy.top,
-// start_implicit, end_implicit, mark, mark)
-//
-// return 1
-//
-//error:
-// STACK_DEL(&context, nodes)
-// yaml_free(version_directive_copy)
-// while (!STACK_EMPTY(&context, tag_directives_copy)) {
-// value yaml_tag_directive_t = POP(&context, tag_directives_copy)
-// yaml_free(value.handle)
-// yaml_free(value.prefix)
-// }
-// STACK_DEL(&context, tag_directives_copy)
-// yaml_free(value.handle)
-// yaml_free(value.prefix)
-//
-// return 0
-//}
-//
-///*
-// * Destroy a document object.
-// */
-//
-//YAML_DECLARE(void)
-//yaml_document_delete(document *yaml_document_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// tag_directive *yaml_tag_directive_t
-//
-// context.error = YAML_NO_ERROR // Eliminate a compiler warning.
-//
-// assert(document) // Non-NULL document object is expected.
-//
-// while (!STACK_EMPTY(&context, document.nodes)) {
-// node yaml_node_t = POP(&context, document.nodes)
-// yaml_free(node.tag)
-// switch (node.type) {
-// case YAML_SCALAR_NODE:
-// yaml_free(node.data.scalar.value)
-// break
-// case YAML_SEQUENCE_NODE:
-// STACK_DEL(&context, node.data.sequence.items)
-// break
-// case YAML_MAPPING_NODE:
-// STACK_DEL(&context, node.data.mapping.pairs)
-// break
-// default:
-// assert(0) // Should not happen.
-// }
-// }
-// STACK_DEL(&context, document.nodes)
-//
-// yaml_free(document.version_directive)
-// for (tag_directive = document.tag_directives.start
-// tag_directive != document.tag_directives.end
-// tag_directive++) {
-// yaml_free(tag_directive.handle)
-// yaml_free(tag_directive.prefix)
-// }
-// yaml_free(document.tag_directives.start)
-//
-// memset(document, 0, sizeof(yaml_document_t))
-//}
-//
-///**
-// * Get a document node.
-// */
-//
-//YAML_DECLARE(yaml_node_t *)
-//yaml_document_get_node(document *yaml_document_t, index int)
-//{
-// assert(document) // Non-NULL document object is expected.
-//
-// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
-// return document.nodes.start + index - 1
-// }
-// return NULL
-//}
-//
-///**
-// * Get the root object.
-// */
-//
-//YAML_DECLARE(yaml_node_t *)
-//yaml_document_get_root_node(document *yaml_document_t)
-//{
-// assert(document) // Non-NULL document object is expected.
-//
-// if (document.nodes.top != document.nodes.start) {
-// return document.nodes.start
-// }
-// return NULL
-//}
-//
-///*
-// * Add a scalar node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_scalar(document *yaml_document_t,
-// tag *yaml_char_t, value *yaml_char_t, length int,
-// style yaml_scalar_style_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// mark yaml_mark_t = { 0, 0, 0 }
-// tag_copy *yaml_char_t = NULL
-// value_copy *yaml_char_t = NULL
-// node yaml_node_t
-//
-// assert(document) // Non-NULL document object is expected.
-// assert(value) // Non-NULL value is expected.
-//
-// if (!tag) {
-// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
-// }
-//
-// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-// tag_copy = yaml_strdup(tag)
-// if (!tag_copy) goto error
-//
-// if (length < 0) {
-// length = strlen((char *)value)
-// }
-//
-// if (!yaml_check_utf8(value, length)) goto error
-// value_copy = yaml_malloc(length+1)
-// if (!value_copy) goto error
-// memcpy(value_copy, value, length)
-// value_copy[length] = '\0'
-//
-// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
-// if (!PUSH(&context, document.nodes, node)) goto error
-//
-// return document.nodes.top - document.nodes.start
-//
-//error:
-// yaml_free(tag_copy)
-// yaml_free(value_copy)
-//
-// return 0
-//}
-//
-///*
-// * Add a sequence node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_sequence(document *yaml_document_t,
-// tag *yaml_char_t, style yaml_sequence_style_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// mark yaml_mark_t = { 0, 0, 0 }
-// tag_copy *yaml_char_t = NULL
-// struct {
-// start *yaml_node_item_t
-// end *yaml_node_item_t
-// top *yaml_node_item_t
-// } items = { NULL, NULL, NULL }
-// node yaml_node_t
-//
-// assert(document) // Non-NULL document object is expected.
-//
-// if (!tag) {
-// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
-// }
-//
-// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-// tag_copy = yaml_strdup(tag)
-// if (!tag_copy) goto error
-//
-// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
-//
-// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
-// style, mark, mark)
-// if (!PUSH(&context, document.nodes, node)) goto error
-//
-// return document.nodes.top - document.nodes.start
-//
-//error:
-// STACK_DEL(&context, items)
-// yaml_free(tag_copy)
-//
-// return 0
-//}
-//
-///*
-// * Add a mapping node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_mapping(document *yaml_document_t,
-// tag *yaml_char_t, style yaml_mapping_style_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// mark yaml_mark_t = { 0, 0, 0 }
-// tag_copy *yaml_char_t = NULL
-// struct {
-// start *yaml_node_pair_t
-// end *yaml_node_pair_t
-// top *yaml_node_pair_t
-// } pairs = { NULL, NULL, NULL }
-// node yaml_node_t
-//
-// assert(document) // Non-NULL document object is expected.
-//
-// if (!tag) {
-// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
-// }
-//
-// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-// tag_copy = yaml_strdup(tag)
-// if (!tag_copy) goto error
-//
-// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
-//
-// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
-// style, mark, mark)
-// if (!PUSH(&context, document.nodes, node)) goto error
-//
-// return document.nodes.top - document.nodes.start
-//
-//error:
-// STACK_DEL(&context, pairs)
-// yaml_free(tag_copy)
-//
-// return 0
-//}
-//
-///*
-// * Append an item to a sequence node.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_append_sequence_item(document *yaml_document_t,
-// sequence int, item int)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-//
-// assert(document) // Non-NULL document is required.
-// assert(sequence > 0
-// && document.nodes.start + sequence <= document.nodes.top)
-// // Valid sequence id is required.
-// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
-// // A sequence node is required.
-// assert(item > 0 && document.nodes.start + item <= document.nodes.top)
-// // Valid item id is required.
-//
-// if (!PUSH(&context,
-// document.nodes.start[sequence-1].data.sequence.items, item))
-// return 0
-//
-// return 1
-//}
-//
-///*
-// * Append a pair of a key and a value to a mapping node.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_append_mapping_pair(document *yaml_document_t,
-// mapping int, key int, value int)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-//
-// pair yaml_node_pair_t
-//
-// assert(document) // Non-NULL document is required.
-// assert(mapping > 0
-// && document.nodes.start + mapping <= document.nodes.top)
-// // Valid mapping id is required.
-// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
-// // A mapping node is required.
-// assert(key > 0 && document.nodes.start + key <= document.nodes.top)
-// // Valid key id is required.
-// assert(value > 0 && document.nodes.start + value <= document.nodes.top)
-// // Valid value id is required.
-//
-// pair.key = key
-// pair.value = value
-//
-// if (!PUSH(&context,
-// document.nodes.start[mapping-1].data.mapping.pairs, pair))
-// return 0
-//
-// return 1
-//}
-//
-//
diff --git a/cli/internal/yaml/decode.go b/cli/internal/yaml/decode.go
deleted file mode 100644
index 0173b69..0000000
--- a/cli/internal/yaml/decode.go
+++ /dev/null
@@ -1,1000 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
- "encoding"
- "encoding/base64"
- "fmt"
- "io"
- "math"
- "reflect"
- "strconv"
- "time"
-)
-
-// ----------------------------------------------------------------------------
-// Parser, produces a node tree out of a libyaml event stream.
-
-type parser struct {
- parser yaml_parser_t
- event yaml_event_t
- doc *Node
- anchors map[string]*Node
- doneInit bool
- textless bool
-}
-
-func newParser(b []byte) *parser {
- p := parser{}
- if !yaml_parser_initialize(&p.parser) {
- panic("failed to initialize YAML emitter")
- }
- if len(b) == 0 {
- b = []byte{'\n'}
- }
- yaml_parser_set_input_string(&p.parser, b)
- return &p
-}
-
-func newParserFromReader(r io.Reader) *parser {
- p := parser{}
- if !yaml_parser_initialize(&p.parser) {
- panic("failed to initialize YAML emitter")
- }
- yaml_parser_set_input_reader(&p.parser, r)
- return &p
-}
-
-func (p *parser) init() {
- if p.doneInit {
- return
- }
- p.anchors = make(map[string]*Node)
- p.expect(yaml_STREAM_START_EVENT)
- p.doneInit = true
-}
-
-func (p *parser) destroy() {
- if p.event.typ != yaml_NO_EVENT {
- yaml_event_delete(&p.event)
- }
- yaml_parser_delete(&p.parser)
-}
-
-// expect consumes an event from the event stream and
-// checks that it's of the expected type.
-func (p *parser) expect(e yaml_event_type_t) {
- if p.event.typ == yaml_NO_EVENT {
- if !yaml_parser_parse(&p.parser, &p.event) {
- p.fail()
- }
- }
- if p.event.typ == yaml_STREAM_END_EVENT {
- failf("attempted to go past the end of stream; corrupted value?")
- }
- if p.event.typ != e {
- p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
- p.fail()
- }
- yaml_event_delete(&p.event)
- p.event.typ = yaml_NO_EVENT
-}
-
-// peek peeks at the next event in the event stream,
-// puts the results into p.event and returns the event type.
-func (p *parser) peek() yaml_event_type_t {
- if p.event.typ != yaml_NO_EVENT {
- return p.event.typ
- }
- // It's curious choice from the underlying API to generally return a
- // positive result on success, but on this case return true in an error
- // scenario. This was the source of bugs in the past (issue #666).
- if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
- p.fail()
- }
- return p.event.typ
-}
-
-func (p *parser) fail() {
- var where string
- var line int
- if p.parser.context_mark.line != 0 {
- line = p.parser.context_mark.line
- // Scanner errors don't iterate line before returning error
- if p.parser.error == yaml_SCANNER_ERROR {
- line++
- }
- } else if p.parser.problem_mark.line != 0 {
- line = p.parser.problem_mark.line
- // Scanner errors don't iterate line before returning error
- if p.parser.error == yaml_SCANNER_ERROR {
- line++
- }
- }
- if line != 0 {
- where = "line " + strconv.Itoa(line) + ": "
- }
- var msg string
- if len(p.parser.problem) > 0 {
- msg = p.parser.problem
- } else {
- msg = "unknown problem parsing YAML content"
- }
- failf("%s%s", where, msg)
-}
-
-func (p *parser) anchor(n *Node, anchor []byte) {
- if anchor != nil {
- n.Anchor = string(anchor)
- p.anchors[n.Anchor] = n
- }
-}
-
-func (p *parser) parse() *Node {
- p.init()
- switch p.peek() {
- case yaml_SCALAR_EVENT:
- return p.scalar()
- case yaml_ALIAS_EVENT:
- return p.alias()
- case yaml_MAPPING_START_EVENT:
- return p.mapping()
- case yaml_SEQUENCE_START_EVENT:
- return p.sequence()
- case yaml_DOCUMENT_START_EVENT:
- return p.document()
- case yaml_STREAM_END_EVENT:
- // Happens when attempting to decode an empty buffer.
- return nil
- case yaml_TAIL_COMMENT_EVENT:
- panic("internal error: unexpected tail comment event (please report)")
- default:
- panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
- }
-}
-
-func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
- var style Style
- if tag != "" && tag != "!" {
- tag = shortTag(tag)
- style = TaggedStyle
- } else if defaultTag != "" {
- tag = defaultTag
- } else if kind == ScalarNode {
- tag, _ = resolve("", value)
- }
- n := &Node{
- Kind: kind,
- Tag: tag,
- Value: value,
- Style: style,
- }
- if !p.textless {
- n.Line = p.event.start_mark.line + 1
- n.Column = p.event.start_mark.column + 1
- n.HeadComment = string(p.event.head_comment)
- n.LineComment = string(p.event.line_comment)
- n.FootComment = string(p.event.foot_comment)
- }
- return n
-}
-
-func (p *parser) parseChild(parent *Node) *Node {
- child := p.parse()
- parent.Content = append(parent.Content, child)
- return child
-}
-
-func (p *parser) document() *Node {
- n := p.node(DocumentNode, "", "", "")
- p.doc = n
- p.expect(yaml_DOCUMENT_START_EVENT)
- p.parseChild(n)
- if p.peek() == yaml_DOCUMENT_END_EVENT {
- n.FootComment = string(p.event.foot_comment)
- }
- p.expect(yaml_DOCUMENT_END_EVENT)
- return n
-}
-
-func (p *parser) alias() *Node {
- n := p.node(AliasNode, "", "", string(p.event.anchor))
- n.Alias = p.anchors[n.Value]
- if n.Alias == nil {
- failf("unknown anchor '%s' referenced", n.Value)
- }
- p.expect(yaml_ALIAS_EVENT)
- return n
-}
-
-func (p *parser) scalar() *Node {
- var parsedStyle = p.event.scalar_style()
- var nodeStyle Style
- switch {
- case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
- nodeStyle = DoubleQuotedStyle
- case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
- nodeStyle = SingleQuotedStyle
- case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
- nodeStyle = LiteralStyle
- case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
- nodeStyle = FoldedStyle
- }
- var nodeValue = string(p.event.value)
- var nodeTag = string(p.event.tag)
- var defaultTag string
- if nodeStyle == 0 {
- if nodeValue == "<<" {
- defaultTag = mergeTag
- }
- } else {
- defaultTag = strTag
- }
- n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
- n.Style |= nodeStyle
- p.anchor(n, p.event.anchor)
- p.expect(yaml_SCALAR_EVENT)
- return n
-}
-
-func (p *parser) sequence() *Node {
- n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
- if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
- n.Style |= FlowStyle
- }
- p.anchor(n, p.event.anchor)
- p.expect(yaml_SEQUENCE_START_EVENT)
- for p.peek() != yaml_SEQUENCE_END_EVENT {
- p.parseChild(n)
- }
- n.LineComment = string(p.event.line_comment)
- n.FootComment = string(p.event.foot_comment)
- p.expect(yaml_SEQUENCE_END_EVENT)
- return n
-}
-
-func (p *parser) mapping() *Node {
- n := p.node(MappingNode, mapTag, string(p.event.tag), "")
- block := true
- if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
- block = false
- n.Style |= FlowStyle
- }
- p.anchor(n, p.event.anchor)
- p.expect(yaml_MAPPING_START_EVENT)
- for p.peek() != yaml_MAPPING_END_EVENT {
- k := p.parseChild(n)
- if block && k.FootComment != "" {
- // Must be a foot comment for the prior value when being dedented.
- if len(n.Content) > 2 {
- n.Content[len(n.Content)-3].FootComment = k.FootComment
- k.FootComment = ""
- }
- }
- v := p.parseChild(n)
- if k.FootComment == "" && v.FootComment != "" {
- k.FootComment = v.FootComment
- v.FootComment = ""
- }
- if p.peek() == yaml_TAIL_COMMENT_EVENT {
- if k.FootComment == "" {
- k.FootComment = string(p.event.foot_comment)
- }
- p.expect(yaml_TAIL_COMMENT_EVENT)
- }
- }
- n.LineComment = string(p.event.line_comment)
- n.FootComment = string(p.event.foot_comment)
- if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
- n.Content[len(n.Content)-2].FootComment = n.FootComment
- n.FootComment = ""
- }
- p.expect(yaml_MAPPING_END_EVENT)
- return n
-}
-
-// ----------------------------------------------------------------------------
-// Decoder, unmarshals a node into a provided value.
-
-type decoder struct {
- doc *Node
- aliases map[*Node]bool
- terrors []string
-
- stringMapType reflect.Type
- generalMapType reflect.Type
-
- knownFields bool
- uniqueKeys bool
- decodeCount int
- aliasCount int
- aliasDepth int
-
- mergedFields map[interface{}]bool
-}
-
-var (
- nodeType = reflect.TypeOf(Node{})
- durationType = reflect.TypeOf(time.Duration(0))
- stringMapType = reflect.TypeOf(map[string]interface{}{})
- generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
- ifaceType = generalMapType.Elem()
- timeType = reflect.TypeOf(time.Time{})
- ptrTimeType = reflect.TypeOf(&time.Time{})
-)
-
-func newDecoder() *decoder {
- d := &decoder{
- stringMapType: stringMapType,
- generalMapType: generalMapType,
- uniqueKeys: true,
- }
- d.aliases = make(map[*Node]bool)
- return d
-}
-
-func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
- if n.Tag != "" {
- tag = n.Tag
- }
- value := n.Value
- if tag != seqTag && tag != mapTag {
- if len(value) > 10 {
- value = " `" + value[:7] + "...`"
- } else {
- value = " `" + value + "`"
- }
- }
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
-}
-
-func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
- err := u.UnmarshalYAML(n)
- if e, ok := err.(*TypeError); ok {
- d.terrors = append(d.terrors, e.Errors...)
- return false
- }
- if err != nil {
- fail(err)
- }
- return true
-}
-
-func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
- terrlen := len(d.terrors)
- err := u.UnmarshalYAML(func(v interface{}) (err error) {
- defer handleErr(&err)
- d.unmarshal(n, reflect.ValueOf(v))
- if len(d.terrors) > terrlen {
- issues := d.terrors[terrlen:]
- d.terrors = d.terrors[:terrlen]
- return &TypeError{issues}
- }
- return nil
- })
- if e, ok := err.(*TypeError); ok {
- d.terrors = append(d.terrors, e.Errors...)
- return false
- }
- if err != nil {
- fail(err)
- }
- return true
-}
-
-// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
-// if a value is found to implement it.
-// It returns the initialized and dereferenced out value, whether
-// unmarshalling was already done by UnmarshalYAML, and if so whether
-// its types unmarshalled appropriately.
-//
-// If n holds a null value, prepare returns before doing anything.
-func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
- if n.ShortTag() == nullTag {
- return out, false, false
- }
- again := true
- for again {
- again = false
- if out.Kind() == reflect.Ptr {
- if out.IsNil() {
- out.Set(reflect.New(out.Type().Elem()))
- }
- out = out.Elem()
- again = true
- }
- if out.CanAddr() {
- outi := out.Addr().Interface()
- if u, ok := outi.(Unmarshaler); ok {
- good = d.callUnmarshaler(n, u)
- return out, true, good
- }
- if u, ok := outi.(obsoleteUnmarshaler); ok {
- good = d.callObsoleteUnmarshaler(n, u)
- return out, true, good
- }
- }
- }
- return out, false, false
-}
-
-func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
- if n.ShortTag() == nullTag {
- return reflect.Value{}
- }
- for _, num := range index {
- for {
- if v.Kind() == reflect.Ptr {
- if v.IsNil() {
- v.Set(reflect.New(v.Type().Elem()))
- }
- v = v.Elem()
- continue
- }
- break
- }
- v = v.Field(num)
- }
- return v
-}
-
-const (
- // 400,000 decode operations is ~500kb of dense object declarations, or
- // ~5kb of dense object declarations with 10000% alias expansion
- alias_ratio_range_low = 400000
-
- // 4,000,000 decode operations is ~5MB of dense object declarations, or
- // ~4.5MB of dense object declarations with 10% alias expansion
- alias_ratio_range_high = 4000000
-
- // alias_ratio_range is the range over which we scale allowed alias ratios
- alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
-)
-
-func allowedAliasRatio(decodeCount int) float64 {
- switch {
- case decodeCount <= alias_ratio_range_low:
- // allow 99% to come from alias expansion for small-to-medium documents
- return 0.99
- case decodeCount >= alias_ratio_range_high:
- // allow 10% to come from alias expansion for very large documents
- return 0.10
- default:
- // scale smoothly from 99% down to 10% over the range.
- // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
- // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
- return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
- }
-}
-
-func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
- d.decodeCount++
- if d.aliasDepth > 0 {
- d.aliasCount++
- }
- if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
- failf("document contains excessive aliasing")
- }
- if out.Type() == nodeType {
- out.Set(reflect.ValueOf(n).Elem())
- return true
- }
- switch n.Kind {
- case DocumentNode:
- return d.document(n, out)
- case AliasNode:
- return d.alias(n, out)
- }
- out, unmarshaled, good := d.prepare(n, out)
- if unmarshaled {
- return good
- }
- switch n.Kind {
- case ScalarNode:
- good = d.scalar(n, out)
- case MappingNode:
- good = d.mapping(n, out)
- case SequenceNode:
- good = d.sequence(n, out)
- case 0:
- if n.IsZero() {
- return d.null(out)
- }
- fallthrough
- default:
- failf("cannot decode node with unknown kind %d", n.Kind)
- }
- return good
-}
-
-func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
- if len(n.Content) == 1 {
- d.doc = n
- d.unmarshal(n.Content[0], out)
- return true
- }
- return false
-}
-
-func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
- if d.aliases[n] {
- // TODO this could actually be allowed in some circumstances.
- failf("anchor '%s' value contains itself", n.Value)
- }
- d.aliases[n] = true
- d.aliasDepth++
- good = d.unmarshal(n.Alias, out)
- d.aliasDepth--
- delete(d.aliases, n)
- return good
-}
-
-var zeroValue reflect.Value
-
-func resetMap(out reflect.Value) {
- for _, k := range out.MapKeys() {
- out.SetMapIndex(k, zeroValue)
- }
-}
-
-func (d *decoder) null(out reflect.Value) bool {
- if out.CanAddr() {
- switch out.Kind() {
- case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
- out.Set(reflect.Zero(out.Type()))
- return true
- }
- }
- return false
-}
-
-func (d *decoder) scalar(n *Node, out reflect.Value) bool {
- var tag string
- var resolved interface{}
- if n.indicatedString() {
- tag = strTag
- resolved = n.Value
- } else {
- tag, resolved = resolve(n.Tag, n.Value)
- if tag == binaryTag {
- data, err := base64.StdEncoding.DecodeString(resolved.(string))
- if err != nil {
- failf("!!binary value contains invalid base64 data")
- }
- resolved = string(data)
- }
- }
- if resolved == nil {
- return d.null(out)
- }
- if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
- // We've resolved to exactly the type we want, so use that.
- out.Set(resolvedv)
- return true
- }
- // Perhaps we can use the value as a TextUnmarshaler to
- // set its value.
- if out.CanAddr() {
- u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
- if ok {
- var text []byte
- if tag == binaryTag {
- text = []byte(resolved.(string))
- } else {
- // We let any value be unmarshaled into TextUnmarshaler.
- // That might be more lax than we'd like, but the
- // TextUnmarshaler itself should bowl out any dubious values.
- text = []byte(n.Value)
- }
- err := u.UnmarshalText(text)
- if err != nil {
- fail(err)
- }
- return true
- }
- }
- switch out.Kind() {
- case reflect.String:
- if tag == binaryTag {
- out.SetString(resolved.(string))
- return true
- }
- out.SetString(n.Value)
- return true
- case reflect.Interface:
- out.Set(reflect.ValueOf(resolved))
- return true
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- // This used to work in v2, but it's very unfriendly.
- isDuration := out.Type() == durationType
-
- switch resolved := resolved.(type) {
- case int:
- if !isDuration && !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- return true
- }
- case int64:
- if !isDuration && !out.OverflowInt(resolved) {
- out.SetInt(resolved)
- return true
- }
- case uint64:
- if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- return true
- }
- case float64:
- if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- return true
- }
- case string:
- if out.Type() == durationType {
- d, err := time.ParseDuration(resolved)
- if err == nil {
- out.SetInt(int64(d))
- return true
- }
- }
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- switch resolved := resolved.(type) {
- case int:
- if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- case int64:
- if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- case uint64:
- if !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- case float64:
- if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- }
- case reflect.Bool:
- switch resolved := resolved.(type) {
- case bool:
- out.SetBool(resolved)
- return true
- case string:
- // This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
- // It only works if explicitly attempting to unmarshal into a typed bool value.
- switch resolved {
- case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
- out.SetBool(true)
- return true
- case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
- out.SetBool(false)
- return true
- }
- }
- case reflect.Float32, reflect.Float64:
- switch resolved := resolved.(type) {
- case int:
- out.SetFloat(float64(resolved))
- return true
- case int64:
- out.SetFloat(float64(resolved))
- return true
- case uint64:
- out.SetFloat(float64(resolved))
- return true
- case float64:
- out.SetFloat(resolved)
- return true
- }
- case reflect.Struct:
- if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
- out.Set(resolvedv)
- return true
- }
- case reflect.Ptr:
- panic("yaml internal error: please report the issue")
- }
- d.terror(n, tag, out)
- return false
-}
-
-func settableValueOf(i interface{}) reflect.Value {
- v := reflect.ValueOf(i)
- sv := reflect.New(v.Type()).Elem()
- sv.Set(v)
- return sv
-}
-
-func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
- l := len(n.Content)
-
- var iface reflect.Value
- switch out.Kind() {
- case reflect.Slice:
- out.Set(reflect.MakeSlice(out.Type(), l, l))
- case reflect.Array:
- if l != out.Len() {
- failf("invalid array: want %d elements but got %d", out.Len(), l)
- }
- case reflect.Interface:
- // No type hints. Will have to use a generic sequence.
- iface = out
- out = settableValueOf(make([]interface{}, l))
- default:
- d.terror(n, seqTag, out)
- return false
- }
- et := out.Type().Elem()
-
- j := 0
- for i := 0; i < l; i++ {
- e := reflect.New(et).Elem()
- if ok := d.unmarshal(n.Content[i], e); ok {
- out.Index(j).Set(e)
- j++
- }
- }
- if out.Kind() != reflect.Array {
- out.Set(out.Slice(0, j))
- }
- if iface.IsValid() {
- iface.Set(out)
- }
- return true
-}
-
-func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
- l := len(n.Content)
- if d.uniqueKeys {
- nerrs := len(d.terrors)
- for i := 0; i < l; i += 2 {
- ni := n.Content[i]
- for j := i + 2; j < l; j += 2 {
- nj := n.Content[j]
- if ni.Kind == nj.Kind && ni.Value == nj.Value {
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
- }
- }
- }
- if len(d.terrors) > nerrs {
- return false
- }
- }
- switch out.Kind() {
- case reflect.Struct:
- return d.mappingStruct(n, out)
- case reflect.Map:
- // okay
- case reflect.Interface:
- iface := out
- if isStringMap(n) {
- out = reflect.MakeMap(d.stringMapType)
- } else {
- out = reflect.MakeMap(d.generalMapType)
- }
- iface.Set(out)
- default:
- d.terror(n, mapTag, out)
- return false
- }
-
- outt := out.Type()
- kt := outt.Key()
- et := outt.Elem()
-
- stringMapType := d.stringMapType
- generalMapType := d.generalMapType
- if outt.Elem() == ifaceType {
- if outt.Key().Kind() == reflect.String {
- d.stringMapType = outt
- } else if outt.Key() == ifaceType {
- d.generalMapType = outt
- }
- }
-
- mergedFields := d.mergedFields
- d.mergedFields = nil
-
- var mergeNode *Node
-
- mapIsNew := false
- if out.IsNil() {
- out.Set(reflect.MakeMap(outt))
- mapIsNew = true
- }
- for i := 0; i < l; i += 2 {
- if isMerge(n.Content[i]) {
- mergeNode = n.Content[i+1]
- continue
- }
- k := reflect.New(kt).Elem()
- if d.unmarshal(n.Content[i], k) {
- if mergedFields != nil {
- ki := k.Interface()
- if mergedFields[ki] {
- continue
- }
- mergedFields[ki] = true
- }
- kkind := k.Kind()
- if kkind == reflect.Interface {
- kkind = k.Elem().Kind()
- }
- if kkind == reflect.Map || kkind == reflect.Slice {
- failf("invalid map key: %#v", k.Interface())
- }
- e := reflect.New(et).Elem()
- if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {
- out.SetMapIndex(k, e)
- }
- }
- }
-
- d.mergedFields = mergedFields
- if mergeNode != nil {
- d.merge(n, mergeNode, out)
- }
-
- d.stringMapType = stringMapType
- d.generalMapType = generalMapType
- return true
-}
-
-func isStringMap(n *Node) bool {
- if n.Kind != MappingNode {
- return false
- }
- l := len(n.Content)
- for i := 0; i < l; i += 2 {
- shortTag := n.Content[i].ShortTag()
- if shortTag != strTag && shortTag != mergeTag {
- return false
- }
- }
- return true
-}
-
-func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
- sinfo, err := getStructInfo(out.Type())
- if err != nil {
- panic(err)
- }
-
- var inlineMap reflect.Value
- var elemType reflect.Type
- if sinfo.InlineMap != -1 {
- inlineMap = out.Field(sinfo.InlineMap)
- elemType = inlineMap.Type().Elem()
- }
-
- for _, index := range sinfo.InlineUnmarshalers {
- field := d.fieldByIndex(n, out, index)
- d.prepare(n, field)
- }
-
- mergedFields := d.mergedFields
- d.mergedFields = nil
- var mergeNode *Node
- var doneFields []bool
- if d.uniqueKeys {
- doneFields = make([]bool, len(sinfo.FieldsList))
- }
- name := settableValueOf("")
- l := len(n.Content)
- for i := 0; i < l; i += 2 {
- ni := n.Content[i]
- if isMerge(ni) {
- mergeNode = n.Content[i+1]
- continue
- }
- if !d.unmarshal(ni, name) {
- continue
- }
- sname := name.String()
- if mergedFields != nil {
- if mergedFields[sname] {
- continue
- }
- mergedFields[sname] = true
- }
- if info, ok := sinfo.FieldsMap[sname]; ok {
- if d.uniqueKeys {
- if doneFields[info.Id] {
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
- continue
- }
- doneFields[info.Id] = true
- }
- var field reflect.Value
- if info.Inline == nil {
- field = out.Field(info.Num)
- } else {
- field = d.fieldByIndex(n, out, info.Inline)
- }
- d.unmarshal(n.Content[i+1], field)
- } else if sinfo.InlineMap != -1 {
- if inlineMap.IsNil() {
- inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
- }
- value := reflect.New(elemType).Elem()
- d.unmarshal(n.Content[i+1], value)
- inlineMap.SetMapIndex(name, value)
- } else if d.knownFields {
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
- }
- }
-
- d.mergedFields = mergedFields
- if mergeNode != nil {
- d.merge(n, mergeNode, out)
- }
- return true
-}
-
-func failWantMap() {
- failf("map merge requires map or sequence of maps as the value")
-}
-
-func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
- mergedFields := d.mergedFields
- if mergedFields == nil {
- d.mergedFields = make(map[interface{}]bool)
- for i := 0; i < len(parent.Content); i += 2 {
- k := reflect.New(ifaceType).Elem()
- if d.unmarshal(parent.Content[i], k) {
- d.mergedFields[k.Interface()] = true
- }
- }
- }
-
- switch merge.Kind {
- case MappingNode:
- d.unmarshal(merge, out)
- case AliasNode:
- if merge.Alias != nil && merge.Alias.Kind != MappingNode {
- failWantMap()
- }
- d.unmarshal(merge, out)
- case SequenceNode:
- for i := 0; i < len(merge.Content); i++ {
- ni := merge.Content[i]
- if ni.Kind == AliasNode {
- if ni.Alias != nil && ni.Alias.Kind != MappingNode {
- failWantMap()
- }
- } else if ni.Kind != MappingNode {
- failWantMap()
- }
- d.unmarshal(ni, out)
- }
- default:
- failWantMap()
- }
-
- d.mergedFields = mergedFields
-}
-
-func isMerge(n *Node) bool {
- return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
-}
diff --git a/cli/internal/yaml/emitterc.go b/cli/internal/yaml/emitterc.go
deleted file mode 100644
index dde20e5..0000000
--- a/cli/internal/yaml/emitterc.go
+++ /dev/null
@@ -1,2019 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
- "bytes"
- "fmt"
-)
-
-// Flush the buffer if needed.
-func flush(emitter *yaml_emitter_t) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) {
- return yaml_emitter_flush(emitter)
- }
- return true
-}
-
-// Put a character to the output buffer.
-func put(emitter *yaml_emitter_t, value byte) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
- return false
- }
- emitter.buffer[emitter.buffer_pos] = value
- emitter.buffer_pos++
- emitter.column++
- return true
-}
-
-// Put a line break to the output buffer.
-func put_break(emitter *yaml_emitter_t) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
- return false
- }
- switch emitter.line_break {
- case yaml_CR_BREAK:
- emitter.buffer[emitter.buffer_pos] = '\r'
- emitter.buffer_pos += 1
- case yaml_LN_BREAK:
- emitter.buffer[emitter.buffer_pos] = '\n'
- emitter.buffer_pos += 1
- case yaml_CRLN_BREAK:
- emitter.buffer[emitter.buffer_pos+0] = '\r'
- emitter.buffer[emitter.buffer_pos+1] = '\n'
- emitter.buffer_pos += 2
- default:
- panic("unknown line break setting")
- }
- if emitter.column == 0 {
- emitter.space_above = true
- }
- emitter.column = 0
- emitter.line++
- // [Go] Do this here and below and drop from everywhere else (see commented lines).
- emitter.indention = true
- return true
-}
-
-// Copy a character from a string into buffer.
-func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
- return false
- }
- p := emitter.buffer_pos
- w := width(s[*i])
- switch w {
- case 4:
- emitter.buffer[p+3] = s[*i+3]
- fallthrough
- case 3:
- emitter.buffer[p+2] = s[*i+2]
- fallthrough
- case 2:
- emitter.buffer[p+1] = s[*i+1]
- fallthrough
- case 1:
- emitter.buffer[p+0] = s[*i+0]
- default:
- panic("unknown character width")
- }
- emitter.column++
- emitter.buffer_pos += w
- *i += w
- return true
-}
-
-// Write a whole string into buffer.
-func write_all(emitter *yaml_emitter_t, s []byte) bool {
- for i := 0; i < len(s); {
- if !write(emitter, s, &i) {
- return false
- }
- }
- return true
-}
-
-// Copy a line break character from a string into buffer.
-func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
- if s[*i] == '\n' {
- if !put_break(emitter) {
- return false
- }
- *i++
- } else {
- if !write(emitter, s, i) {
- return false
- }
- if emitter.column == 0 {
- emitter.space_above = true
- }
- emitter.column = 0
- emitter.line++
- // [Go] Do this here and above and drop from everywhere else (see commented lines).
- emitter.indention = true
- }
- return true
-}
-
-// Set an emitter error and return false.
-func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
- emitter.error = yaml_EMITTER_ERROR
- emitter.problem = problem
- return false
-}
-
-// Emit an event.
-func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- emitter.events = append(emitter.events, *event)
- for !yaml_emitter_need_more_events(emitter) {
- event := &emitter.events[emitter.events_head]
- if !yaml_emitter_analyze_event(emitter, event) {
- return false
- }
- if !yaml_emitter_state_machine(emitter, event) {
- return false
- }
- yaml_event_delete(event)
- emitter.events_head++
- }
- return true
-}
-
-// Check if we need to accumulate more events before emitting.
-//
-// We accumulate extra
-// - 1 event for DOCUMENT-START
-// - 2 events for SEQUENCE-START
-// - 3 events for MAPPING-START
-func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
- if emitter.events_head == len(emitter.events) {
- return true
- }
- var accumulate int
- switch emitter.events[emitter.events_head].typ {
- case yaml_DOCUMENT_START_EVENT:
- accumulate = 1
- break
- case yaml_SEQUENCE_START_EVENT:
- accumulate = 2
- break
- case yaml_MAPPING_START_EVENT:
- accumulate = 3
- break
- default:
- return false
- }
- if len(emitter.events)-emitter.events_head > accumulate {
- return false
- }
- var level int
- for i := emitter.events_head; i < len(emitter.events); i++ {
- switch emitter.events[i].typ {
- case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
- level++
- case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
- level--
- }
- if level == 0 {
- return false
- }
- }
- return true
-}
-
-// Append a directive to the directives stack.
-func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
- for i := 0; i < len(emitter.tag_directives); i++ {
- if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
- if allow_duplicates {
- return true
- }
- return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
- }
- }
-
- // [Go] Do we actually need to copy this given garbage collection
- // and the lack of deallocating destructors?
- tag_copy := yaml_tag_directive_t{
- handle: make([]byte, len(value.handle)),
- prefix: make([]byte, len(value.prefix)),
- }
- copy(tag_copy.handle, value.handle)
- copy(tag_copy.prefix, value.prefix)
- emitter.tag_directives = append(emitter.tag_directives, tag_copy)
- return true
-}
-
-// Increase the indentation level.
-func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
- emitter.indents = append(emitter.indents, emitter.indent)
- if emitter.indent < 0 {
- if flow {
- emitter.indent = emitter.best_indent
- } else {
- emitter.indent = 0
- }
- } else if !indentless {
- // [Go] This was changed so that indentations are more regular.
- if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE {
- // The first indent inside a sequence will just skip the "- " indicator.
- emitter.indent += 2
- } else {
- // Everything else aligns to the chosen indentation.
- emitter.indent = emitter.best_indent * ((emitter.indent + emitter.best_indent) / emitter.best_indent)
- }
- }
- return true
-}
-
-// State dispatcher.
-func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- switch emitter.state {
- default:
- case yaml_EMIT_STREAM_START_STATE:
- return yaml_emitter_emit_stream_start(emitter, event)
-
- case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
- return yaml_emitter_emit_document_start(emitter, event, true)
-
- case yaml_EMIT_DOCUMENT_START_STATE:
- return yaml_emitter_emit_document_start(emitter, event, false)
-
- case yaml_EMIT_DOCUMENT_CONTENT_STATE:
- return yaml_emitter_emit_document_content(emitter, event)
-
- case yaml_EMIT_DOCUMENT_END_STATE:
- return yaml_emitter_emit_document_end(emitter, event)
-
- case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
- return yaml_emitter_emit_flow_sequence_item(emitter, event, true, false)
-
- case yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE:
- return yaml_emitter_emit_flow_sequence_item(emitter, event, false, true)
-
- case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
- return yaml_emitter_emit_flow_sequence_item(emitter, event, false, false)
-
- case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
- return yaml_emitter_emit_flow_mapping_key(emitter, event, true, false)
-
- case yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE:
- return yaml_emitter_emit_flow_mapping_key(emitter, event, false, true)
-
- case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
- return yaml_emitter_emit_flow_mapping_key(emitter, event, false, false)
-
- case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
- return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
-
- case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
- return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
-
- case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
- return yaml_emitter_emit_block_sequence_item(emitter, event, true)
-
- case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
- return yaml_emitter_emit_block_sequence_item(emitter, event, false)
-
- case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
- return yaml_emitter_emit_block_mapping_key(emitter, event, true)
-
- case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
- return yaml_emitter_emit_block_mapping_key(emitter, event, false)
-
- case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
- return yaml_emitter_emit_block_mapping_value(emitter, event, true)
-
- case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
- return yaml_emitter_emit_block_mapping_value(emitter, event, false)
-
- case yaml_EMIT_END_STATE:
- return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
- }
- panic("invalid emitter state")
-}
-
-// Expect STREAM-START.
-func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if event.typ != yaml_STREAM_START_EVENT {
- return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
- }
- if emitter.encoding == yaml_ANY_ENCODING {
- emitter.encoding = event.encoding
- if emitter.encoding == yaml_ANY_ENCODING {
- emitter.encoding = yaml_UTF8_ENCODING
- }
- }
- if emitter.best_indent < 2 || emitter.best_indent > 9 {
- emitter.best_indent = 2
- }
- if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
- emitter.best_width = 80
- }
- if emitter.best_width < 0 {
- emitter.best_width = 1<<31 - 1
- }
- if emitter.line_break == yaml_ANY_BREAK {
- emitter.line_break = yaml_LN_BREAK
- }
-
- emitter.indent = -1
- emitter.line = 0
- emitter.column = 0
- emitter.whitespace = true
- emitter.indention = true
- emitter.space_above = true
- emitter.foot_indent = -1
-
- if emitter.encoding != yaml_UTF8_ENCODING {
- if !yaml_emitter_write_bom(emitter) {
- return false
- }
- }
- emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
- return true
-}
-
-// Expect DOCUMENT-START or STREAM-END.
-func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
-
- if event.typ == yaml_DOCUMENT_START_EVENT {
-
- if event.version_directive != nil {
- if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
- return false
- }
- }
-
- for i := 0; i < len(event.tag_directives); i++ {
- tag_directive := &event.tag_directives[i]
- if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
- return false
- }
- if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
- return false
- }
- }
-
- for i := 0; i < len(default_tag_directives); i++ {
- tag_directive := &default_tag_directives[i]
- if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
- return false
- }
- }
-
- implicit := event.implicit
- if !first || emitter.canonical {
- implicit = false
- }
-
- if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
- if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if event.version_directive != nil {
- implicit = false
- if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if len(event.tag_directives) > 0 {
- implicit = false
- for i := 0; i < len(event.tag_directives); i++ {
- tag_directive := &event.tag_directives[i]
- if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
- return false
- }
- if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- }
-
- if yaml_emitter_check_empty_document(emitter) {
- implicit = false
- }
- if !implicit {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
- return false
- }
- if emitter.canonical || true {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- }
-
- if len(emitter.head_comment) > 0 {
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
- if !put_break(emitter) {
- return false
- }
- }
-
- emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
- return true
- }
-
- if event.typ == yaml_STREAM_END_EVENT {
- if emitter.open_ended {
- if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_flush(emitter) {
- return false
- }
- emitter.state = yaml_EMIT_END_STATE
- return true
- }
-
- return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
-}
-
-// Expect the root node.
-func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
-
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
- if !yaml_emitter_emit_node(emitter, event, true, false, false, false) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- return true
-}
-
-// Expect DOCUMENT-END.
-func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if event.typ != yaml_DOCUMENT_END_EVENT {
- return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
- }
- // [Go] Force document foot separation.
- emitter.foot_indent = 0
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- emitter.foot_indent = -1
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !event.implicit {
- // [Go] Allocate the slice elsewhere.
- if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_flush(emitter) {
- return false
- }
- emitter.state = yaml_EMIT_DOCUMENT_START_STATE
- emitter.tag_directives = emitter.tag_directives[:0]
- return true
-}
-
-// Expect a flow item node.
-func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
- if first {
- if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
- return false
- }
- if !yaml_emitter_increase_indent(emitter, true, false) {
- return false
- }
- emitter.flow_level++
- }
-
- if event.typ == yaml_SEQUENCE_END_EVENT {
- if emitter.canonical && !first && !trail {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
- emitter.flow_level--
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- if emitter.column == 0 || emitter.canonical && !first {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
-
- return true
- }
-
- if !first && !trail {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
-
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
- if emitter.column == 0 {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if emitter.canonical || emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE)
- } else {
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
- }
- if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
- return false
- }
- if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- return true
-}
-
-// Expect a flow key node.
-func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
- if first {
- if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
- return false
- }
- if !yaml_emitter_increase_indent(emitter, true, false) {
- return false
- }
- emitter.flow_level++
- }
-
- if event.typ == yaml_MAPPING_END_EVENT {
- if (emitter.canonical || len(emitter.head_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0) && !first && !trail {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
- emitter.flow_level--
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- if emitter.canonical && !first {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
- }
-
- if !first && !trail {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
-
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
-
- if emitter.column == 0 {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if emitter.canonical || emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, true)
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
- return false
- }
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a flow value node.
-func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
- if simple {
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
- return false
- }
- } else {
- if emitter.canonical || emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
- return false
- }
- }
- if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE)
- } else {
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
- }
- if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
- return false
- }
- if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- return true
-}
-
-// Expect a block item node.
-func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
- if first {
- if !yaml_emitter_increase_indent(emitter, false, false) {
- return false
- }
- }
- if event.typ == yaml_SEQUENCE_END_EVENT {
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
- }
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
- return false
- }
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
- if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- return true
-}
-
-// Expect a block key node.
-func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
- if first {
- if !yaml_emitter_increase_indent(emitter, false, false) {
- return false
- }
- }
- if !yaml_emitter_process_head_comment(emitter) {
- return false
- }
- if event.typ == yaml_MAPPING_END_EVENT {
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if len(emitter.line_comment) > 0 {
- // [Go] A line comment was provided for the key. That's unusual as the
- // scanner associates line comments with the value. Either way,
- // save the line comment and render it appropriately later.
- emitter.key_line_comment = emitter.line_comment
- emitter.line_comment = nil
- }
- if yaml_emitter_check_simple_key(emitter) {
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, true)
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
- return false
- }
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a block value node.
-func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
- if simple {
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
- return false
- }
- } else {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
- return false
- }
- }
- if len(emitter.key_line_comment) > 0 {
- // [Go] Line comments are generally associated with the value, but when there's
- // no value on the same line as a mapping key they end up attached to the
- // key itself.
- if event.typ == yaml_SCALAR_EVENT {
- if len(emitter.line_comment) == 0 {
- // A scalar is coming and it has no line comments by itself yet,
- // so just let it handle the line comment as usual. If it has a
- // line comment, we can't have both so the one from the key is lost.
- emitter.line_comment = emitter.key_line_comment
- emitter.key_line_comment = nil
- }
- } else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) {
- // An indented block follows, so write the comment right now.
- emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
- }
- }
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
- if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- if !yaml_emitter_process_foot_comment(emitter) {
- return false
- }
- return true
-}
-
-func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0
-}
-
-// Expect a node.
-func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
- root bool, sequence bool, mapping bool, simple_key bool) bool {
-
- emitter.root_context = root
- emitter.sequence_context = sequence
- emitter.mapping_context = mapping
- emitter.simple_key_context = simple_key
-
- switch event.typ {
- case yaml_ALIAS_EVENT:
- return yaml_emitter_emit_alias(emitter, event)
- case yaml_SCALAR_EVENT:
- return yaml_emitter_emit_scalar(emitter, event)
- case yaml_SEQUENCE_START_EVENT:
- return yaml_emitter_emit_sequence_start(emitter, event)
- case yaml_MAPPING_START_EVENT:
- return yaml_emitter_emit_mapping_start(emitter, event)
- default:
- return yaml_emitter_set_emitter_error(emitter,
- fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
- }
-}
-
-// Expect ALIAS.
-func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
-}
-
-// Expect SCALAR.
-func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_select_scalar_style(emitter, event) {
- return false
- }
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- if !yaml_emitter_process_tag(emitter) {
- return false
- }
- if !yaml_emitter_increase_indent(emitter, true, false) {
- return false
- }
- if !yaml_emitter_process_scalar(emitter) {
- return false
- }
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
-}
-
-// Expect SEQUENCE-START.
-func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- if !yaml_emitter_process_tag(emitter) {
- return false
- }
- if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
- yaml_emitter_check_empty_sequence(emitter) {
- emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
- } else {
- emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
- }
- return true
-}
-
-// Expect MAPPING-START.
-func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- if !yaml_emitter_process_tag(emitter) {
- return false
- }
- if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
- yaml_emitter_check_empty_mapping(emitter) {
- emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
- } else {
- emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
- }
- return true
-}
-
-// Check if the document content is an empty scalar.
-func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
- return false // [Go] Huh?
-}
-
-// Check if the next events represent an empty sequence.
-func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
- if len(emitter.events)-emitter.events_head < 2 {
- return false
- }
- return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
- emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
-}
-
-// Check if the next events represent an empty mapping.
-func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
- if len(emitter.events)-emitter.events_head < 2 {
- return false
- }
- return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
- emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
-}
-
-// Check if the next node can be expressed as a simple key.
-func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
- length := 0
- switch emitter.events[emitter.events_head].typ {
- case yaml_ALIAS_EVENT:
- length += len(emitter.anchor_data.anchor)
- case yaml_SCALAR_EVENT:
- if emitter.scalar_data.multiline {
- return false
- }
- length += len(emitter.anchor_data.anchor) +
- len(emitter.tag_data.handle) +
- len(emitter.tag_data.suffix) +
- len(emitter.scalar_data.value)
- case yaml_SEQUENCE_START_EVENT:
- if !yaml_emitter_check_empty_sequence(emitter) {
- return false
- }
- length += len(emitter.anchor_data.anchor) +
- len(emitter.tag_data.handle) +
- len(emitter.tag_data.suffix)
- case yaml_MAPPING_START_EVENT:
- if !yaml_emitter_check_empty_mapping(emitter) {
- return false
- }
- length += len(emitter.anchor_data.anchor) +
- len(emitter.tag_data.handle) +
- len(emitter.tag_data.suffix)
- default:
- return false
- }
- return length <= 128
-}
-
-// Determine an acceptable scalar style.
-func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-
- no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
- if no_tag && !event.implicit && !event.quoted_implicit {
- return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
- }
-
- style := event.scalar_style()
- if style == yaml_ANY_SCALAR_STYLE {
- style = yaml_PLAIN_SCALAR_STYLE
- }
- if emitter.canonical {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- if emitter.simple_key_context && emitter.scalar_data.multiline {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
-
- if style == yaml_PLAIN_SCALAR_STYLE {
- if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
- emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- }
- if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- }
- if no_tag && !event.implicit {
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- }
- }
- if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
- if !emitter.scalar_data.single_quoted_allowed {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- }
- if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
- if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- }
-
- if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
- emitter.tag_data.handle = []byte{'!'}
- }
- emitter.scalar_data.style = style
- return true
-}
-
-// Write an anchor.
-func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
- if emitter.anchor_data.anchor == nil {
- return true
- }
- c := []byte{'&'}
- if emitter.anchor_data.alias {
- c[0] = '*'
- }
- if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
- return false
- }
- return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
-}
-
-// Write a tag.
-func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
- if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
- return true
- }
- if len(emitter.tag_data.handle) > 0 {
- if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
- return false
- }
- if len(emitter.tag_data.suffix) > 0 {
- if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
- return false
- }
- }
- } else {
- // [Go] Allocate these slices elsewhere.
- if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
- return false
- }
- }
- return true
-}
-
-// Write a scalar.
-func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
- switch emitter.scalar_data.style {
- case yaml_PLAIN_SCALAR_STYLE:
- return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
- case yaml_SINGLE_QUOTED_SCALAR_STYLE:
- return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
- case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
- return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
- case yaml_LITERAL_SCALAR_STYLE:
- return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
-
- case yaml_FOLDED_SCALAR_STYLE:
- return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
- }
- panic("unknown scalar style")
-}
-
-// Write a head comment.
-func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool {
- if len(emitter.tail_comment) > 0 {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_comment(emitter, emitter.tail_comment) {
- return false
- }
- emitter.tail_comment = emitter.tail_comment[:0]
- emitter.foot_indent = emitter.indent
- if emitter.foot_indent < 0 {
- emitter.foot_indent = 0
- }
- }
-
- if len(emitter.head_comment) == 0 {
- return true
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_comment(emitter, emitter.head_comment) {
- return false
- }
- emitter.head_comment = emitter.head_comment[:0]
- return true
-}
-
-// Write an line comment.
-func yaml_emitter_process_line_comment(emitter *yaml_emitter_t) bool {
- if len(emitter.line_comment) == 0 {
- return true
- }
- if !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- if !yaml_emitter_write_comment(emitter, emitter.line_comment) {
- return false
- }
- emitter.line_comment = emitter.line_comment[:0]
- return true
-}
-
-// Write a foot comment.
-func yaml_emitter_process_foot_comment(emitter *yaml_emitter_t) bool {
- if len(emitter.foot_comment) == 0 {
- return true
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_comment(emitter, emitter.foot_comment) {
- return false
- }
- emitter.foot_comment = emitter.foot_comment[:0]
- emitter.foot_indent = emitter.indent
- if emitter.foot_indent < 0 {
- emitter.foot_indent = 0
- }
- return true
-}
-
-// Check if a %YAML directive is valid.
-func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
- if version_directive.major != 1 || version_directive.minor != 1 {
- return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
- }
- return true
-}
-
-// Check if a %TAG directive is valid.
-func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
- handle := tag_directive.handle
- prefix := tag_directive.prefix
- if len(handle) == 0 {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
- }
- if handle[0] != '!' {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
- }
- if handle[len(handle)-1] != '!' {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
- }
- for i := 1; i < len(handle)-1; i += width(handle[i]) {
- if !is_alpha(handle, i) {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
- }
- }
- if len(prefix) == 0 {
- return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
- }
- return true
-}
-
-// Check if an anchor is valid.
-func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
- if len(anchor) == 0 {
- problem := "anchor value must not be empty"
- if alias {
- problem = "alias value must not be empty"
- }
- return yaml_emitter_set_emitter_error(emitter, problem)
- }
- for i := 0; i < len(anchor); i += width(anchor[i]) {
- if !is_alpha(anchor, i) {
- problem := "anchor value must contain alphanumerical characters only"
- if alias {
- problem = "alias value must contain alphanumerical characters only"
- }
- return yaml_emitter_set_emitter_error(emitter, problem)
- }
- }
- emitter.anchor_data.anchor = anchor
- emitter.anchor_data.alias = alias
- return true
-}
-
-// Check if a tag is valid.
-func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
- if len(tag) == 0 {
- return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
- }
- for i := 0; i < len(emitter.tag_directives); i++ {
- tag_directive := &emitter.tag_directives[i]
- if bytes.HasPrefix(tag, tag_directive.prefix) {
- emitter.tag_data.handle = tag_directive.handle
- emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
- return true
- }
- }
- emitter.tag_data.suffix = tag
- return true
-}
-
-// Check if a scalar is valid.
-func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
- var (
- block_indicators = false
- flow_indicators = false
- line_breaks = false
- special_characters = false
- tab_characters = false
-
- leading_space = false
- leading_break = false
- trailing_space = false
- trailing_break = false
- break_space = false
- space_break = false
-
- preceded_by_whitespace = false
- followed_by_whitespace = false
- previous_space = false
- previous_break = false
- )
-
- emitter.scalar_data.value = value
-
- if len(value) == 0 {
- emitter.scalar_data.multiline = false
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = true
- emitter.scalar_data.single_quoted_allowed = true
- emitter.scalar_data.block_allowed = false
- return true
- }
-
- if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
- block_indicators = true
- flow_indicators = true
- }
-
- preceded_by_whitespace = true
- for i, w := 0, 0; i < len(value); i += w {
- w = width(value[i])
- followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
-
- if i == 0 {
- switch value[i] {
- case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
- flow_indicators = true
- block_indicators = true
- case '?', ':':
- flow_indicators = true
- if followed_by_whitespace {
- block_indicators = true
- }
- case '-':
- if followed_by_whitespace {
- flow_indicators = true
- block_indicators = true
- }
- }
- } else {
- switch value[i] {
- case ',', '?', '[', ']', '{', '}':
- flow_indicators = true
- case ':':
- flow_indicators = true
- if followed_by_whitespace {
- block_indicators = true
- }
- case '#':
- if preceded_by_whitespace {
- flow_indicators = true
- block_indicators = true
- }
- }
- }
-
- if value[i] == '\t' {
- tab_characters = true
- } else if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
- special_characters = true
- }
- if is_space(value, i) {
- if i == 0 {
- leading_space = true
- }
- if i+width(value[i]) == len(value) {
- trailing_space = true
- }
- if previous_break {
- break_space = true
- }
- previous_space = true
- previous_break = false
- } else if is_break(value, i) {
- line_breaks = true
- if i == 0 {
- leading_break = true
- }
- if i+width(value[i]) == len(value) {
- trailing_break = true
- }
- if previous_space {
- space_break = true
- }
- previous_space = false
- previous_break = true
- } else {
- previous_space = false
- previous_break = false
- }
-
- // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
- preceded_by_whitespace = is_blankz(value, i)
- }
-
- emitter.scalar_data.multiline = line_breaks
- emitter.scalar_data.flow_plain_allowed = true
- emitter.scalar_data.block_plain_allowed = true
- emitter.scalar_data.single_quoted_allowed = true
- emitter.scalar_data.block_allowed = true
-
- if leading_space || leading_break || trailing_space || trailing_break {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- }
- if trailing_space {
- emitter.scalar_data.block_allowed = false
- }
- if break_space {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- emitter.scalar_data.single_quoted_allowed = false
- }
- if space_break || tab_characters || special_characters {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- emitter.scalar_data.single_quoted_allowed = false
- }
- if space_break || special_characters {
- emitter.scalar_data.block_allowed = false
- }
- if line_breaks {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- }
- if flow_indicators {
- emitter.scalar_data.flow_plain_allowed = false
- }
- if block_indicators {
- emitter.scalar_data.block_plain_allowed = false
- }
- return true
-}
-
-// Check if the event data is valid.
-func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-
- emitter.anchor_data.anchor = nil
- emitter.tag_data.handle = nil
- emitter.tag_data.suffix = nil
- emitter.scalar_data.value = nil
-
- if len(event.head_comment) > 0 {
- emitter.head_comment = event.head_comment
- }
- if len(event.line_comment) > 0 {
- emitter.line_comment = event.line_comment
- }
- if len(event.foot_comment) > 0 {
- emitter.foot_comment = event.foot_comment
- }
- if len(event.tail_comment) > 0 {
- emitter.tail_comment = event.tail_comment
- }
-
- switch event.typ {
- case yaml_ALIAS_EVENT:
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
- return false
- }
-
- case yaml_SCALAR_EVENT:
- if len(event.anchor) > 0 {
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
- return false
- }
- }
- if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
- if !yaml_emitter_analyze_tag(emitter, event.tag) {
- return false
- }
- }
- if !yaml_emitter_analyze_scalar(emitter, event.value) {
- return false
- }
-
- case yaml_SEQUENCE_START_EVENT:
- if len(event.anchor) > 0 {
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
- return false
- }
- }
- if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
- if !yaml_emitter_analyze_tag(emitter, event.tag) {
- return false
- }
- }
-
- case yaml_MAPPING_START_EVENT:
- if len(event.anchor) > 0 {
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
- return false
- }
- }
- if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
- if !yaml_emitter_analyze_tag(emitter, event.tag) {
- return false
- }
- }
- }
- return true
-}
-
-// Write the BOM character.
-func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
- if !flush(emitter) {
- return false
- }
- pos := emitter.buffer_pos
- emitter.buffer[pos+0] = '\xEF'
- emitter.buffer[pos+1] = '\xBB'
- emitter.buffer[pos+2] = '\xBF'
- emitter.buffer_pos += 3
- return true
-}
-
-func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
- indent := emitter.indent
- if indent < 0 {
- indent = 0
- }
- if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
- if !put_break(emitter) {
- return false
- }
- }
- if emitter.foot_indent == indent {
- if !put_break(emitter) {
- return false
- }
- }
- for emitter.column < indent {
- if !put(emitter, ' ') {
- return false
- }
- }
- emitter.whitespace = true
- //emitter.indention = true
- emitter.space_above = false
- emitter.foot_indent = -1
- return true
-}
-
-func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
- if need_whitespace && !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- if !write_all(emitter, indicator) {
- return false
- }
- emitter.whitespace = is_whitespace
- emitter.indention = (emitter.indention && is_indention)
- emitter.open_ended = false
- return true
-}
-
-func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
- if !write_all(emitter, value) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
- if !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- if !write_all(emitter, value) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
- if need_whitespace && !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- for i := 0; i < len(value); {
- var must_write bool
- switch value[i] {
- case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
- must_write = true
- default:
- must_write = is_alpha(value, i)
- }
- if must_write {
- if !write(emitter, value, &i) {
- return false
- }
- } else {
- w := width(value[i])
- for k := 0; k < w; k++ {
- octet := value[i]
- i++
- if !put(emitter, '%') {
- return false
- }
-
- c := octet >> 4
- if c < 10 {
- c += '0'
- } else {
- c += 'A' - 10
- }
- if !put(emitter, c) {
- return false
- }
-
- c = octet & 0x0f
- if c < 10 {
- c += '0'
- } else {
- c += 'A' - 10
- }
- if !put(emitter, c) {
- return false
- }
- }
- }
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
- if len(value) > 0 && !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
-
- spaces := false
- breaks := false
- for i := 0; i < len(value); {
- if is_space(value, i) {
- if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- i += width(value[i])
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- }
- spaces = true
- } else if is_break(value, i) {
- if !breaks && value[i] == '\n' {
- if !put_break(emitter) {
- return false
- }
- }
- if !write_break(emitter, value, &i) {
- return false
- }
- //emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !write(emitter, value, &i) {
- return false
- }
- emitter.indention = false
- spaces = false
- breaks = false
- }
- }
-
- if len(value) > 0 {
- emitter.whitespace = false
- }
- emitter.indention = false
- if emitter.root_context {
- emitter.open_ended = true
- }
-
- return true
-}
-
-func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
-
- if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
- return false
- }
-
- spaces := false
- breaks := false
- for i := 0; i < len(value); {
- if is_space(value, i) {
- if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- i += width(value[i])
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- }
- spaces = true
- } else if is_break(value, i) {
- if !breaks && value[i] == '\n' {
- if !put_break(emitter) {
- return false
- }
- }
- if !write_break(emitter, value, &i) {
- return false
- }
- //emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if value[i] == '\'' {
- if !put(emitter, '\'') {
- return false
- }
- }
- if !write(emitter, value, &i) {
- return false
- }
- emitter.indention = false
- spaces = false
- breaks = false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
- spaces := false
- if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
- return false
- }
-
- for i := 0; i < len(value); {
- if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
- is_bom(value, i) || is_break(value, i) ||
- value[i] == '"' || value[i] == '\\' {
-
- octet := value[i]
-
- var w int
- var v rune
- switch {
- case octet&0x80 == 0x00:
- w, v = 1, rune(octet&0x7F)
- case octet&0xE0 == 0xC0:
- w, v = 2, rune(octet&0x1F)
- case octet&0xF0 == 0xE0:
- w, v = 3, rune(octet&0x0F)
- case octet&0xF8 == 0xF0:
- w, v = 4, rune(octet&0x07)
- }
- for k := 1; k < w; k++ {
- octet = value[i+k]
- v = (v << 6) + (rune(octet) & 0x3F)
- }
- i += w
-
- if !put(emitter, '\\') {
- return false
- }
-
- var ok bool
- switch v {
- case 0x00:
- ok = put(emitter, '0')
- case 0x07:
- ok = put(emitter, 'a')
- case 0x08:
- ok = put(emitter, 'b')
- case 0x09:
- ok = put(emitter, 't')
- case 0x0A:
- ok = put(emitter, 'n')
- case 0x0b:
- ok = put(emitter, 'v')
- case 0x0c:
- ok = put(emitter, 'f')
- case 0x0d:
- ok = put(emitter, 'r')
- case 0x1b:
- ok = put(emitter, 'e')
- case 0x22:
- ok = put(emitter, '"')
- case 0x5c:
- ok = put(emitter, '\\')
- case 0x85:
- ok = put(emitter, 'N')
- case 0xA0:
- ok = put(emitter, '_')
- case 0x2028:
- ok = put(emitter, 'L')
- case 0x2029:
- ok = put(emitter, 'P')
- default:
- if v <= 0xFF {
- ok = put(emitter, 'x')
- w = 2
- } else if v <= 0xFFFF {
- ok = put(emitter, 'u')
- w = 4
- } else {
- ok = put(emitter, 'U')
- w = 8
- }
- for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
- digit := byte((v >> uint(k)) & 0x0F)
- if digit < 10 {
- ok = put(emitter, digit+'0')
- } else {
- ok = put(emitter, digit+'A'-10)
- }
- }
- }
- if !ok {
- return false
- }
- spaces = false
- } else if is_space(value, i) {
- if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if is_space(value, i+1) {
- if !put(emitter, '\\') {
- return false
- }
- }
- i += width(value[i])
- } else if !write(emitter, value, &i) {
- return false
- }
- spaces = true
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- spaces = false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
- if is_space(value, 0) || is_break(value, 0) {
- indent_hint := []byte{'0' + byte(emitter.best_indent)}
- if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
- return false
- }
- }
-
- emitter.open_ended = false
-
- var chomp_hint [1]byte
- if len(value) == 0 {
- chomp_hint[0] = '-'
- } else {
- i := len(value) - 1
- for value[i]&0xC0 == 0x80 {
- i--
- }
- if !is_break(value, i) {
- chomp_hint[0] = '-'
- } else if i == 0 {
- chomp_hint[0] = '+'
- emitter.open_ended = true
- } else {
- i--
- for value[i]&0xC0 == 0x80 {
- i--
- }
- if is_break(value, i) {
- chomp_hint[0] = '+'
- emitter.open_ended = true
- }
- }
- }
- if chomp_hint[0] != 0 {
- if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
- return false
- }
- }
- return true
-}
-
-func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
- if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
- return false
- }
- if !yaml_emitter_write_block_scalar_hints(emitter, value) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
- //emitter.indention = true
- emitter.whitespace = true
- breaks := true
- for i := 0; i < len(value); {
- if is_break(value, i) {
- if !write_break(emitter, value, &i) {
- return false
- }
- //emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !write(emitter, value, &i) {
- return false
- }
- emitter.indention = false
- breaks = false
- }
- }
-
- return true
-}
-
-func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
- if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
- return false
- }
- if !yaml_emitter_write_block_scalar_hints(emitter, value) {
- return false
- }
- if !yaml_emitter_process_line_comment(emitter) {
- return false
- }
-
- //emitter.indention = true
- emitter.whitespace = true
-
- breaks := true
- leading_spaces := true
- for i := 0; i < len(value); {
- if is_break(value, i) {
- if !breaks && !leading_spaces && value[i] == '\n' {
- k := 0
- for is_break(value, k) {
- k += width(value[k])
- }
- if !is_blankz(value, k) {
- if !put_break(emitter) {
- return false
- }
- }
- }
- if !write_break(emitter, value, &i) {
- return false
- }
- //emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- leading_spaces = is_blank(value, i)
- }
- if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- i += width(value[i])
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- }
- emitter.indention = false
- breaks = false
- }
- }
- return true
-}
-
-func yaml_emitter_write_comment(emitter *yaml_emitter_t, comment []byte) bool {
- breaks := false
- pound := false
- for i := 0; i < len(comment); {
- if is_break(comment, i) {
- if !write_break(emitter, comment, &i) {
- return false
- }
- //emitter.indention = true
- breaks = true
- pound = false
- } else {
- if breaks && !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !pound {
- if comment[i] != '#' && (!put(emitter, '#') || !put(emitter, ' ')) {
- return false
- }
- pound = true
- }
- if !write(emitter, comment, &i) {
- return false
- }
- emitter.indention = false
- breaks = false
- }
- }
- if !breaks && !put_break(emitter) {
- return false
- }
-
- emitter.whitespace = true
- //emitter.indention = true
- return true
-}
diff --git a/cli/internal/yaml/encode.go b/cli/internal/yaml/encode.go
deleted file mode 100644
index de9e72a..0000000
--- a/cli/internal/yaml/encode.go
+++ /dev/null
@@ -1,577 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
- "encoding"
- "fmt"
- "io"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "time"
- "unicode/utf8"
-)
-
-type encoder struct {
- emitter yaml_emitter_t
- event yaml_event_t
- out []byte
- flow bool
- indent int
- doneInit bool
-}
-
-func newEncoder() *encoder {
- e := &encoder{}
- yaml_emitter_initialize(&e.emitter)
- yaml_emitter_set_output_string(&e.emitter, &e.out)
- yaml_emitter_set_unicode(&e.emitter, true)
- return e
-}
-
-func newEncoderWithWriter(w io.Writer) *encoder {
- e := &encoder{}
- yaml_emitter_initialize(&e.emitter)
- yaml_emitter_set_output_writer(&e.emitter, w)
- yaml_emitter_set_unicode(&e.emitter, true)
- return e
-}
-
-func (e *encoder) init() {
- if e.doneInit {
- return
- }
- if e.indent == 0 {
- e.indent = 4
- }
- e.emitter.best_indent = e.indent
- yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
- e.emit()
- e.doneInit = true
-}
-
-func (e *encoder) finish() {
- e.emitter.open_ended = false
- yaml_stream_end_event_initialize(&e.event)
- e.emit()
-}
-
-func (e *encoder) destroy() {
- yaml_emitter_delete(&e.emitter)
-}
-
-func (e *encoder) emit() {
- // This will internally delete the e.event value.
- e.must(yaml_emitter_emit(&e.emitter, &e.event))
-}
-
-func (e *encoder) must(ok bool) {
- if !ok {
- msg := e.emitter.problem
- if msg == "" {
- msg = "unknown problem generating YAML content"
- }
- failf("%s", msg)
- }
-}
-
-func (e *encoder) marshalDoc(tag string, in reflect.Value) {
- e.init()
- var node *Node
- if in.IsValid() {
- node, _ = in.Interface().(*Node)
- }
- if node != nil && node.Kind == DocumentNode {
- e.nodev(in)
- } else {
- yaml_document_start_event_initialize(&e.event, nil, nil, true)
- e.emit()
- e.marshal(tag, in)
- yaml_document_end_event_initialize(&e.event, true)
- e.emit()
- }
-}
-
-func (e *encoder) marshal(tag string, in reflect.Value) {
- tag = shortTag(tag)
- if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
- e.nilv()
- return
- }
- iface := in.Interface()
- switch value := iface.(type) {
- case *Node:
- e.nodev(in)
- return
- case Node:
- if !in.CanAddr() {
- var n = reflect.New(in.Type()).Elem()
- n.Set(in)
- in = n
- }
- e.nodev(in.Addr())
- return
- case time.Time:
- e.timev(tag, in)
- return
- case *time.Time:
- e.timev(tag, in.Elem())
- return
- case time.Duration:
- e.stringv(tag, reflect.ValueOf(value.String()))
- return
- case Marshaler:
- v, err := value.MarshalYAML()
- if err != nil {
- fail(err)
- }
- if v == nil {
- e.nilv()
- return
- }
- e.marshal(tag, reflect.ValueOf(v))
- return
- case encoding.TextMarshaler:
- text, err := value.MarshalText()
- if err != nil {
- fail(err)
- }
- in = reflect.ValueOf(string(text))
- case nil:
- e.nilv()
- return
- }
- switch in.Kind() {
- case reflect.Interface:
- e.marshal(tag, in.Elem())
- case reflect.Map:
- e.mapv(tag, in)
- case reflect.Ptr:
- e.marshal(tag, in.Elem())
- case reflect.Struct:
- e.structv(tag, in)
- case reflect.Slice, reflect.Array:
- e.slicev(tag, in)
- case reflect.String:
- e.stringv(tag, in)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- e.intv(tag, in)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- e.uintv(tag, in)
- case reflect.Float32, reflect.Float64:
- e.floatv(tag, in)
- case reflect.Bool:
- e.boolv(tag, in)
- default:
- panic("cannot marshal type: " + in.Type().String())
- }
-}
-
-func (e *encoder) mapv(tag string, in reflect.Value) {
- e.mappingv(tag, func() {
- keys := keyList(in.MapKeys())
- sort.Sort(keys)
- for _, k := range keys {
- e.marshal("", k)
- e.marshal("", in.MapIndex(k))
- }
- })
-}
-
-func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) {
- for _, num := range index {
- for {
- if v.Kind() == reflect.Ptr {
- if v.IsNil() {
- return reflect.Value{}
- }
- v = v.Elem()
- continue
- }
- break
- }
- v = v.Field(num)
- }
- return v
-}
-
-func (e *encoder) structv(tag string, in reflect.Value) {
- sinfo, err := getStructInfo(in.Type())
- if err != nil {
- panic(err)
- }
- e.mappingv(tag, func() {
- for _, info := range sinfo.FieldsList {
- var value reflect.Value
- if info.Inline == nil {
- value = in.Field(info.Num)
- } else {
- value = e.fieldByIndex(in, info.Inline)
- if !value.IsValid() {
- continue
- }
- }
- if info.OmitEmpty && isZero(value) {
- continue
- }
- e.marshal("", reflect.ValueOf(info.Key))
- e.flow = info.Flow
- e.marshal("", value)
- }
- if sinfo.InlineMap >= 0 {
- m := in.Field(sinfo.InlineMap)
- if m.Len() > 0 {
- e.flow = false
- keys := keyList(m.MapKeys())
- sort.Sort(keys)
- for _, k := range keys {
- if _, found := sinfo.FieldsMap[k.String()]; found {
- panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String()))
- }
- e.marshal("", k)
- e.flow = false
- e.marshal("", m.MapIndex(k))
- }
- }
- }
- })
-}
-
-func (e *encoder) mappingv(tag string, f func()) {
- implicit := tag == ""
- style := yaml_BLOCK_MAPPING_STYLE
- if e.flow {
- e.flow = false
- style = yaml_FLOW_MAPPING_STYLE
- }
- yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
- e.emit()
- f()
- yaml_mapping_end_event_initialize(&e.event)
- e.emit()
-}
-
-func (e *encoder) slicev(tag string, in reflect.Value) {
- implicit := tag == ""
- style := yaml_BLOCK_SEQUENCE_STYLE
- if e.flow {
- e.flow = false
- style = yaml_FLOW_SEQUENCE_STYLE
- }
- e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
- e.emit()
- n := in.Len()
- for i := 0; i < n; i++ {
- e.marshal("", in.Index(i))
- }
- e.must(yaml_sequence_end_event_initialize(&e.event))
- e.emit()
-}
-
-// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
-//
-// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
-// in YAML 1.2 and by this package, but these should be marshalled quoted for
-// the time being for compatibility with other parsers.
-func isBase60Float(s string) (result bool) {
- // Fast path.
- if s == "" {
- return false
- }
- c := s[0]
- if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
- return false
- }
- // Do the full match.
- return base60float.MatchString(s)
-}
-
-// From http://yaml.org/type/float.html, except the regular expression there
-// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
-var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
-
-// isOldBool returns whether s is bool notation as defined in YAML 1.1.
-//
-// We continue to force strings that YAML 1.1 would interpret as booleans to be
-// rendered as quotes strings so that the marshalled output valid for YAML 1.1
-// parsing.
-func isOldBool(s string) (result bool) {
- switch s {
- case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON",
- "n", "N", "no", "No", "NO", "off", "Off", "OFF":
- return true
- default:
- return false
- }
-}
-
-func (e *encoder) stringv(tag string, in reflect.Value) {
- var style yaml_scalar_style_t
- s := in.String()
- canUsePlain := true
- switch {
- case !utf8.ValidString(s):
- if tag == binaryTag {
- failf("explicitly tagged !!binary data must be base64-encoded")
- }
- if tag != "" {
- failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
- }
- // It can't be encoded directly as YAML so use a binary tag
- // and encode it as base64.
- tag = binaryTag
- s = encodeBase64(s)
- case tag == "":
- // Check to see if it would resolve to a specific
- // tag when encoded unquoted. If it doesn't,
- // there's no need to quote it.
- rtag, _ := resolve("", s)
- canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s))
- }
- // Note: it's possible for user code to emit invalid YAML
- // if they explicitly specify a tag and a string containing
- // text that's incompatible with that tag.
- switch {
- case strings.Contains(s, "\n"):
- if e.flow {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- } else {
- style = yaml_LITERAL_SCALAR_STYLE
- }
- case canUsePlain:
- style = yaml_PLAIN_SCALAR_STYLE
- default:
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- e.emitScalar(s, "", tag, style, nil, nil, nil, nil)
-}
-
-func (e *encoder) boolv(tag string, in reflect.Value) {
- var s string
- if in.Bool() {
- s = "true"
- } else {
- s = "false"
- }
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) intv(tag string, in reflect.Value) {
- s := strconv.FormatInt(in.Int(), 10)
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) uintv(tag string, in reflect.Value) {
- s := strconv.FormatUint(in.Uint(), 10)
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) timev(tag string, in reflect.Value) {
- t := in.Interface().(time.Time)
- s := t.Format(time.RFC3339Nano)
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) floatv(tag string, in reflect.Value) {
- // Issue #352: When formatting, use the precision of the underlying value
- precision := 64
- if in.Kind() == reflect.Float32 {
- precision = 32
- }
-
- s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
- switch s {
- case "+Inf":
- s = ".inf"
- case "-Inf":
- s = "-.inf"
- case "NaN":
- s = ".nan"
- }
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) nilv() {
- e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) {
- // TODO Kill this function. Replace all initialize calls by their underlining Go literals.
- implicit := tag == ""
- if !implicit {
- tag = longTag(tag)
- }
- e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
- e.event.head_comment = head
- e.event.line_comment = line
- e.event.foot_comment = foot
- e.event.tail_comment = tail
- e.emit()
-}
-
-func (e *encoder) nodev(in reflect.Value) {
- e.node(in.Interface().(*Node), "")
-}
-
-func (e *encoder) node(node *Node, tail string) {
- // Zero nodes behave as nil.
- if node.Kind == 0 && node.IsZero() {
- e.nilv()
- return
- }
-
- // If the tag was not explicitly requested, and dropping it won't change the
- // implicit tag of the value, don't include it in the presentation.
- var tag = node.Tag
- var stag = shortTag(tag)
- var forceQuoting bool
- if tag != "" && node.Style&TaggedStyle == 0 {
- if node.Kind == ScalarNode {
- if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
- tag = ""
- } else {
- rtag, _ := resolve("", node.Value)
- if rtag == stag {
- tag = ""
- } else if stag == strTag {
- tag = ""
- forceQuoting = true
- }
- }
- } else {
- var rtag string
- switch node.Kind {
- case MappingNode:
- rtag = mapTag
- case SequenceNode:
- rtag = seqTag
- }
- if rtag == stag {
- tag = ""
- }
- }
- }
-
- switch node.Kind {
- case DocumentNode:
- yaml_document_start_event_initialize(&e.event, nil, nil, true)
- e.event.head_comment = []byte(node.HeadComment)
- e.emit()
- for _, node := range node.Content {
- e.node(node, "")
- }
- yaml_document_end_event_initialize(&e.event, true)
- e.event.foot_comment = []byte(node.FootComment)
- e.emit()
-
- case SequenceNode:
- style := yaml_BLOCK_SEQUENCE_STYLE
- if node.Style&FlowStyle != 0 {
- style = yaml_FLOW_SEQUENCE_STYLE
- }
- e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style))
- e.event.head_comment = []byte(node.HeadComment)
- e.emit()
- for _, node := range node.Content {
- e.node(node, "")
- }
- e.must(yaml_sequence_end_event_initialize(&e.event))
- e.event.line_comment = []byte(node.LineComment)
- e.event.foot_comment = []byte(node.FootComment)
- e.emit()
-
- case MappingNode:
- style := yaml_BLOCK_MAPPING_STYLE
- if node.Style&FlowStyle != 0 {
- style = yaml_FLOW_MAPPING_STYLE
- }
- yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)
- e.event.tail_comment = []byte(tail)
- e.event.head_comment = []byte(node.HeadComment)
- e.emit()
-
- // The tail logic below moves the foot comment of prior keys to the following key,
- // since the value for each key may be a nested structure and the foot needs to be
- // processed only the entirety of the value is streamed. The last tail is processed
- // with the mapping end event.
- var tail string
- for i := 0; i+1 < len(node.Content); i += 2 {
- k := node.Content[i]
- foot := k.FootComment
- if foot != "" {
- kopy := *k
- kopy.FootComment = ""
- k = &kopy
- }
- e.node(k, tail)
- tail = foot
-
- v := node.Content[i+1]
- e.node(v, "")
- }
-
- yaml_mapping_end_event_initialize(&e.event)
- e.event.tail_comment = []byte(tail)
- e.event.line_comment = []byte(node.LineComment)
- e.event.foot_comment = []byte(node.FootComment)
- e.emit()
-
- case AliasNode:
- yaml_alias_event_initialize(&e.event, []byte(node.Value))
- e.event.head_comment = []byte(node.HeadComment)
- e.event.line_comment = []byte(node.LineComment)
- e.event.foot_comment = []byte(node.FootComment)
- e.emit()
-
- case ScalarNode:
- value := node.Value
- if !utf8.ValidString(value) {
- if stag == binaryTag {
- failf("explicitly tagged !!binary data must be base64-encoded")
- }
- if stag != "" {
- failf("cannot marshal invalid UTF-8 data as %s", stag)
- }
- // It can't be encoded directly as YAML so use a binary tag
- // and encode it as base64.
- tag = binaryTag
- value = encodeBase64(value)
- }
-
- style := yaml_PLAIN_SCALAR_STYLE
- switch {
- case node.Style&DoubleQuotedStyle != 0:
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- case node.Style&SingleQuotedStyle != 0:
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- case node.Style&LiteralStyle != 0:
- style = yaml_LITERAL_SCALAR_STYLE
- case node.Style&FoldedStyle != 0:
- style = yaml_FOLDED_SCALAR_STYLE
- case strings.Contains(value, "\n"):
- style = yaml_LITERAL_SCALAR_STYLE
- case forceQuoting:
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
-
- e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
- default:
- failf("cannot encode node with unknown kind %d", node.Kind)
- }
-}
diff --git a/cli/internal/yaml/parserc.go b/cli/internal/yaml/parserc.go
deleted file mode 100644
index 25fe823..0000000
--- a/cli/internal/yaml/parserc.go
+++ /dev/null
@@ -1,1274 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
- "bytes"
-)
-
-// The parser implements the following grammar:
-//
-// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
-// implicit_document ::= block_node DOCUMENT-END*
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-// block_node_or_indentless_sequence ::=
-// ALIAS
-// | properties (block_content | indentless_block_sequence)?
-// | block_content
-// | indentless_block_sequence
-// block_node ::= ALIAS
-// | properties block_content?
-// | block_content
-// flow_node ::= ALIAS
-// | properties flow_content?
-// | flow_content
-// properties ::= TAG ANCHOR? | ANCHOR TAG?
-// block_content ::= block_collection | flow_collection | SCALAR
-// flow_content ::= flow_collection | SCALAR
-// block_collection ::= block_sequence | block_mapping
-// flow_collection ::= flow_sequence | flow_mapping
-// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
-// block_mapping ::= BLOCK-MAPPING_START
-// ((KEY block_node_or_indentless_sequence?)?
-// (VALUE block_node_or_indentless_sequence?)?)*
-// BLOCK-END
-// flow_sequence ::= FLOW-SEQUENCE-START
-// (flow_sequence_entry FLOW-ENTRY)*
-// flow_sequence_entry?
-// FLOW-SEQUENCE-END
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// flow_mapping ::= FLOW-MAPPING-START
-// (flow_mapping_entry FLOW-ENTRY)*
-// flow_mapping_entry?
-// FLOW-MAPPING-END
-// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-
-// Peek the next token in the token queue.
-func peek_token(parser *yaml_parser_t) *yaml_token_t {
- if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
- token := &parser.tokens[parser.tokens_head]
- yaml_parser_unfold_comments(parser, token)
- return token
- }
- return nil
-}
-
-// yaml_parser_unfold_comments walks through the comments queue and joins all
-// comments behind the position of the provided token into the respective
-// top-level comment slices in the parser.
-func yaml_parser_unfold_comments(parser *yaml_parser_t, token *yaml_token_t) {
- for parser.comments_head < len(parser.comments) && token.start_mark.index >= parser.comments[parser.comments_head].token_mark.index {
- comment := &parser.comments[parser.comments_head]
- if len(comment.head) > 0 {
- if token.typ == yaml_BLOCK_END_TOKEN {
- // No heads on ends, so keep comment.head for a follow up token.
- break
- }
- if len(parser.head_comment) > 0 {
- parser.head_comment = append(parser.head_comment, '\n')
- }
- parser.head_comment = append(parser.head_comment, comment.head...)
- }
- if len(comment.foot) > 0 {
- if len(parser.foot_comment) > 0 {
- parser.foot_comment = append(parser.foot_comment, '\n')
- }
- parser.foot_comment = append(parser.foot_comment, comment.foot...)
- }
- if len(comment.line) > 0 {
- if len(parser.line_comment) > 0 {
- parser.line_comment = append(parser.line_comment, '\n')
- }
- parser.line_comment = append(parser.line_comment, comment.line...)
- }
- *comment = yaml_comment_t{}
- parser.comments_head++
- }
-}
-
-// Remove the next token from the queue (must be called after peek_token).
-func skip_token(parser *yaml_parser_t) {
- parser.token_available = false
- parser.tokens_parsed++
- parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
- parser.tokens_head++
-}
-
-// Get the next event.
-func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
- // Erase the event object.
- *event = yaml_event_t{}
-
- // No events after the end of the stream or error.
- if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
- return true
- }
-
- // Generate the next event.
- return yaml_parser_state_machine(parser, event)
-}
-
-// Set parser error.
-func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
- parser.error = yaml_PARSER_ERROR
- parser.problem = problem
- parser.problem_mark = problem_mark
- return false
-}
-
-func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
- parser.error = yaml_PARSER_ERROR
- parser.context = context
- parser.context_mark = context_mark
- parser.problem = problem
- parser.problem_mark = problem_mark
- return false
-}
-
-// State dispatcher.
-func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
- //trace("yaml_parser_state_machine", "state:", parser.state.String())
-
- switch parser.state {
- case yaml_PARSE_STREAM_START_STATE:
- return yaml_parser_parse_stream_start(parser, event)
-
- case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
- return yaml_parser_parse_document_start(parser, event, true)
-
- case yaml_PARSE_DOCUMENT_START_STATE:
- return yaml_parser_parse_document_start(parser, event, false)
-
- case yaml_PARSE_DOCUMENT_CONTENT_STATE:
- return yaml_parser_parse_document_content(parser, event)
-
- case yaml_PARSE_DOCUMENT_END_STATE:
- return yaml_parser_parse_document_end(parser, event)
-
- case yaml_PARSE_BLOCK_NODE_STATE:
- return yaml_parser_parse_node(parser, event, true, false)
-
- case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
- return yaml_parser_parse_node(parser, event, true, true)
-
- case yaml_PARSE_FLOW_NODE_STATE:
- return yaml_parser_parse_node(parser, event, false, false)
-
- case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
- return yaml_parser_parse_block_sequence_entry(parser, event, true)
-
- case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
- return yaml_parser_parse_block_sequence_entry(parser, event, false)
-
- case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
- return yaml_parser_parse_indentless_sequence_entry(parser, event)
-
- case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
- return yaml_parser_parse_block_mapping_key(parser, event, true)
-
- case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
- return yaml_parser_parse_block_mapping_key(parser, event, false)
-
- case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
- return yaml_parser_parse_block_mapping_value(parser, event)
-
- case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
- return yaml_parser_parse_flow_sequence_entry(parser, event, true)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
- return yaml_parser_parse_flow_sequence_entry(parser, event, false)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
- return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
- return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
- return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
-
- case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
- return yaml_parser_parse_flow_mapping_key(parser, event, true)
-
- case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
- return yaml_parser_parse_flow_mapping_key(parser, event, false)
-
- case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
- return yaml_parser_parse_flow_mapping_value(parser, event, false)
-
- case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
- return yaml_parser_parse_flow_mapping_value(parser, event, true)
-
- default:
- panic("invalid parser state")
- }
-}
-
-// Parse the production:
-// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
-//
-// ************
-func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_STREAM_START_TOKEN {
- return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)
- }
- parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
- *event = yaml_event_t{
- typ: yaml_STREAM_START_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- encoding: token.encoding,
- }
- skip_token(parser)
- return true
-}
-
-// Parse the productions:
-// implicit_document ::= block_node DOCUMENT-END*
-//
-// *
-//
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-//
-// *************************
-func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- // Parse extra document end indicators.
- if !implicit {
- for token.typ == yaml_DOCUMENT_END_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
- }
-
- if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
- token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
- token.typ != yaml_DOCUMENT_START_TOKEN &&
- token.typ != yaml_STREAM_END_TOKEN {
- // Parse an implicit document.
- if !yaml_parser_process_directives(parser, nil, nil) {
- return false
- }
- parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
- parser.state = yaml_PARSE_BLOCK_NODE_STATE
-
- var head_comment []byte
- if len(parser.head_comment) > 0 {
- // [Go] Scan the header comment backwards, and if an empty line is found, break
- // the header so the part before the last empty line goes into the
- // document header, while the bottom of it goes into a follow up event.
- for i := len(parser.head_comment) - 1; i > 0; i-- {
- if parser.head_comment[i] == '\n' {
- if i == len(parser.head_comment)-1 {
- head_comment = parser.head_comment[:i]
- parser.head_comment = parser.head_comment[i+1:]
- break
- } else if parser.head_comment[i-1] == '\n' {
- head_comment = parser.head_comment[:i-1]
- parser.head_comment = parser.head_comment[i+1:]
- break
- }
- }
- }
- }
-
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_START_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
-
- head_comment: head_comment,
- }
-
- } else if token.typ != yaml_STREAM_END_TOKEN {
- // Parse an explicit document.
- var version_directive *yaml_version_directive_t
- var tag_directives []yaml_tag_directive_t
- start_mark := token.start_mark
- if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
- return false
- }
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_DOCUMENT_START_TOKEN {
- yaml_parser_set_parser_error(parser,
- "did not find expected <document start>", token.start_mark)
- return false
- }
- parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
- parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
- end_mark := token.end_mark
-
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- version_directive: version_directive,
- tag_directives: tag_directives,
- implicit: false,
- }
- skip_token(parser)
-
- } else {
- // Parse the stream end.
- parser.state = yaml_PARSE_END_STATE
- *event = yaml_event_t{
- typ: yaml_STREAM_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- skip_token(parser)
- }
-
- return true
-}
-
-// Parse the productions:
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-//
-// ***********
-func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
- token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
- token.typ == yaml_DOCUMENT_START_TOKEN ||
- token.typ == yaml_DOCUMENT_END_TOKEN ||
- token.typ == yaml_STREAM_END_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- return yaml_parser_process_empty_scalar(parser, event,
- token.start_mark)
- }
- return yaml_parser_parse_node(parser, event, true, false)
-}
-
-// Parse the productions:
-// implicit_document ::= block_node DOCUMENT-END*
-//
-// *************
-//
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- start_mark := token.start_mark
- end_mark := token.start_mark
-
- implicit := true
- if token.typ == yaml_DOCUMENT_END_TOKEN {
- end_mark = token.end_mark
- skip_token(parser)
- implicit = false
- }
-
- parser.tag_directives = parser.tag_directives[:0]
-
- parser.state = yaml_PARSE_DOCUMENT_START_STATE
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_END_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- implicit: implicit,
- }
- yaml_parser_set_event_comments(parser, event)
- if len(event.head_comment) > 0 && len(event.foot_comment) == 0 {
- event.foot_comment = event.head_comment
- event.head_comment = nil
- }
- return true
-}
-
-func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) {
- event.head_comment = parser.head_comment
- event.line_comment = parser.line_comment
- event.foot_comment = parser.foot_comment
- parser.head_comment = nil
- parser.line_comment = nil
- parser.foot_comment = nil
- parser.tail_comment = nil
- parser.stem_comment = nil
-}
-
-// Parse the productions:
-// block_node_or_indentless_sequence ::=
-//
-// ALIAS
-// *****
-// | properties (block_content | indentless_block_sequence)?
-// ********** *
-// | block_content | indentless_block_sequence
-// *
-//
-// block_node ::= ALIAS
-//
-// *****
-// | properties block_content?
-// ********** *
-// | block_content
-// *
-//
-// flow_node ::= ALIAS
-//
-// *****
-// | properties flow_content?
-// ********** *
-// | flow_content
-// *
-//
-// properties ::= TAG ANCHOR? | ANCHOR TAG?
-//
-// *************************
-//
-// block_content ::= block_collection | flow_collection | SCALAR
-//
-// ******
-//
-// flow_content ::= flow_collection | SCALAR
-//
-// ******
-func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
- //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_ALIAS_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- *event = yaml_event_t{
- typ: yaml_ALIAS_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- anchor: token.value,
- }
- yaml_parser_set_event_comments(parser, event)
- skip_token(parser)
- return true
- }
-
- start_mark := token.start_mark
- end_mark := token.start_mark
-
- var tag_token bool
- var tag_handle, tag_suffix, anchor []byte
- var tag_mark yaml_mark_t
- if token.typ == yaml_ANCHOR_TOKEN {
- anchor = token.value
- start_mark = token.start_mark
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_TAG_TOKEN {
- tag_token = true
- tag_handle = token.value
- tag_suffix = token.suffix
- tag_mark = token.start_mark
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
- } else if token.typ == yaml_TAG_TOKEN {
- tag_token = true
- tag_handle = token.value
- tag_suffix = token.suffix
- start_mark = token.start_mark
- tag_mark = token.start_mark
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_ANCHOR_TOKEN {
- anchor = token.value
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
- }
-
- var tag []byte
- if tag_token {
- if len(tag_handle) == 0 {
- tag = tag_suffix
- tag_suffix = nil
- } else {
- for i := range parser.tag_directives {
- if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
- tag = append([]byte(nil), parser.tag_directives[i].prefix...)
- tag = append(tag, tag_suffix...)
- break
- }
- }
- if len(tag) == 0 {
- yaml_parser_set_parser_error_context(parser,
- "while parsing a node", start_mark,
- "found undefined tag handle", tag_mark)
- return false
- }
- }
- }
-
- implicit := len(tag) == 0
- if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
- }
- return true
- }
- if token.typ == yaml_SCALAR_TOKEN {
- var plain_implicit, quoted_implicit bool
- end_mark = token.end_mark
- if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
- plain_implicit = true
- } else if len(tag) == 0 {
- quoted_implicit = true
- }
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
-
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- value: token.value,
- implicit: plain_implicit,
- quoted_implicit: quoted_implicit,
- style: yaml_style_t(token.style),
- }
- yaml_parser_set_event_comments(parser, event)
- skip_token(parser)
- return true
- }
- if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
- // [Go] Some of the events below can be merged as they differ only on style.
- end_mark = token.end_mark
- parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
- }
- yaml_parser_set_event_comments(parser, event)
- return true
- }
- if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),
- }
- yaml_parser_set_event_comments(parser, event)
- return true
- }
- if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
- }
- if parser.stem_comment != nil {
- event.head_comment = parser.stem_comment
- parser.stem_comment = nil
- }
- return true
- }
- if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
- }
- if parser.stem_comment != nil {
- event.head_comment = parser.stem_comment
- parser.stem_comment = nil
- }
- return true
- }
- if len(anchor) > 0 || len(tag) > 0 {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
-
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- quoted_implicit: false,
- style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
- }
- return true
- }
-
- context := "while parsing a flow node"
- if block {
- context = "while parsing a block node"
- }
- yaml_parser_set_parser_error_context(parser, context, start_mark,
- "did not find expected node content", token.start_mark)
- return false
-}
-
-// Parse the productions:
-// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-//
-// ******************** *********** * *********
-func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_BLOCK_ENTRY_TOKEN {
- mark := token.end_mark
- prior_head_len := len(parser.head_comment)
- skip_token(parser)
- yaml_parser_split_stem_comment(parser, prior_head_len)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
- return yaml_parser_parse_node(parser, event, true, false)
- } else {
- parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- }
- if token.typ == yaml_BLOCK_END_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
-
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
-
- skip_token(parser)
- return true
- }
-
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a block collection", context_mark,
- "did not find expected '-' indicator", token.start_mark)
-}
-
-// Parse the productions:
-// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
-//
-// *********** *
-func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_BLOCK_ENTRY_TOKEN {
- mark := token.end_mark
- prior_head_len := len(parser.head_comment)
- skip_token(parser)
- yaml_parser_split_stem_comment(parser, prior_head_len)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
- token.typ != yaml_KEY_TOKEN &&
- token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
- return yaml_parser_parse_node(parser, event, true, false)
- }
- parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
-
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark?
- }
- return true
-}
-
-// Split stem comment from head comment.
-//
-// When a sequence or map is found under a sequence entry, the former head comment
-// is assigned to the underlying sequence or map as a whole, not the individual
-// sequence or map entry as would be expected otherwise. To handle this case the
-// previous head comment is moved aside as the stem comment.
-func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
- if stem_len == 0 {
- return
- }
-
- token := peek_token(parser)
- if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
- return
- }
-
- parser.stem_comment = parser.head_comment[:stem_len]
- if len(parser.head_comment) == stem_len {
- parser.head_comment = nil
- } else {
- // Copy suffix to prevent very strange bugs if someone ever appends
- // further bytes to the prefix in the stem_comment slice above.
- parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...)
- }
-}
-
-// Parse the productions:
-// block_mapping ::= BLOCK-MAPPING_START
-//
-// *******************
-// ((KEY block_node_or_indentless_sequence?)?
-// *** *
-// (VALUE block_node_or_indentless_sequence?)?)*
-//
-// BLOCK-END
-// *********
-func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- // [Go] A tail comment was left from the prior mapping value processed. Emit an event
- // as it needs to be processed with that value and not the following key.
- if len(parser.tail_comment) > 0 {
- *event = yaml_event_t{
- typ: yaml_TAIL_COMMENT_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- foot_comment: parser.tail_comment,
- }
- parser.tail_comment = nil
- return true
- }
-
- if token.typ == yaml_KEY_TOKEN {
- mark := token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_KEY_TOKEN &&
- token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, true, true)
- } else {
- parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- } else if token.typ == yaml_BLOCK_END_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- yaml_parser_set_event_comments(parser, event)
- skip_token(parser)
- return true
- }
-
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a block mapping", context_mark,
- "did not find expected key", token.start_mark)
-}
-
-// Parse the productions:
-// block_mapping ::= BLOCK-MAPPING_START
-//
-// ((KEY block_node_or_indentless_sequence?)?
-//
-// (VALUE block_node_or_indentless_sequence?)?)*
-// ***** *
-// BLOCK-END
-func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_VALUE_TOKEN {
- mark := token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_KEY_TOKEN &&
- token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
- return yaml_parser_parse_node(parser, event, true, true)
- }
- parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Parse the productions:
-// flow_sequence ::= FLOW-SEQUENCE-START
-//
-// *******************
-// (flow_sequence_entry FLOW-ENTRY)*
-// * **********
-// flow_sequence_entry?
-// *
-// FLOW-SEQUENCE-END
-// *****************
-//
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-// *
-func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- if !first {
- if token.typ == yaml_FLOW_ENTRY_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- } else {
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a flow sequence", context_mark,
- "did not find expected ',' or ']'", token.start_mark)
- }
- }
-
- if token.typ == yaml_KEY_TOKEN {
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- implicit: true,
- style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),
- }
- skip_token(parser)
- return true
- } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
-
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
-
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- yaml_parser_set_event_comments(parser, event)
-
- skip_token(parser)
- return true
-}
-
-// Parse the productions:
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-// *** *
-func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_FLOW_ENTRY_TOKEN &&
- token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- mark := token.end_mark
- skip_token(parser)
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
-}
-
-// Parse the productions:
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-// ***** *
-func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_VALUE_TOKEN {
- skip_token(parser)
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Parse the productions:
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-// *
-func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.start_mark, // [Go] Shouldn't this be end_mark?
- }
- return true
-}
-
-// Parse the productions:
-// flow_mapping ::= FLOW-MAPPING-START
-//
-// ******************
-// (flow_mapping_entry FLOW-ENTRY)*
-// * **********
-// flow_mapping_entry?
-// ******************
-// FLOW-MAPPING-END
-// ****************
-//
-// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// - *** *
-func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- if !first {
- if token.typ == yaml_FLOW_ENTRY_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- } else {
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a flow mapping", context_mark,
- "did not find expected ',' or '}'", token.start_mark)
- }
- }
-
- if token.typ == yaml_KEY_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_FLOW_ENTRY_TOKEN &&
- token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- } else {
- parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
- }
- } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
-
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- yaml_parser_set_event_comments(parser, event)
- skip_token(parser)
- return true
-}
-
-// Parse the productions:
-// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// - ***** *
-func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if empty {
- parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
- }
- if token.typ == yaml_VALUE_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
- parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Generate an empty scalar event.
-func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- start_mark: mark,
- end_mark: mark,
- value: nil, // Empty
- implicit: true,
- style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
- }
- return true
-}
-
-var default_tag_directives = []yaml_tag_directive_t{
- {[]byte("!"), []byte("!")},
- {[]byte("!!"), []byte("tag:yaml.org,2002:")},
-}
-
-// Parse directives.
-func yaml_parser_process_directives(parser *yaml_parser_t,
- version_directive_ref **yaml_version_directive_t,
- tag_directives_ref *[]yaml_tag_directive_t) bool {
-
- var version_directive *yaml_version_directive_t
- var tag_directives []yaml_tag_directive_t
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
- if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
- if version_directive != nil {
- yaml_parser_set_parser_error(parser,
- "found duplicate %YAML directive", token.start_mark)
- return false
- }
- if token.major != 1 || token.minor != 1 {
- yaml_parser_set_parser_error(parser,
- "found incompatible YAML document", token.start_mark)
- return false
- }
- version_directive = &yaml_version_directive_t{
- major: token.major,
- minor: token.minor,
- }
- } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
- value := yaml_tag_directive_t{
- handle: token.value,
- prefix: token.prefix,
- }
- if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
- return false
- }
- tag_directives = append(tag_directives, value)
- }
-
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
-
- for i := range default_tag_directives {
- if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
- return false
- }
- }
-
- if version_directive_ref != nil {
- *version_directive_ref = version_directive
- }
- if tag_directives_ref != nil {
- *tag_directives_ref = tag_directives
- }
- return true
-}
-
-// Append a tag directive to the directives stack.
-func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
- for i := range parser.tag_directives {
- if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
- if allow_duplicates {
- return true
- }
- return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
- }
- }
-
- // [Go] I suspect the copy is unnecessary. This was likely done
- // because there was no way to track ownership of the data.
- value_copy := yaml_tag_directive_t{
- handle: make([]byte, len(value.handle)),
- prefix: make([]byte, len(value.prefix)),
- }
- copy(value_copy.handle, value.handle)
- copy(value_copy.prefix, value.prefix)
- parser.tag_directives = append(parser.tag_directives, value_copy)
- return true
-}
diff --git a/cli/internal/yaml/readerc.go b/cli/internal/yaml/readerc.go
deleted file mode 100644
index 56af245..0000000
--- a/cli/internal/yaml/readerc.go
+++ /dev/null
@@ -1,434 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
- "io"
-)
-
-// Set the reader error and return 0.
-func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
- parser.error = yaml_READER_ERROR
- parser.problem = problem
- parser.problem_offset = offset
- parser.problem_value = value
- return false
-}
-
-// Byte order marks.
-const (
- bom_UTF8 = "\xef\xbb\xbf"
- bom_UTF16LE = "\xff\xfe"
- bom_UTF16BE = "\xfe\xff"
-)
-
-// Determine the input stream encoding by checking the BOM symbol. If no BOM is
-// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
-func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
- // Ensure that we had enough bytes in the raw buffer.
- for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
- if !yaml_parser_update_raw_buffer(parser) {
- return false
- }
- }
-
- // Determine the encoding.
- buf := parser.raw_buffer
- pos := parser.raw_buffer_pos
- avail := len(buf) - pos
- if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
- parser.encoding = yaml_UTF16LE_ENCODING
- parser.raw_buffer_pos += 2
- parser.offset += 2
- } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
- parser.encoding = yaml_UTF16BE_ENCODING
- parser.raw_buffer_pos += 2
- parser.offset += 2
- } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
- parser.encoding = yaml_UTF8_ENCODING
- parser.raw_buffer_pos += 3
- parser.offset += 3
- } else {
- parser.encoding = yaml_UTF8_ENCODING
- }
- return true
-}
-
-// Update the raw buffer.
-func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
- size_read := 0
-
- // Return if the raw buffer is full.
- if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
- return true
- }
-
- // Return on EOF.
- if parser.eof {
- return true
- }
-
- // Move the remaining bytes in the raw buffer to the beginning.
- if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
- copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
- }
- parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
- parser.raw_buffer_pos = 0
-
- // Call the read handler to fill the buffer.
- size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
- parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
- if err == io.EOF {
- parser.eof = true
- } else if err != nil {
- return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
- }
- return true
-}
-
-// Ensure that the buffer contains at least `length` characters.
-// Return true on success, false on failure.
-//
-// The length is supposed to be significantly less that the buffer size.
-func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
- if parser.read_handler == nil {
- panic("read handler must be set")
- }
-
- // [Go] This function was changed to guarantee the requested length size at EOF.
- // The fact we need to do this is pretty awful, but the description above implies
- // for that to be the case, and there are tests
-
- // If the EOF flag is set and the raw buffer is empty, do nothing.
- if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
- // [Go] ACTUALLY! Read the documentation of this function above.
- // This is just broken. To return true, we need to have the
- // given length in the buffer. Not doing that means every single
- // check that calls this function to make sure the buffer has a
- // given length is Go) panicking; or C) accessing invalid memory.
- //return true
- }
-
- // Return if the buffer contains enough characters.
- if parser.unread >= length {
- return true
- }
-
- // Determine the input encoding if it is not known yet.
- if parser.encoding == yaml_ANY_ENCODING {
- if !yaml_parser_determine_encoding(parser) {
- return false
- }
- }
-
- // Move the unread characters to the beginning of the buffer.
- buffer_len := len(parser.buffer)
- if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
- copy(parser.buffer, parser.buffer[parser.buffer_pos:])
- buffer_len -= parser.buffer_pos
- parser.buffer_pos = 0
- } else if parser.buffer_pos == buffer_len {
- buffer_len = 0
- parser.buffer_pos = 0
- }
-
- // Open the whole buffer for writing, and cut it before returning.
- parser.buffer = parser.buffer[:cap(parser.buffer)]
-
- // Fill the buffer until it has enough characters.
- first := true
- for parser.unread < length {
-
- // Fill the raw buffer if necessary.
- if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
- if !yaml_parser_update_raw_buffer(parser) {
- parser.buffer = parser.buffer[:buffer_len]
- return false
- }
- }
- first = false
-
- // Decode the raw buffer.
- inner:
- for parser.raw_buffer_pos != len(parser.raw_buffer) {
- var value rune
- var width int
-
- raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
-
- // Decode the next character.
- switch parser.encoding {
- case yaml_UTF8_ENCODING:
- // Decode a UTF-8 character. Check RFC 3629
- // (http://www.ietf.org/rfc/rfc3629.txt) for more details.
- //
- // The following table (taken from the RFC) is used for
- // decoding.
- //
- // Char. number range | UTF-8 octet sequence
- // (hexadecimal) | (binary)
- // --------------------+------------------------------------
- // 0000 0000-0000 007F | 0xxxxxxx
- // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
- // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
- // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- //
- // Additionally, the characters in the range 0xD800-0xDFFF
- // are prohibited as they are reserved for use with UTF-16
- // surrogate pairs.
-
- // Determine the length of the UTF-8 sequence.
- octet := parser.raw_buffer[parser.raw_buffer_pos]
- switch {
- case octet&0x80 == 0x00:
- width = 1
- case octet&0xE0 == 0xC0:
- width = 2
- case octet&0xF0 == 0xE0:
- width = 3
- case octet&0xF8 == 0xF0:
- width = 4
- default:
- // The leading octet is invalid.
- return yaml_parser_set_reader_error(parser,
- "invalid leading UTF-8 octet",
- parser.offset, int(octet))
- }
-
- // Check if the raw buffer contains an incomplete character.
- if width > raw_unread {
- if parser.eof {
- return yaml_parser_set_reader_error(parser,
- "incomplete UTF-8 octet sequence",
- parser.offset, -1)
- }
- break inner
- }
-
- // Decode the leading octet.
- switch {
- case octet&0x80 == 0x00:
- value = rune(octet & 0x7F)
- case octet&0xE0 == 0xC0:
- value = rune(octet & 0x1F)
- case octet&0xF0 == 0xE0:
- value = rune(octet & 0x0F)
- case octet&0xF8 == 0xF0:
- value = rune(octet & 0x07)
- default:
- value = 0
- }
-
- // Check and decode the trailing octets.
- for k := 1; k < width; k++ {
- octet = parser.raw_buffer[parser.raw_buffer_pos+k]
-
- // Check if the octet is valid.
- if (octet & 0xC0) != 0x80 {
- return yaml_parser_set_reader_error(parser,
- "invalid trailing UTF-8 octet",
- parser.offset+k, int(octet))
- }
-
- // Decode the octet.
- value = (value << 6) + rune(octet&0x3F)
- }
-
- // Check the length of the sequence against the value.
- switch {
- case width == 1:
- case width == 2 && value >= 0x80:
- case width == 3 && value >= 0x800:
- case width == 4 && value >= 0x10000:
- default:
- return yaml_parser_set_reader_error(parser,
- "invalid length of a UTF-8 sequence",
- parser.offset, -1)
- }
-
- // Check the range of the value.
- if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
- return yaml_parser_set_reader_error(parser,
- "invalid Unicode character",
- parser.offset, int(value))
- }
-
- case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
- var low, high int
- if parser.encoding == yaml_UTF16LE_ENCODING {
- low, high = 0, 1
- } else {
- low, high = 1, 0
- }
-
- // The UTF-16 encoding is not as simple as one might
- // naively think. Check RFC 2781
- // (http://www.ietf.org/rfc/rfc2781.txt).
- //
- // Normally, two subsequent bytes describe a Unicode
- // character. However a special technique (called a
- // surrogate pair) is used for specifying character
- // values larger than 0xFFFF.
- //
- // A surrogate pair consists of two pseudo-characters:
- // high surrogate area (0xD800-0xDBFF)
- // low surrogate area (0xDC00-0xDFFF)
- //
- // The following formulas are used for decoding
- // and encoding characters using surrogate pairs:
- //
- // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
- // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
- // W1 = 110110yyyyyyyyyy
- // W2 = 110111xxxxxxxxxx
- //
- // where U is the character value, W1 is the high surrogate
- // area, W2 is the low surrogate area.
-
- // Check for incomplete UTF-16 character.
- if raw_unread < 2 {
- if parser.eof {
- return yaml_parser_set_reader_error(parser,
- "incomplete UTF-16 character",
- parser.offset, -1)
- }
- break inner
- }
-
- // Get the character.
- value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
- (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
-
- // Check for unexpected low surrogate area.
- if value&0xFC00 == 0xDC00 {
- return yaml_parser_set_reader_error(parser,
- "unexpected low surrogate area",
- parser.offset, int(value))
- }
-
- // Check for a high surrogate area.
- if value&0xFC00 == 0xD800 {
- width = 4
-
- // Check for incomplete surrogate pair.
- if raw_unread < 4 {
- if parser.eof {
- return yaml_parser_set_reader_error(parser,
- "incomplete UTF-16 surrogate pair",
- parser.offset, -1)
- }
- break inner
- }
-
- // Get the next character.
- value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
- (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
-
- // Check for a low surrogate area.
- if value2&0xFC00 != 0xDC00 {
- return yaml_parser_set_reader_error(parser,
- "expected low surrogate area",
- parser.offset+2, int(value2))
- }
-
- // Generate the value of the surrogate pair.
- value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
- } else {
- width = 2
- }
-
- default:
- panic("impossible")
- }
-
- // Check if the character is in the allowed range:
- // #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
- // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
- // | [#x10000-#x10FFFF] (32 bit)
- switch {
- case value == 0x09:
- case value == 0x0A:
- case value == 0x0D:
- case value >= 0x20 && value <= 0x7E:
- case value == 0x85:
- case value >= 0xA0 && value <= 0xD7FF:
- case value >= 0xE000 && value <= 0xFFFD:
- case value >= 0x10000 && value <= 0x10FFFF:
- default:
- return yaml_parser_set_reader_error(parser,
- "control characters are not allowed",
- parser.offset, int(value))
- }
-
- // Move the raw pointers.
- parser.raw_buffer_pos += width
- parser.offset += width
-
- // Finally put the character into the buffer.
- if value <= 0x7F {
- // 0000 0000-0000 007F . 0xxxxxxx
- parser.buffer[buffer_len+0] = byte(value)
- buffer_len += 1
- } else if value <= 0x7FF {
- // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
- parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
- parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
- buffer_len += 2
- } else if value <= 0xFFFF {
- // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
- parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
- parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
- parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
- buffer_len += 3
- } else {
- // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
- parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
- parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
- parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
- buffer_len += 4
- }
-
- parser.unread++
- }
-
- // On EOF, put NUL into the buffer and return.
- if parser.eof {
- parser.buffer[buffer_len] = 0
- buffer_len++
- parser.unread++
- break
- }
- }
- // [Go] Read the documentation of this function above. To return true,
- // we need to have the given length in the buffer. Not doing that means
- // every single check that calls this function to make sure the buffer
- // has a given length is Go) panicking; or C) accessing invalid memory.
- // This happens here due to the EOF above breaking early.
- for buffer_len < length {
- parser.buffer[buffer_len] = 0
- buffer_len++
- }
- parser.buffer = parser.buffer[:buffer_len]
- return true
-}
diff --git a/cli/internal/yaml/resolve.go b/cli/internal/yaml/resolve.go
deleted file mode 100644
index 64ae888..0000000
--- a/cli/internal/yaml/resolve.go
+++ /dev/null
@@ -1,326 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
- "encoding/base64"
- "math"
- "regexp"
- "strconv"
- "strings"
- "time"
-)
-
-type resolveMapItem struct {
- value interface{}
- tag string
-}
-
-var resolveTable = make([]byte, 256)
-var resolveMap = make(map[string]resolveMapItem)
-
-func init() {
- t := resolveTable
- t[int('+')] = 'S' // Sign
- t[int('-')] = 'S'
- for _, c := range "0123456789" {
- t[int(c)] = 'D' // Digit
- }
- for _, c := range "yYnNtTfFoO~" {
- t[int(c)] = 'M' // In map
- }
- t[int('.')] = '.' // Float (potentially in map)
-
- var resolveMapList = []struct {
- v interface{}
- tag string
- l []string
- }{
- {true, boolTag, []string{"true", "True", "TRUE"}},
- {false, boolTag, []string{"false", "False", "FALSE"}},
- {nil, nullTag, []string{"", "~", "null", "Null", "NULL"}},
- {math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}},
- {math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}},
- {math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}},
- {math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}},
- {"<<", mergeTag, []string{"<<"}},
- }
-
- m := resolveMap
- for _, item := range resolveMapList {
- for _, s := range item.l {
- m[s] = resolveMapItem{item.v, item.tag}
- }
- }
-}
-
-const (
- nullTag = "!!null"
- boolTag = "!!bool"
- strTag = "!!str"
- intTag = "!!int"
- floatTag = "!!float"
- timestampTag = "!!timestamp"
- seqTag = "!!seq"
- mapTag = "!!map"
- binaryTag = "!!binary"
- mergeTag = "!!merge"
-)
-
-var longTags = make(map[string]string)
-var shortTags = make(map[string]string)
-
-func init() {
- for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} {
- ltag := longTag(stag)
- longTags[stag] = ltag
- shortTags[ltag] = stag
- }
-}
-
-const longTagPrefix = "tag:yaml.org,2002:"
-
-func shortTag(tag string) string {
- if strings.HasPrefix(tag, longTagPrefix) {
- if stag, ok := shortTags[tag]; ok {
- return stag
- }
- return "!!" + tag[len(longTagPrefix):]
- }
- return tag
-}
-
-func longTag(tag string) string {
- if strings.HasPrefix(tag, "!!") {
- if ltag, ok := longTags[tag]; ok {
- return ltag
- }
- return longTagPrefix + tag[2:]
- }
- return tag
-}
-
-func resolvableTag(tag string) bool {
- switch tag {
- case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:
- return true
- }
- return false
-}
-
-var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
-
-func resolve(tag string, in string) (rtag string, out interface{}) {
- tag = shortTag(tag)
- if !resolvableTag(tag) {
- return tag, in
- }
-
- defer func() {
- switch tag {
- case "", rtag, strTag, binaryTag:
- return
- case floatTag:
- if rtag == intTag {
- switch v := out.(type) {
- case int64:
- rtag = floatTag
- out = float64(v)
- return
- case int:
- rtag = floatTag
- out = float64(v)
- return
- }
- }
- }
- failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
- }()
-
- // Any data is accepted as a !!str or !!binary.
- // Otherwise, the prefix is enough of a hint about what it might be.
- hint := byte('N')
- if in != "" {
- hint = resolveTable[in[0]]
- }
- if hint != 0 && tag != strTag && tag != binaryTag {
- // Handle things we can lookup in a map.
- if item, ok := resolveMap[in]; ok {
- return item.tag, item.value
- }
-
- // Base 60 floats are a bad idea, were dropped in YAML 1.2, and
- // are purposefully unsupported here. They're still quoted on
- // the way out for compatibility with other parser, though.
-
- switch hint {
- case 'M':
- // We've already checked the map above.
-
- case '.':
- // Not in the map, so maybe a normal float.
- floatv, err := strconv.ParseFloat(in, 64)
- if err == nil {
- return floatTag, floatv
- }
-
- case 'D', 'S':
- // Int, float, or timestamp.
- // Only try values as a timestamp if the value is unquoted or there's an explicit
- // !!timestamp tag.
- if tag == "" || tag == timestampTag {
- t, ok := parseTimestamp(in)
- if ok {
- return timestampTag, t
- }
- }
-
- plain := strings.Replace(in, "_", "", -1)
- intv, err := strconv.ParseInt(plain, 0, 64)
- if err == nil {
- if intv == int64(int(intv)) {
- return intTag, int(intv)
- } else {
- return intTag, intv
- }
- }
- uintv, err := strconv.ParseUint(plain, 0, 64)
- if err == nil {
- return intTag, uintv
- }
- if yamlStyleFloat.MatchString(plain) {
- floatv, err := strconv.ParseFloat(plain, 64)
- if err == nil {
- return floatTag, floatv
- }
- }
- if strings.HasPrefix(plain, "0b") {
- intv, err := strconv.ParseInt(plain[2:], 2, 64)
- if err == nil {
- if intv == int64(int(intv)) {
- return intTag, int(intv)
- } else {
- return intTag, intv
- }
- }
- uintv, err := strconv.ParseUint(plain[2:], 2, 64)
- if err == nil {
- return intTag, uintv
- }
- } else if strings.HasPrefix(plain, "-0b") {
- intv, err := strconv.ParseInt("-"+plain[3:], 2, 64)
- if err == nil {
- if true || intv == int64(int(intv)) {
- return intTag, int(intv)
- } else {
- return intTag, intv
- }
- }
- }
- // Octals as introduced in version 1.2 of the spec.
- // Octals from the 1.1 spec, spelled as 0777, are still
- // decoded by default in v3 as well for compatibility.
- // May be dropped in v4 depending on how usage evolves.
- if strings.HasPrefix(plain, "0o") {
- intv, err := strconv.ParseInt(plain[2:], 8, 64)
- if err == nil {
- if intv == int64(int(intv)) {
- return intTag, int(intv)
- } else {
- return intTag, intv
- }
- }
- uintv, err := strconv.ParseUint(plain[2:], 8, 64)
- if err == nil {
- return intTag, uintv
- }
- } else if strings.HasPrefix(plain, "-0o") {
- intv, err := strconv.ParseInt("-"+plain[3:], 8, 64)
- if err == nil {
- if true || intv == int64(int(intv)) {
- return intTag, int(intv)
- } else {
- return intTag, intv
- }
- }
- }
- default:
- panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
- }
- }
- return strTag, in
-}
-
-// encodeBase64 encodes s as base64 that is broken up into multiple lines
-// as appropriate for the resulting length.
-func encodeBase64(s string) string {
- const lineLen = 70
- encLen := base64.StdEncoding.EncodedLen(len(s))
- lines := encLen/lineLen + 1
- buf := make([]byte, encLen*2+lines)
- in := buf[0:encLen]
- out := buf[encLen:]
- base64.StdEncoding.Encode(in, []byte(s))
- k := 0
- for i := 0; i < len(in); i += lineLen {
- j := i + lineLen
- if j > len(in) {
- j = len(in)
- }
- k += copy(out[k:], in[i:j])
- if lines > 1 {
- out[k] = '\n'
- k++
- }
- }
- return string(out[:k])
-}
-
-// This is a subset of the formats allowed by the regular expression
-// defined at http://yaml.org/type/timestamp.html.
-var allowedTimestampFormats = []string{
- "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
- "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
- "2006-1-2 15:4:5.999999999", // space separated with no time zone
- "2006-1-2", // date only
- // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
- // from the set of examples.
-}
-
-// parseTimestamp parses s as a timestamp string and
-// returns the timestamp and reports whether it succeeded.
-// Timestamp formats are defined at http://yaml.org/type/timestamp.html
-func parseTimestamp(s string) (time.Time, bool) {
- // TODO write code to check all the formats supported by
- // http://yaml.org/type/timestamp.html instead of using time.Parse.
-
- // Quick check: all date formats start with YYYY-.
- i := 0
- for ; i < len(s); i++ {
- if c := s[i]; c < '0' || c > '9' {
- break
- }
- }
- if i != 4 || i == len(s) || s[i] != '-' {
- return time.Time{}, false
- }
- for _, format := range allowedTimestampFormats {
- if t, err := time.Parse(format, s); err == nil {
- return t, true
- }
- }
- return time.Time{}, false
-}
diff --git a/cli/internal/yaml/scannerc.go b/cli/internal/yaml/scannerc.go
deleted file mode 100644
index 87e46ef..0000000
--- a/cli/internal/yaml/scannerc.go
+++ /dev/null
@@ -1,3040 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
- "bytes"
- "fmt"
-)
-
-// Introduction
-// ************
-//
-// The following notes assume that you are familiar with the YAML specification
-// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in
-// some cases we are less restrictive that it requires.
-//
-// The process of transforming a YAML stream into a sequence of events is
-// divided on two steps: Scanning and Parsing.
-//
-// The Scanner transforms the input stream into a sequence of tokens, while the
-// parser transform the sequence of tokens produced by the Scanner into a
-// sequence of parsing events.
-//
-// The Scanner is rather clever and complicated. The Parser, on the contrary,
-// is a straightforward implementation of a recursive-descendant parser (or,
-// LL(1) parser, as it is usually called).
-//
-// Actually there are two issues of Scanning that might be called "clever", the
-// rest is quite straightforward. The issues are "block collection start" and
-// "simple keys". Both issues are explained below in details.
-//
-// Here the Scanning step is explained and implemented. We start with the list
-// of all the tokens produced by the Scanner together with short descriptions.
-//
-// Now, tokens:
-//
-// STREAM-START(encoding) # The stream start.
-// STREAM-END # The stream end.
-// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
-// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
-// DOCUMENT-START # '---'
-// DOCUMENT-END # '...'
-// BLOCK-SEQUENCE-START # Indentation increase denoting a block
-// BLOCK-MAPPING-START # sequence or a block mapping.
-// BLOCK-END # Indentation decrease.
-// FLOW-SEQUENCE-START # '['
-// FLOW-SEQUENCE-END # ']'
-// BLOCK-SEQUENCE-START # '{'
-// BLOCK-SEQUENCE-END # '}'
-// BLOCK-ENTRY # '-'
-// FLOW-ENTRY # ','
-// KEY # '?' or nothing (simple keys).
-// VALUE # ':'
-// ALIAS(anchor) # '*anchor'
-// ANCHOR(anchor) # '&anchor'
-// TAG(handle,suffix) # '!handle!suffix'
-// SCALAR(value,style) # A scalar.
-//
-// The following two tokens are "virtual" tokens denoting the beginning and the
-// end of the stream:
-//
-// STREAM-START(encoding)
-// STREAM-END
-//
-// We pass the information about the input stream encoding with the
-// STREAM-START token.
-//
-// The next two tokens are responsible for tags:
-//
-// VERSION-DIRECTIVE(major,minor)
-// TAG-DIRECTIVE(handle,prefix)
-//
-// Example:
-//
-// %YAML 1.1
-// %TAG ! !foo
-// %TAG !yaml! tag:yaml.org,2002:
-// ---
-//
-// The correspoding sequence of tokens:
-//
-// STREAM-START(utf-8)
-// VERSION-DIRECTIVE(1,1)
-// TAG-DIRECTIVE("!","!foo")
-// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
-// DOCUMENT-START
-// STREAM-END
-//
-// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
-// line.
-//
-// The document start and end indicators are represented by:
-//
-// DOCUMENT-START
-// DOCUMENT-END
-//
-// Note that if a YAML stream contains an implicit document (without '---'
-// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
-// produced.
-//
-// In the following examples, we present whole documents together with the
-// produced tokens.
-//
-// 1. An implicit document:
-//
-// 'a scalar'
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// SCALAR("a scalar",single-quoted)
-// STREAM-END
-//
-// 2. An explicit document:
-//
-// ---
-// 'a scalar'
-// ...
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// DOCUMENT-START
-// SCALAR("a scalar",single-quoted)
-// DOCUMENT-END
-// STREAM-END
-//
-// 3. Several documents in a stream:
-//
-// 'a scalar'
-// ---
-// 'another scalar'
-// ---
-// 'yet another scalar'
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// SCALAR("a scalar",single-quoted)
-// DOCUMENT-START
-// SCALAR("another scalar",single-quoted)
-// DOCUMENT-START
-// SCALAR("yet another scalar",single-quoted)
-// STREAM-END
-//
-// We have already introduced the SCALAR token above. The following tokens are
-// used to describe aliases, anchors, tag, and scalars:
-//
-// ALIAS(anchor)
-// ANCHOR(anchor)
-// TAG(handle,suffix)
-// SCALAR(value,style)
-//
-// The following series of examples illustrate the usage of these tokens:
-//
-// 1. A recursive sequence:
-//
-// &A [ *A ]
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// ANCHOR("A")
-// FLOW-SEQUENCE-START
-// ALIAS("A")
-// FLOW-SEQUENCE-END
-// STREAM-END
-//
-// 2. A tagged scalar:
-//
-// !!float "3.14" # A good approximation.
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// TAG("!!","float")
-// SCALAR("3.14",double-quoted)
-// STREAM-END
-//
-// 3. Various scalar styles:
-//
-// --- # Implicit empty plain scalars do not produce tokens.
-// --- a plain scalar
-// --- 'a single-quoted scalar'
-// --- "a double-quoted scalar"
-// --- |-
-// a literal scalar
-// --- >-
-// a folded
-// scalar
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// DOCUMENT-START
-// DOCUMENT-START
-// SCALAR("a plain scalar",plain)
-// DOCUMENT-START
-// SCALAR("a single-quoted scalar",single-quoted)
-// DOCUMENT-START
-// SCALAR("a double-quoted scalar",double-quoted)
-// DOCUMENT-START
-// SCALAR("a literal scalar",literal)
-// DOCUMENT-START
-// SCALAR("a folded scalar",folded)
-// STREAM-END
-//
-// Now it's time to review collection-related tokens. We will start with
-// flow collections:
-//
-// FLOW-SEQUENCE-START
-// FLOW-SEQUENCE-END
-// FLOW-MAPPING-START
-// FLOW-MAPPING-END
-// FLOW-ENTRY
-// KEY
-// VALUE
-//
-// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
-// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
-// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the
-// indicators '?' and ':', which are used for denoting mapping keys and values,
-// are represented by the KEY and VALUE tokens.
-//
-// The following examples show flow collections:
-//
-// 1. A flow sequence:
-//
-// [item 1, item 2, item 3]
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// FLOW-SEQUENCE-START
-// SCALAR("item 1",plain)
-// FLOW-ENTRY
-// SCALAR("item 2",plain)
-// FLOW-ENTRY
-// SCALAR("item 3",plain)
-// FLOW-SEQUENCE-END
-// STREAM-END
-//
-// 2. A flow mapping:
-//
-// {
-// a simple key: a value, # Note that the KEY token is produced.
-// ? a complex key: another value,
-// }
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// FLOW-MAPPING-START
-// KEY
-// SCALAR("a simple key",plain)
-// VALUE
-// SCALAR("a value",plain)
-// FLOW-ENTRY
-// KEY
-// SCALAR("a complex key",plain)
-// VALUE
-// SCALAR("another value",plain)
-// FLOW-ENTRY
-// FLOW-MAPPING-END
-// STREAM-END
-//
-// A simple key is a key which is not denoted by the '?' indicator. Note that
-// the Scanner still produce the KEY token whenever it encounters a simple key.
-//
-// For scanning block collections, the following tokens are used (note that we
-// repeat KEY and VALUE here):
-//
-// BLOCK-SEQUENCE-START
-// BLOCK-MAPPING-START
-// BLOCK-END
-// BLOCK-ENTRY
-// KEY
-// VALUE
-//
-// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
-// increase that precedes a block collection (cf. the INDENT token in Python).
-// The token BLOCK-END denote indentation decrease that ends a block collection
-// (cf. the DEDENT token in Python). However YAML has some syntax pecularities
-// that makes detections of these tokens more complex.
-//
-// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
-// '-', '?', and ':' correspondingly.
-//
-// The following examples show how the tokens BLOCK-SEQUENCE-START,
-// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
-//
-// 1. Block sequences:
-//
-// - item 1
-// - item 2
-// -
-// - item 3.1
-// - item 3.2
-// -
-// key 1: value 1
-// key 2: value 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-ENTRY
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 3.1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 3.2",plain)
-// BLOCK-END
-// BLOCK-ENTRY
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// 2. Block mappings:
-//
-// a simple key: a value # The KEY token is produced here.
-// ? a complex key
-// : another value
-// a mapping:
-// key 1: value 1
-// key 2: value 2
-// a sequence:
-// - item 1
-// - item 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("a simple key",plain)
-// VALUE
-// SCALAR("a value",plain)
-// KEY
-// SCALAR("a complex key",plain)
-// VALUE
-// SCALAR("another value",plain)
-// KEY
-// SCALAR("a mapping",plain)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// KEY
-// SCALAR("a sequence",plain)
-// VALUE
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// YAML does not always require to start a new block collection from a new
-// line. If the current line contains only '-', '?', and ':' indicators, a new
-// block collection may start at the current line. The following examples
-// illustrate this case:
-//
-// 1. Collections in a sequence:
-//
-// - - item 1
-// - item 2
-// - key 1: value 1
-// key 2: value 2
-// - ? complex key
-// : complex value
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-// BLOCK-ENTRY
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// BLOCK-ENTRY
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("complex key")
-// VALUE
-// SCALAR("complex value")
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// 2. Collections in a mapping:
-//
-// ? a sequence
-// : - item 1
-// - item 2
-// ? a mapping
-// : key 1: value 1
-// key 2: value 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("a sequence",plain)
-// VALUE
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-// KEY
-// SCALAR("a mapping",plain)
-// VALUE
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// YAML also permits non-indented sequences if they are included into a block
-// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:
-//
-// key:
-// - item 1 # BLOCK-SEQUENCE-START is NOT produced here.
-// - item 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key",plain)
-// VALUE
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-//
-
-// Ensure that the buffer contains the required number of characters.
-// Return true on success, false on failure (reader error or memory error).
-func cache(parser *yaml_parser_t, length int) bool {
- // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
- return parser.unread >= length || yaml_parser_update_buffer(parser, length)
-}
-
-// Advance the buffer pointer.
-func skip(parser *yaml_parser_t) {
- if !is_blank(parser.buffer, parser.buffer_pos) {
- parser.newlines = 0
- }
- parser.mark.index++
- parser.mark.column++
- parser.unread--
- parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
-}
-
-func skip_line(parser *yaml_parser_t) {
- if is_crlf(parser.buffer, parser.buffer_pos) {
- parser.mark.index += 2
- parser.mark.column = 0
- parser.mark.line++
- parser.unread -= 2
- parser.buffer_pos += 2
- parser.newlines++
- } else if is_break(parser.buffer, parser.buffer_pos) {
- parser.mark.index++
- parser.mark.column = 0
- parser.mark.line++
- parser.unread--
- parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
- parser.newlines++
- }
-}
-
-// Copy a character to a string buffer and advance pointers.
-func read(parser *yaml_parser_t, s []byte) []byte {
- if !is_blank(parser.buffer, parser.buffer_pos) {
- parser.newlines = 0
- }
- w := width(parser.buffer[parser.buffer_pos])
- if w == 0 {
- panic("invalid character sequence")
- }
- if len(s) == 0 {
- s = make([]byte, 0, 32)
- }
- if w == 1 && len(s)+w <= cap(s) {
- s = s[:len(s)+1]
- s[len(s)-1] = parser.buffer[parser.buffer_pos]
- parser.buffer_pos++
- } else {
- s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
- parser.buffer_pos += w
- }
- parser.mark.index++
- parser.mark.column++
- parser.unread--
- return s
-}
-
-// Copy a line break character to a string buffer and advance pointers.
-func read_line(parser *yaml_parser_t, s []byte) []byte {
- buf := parser.buffer
- pos := parser.buffer_pos
- switch {
- case buf[pos] == '\r' && buf[pos+1] == '\n':
- // CR LF . LF
- s = append(s, '\n')
- parser.buffer_pos += 2
- parser.mark.index++
- parser.unread--
- case buf[pos] == '\r' || buf[pos] == '\n':
- // CR|LF . LF
- s = append(s, '\n')
- parser.buffer_pos += 1
- case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
- // NEL . LF
- s = append(s, '\n')
- parser.buffer_pos += 2
- case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
- // LS|PS . LS|PS
- s = append(s, buf[parser.buffer_pos:pos+3]...)
- parser.buffer_pos += 3
- default:
- return s
- }
- parser.mark.index++
- parser.mark.column = 0
- parser.mark.line++
- parser.unread--
- parser.newlines++
- return s
-}
-
-// Get the next token.
-func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
- // Erase the token object.
- *token = yaml_token_t{} // [Go] Is this necessary?
-
- // No tokens after STREAM-END or error.
- if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
- return true
- }
-
- // Ensure that the tokens queue contains enough tokens.
- if !parser.token_available {
- if !yaml_parser_fetch_more_tokens(parser) {
- return false
- }
- }
-
- // Fetch the next token from the queue.
- *token = parser.tokens[parser.tokens_head]
- parser.tokens_head++
- parser.tokens_parsed++
- parser.token_available = false
-
- if token.typ == yaml_STREAM_END_TOKEN {
- parser.stream_end_produced = true
- }
- return true
-}
-
-// Set the scanner error and return false.
-func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
- parser.error = yaml_SCANNER_ERROR
- parser.context = context
- parser.context_mark = context_mark
- parser.problem = problem
- parser.problem_mark = parser.mark
- return false
-}
-
-func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
- context := "while parsing a tag"
- if directive {
- context = "while parsing a %TAG directive"
- }
- return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
-}
-
-func trace(args ...interface{}) func() {
- pargs := append([]interface{}{"+++"}, args...)
- fmt.Println(pargs...)
- pargs = append([]interface{}{"---"}, args...)
- return func() { fmt.Println(pargs...) }
-}
-
-// Ensure that the tokens queue contains at least one token which can be
-// returned to the Parser.
-func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
- // While we need more tokens to fetch, do it.
- for {
- // [Go] The comment parsing logic requires a lookahead of two tokens
- // so that foot comments may be parsed in time of associating them
- // with the tokens that are parsed before them, and also for line
- // comments to be transformed into head comments in some edge cases.
- if parser.tokens_head < len(parser.tokens)-2 {
- // If a potential simple key is at the head position, we need to fetch
- // the next token to disambiguate it.
- head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
- if !ok {
- break
- } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
- return false
- } else if !valid {
- break
- }
- }
- // Fetch the next token.
- if !yaml_parser_fetch_next_token(parser) {
- return false
- }
- }
-
- parser.token_available = true
- return true
-}
-
-// The dispatcher for token fetchers.
-func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) {
- // Ensure that the buffer is initialized.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // Check if we just started scanning. Fetch STREAM-START then.
- if !parser.stream_start_produced {
- return yaml_parser_fetch_stream_start(parser)
- }
-
- scan_mark := parser.mark
-
- // Eat whitespaces and comments until we reach the next token.
- if !yaml_parser_scan_to_next_token(parser) {
- return false
- }
-
- // [Go] While unrolling indents, transform the head comments of prior
- // indentation levels observed after scan_start into foot comments at
- // the respective indexes.
-
- // Check the indentation level against the current column.
- if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) {
- return false
- }
-
- // Ensure that the buffer contains at least 4 characters. 4 is the length
- // of the longest indicators ('--- ' and '... ').
- if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
- return false
- }
-
- // Is it the end of the stream?
- if is_z(parser.buffer, parser.buffer_pos) {
- return yaml_parser_fetch_stream_end(parser)
- }
-
- // Is it a directive?
- if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
- return yaml_parser_fetch_directive(parser)
- }
-
- buf := parser.buffer
- pos := parser.buffer_pos
-
- // Is it the document start indicator?
- if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
- return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
- }
-
- // Is it the document end indicator?
- if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
- return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
- }
-
- comment_mark := parser.mark
- if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') {
- // Associate any following comments with the prior token.
- comment_mark = parser.tokens[len(parser.tokens)-1].start_mark
- }
- defer func() {
- if !ok {
- return
- }
- if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN {
- // Sequence indicators alone have no line comments. It becomes
- // a head comment for whatever follows.
- return
- }
- if !yaml_parser_scan_line_comment(parser, comment_mark) {
- ok = false
- return
- }
- }()
-
- // Is it the flow sequence start indicator?
- if buf[pos] == '[' {
- return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
- }
-
- // Is it the flow mapping start indicator?
- if parser.buffer[parser.buffer_pos] == '{' {
- return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
- }
-
- // Is it the flow sequence end indicator?
- if parser.buffer[parser.buffer_pos] == ']' {
- return yaml_parser_fetch_flow_collection_end(parser,
- yaml_FLOW_SEQUENCE_END_TOKEN)
- }
-
- // Is it the flow mapping end indicator?
- if parser.buffer[parser.buffer_pos] == '}' {
- return yaml_parser_fetch_flow_collection_end(parser,
- yaml_FLOW_MAPPING_END_TOKEN)
- }
-
- // Is it the flow entry indicator?
- if parser.buffer[parser.buffer_pos] == ',' {
- return yaml_parser_fetch_flow_entry(parser)
- }
-
- // Is it the block entry indicator?
- if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
- return yaml_parser_fetch_block_entry(parser)
- }
-
- // Is it the key indicator?
- if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
- return yaml_parser_fetch_key(parser)
- }
-
- // Is it the value indicator?
- if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
- return yaml_parser_fetch_value(parser)
- }
-
- // Is it an alias?
- if parser.buffer[parser.buffer_pos] == '*' {
- return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
- }
-
- // Is it an anchor?
- if parser.buffer[parser.buffer_pos] == '&' {
- return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
- }
-
- // Is it a tag?
- if parser.buffer[parser.buffer_pos] == '!' {
- return yaml_parser_fetch_tag(parser)
- }
-
- // Is it a literal scalar?
- if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
- return yaml_parser_fetch_block_scalar(parser, true)
- }
-
- // Is it a folded scalar?
- if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
- return yaml_parser_fetch_block_scalar(parser, false)
- }
-
- // Is it a single-quoted scalar?
- if parser.buffer[parser.buffer_pos] == '\'' {
- return yaml_parser_fetch_flow_scalar(parser, true)
- }
-
- // Is it a double-quoted scalar?
- if parser.buffer[parser.buffer_pos] == '"' {
- return yaml_parser_fetch_flow_scalar(parser, false)
- }
-
- // Is it a plain scalar?
- //
- // A plain scalar may start with any non-blank characters except
- //
- // '-', '?', ':', ',', '[', ']', '{', '}',
- // '#', '&', '*', '!', '|', '>', '\'', '\"',
- // '%', '@', '`'.
- //
- // In the block context (and, for the '-' indicator, in the flow context
- // too), it may also start with the characters
- //
- // '-', '?', ':'
- //
- // if it is followed by a non-space character.
- //
- // The last rule is more restrictive than the specification requires.
- // [Go] TODO Make this logic more reasonable.
- //switch parser.buffer[parser.buffer_pos] {
- //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
- //}
- if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
- parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
- parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
- parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
- parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
- parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
- parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
- parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
- parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
- parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
- (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
- (parser.flow_level == 0 &&
- (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
- !is_blankz(parser.buffer, parser.buffer_pos+1)) {
- return yaml_parser_fetch_plain_scalar(parser)
- }
-
- // If we don't determine the token type so far, it is an error.
- return yaml_parser_set_scanner_error(parser,
- "while scanning for the next token", parser.mark,
- "found character that cannot start any token")
-}
-
-func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
- if !simple_key.possible {
- return false, true
- }
-
- // The 1.2 specification says:
- //
- // "If the ? indicator is omitted, parsing needs to see past the
- // implicit key to recognize it as such. To limit the amount of
- // lookahead required, the “:” indicator must appear at most 1024
- // Unicode characters beyond the start of the key. In addition, the key
- // is restricted to a single line."
- //
- if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
- // Check if the potential simple key to be removed is required.
- if simple_key.required {
- return false, yaml_parser_set_scanner_error(parser,
- "while scanning a simple key", simple_key.mark,
- "could not find expected ':'")
- }
- simple_key.possible = false
- return false, true
- }
- return true, true
-}
-
-// Check if a simple key may start at the current position and add it if
-// needed.
-func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
- // A simple key is required at the current position if the scanner is in
- // the block context and the current column coincides with the indentation
- // level.
-
- required := parser.flow_level == 0 && parser.indent == parser.mark.column
-
- //
- // If the current position may start a simple key, save it.
- //
- if parser.simple_key_allowed {
- simple_key := yaml_simple_key_t{
- possible: true,
- required: required,
- token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
- mark: parser.mark,
- }
-
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
- parser.simple_keys[len(parser.simple_keys)-1] = simple_key
- parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
- }
- return true
-}
-
-// Remove a potential simple key at the current flow level.
-func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
- i := len(parser.simple_keys) - 1
- if parser.simple_keys[i].possible {
- // If the key is required, it is an error.
- if parser.simple_keys[i].required {
- return yaml_parser_set_scanner_error(parser,
- "while scanning a simple key", parser.simple_keys[i].mark,
- "could not find expected ':'")
- }
- // Remove the key from the stack.
- parser.simple_keys[i].possible = false
- delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
- }
- return true
-}
-
-// max_flow_level limits the flow_level
-const max_flow_level = 10000
-
-// Increase the flow level and resize the simple key list if needed.
-func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
- // Reset the simple key on the next level.
- parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
- possible: false,
- required: false,
- token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
- mark: parser.mark,
- })
-
- // Increase the flow level.
- parser.flow_level++
- if parser.flow_level > max_flow_level {
- return yaml_parser_set_scanner_error(parser,
- "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
- fmt.Sprintf("exceeded max depth of %d", max_flow_level))
- }
- return true
-}
-
-// Decrease the flow level.
-func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
- if parser.flow_level > 0 {
- parser.flow_level--
- last := len(parser.simple_keys) - 1
- delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
- parser.simple_keys = parser.simple_keys[:last]
- }
- return true
-}
-
-// max_indents limits the indents stack size
-const max_indents = 10000
-
-// Push the current indentation level to the stack and set the new level
-// the current column is greater than the indentation level. In this case,
-// append or insert the specified token into the token queue.
-func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
- // In the flow context, do nothing.
- if parser.flow_level > 0 {
- return true
- }
-
- if parser.indent < column {
- // Push the current indentation level to the stack and set the new
- // indentation level.
- parser.indents = append(parser.indents, parser.indent)
- parser.indent = column
- if len(parser.indents) > max_indents {
- return yaml_parser_set_scanner_error(parser,
- "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
- fmt.Sprintf("exceeded max depth of %d", max_indents))
- }
-
- // Create a token and insert it into the queue.
- token := yaml_token_t{
- typ: typ,
- start_mark: mark,
- end_mark: mark,
- }
- if number > -1 {
- number -= parser.tokens_parsed
- }
- yaml_insert_token(parser, number, &token)
- }
- return true
-}
-
-// Pop indentation levels from the indents stack until the current level
-// becomes less or equal to the column. For each indentation level, append
-// the BLOCK-END token.
-func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool {
- // In the flow context, do nothing.
- if parser.flow_level > 0 {
- return true
- }
-
- block_mark := scan_mark
- block_mark.index--
-
- // Loop through the indentation levels in the stack.
- for parser.indent > column {
-
- // [Go] Reposition the end token before potential following
- // foot comments of parent blocks. For that, search
- // backwards for recent comments that were at the same
- // indent as the block that is ending now.
- stop_index := block_mark.index
- for i := len(parser.comments) - 1; i >= 0; i-- {
- comment := &parser.comments[i]
-
- if comment.end_mark.index < stop_index {
- // Don't go back beyond the start of the comment/whitespace scan, unless column < 0.
- // If requested indent column is < 0, then the document is over and everything else
- // is a foot anyway.
- break
- }
- if comment.start_mark.column == parser.indent+1 {
- // This is a good match. But maybe there's a former comment
- // at that same indent level, so keep searching.
- block_mark = comment.start_mark
- }
-
- // While the end of the former comment matches with
- // the start of the following one, we know there's
- // nothing in between and scanning is still safe.
- stop_index = comment.scan_mark.index
- }
-
- // Create a token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_BLOCK_END_TOKEN,
- start_mark: block_mark,
- end_mark: block_mark,
- }
- yaml_insert_token(parser, -1, &token)
-
- // Pop the indentation level.
- parser.indent = parser.indents[len(parser.indents)-1]
- parser.indents = parser.indents[:len(parser.indents)-1]
- }
- return true
-}
-
-// Initialize the scanner and produce the STREAM-START token.
-func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
-
- // Set the initial indentation.
- parser.indent = -1
-
- // Initialize the simple key stack.
- parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
-
- parser.simple_keys_by_tok = make(map[int]int)
-
- // A simple key is allowed at the beginning of the stream.
- parser.simple_key_allowed = true
-
- // We have started.
- parser.stream_start_produced = true
-
- // Create the STREAM-START token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_STREAM_START_TOKEN,
- start_mark: parser.mark,
- end_mark: parser.mark,
- encoding: parser.encoding,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the STREAM-END token and shut down the scanner.
-func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
-
- // Force new line.
- if parser.mark.column != 0 {
- parser.mark.column = 0
- parser.mark.line++
- }
-
- // Reset the indentation level.
- if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
- return false
- }
-
- // Reset simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- parser.simple_key_allowed = false
-
- // Create the STREAM-END token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_STREAM_END_TOKEN,
- start_mark: parser.mark,
- end_mark: parser.mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
-func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
- // Reset the indentation level.
- if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
- return false
- }
-
- // Reset simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- parser.simple_key_allowed = false
-
- // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
- token := yaml_token_t{}
- if !yaml_parser_scan_directive(parser, &token) {
- return false
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the DOCUMENT-START or DOCUMENT-END token.
-func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // Reset the indentation level.
- if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
- return false
- }
-
- // Reset simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- parser.simple_key_allowed = false
-
- // Consume the token.
- start_mark := parser.mark
-
- skip(parser)
- skip(parser)
- skip(parser)
-
- end_mark := parser.mark
-
- // Create the DOCUMENT-START or DOCUMENT-END token.
- token := yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
-func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
-
- // The indicators '[' and '{' may start a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // Increase the flow level.
- if !yaml_parser_increase_flow_level(parser) {
- return false
- }
-
- // A simple key may follow the indicators '[' and '{'.
- parser.simple_key_allowed = true
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
- token := yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
-func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // Reset any potential simple key on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Decrease the flow level.
- if !yaml_parser_decrease_flow_level(parser) {
- return false
- }
-
- // No simple keys after the indicators ']' and '}'.
- parser.simple_key_allowed = false
-
- // Consume the token.
-
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
- token := yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the FLOW-ENTRY token.
-func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
- // Reset any potential simple keys on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Simple keys are allowed after ','.
- parser.simple_key_allowed = true
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the FLOW-ENTRY token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_FLOW_ENTRY_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the BLOCK-ENTRY token.
-func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
- // Check if the scanner is in the block context.
- if parser.flow_level == 0 {
- // Check if we are allowed to start a new entry.
- if !parser.simple_key_allowed {
- return yaml_parser_set_scanner_error(parser, "", parser.mark,
- "block sequence entries are not allowed in this context")
- }
- // Add the BLOCK-SEQUENCE-START token if needed.
- if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
- return false
- }
- } else {
- // It is an error for the '-' indicator to occur in the flow context,
- // but we let the Parser detect and report about it because the Parser
- // is able to point to the context.
- }
-
- // Reset any potential simple keys on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Simple keys are allowed after '-'.
- parser.simple_key_allowed = true
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the BLOCK-ENTRY token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_BLOCK_ENTRY_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the KEY token.
-func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
-
- // In the block context, additional checks are required.
- if parser.flow_level == 0 {
- // Check if we are allowed to start a new key (not nessesary simple).
- if !parser.simple_key_allowed {
- return yaml_parser_set_scanner_error(parser, "", parser.mark,
- "mapping keys are not allowed in this context")
- }
- // Add the BLOCK-MAPPING-START token if needed.
- if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
- return false
- }
- }
-
- // Reset any potential simple keys on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Simple keys are allowed after '?' in the block context.
- parser.simple_key_allowed = parser.flow_level == 0
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the KEY token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_KEY_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the VALUE token.
-func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
-
- simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
-
- // Have we found a simple key?
- if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
- return false
-
- } else if valid {
-
- // Create the KEY token and insert it into the queue.
- token := yaml_token_t{
- typ: yaml_KEY_TOKEN,
- start_mark: simple_key.mark,
- end_mark: simple_key.mark,
- }
- yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
-
- // In the block context, we may need to add the BLOCK-MAPPING-START token.
- if !yaml_parser_roll_indent(parser, simple_key.mark.column,
- simple_key.token_number,
- yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
- return false
- }
-
- // Remove the simple key.
- simple_key.possible = false
- delete(parser.simple_keys_by_tok, simple_key.token_number)
-
- // A simple key cannot follow another simple key.
- parser.simple_key_allowed = false
-
- } else {
- // The ':' indicator follows a complex key.
-
- // In the block context, extra checks are required.
- if parser.flow_level == 0 {
-
- // Check if we are allowed to start a complex value.
- if !parser.simple_key_allowed {
- return yaml_parser_set_scanner_error(parser, "", parser.mark,
- "mapping values are not allowed in this context")
- }
-
- // Add the BLOCK-MAPPING-START token if needed.
- if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
- return false
- }
- }
-
- // Simple keys after ':' are allowed in the block context.
- parser.simple_key_allowed = parser.flow_level == 0
- }
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the VALUE token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_VALUE_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the ALIAS or ANCHOR token.
-func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // An anchor or an alias could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow an anchor or an alias.
- parser.simple_key_allowed = false
-
- // Create the ALIAS or ANCHOR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_anchor(parser, &token, typ) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the TAG token.
-func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
- // A tag could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow a tag.
- parser.simple_key_allowed = false
-
- // Create the TAG token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_tag(parser, &token) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
-func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
- // Remove any potential simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // A simple key may follow a block scalar.
- parser.simple_key_allowed = true
-
- // Create the SCALAR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_block_scalar(parser, &token, literal) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
-func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
- // A plain scalar could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow a flow scalar.
- parser.simple_key_allowed = false
-
- // Create the SCALAR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_flow_scalar(parser, &token, single) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the SCALAR(...,plain) token.
-func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
- // A plain scalar could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow a flow scalar.
- parser.simple_key_allowed = false
-
- // Create the SCALAR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_plain_scalar(parser, &token) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Eat whitespaces and comments until the next token is found.
-func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
-
- scan_mark := parser.mark
-
- // Until the next token is not found.
- for {
- // Allow the BOM mark to start a line.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
- skip(parser)
- }
-
- // Eat whitespaces.
- // Tabs are allowed:
- // - in the flow context
- // - in the block context, but not at the beginning of the line or
- // after '-', '?', or ':' (complex value).
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if we just had a line comment under a sequence entry that
- // looks more like a header to the following content. Similar to this:
- //
- // - # The comment
- // - Some data
- //
- // If so, transform the line comment to a head comment and reposition.
- if len(parser.comments) > 0 && len(parser.tokens) > 1 {
- tokenA := parser.tokens[len(parser.tokens)-2]
- tokenB := parser.tokens[len(parser.tokens)-1]
- comment := &parser.comments[len(parser.comments)-1]
- if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) {
- // If it was in the prior line, reposition so it becomes a
- // header of the follow up token. Otherwise, keep it in place
- // so it becomes a header of the former.
- comment.head = comment.line
- comment.line = nil
- if comment.start_mark.line == parser.mark.line-1 {
- comment.token_mark = parser.mark
- }
- }
- }
-
- // Eat a comment until a line break.
- if parser.buffer[parser.buffer_pos] == '#' {
- if !yaml_parser_scan_comments(parser, scan_mark) {
- return false
- }
- }
-
- // If it is a line break, eat it.
- if is_break(parser.buffer, parser.buffer_pos) {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
-
- // In the block context, a new line may start a simple key.
- if parser.flow_level == 0 {
- parser.simple_key_allowed = true
- }
- } else {
- break // We have found a token.
- }
- }
-
- return true
-}
-
-// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
-//
-// Scope:
-//
-// %YAML 1.1 # a comment \n
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-// %TAG !yaml! tag:yaml.org,2002: \n
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
- // Eat '%'.
- start_mark := parser.mark
- skip(parser)
-
- // Scan the directive name.
- var name []byte
- if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
- return false
- }
-
- // Is it a YAML directive?
- if bytes.Equal(name, []byte("YAML")) {
- // Scan the VERSION directive value.
- var major, minor int8
- if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
- return false
- }
- end_mark := parser.mark
-
- // Create a VERSION-DIRECTIVE token.
- *token = yaml_token_t{
- typ: yaml_VERSION_DIRECTIVE_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- major: major,
- minor: minor,
- }
-
- // Is it a TAG directive?
- } else if bytes.Equal(name, []byte("TAG")) {
- // Scan the TAG directive value.
- var handle, prefix []byte
- if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
- return false
- }
- end_mark := parser.mark
-
- // Create a TAG-DIRECTIVE token.
- *token = yaml_token_t{
- typ: yaml_TAG_DIRECTIVE_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: handle,
- prefix: prefix,
- }
-
- // Unknown directive.
- } else {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "found unknown directive name")
- return false
- }
-
- // Eat the rest of the line including any comments.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- if parser.buffer[parser.buffer_pos] == '#' {
- // [Go] Discard this inline comment for the time being.
- //if !yaml_parser_scan_line_comment(parser, start_mark) {
- // return false
- //}
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- }
-
- // Check if we are at the end of the line.
- if !is_breakz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "did not find expected comment or line break")
- return false
- }
-
- // Eat a line break.
- if is_break(parser.buffer, parser.buffer_pos) {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
- }
-
- return true
-}
-
-// Scan the directive name.
-//
-// Scope:
-//
-// %YAML 1.1 # a comment \n
-// ^^^^
-// %TAG !yaml! tag:yaml.org,2002: \n
-// ^^^
-func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
- // Consume the directive name.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- var s []byte
- for is_alpha(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if the name is empty.
- if len(s) == 0 {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "could not find expected directive name")
- return false
- }
-
- // Check for an blank character after the name.
- if !is_blankz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "found unexpected non-alphabetical character")
- return false
- }
- *name = s
- return true
-}
-
-// Scan the value of VERSION-DIRECTIVE.
-//
-// Scope:
-//
-// %YAML 1.1 # a comment \n
-// ^^^^^^
-func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
- // Eat whitespaces.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Consume the major version number.
- if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
- return false
- }
-
- // Eat '.'.
- if parser.buffer[parser.buffer_pos] != '.' {
- return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
- start_mark, "did not find expected digit or '.' character")
- }
-
- skip(parser)
-
- // Consume the minor version number.
- if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
- return false
- }
- return true
-}
-
-const max_number_length = 2
-
-// Scan the version number of VERSION-DIRECTIVE.
-//
-// Scope:
-//
-// %YAML 1.1 # a comment \n
-// ^
-// %YAML 1.1 # a comment \n
-// ^
-func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
-
- // Repeat while the next character is digit.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- var value, length int8
- for is_digit(parser.buffer, parser.buffer_pos) {
- // Check if the number is too long.
- length++
- if length > max_number_length {
- return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
- start_mark, "found extremely long version number")
- }
- value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if the number was present.
- if length == 0 {
- return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
- start_mark, "did not find expected version number")
- }
- *number = value
- return true
-}
-
-// Scan the value of a TAG-DIRECTIVE token.
-//
-// Scope:
-//
-// %TAG !yaml! tag:yaml.org,2002: \n
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
- var handle_value, prefix_value []byte
-
- // Eat whitespaces.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Scan a handle.
- if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
- return false
- }
-
- // Expect a whitespace.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if !is_blank(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
- start_mark, "did not find expected whitespace")
- return false
- }
-
- // Eat whitespaces.
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Scan a prefix.
- if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
- return false
- }
-
- // Expect a whitespace or line break.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if !is_blankz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
- start_mark, "did not find expected whitespace or line break")
- return false
- }
-
- *handle = handle_value
- *prefix = prefix_value
- return true
-}
-
-func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
- var s []byte
-
- // Eat the indicator character.
- start_mark := parser.mark
- skip(parser)
-
- // Consume the value.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_alpha(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- end_mark := parser.mark
-
- /*
- * Check if length of the anchor is greater than 0 and it is followed by
- * a whitespace character or one of the indicators:
- *
- * '?', ':', ',', ']', '}', '%', '@', '`'.
- */
-
- if len(s) == 0 ||
- !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
- parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
- parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
- parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
- parser.buffer[parser.buffer_pos] == '`') {
- context := "while scanning an alias"
- if typ == yaml_ANCHOR_TOKEN {
- context = "while scanning an anchor"
- }
- yaml_parser_set_scanner_error(parser, context, start_mark,
- "did not find expected alphabetic or numeric character")
- return false
- }
-
- // Create a token.
- *token = yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- }
-
- return true
-}
-
-/*
- * Scan a TAG token.
- */
-
-func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
- var handle, suffix []byte
-
- start_mark := parser.mark
-
- // Check if the tag is in the canonical form.
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- if parser.buffer[parser.buffer_pos+1] == '<' {
- // Keep the handle as ''
-
- // Eat '!<'
- skip(parser)
- skip(parser)
-
- // Consume the tag value.
- if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
- return false
- }
-
- // Check for '>' and eat it.
- if parser.buffer[parser.buffer_pos] != '>' {
- yaml_parser_set_scanner_error(parser, "while scanning a tag",
- start_mark, "did not find the expected '>'")
- return false
- }
-
- skip(parser)
- } else {
- // The tag has either the '!suffix' or the '!handle!suffix' form.
-
- // First, try to scan a handle.
- if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
- return false
- }
-
- // Check if it is, indeed, handle.
- if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
- // Scan the suffix now.
- if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
- return false
- }
- } else {
- // It wasn't a handle after all. Scan the rest of the tag.
- if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
- return false
- }
-
- // Set the handle to '!'.
- handle = []byte{'!'}
-
- // A special case: the '!' tag. Set the handle to '' and the
- // suffix to '!'.
- if len(suffix) == 0 {
- handle, suffix = suffix, handle
- }
- }
- }
-
- // Check the character which ends the tag.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if !is_blankz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a tag",
- start_mark, "did not find expected whitespace or line break")
- return false
- }
-
- end_mark := parser.mark
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_TAG_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: handle,
- suffix: suffix,
- }
- return true
-}
-
-// Scan a tag handle.
-func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
- // Check the initial '!' character.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if parser.buffer[parser.buffer_pos] != '!' {
- yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find expected '!'")
- return false
- }
-
- var s []byte
-
- // Copy the '!' character.
- s = read(parser, s)
-
- // Copy all subsequent alphabetical and numerical characters.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for is_alpha(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if the trailing character is '!' and copy it.
- if parser.buffer[parser.buffer_pos] == '!' {
- s = read(parser, s)
- } else {
- // It's either the '!' tag or not really a tag handle. If it's a %TAG
- // directive, it's an error. If it's a tag token, it must be a part of URI.
- if directive && string(s) != "!" {
- yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find expected '!'")
- return false
- }
- }
-
- *handle = s
- return true
-}
-
-// Scan a tag.
-func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
- //size_t length = head ? strlen((char *)head) : 0
- var s []byte
- hasTag := len(head) > 0
-
- // Copy the head if needed.
- //
- // Note that we don't copy the leading '!' character.
- if len(head) > 1 {
- s = append(s, head[1:]...)
- }
-
- // Scan the tag.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // The set of characters that may appear in URI is as follows:
- //
- // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
- // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
- // '%'.
- // [Go] TODO Convert this into more reasonable logic.
- for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
- parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
- parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
- parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
- parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
- parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
- parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
- parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
- parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
- parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
- parser.buffer[parser.buffer_pos] == '%' {
- // Check if it is a URI-escape sequence.
- if parser.buffer[parser.buffer_pos] == '%' {
- if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
- return false
- }
- } else {
- s = read(parser, s)
- }
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- hasTag = true
- }
-
- if !hasTag {
- yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find expected tag URI")
- return false
- }
- *uri = s
- return true
-}
-
-// Decode an URI-escape sequence corresponding to a single UTF-8 character.
-func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
-
- // Decode the required number of characters.
- w := 1024
- for w > 0 {
- // Check for a URI-escaped octet.
- if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
- return false
- }
-
- if !(parser.buffer[parser.buffer_pos] == '%' &&
- is_hex(parser.buffer, parser.buffer_pos+1) &&
- is_hex(parser.buffer, parser.buffer_pos+2)) {
- return yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find URI escaped octet")
- }
-
- // Get the octet.
- octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
-
- // If it is the leading octet, determine the length of the UTF-8 sequence.
- if w == 1024 {
- w = width(octet)
- if w == 0 {
- return yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "found an incorrect leading UTF-8 octet")
- }
- } else {
- // Check if the trailing octet is correct.
- if octet&0xC0 != 0x80 {
- return yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "found an incorrect trailing UTF-8 octet")
- }
- }
-
- // Copy the octet and move the pointers.
- *s = append(*s, octet)
- skip(parser)
- skip(parser)
- skip(parser)
- w--
- }
- return true
-}
-
-// Scan a block scalar.
-func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
- // Eat the indicator '|' or '>'.
- start_mark := parser.mark
- skip(parser)
-
- // Scan the additional block scalar indicators.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // Check for a chomping indicator.
- var chomping, increment int
- if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
- // Set the chomping method and eat the indicator.
- if parser.buffer[parser.buffer_pos] == '+' {
- chomping = +1
- } else {
- chomping = -1
- }
- skip(parser)
-
- // Check for an indentation indicator.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if is_digit(parser.buffer, parser.buffer_pos) {
- // Check that the indentation is greater than 0.
- if parser.buffer[parser.buffer_pos] == '0' {
- yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "found an indentation indicator equal to 0")
- return false
- }
-
- // Get the indentation level and eat the indicator.
- increment = as_digit(parser.buffer, parser.buffer_pos)
- skip(parser)
- }
-
- } else if is_digit(parser.buffer, parser.buffer_pos) {
- // Do the same as above, but in the opposite order.
-
- if parser.buffer[parser.buffer_pos] == '0' {
- yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "found an indentation indicator equal to 0")
- return false
- }
- increment = as_digit(parser.buffer, parser.buffer_pos)
- skip(parser)
-
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
- if parser.buffer[parser.buffer_pos] == '+' {
- chomping = +1
- } else {
- chomping = -1
- }
- skip(parser)
- }
- }
-
- // Eat whitespaces and comments to the end of the line.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- if parser.buffer[parser.buffer_pos] == '#' {
- if !yaml_parser_scan_line_comment(parser, start_mark) {
- return false
- }
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- }
-
- // Check if we are at the end of the line.
- if !is_breakz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "did not find expected comment or line break")
- return false
- }
-
- // Eat a line break.
- if is_break(parser.buffer, parser.buffer_pos) {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
- }
-
- end_mark := parser.mark
-
- // Set the indentation level if it was specified.
- var indent int
- if increment > 0 {
- if parser.indent >= 0 {
- indent = parser.indent + increment
- } else {
- indent = increment
- }
- }
-
- // Scan the leading line breaks and determine the indentation level if needed.
- var s, leading_break, trailing_breaks []byte
- if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
- return false
- }
-
- // Scan the block scalar content.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- var leading_blank, trailing_blank bool
- for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
- // We are at the beginning of a non-empty line.
-
- // Is it a trailing whitespace?
- trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
-
- // Check if we need to fold the leading line break.
- if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
- // Do we need to join the lines by space?
- if len(trailing_breaks) == 0 {
- s = append(s, ' ')
- }
- } else {
- s = append(s, leading_break...)
- }
- leading_break = leading_break[:0]
-
- // Append the remaining line breaks.
- s = append(s, trailing_breaks...)
- trailing_breaks = trailing_breaks[:0]
-
- // Is it a leading whitespace?
- leading_blank = is_blank(parser.buffer, parser.buffer_pos)
-
- // Consume the current line.
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Consume the line break.
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- leading_break = read_line(parser, leading_break)
-
- // Eat the following indentation spaces and line breaks.
- if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
- return false
- }
- }
-
- // Chomp the tail.
- if chomping != -1 {
- s = append(s, leading_break...)
- }
- if chomping == 1 {
- s = append(s, trailing_breaks...)
- }
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_SCALAR_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- style: yaml_LITERAL_SCALAR_STYLE,
- }
- if !literal {
- token.style = yaml_FOLDED_SCALAR_STYLE
- }
- return true
-}
-
-// Scan indentation spaces and line breaks for a block scalar. Determine the
-// indentation level if needed.
-func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
- *end_mark = parser.mark
-
- // Eat the indentation spaces and line breaks.
- max_indent := 0
- for {
- // Eat the indentation spaces.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- if parser.mark.column > max_indent {
- max_indent = parser.mark.column
- }
-
- // Check for a tab character messing the indentation.
- if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
- return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "found a tab character where an indentation space is expected")
- }
-
- // Have we found a non-empty line?
- if !is_break(parser.buffer, parser.buffer_pos) {
- break
- }
-
- // Consume the line break.
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- // [Go] Should really be returning breaks instead.
- *breaks = read_line(parser, *breaks)
- *end_mark = parser.mark
- }
-
- // Determine the indentation level if needed.
- if *indent == 0 {
- *indent = max_indent
- if *indent < parser.indent+1 {
- *indent = parser.indent + 1
- }
- if *indent < 1 {
- *indent = 1
- }
- }
- return true
-}
-
-// Scan a quoted scalar.
-func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
- // Eat the left quote.
- start_mark := parser.mark
- skip(parser)
-
- // Consume the content of the quoted scalar.
- var s, leading_break, trailing_breaks, whitespaces []byte
- for {
- // Check that there are no document indicators at the beginning of the line.
- if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
- return false
- }
-
- if parser.mark.column == 0 &&
- ((parser.buffer[parser.buffer_pos+0] == '-' &&
- parser.buffer[parser.buffer_pos+1] == '-' &&
- parser.buffer[parser.buffer_pos+2] == '-') ||
- (parser.buffer[parser.buffer_pos+0] == '.' &&
- parser.buffer[parser.buffer_pos+1] == '.' &&
- parser.buffer[parser.buffer_pos+2] == '.')) &&
- is_blankz(parser.buffer, parser.buffer_pos+3) {
- yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
- start_mark, "found unexpected document indicator")
- return false
- }
-
- // Check for EOF.
- if is_z(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
- start_mark, "found unexpected end of stream")
- return false
- }
-
- // Consume non-blank characters.
- leading_blanks := false
- for !is_blankz(parser.buffer, parser.buffer_pos) {
- if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
- // Is is an escaped single quote.
- s = append(s, '\'')
- skip(parser)
- skip(parser)
-
- } else if single && parser.buffer[parser.buffer_pos] == '\'' {
- // It is a right single quote.
- break
- } else if !single && parser.buffer[parser.buffer_pos] == '"' {
- // It is a right double quote.
- break
-
- } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
- // It is an escaped line break.
- if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
- return false
- }
- skip(parser)
- skip_line(parser)
- leading_blanks = true
- break
-
- } else if !single && parser.buffer[parser.buffer_pos] == '\\' {
- // It is an escape sequence.
- code_length := 0
-
- // Check the escape character.
- switch parser.buffer[parser.buffer_pos+1] {
- case '0':
- s = append(s, 0)
- case 'a':
- s = append(s, '\x07')
- case 'b':
- s = append(s, '\x08')
- case 't', '\t':
- s = append(s, '\x09')
- case 'n':
- s = append(s, '\x0A')
- case 'v':
- s = append(s, '\x0B')
- case 'f':
- s = append(s, '\x0C')
- case 'r':
- s = append(s, '\x0D')
- case 'e':
- s = append(s, '\x1B')
- case ' ':
- s = append(s, '\x20')
- case '"':
- s = append(s, '"')
- case '\'':
- s = append(s, '\'')
- case '\\':
- s = append(s, '\\')
- case 'N': // NEL (#x85)
- s = append(s, '\xC2')
- s = append(s, '\x85')
- case '_': // #xA0
- s = append(s, '\xC2')
- s = append(s, '\xA0')
- case 'L': // LS (#x2028)
- s = append(s, '\xE2')
- s = append(s, '\x80')
- s = append(s, '\xA8')
- case 'P': // PS (#x2029)
- s = append(s, '\xE2')
- s = append(s, '\x80')
- s = append(s, '\xA9')
- case 'x':
- code_length = 2
- case 'u':
- code_length = 4
- case 'U':
- code_length = 8
- default:
- yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
- start_mark, "found unknown escape character")
- return false
- }
-
- skip(parser)
- skip(parser)
-
- // Consume an arbitrary escape code.
- if code_length > 0 {
- var value int
-
- // Scan the character value.
- if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
- return false
- }
- for k := 0; k < code_length; k++ {
- if !is_hex(parser.buffer, parser.buffer_pos+k) {
- yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
- start_mark, "did not find expected hexdecimal number")
- return false
- }
- value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
- }
-
- // Check the value and write the character.
- if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
- yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
- start_mark, "found invalid Unicode character escape code")
- return false
- }
- if value <= 0x7F {
- s = append(s, byte(value))
- } else if value <= 0x7FF {
- s = append(s, byte(0xC0+(value>>6)))
- s = append(s, byte(0x80+(value&0x3F)))
- } else if value <= 0xFFFF {
- s = append(s, byte(0xE0+(value>>12)))
- s = append(s, byte(0x80+((value>>6)&0x3F)))
- s = append(s, byte(0x80+(value&0x3F)))
- } else {
- s = append(s, byte(0xF0+(value>>18)))
- s = append(s, byte(0x80+((value>>12)&0x3F)))
- s = append(s, byte(0x80+((value>>6)&0x3F)))
- s = append(s, byte(0x80+(value&0x3F)))
- }
-
- // Advance the pointer.
- for k := 0; k < code_length; k++ {
- skip(parser)
- }
- }
- } else {
- // It is a non-escaped non-blank character.
- s = read(parser, s)
- }
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- }
-
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // Check if we are at the end of the scalar.
- if single {
- if parser.buffer[parser.buffer_pos] == '\'' {
- break
- }
- } else {
- if parser.buffer[parser.buffer_pos] == '"' {
- break
- }
- }
-
- // Consume blank characters.
- for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
- if is_blank(parser.buffer, parser.buffer_pos) {
- // Consume a space or a tab character.
- if !leading_blanks {
- whitespaces = read(parser, whitespaces)
- } else {
- skip(parser)
- }
- } else {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- // Check if it is a first line break.
- if !leading_blanks {
- whitespaces = whitespaces[:0]
- leading_break = read_line(parser, leading_break)
- leading_blanks = true
- } else {
- trailing_breaks = read_line(parser, trailing_breaks)
- }
- }
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Join the whitespaces or fold line breaks.
- if leading_blanks {
- // Do we need to fold line breaks?
- if len(leading_break) > 0 && leading_break[0] == '\n' {
- if len(trailing_breaks) == 0 {
- s = append(s, ' ')
- } else {
- s = append(s, trailing_breaks...)
- }
- } else {
- s = append(s, leading_break...)
- s = append(s, trailing_breaks...)
- }
- trailing_breaks = trailing_breaks[:0]
- leading_break = leading_break[:0]
- } else {
- s = append(s, whitespaces...)
- whitespaces = whitespaces[:0]
- }
- }
-
- // Eat the right quote.
- skip(parser)
- end_mark := parser.mark
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_SCALAR_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- style: yaml_SINGLE_QUOTED_SCALAR_STYLE,
- }
- if !single {
- token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- return true
-}
-
-// Scan a plain scalar.
-func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
-
- var s, leading_break, trailing_breaks, whitespaces []byte
- var leading_blanks bool
- var indent = parser.indent + 1
-
- start_mark := parser.mark
- end_mark := parser.mark
-
- // Consume the content of the plain scalar.
- for {
- // Check for a document indicator.
- if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
- return false
- }
- if parser.mark.column == 0 &&
- ((parser.buffer[parser.buffer_pos+0] == '-' &&
- parser.buffer[parser.buffer_pos+1] == '-' &&
- parser.buffer[parser.buffer_pos+2] == '-') ||
- (parser.buffer[parser.buffer_pos+0] == '.' &&
- parser.buffer[parser.buffer_pos+1] == '.' &&
- parser.buffer[parser.buffer_pos+2] == '.')) &&
- is_blankz(parser.buffer, parser.buffer_pos+3) {
- break
- }
-
- // Check for a comment.
- if parser.buffer[parser.buffer_pos] == '#' {
- break
- }
-
- // Consume non-blank characters.
- for !is_blankz(parser.buffer, parser.buffer_pos) {
-
- // Check for indicators that may end a plain scalar.
- if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
- (parser.flow_level > 0 &&
- (parser.buffer[parser.buffer_pos] == ',' ||
- parser.buffer[parser.buffer_pos] == '[' ||
- parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
- parser.buffer[parser.buffer_pos] == '}')) {
- break
- }
-
- // Check if we need to join whitespaces and breaks.
- if leading_blanks || len(whitespaces) > 0 {
- if leading_blanks {
- // Do we need to fold line breaks?
- if leading_break[0] == '\n' {
- if len(trailing_breaks) == 0 {
- s = append(s, ' ')
- } else {
- s = append(s, trailing_breaks...)
- }
- } else {
- s = append(s, leading_break...)
- s = append(s, trailing_breaks...)
- }
- trailing_breaks = trailing_breaks[:0]
- leading_break = leading_break[:0]
- leading_blanks = false
- } else {
- s = append(s, whitespaces...)
- whitespaces = whitespaces[:0]
- }
- }
-
- // Copy the character.
- s = read(parser, s)
-
- end_mark = parser.mark
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- }
-
- // Is it the end?
- if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
- break
- }
-
- // Consume blank characters.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
- if is_blank(parser.buffer, parser.buffer_pos) {
-
- // Check for tab characters that abuse indentation.
- if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
- start_mark, "found a tab character that violates indentation")
- return false
- }
-
- // Consume a space or a tab character.
- if !leading_blanks {
- whitespaces = read(parser, whitespaces)
- } else {
- skip(parser)
- }
- } else {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- // Check if it is a first line break.
- if !leading_blanks {
- whitespaces = whitespaces[:0]
- leading_break = read_line(parser, leading_break)
- leading_blanks = true
- } else {
- trailing_breaks = read_line(parser, trailing_breaks)
- }
- }
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check indentation level.
- if parser.flow_level == 0 && parser.mark.column < indent {
- break
- }
- }
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_SCALAR_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- style: yaml_PLAIN_SCALAR_STYLE,
- }
-
- // Note that we change the 'simple_key_allowed' flag.
- if leading_blanks {
- parser.simple_key_allowed = true
- }
- return true
-}
-
-func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool {
- if parser.newlines > 0 {
- return true
- }
-
- var start_mark yaml_mark_t
- var text []byte
-
- for peek := 0; peek < 512; peek++ {
- if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
- break
- }
- if is_blank(parser.buffer, parser.buffer_pos+peek) {
- continue
- }
- if parser.buffer[parser.buffer_pos+peek] == '#' {
- seen := parser.mark.index + peek
- for {
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if is_breakz(parser.buffer, parser.buffer_pos) {
- if parser.mark.index >= seen {
- break
- }
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
- } else if parser.mark.index >= seen {
- if len(text) == 0 {
- start_mark = parser.mark
- }
- text = read(parser, text)
- } else {
- skip(parser)
- }
- }
- }
- break
- }
- if len(text) > 0 {
- parser.comments = append(parser.comments, yaml_comment_t{
- token_mark: token_mark,
- start_mark: start_mark,
- line: text,
- })
- }
- return true
-}
-
-func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool {
- token := parser.tokens[len(parser.tokens)-1]
-
- if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 {
- token = parser.tokens[len(parser.tokens)-2]
- }
-
- var token_mark = token.start_mark
- var start_mark yaml_mark_t
- var next_indent = parser.indent
- if next_indent < 0 {
- next_indent = 0
- }
-
- var recent_empty = false
- var first_empty = parser.newlines <= 1
-
- var line = parser.mark.line
- var column = parser.mark.column
-
- var text []byte
-
- // The foot line is the place where a comment must start to
- // still be considered as a foot of the prior content.
- // If there's some content in the currently parsed line, then
- // the foot is the line below it.
- var foot_line = -1
- if scan_mark.line > 0 {
- foot_line = parser.mark.line - parser.newlines + 1
- if parser.newlines == 0 && parser.mark.column > 1 {
- foot_line++
- }
- }
-
- var peek = 0
- for ; peek < 512; peek++ {
- if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
- break
- }
- column++
- if is_blank(parser.buffer, parser.buffer_pos+peek) {
- continue
- }
- c := parser.buffer[parser.buffer_pos+peek]
- var close_flow = parser.flow_level > 0 && (c == ']' || c == '}')
- if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) {
- // Got line break or terminator.
- if close_flow || !recent_empty {
- if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) {
- // This is the first empty line and there were no empty lines before,
- // so this initial part of the comment is a foot of the prior token
- // instead of being a head for the following one. Split it up.
- // Alternatively, this might also be the last comment inside a flow
- // scope, so it must be a footer.
- if len(text) > 0 {
- if start_mark.column-1 < next_indent {
- // If dedented it's unrelated to the prior token.
- token_mark = start_mark
- }
- parser.comments = append(parser.comments, yaml_comment_t{
- scan_mark: scan_mark,
- token_mark: token_mark,
- start_mark: start_mark,
- end_mark: yaml_mark_t{parser.mark.index + peek, line, column},
- foot: text,
- })
- scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
- token_mark = scan_mark
- text = nil
- }
- } else {
- if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 {
- text = append(text, '\n')
- }
- }
- }
- if !is_break(parser.buffer, parser.buffer_pos+peek) {
- break
- }
- first_empty = false
- recent_empty = true
- column = 0
- line++
- continue
- }
-
- if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) {
- // The comment at the different indentation is a foot of the
- // preceding data rather than a head of the upcoming one.
- parser.comments = append(parser.comments, yaml_comment_t{
- scan_mark: scan_mark,
- token_mark: token_mark,
- start_mark: start_mark,
- end_mark: yaml_mark_t{parser.mark.index + peek, line, column},
- foot: text,
- })
- scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
- token_mark = scan_mark
- text = nil
- }
-
- if parser.buffer[parser.buffer_pos+peek] != '#' {
- break
- }
-
- if len(text) == 0 {
- start_mark = yaml_mark_t{parser.mark.index + peek, line, column}
- } else {
- text = append(text, '\n')
- }
-
- recent_empty = false
-
- // Consume until after the consumed comment line.
- seen := parser.mark.index + peek
- for {
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if is_breakz(parser.buffer, parser.buffer_pos) {
- if parser.mark.index >= seen {
- break
- }
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
- } else if parser.mark.index >= seen {
- text = read(parser, text)
- } else {
- skip(parser)
- }
- }
-
- peek = 0
- column = 0
- line = parser.mark.line
- next_indent = parser.indent
- if next_indent < 0 {
- next_indent = 0
- }
- }
-
- if len(text) > 0 {
- parser.comments = append(parser.comments, yaml_comment_t{
- scan_mark: scan_mark,
- token_mark: start_mark,
- start_mark: start_mark,
- end_mark: yaml_mark_t{parser.mark.index + peek - 1, line, column},
- head: text,
- })
- }
- return true
-}
diff --git a/cli/internal/yaml/sorter.go b/cli/internal/yaml/sorter.go
deleted file mode 100644
index 9210ece..0000000
--- a/cli/internal/yaml/sorter.go
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
- "reflect"
- "unicode"
-)
-
-type keyList []reflect.Value
-
-func (l keyList) Len() int { return len(l) }
-func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
-func (l keyList) Less(i, j int) bool {
- a := l[i]
- b := l[j]
- ak := a.Kind()
- bk := b.Kind()
- for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
- a = a.Elem()
- ak = a.Kind()
- }
- for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
- b = b.Elem()
- bk = b.Kind()
- }
- af, aok := keyFloat(a)
- bf, bok := keyFloat(b)
- if aok && bok {
- if af != bf {
- return af < bf
- }
- if ak != bk {
- return ak < bk
- }
- return numLess(a, b)
- }
- if ak != reflect.String || bk != reflect.String {
- return ak < bk
- }
- ar, br := []rune(a.String()), []rune(b.String())
- digits := false
- for i := 0; i < len(ar) && i < len(br); i++ {
- if ar[i] == br[i] {
- digits = unicode.IsDigit(ar[i])
- continue
- }
- al := unicode.IsLetter(ar[i])
- bl := unicode.IsLetter(br[i])
- if al && bl {
- return ar[i] < br[i]
- }
- if al || bl {
- if digits {
- return al
- } else {
- return bl
- }
- }
- var ai, bi int
- var an, bn int64
- if ar[i] == '0' || br[i] == '0' {
- for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
- if ar[j] != '0' {
- an = 1
- bn = 1
- break
- }
- }
- }
- for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
- an = an*10 + int64(ar[ai]-'0')
- }
- for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
- bn = bn*10 + int64(br[bi]-'0')
- }
- if an != bn {
- return an < bn
- }
- if ai != bi {
- return ai < bi
- }
- return ar[i] < br[i]
- }
- return len(ar) < len(br)
-}
-
-// keyFloat returns a float value for v if it is a number/bool
-// and whether it is a number/bool or not.
-func keyFloat(v reflect.Value) (f float64, ok bool) {
- switch v.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return float64(v.Int()), true
- case reflect.Float32, reflect.Float64:
- return v.Float(), true
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return float64(v.Uint()), true
- case reflect.Bool:
- if v.Bool() {
- return 1, true
- }
- return 0, true
- }
- return 0, false
-}
-
-// numLess returns whether a < b.
-// a and b must necessarily have the same kind.
-func numLess(a, b reflect.Value) bool {
- switch a.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return a.Int() < b.Int()
- case reflect.Float32, reflect.Float64:
- return a.Float() < b.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return a.Uint() < b.Uint()
- case reflect.Bool:
- return !a.Bool() && b.Bool()
- }
- panic("not a number")
-}
diff --git a/cli/internal/yaml/writerc.go b/cli/internal/yaml/writerc.go
deleted file mode 100644
index 266d0b0..0000000
--- a/cli/internal/yaml/writerc.go
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-// Set the writer error and return false.
-func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
- emitter.error = yaml_WRITER_ERROR
- emitter.problem = problem
- return false
-}
-
-// Flush the output buffer.
-func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
- if emitter.write_handler == nil {
- panic("write handler not set")
- }
-
- // Check if the buffer is empty.
- if emitter.buffer_pos == 0 {
- return true
- }
-
- if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
- return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
- }
- emitter.buffer_pos = 0
- return true
-}
diff --git a/cli/internal/yaml/yaml.go b/cli/internal/yaml/yaml.go
deleted file mode 100644
index f0bedf3..0000000
--- a/cli/internal/yaml/yaml.go
+++ /dev/null
@@ -1,693 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package yaml implements YAML support for the Go language.
-//
-// Source code and other details for the project are available at GitHub:
-//
-// https://github.com/go-yaml/yaml
-package yaml
-
-import (
- "errors"
- "fmt"
- "io"
- "reflect"
- "strings"
- "sync"
- "unicode/utf8"
-)
-
-// The Unmarshaler interface may be implemented by types to customize their
-// behavior when being unmarshaled from a YAML document.
-type Unmarshaler interface {
- UnmarshalYAML(value *Node) error
-}
-
-type obsoleteUnmarshaler interface {
- UnmarshalYAML(unmarshal func(interface{}) error) error
-}
-
-// The Marshaler interface may be implemented by types to customize their
-// behavior when being marshaled into a YAML document. The returned value
-// is marshaled in place of the original value implementing Marshaler.
-//
-// If an error is returned by MarshalYAML, the marshaling procedure stops
-// and returns with the provided error.
-type Marshaler interface {
- MarshalYAML() (interface{}, error)
-}
-
-// Unmarshal decodes the first document found within the in byte slice
-// and assigns decoded values into the out value.
-//
-// Maps and pointers (to a struct, string, int, etc) are accepted as out
-// values. If an internal pointer within a struct is not initialized,
-// the yaml package will initialize it if necessary for unmarshalling
-// the provided data. The out parameter must not be nil.
-//
-// The type of the decoded values should be compatible with the respective
-// values in out. If one or more values cannot be decoded due to a type
-// mismatches, decoding continues partially until the end of the YAML
-// content, and a *yaml.TypeError is returned with details for all
-// missed values.
-//
-// Struct fields are only unmarshalled if they are exported (have an
-// upper case first letter), and are unmarshalled using the field name
-// lowercased as the default key. Custom keys may be defined via the
-// "yaml" name in the field tag: the content preceding the first comma
-// is used as the key, and the following comma-separated options are
-// used to tweak the marshalling process (see Marshal).
-// Conflicting names result in a runtime error.
-//
-// For example:
-//
-// type T struct {
-// F int `yaml:"a,omitempty"`
-// B int
-// }
-// var t T
-// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
-//
-// See the documentation of Marshal for the format of tags and a list of
-// supported tag options.
-func Unmarshal(in []byte, out interface{}) (err error) {
- return unmarshal(in, out, false)
-}
-
-// A Decoder reads and decodes YAML values from an input stream.
-type Decoder struct {
- parser *parser
- knownFields bool
-}
-
-// NewDecoder returns a new decoder that reads from r.
-//
-// The decoder introduces its own buffering and may read
-// data from r beyond the YAML values requested.
-func NewDecoder(r io.Reader) *Decoder {
- return &Decoder{
- parser: newParserFromReader(r),
- }
-}
-
-// KnownFields ensures that the keys in decoded mappings to
-// exist as fields in the struct being decoded into.
-func (dec *Decoder) KnownFields(enable bool) {
- dec.knownFields = enable
-}
-
-// Decode reads the next YAML-encoded value from its input
-// and stores it in the value pointed to by v.
-//
-// See the documentation for Unmarshal for details about the
-// conversion of YAML into a Go value.
-func (dec *Decoder) Decode(v interface{}) (err error) {
- d := newDecoder()
- d.knownFields = dec.knownFields
- defer handleErr(&err)
- node := dec.parser.parse()
- if node == nil {
- return io.EOF
- }
- out := reflect.ValueOf(v)
- if out.Kind() == reflect.Ptr && !out.IsNil() {
- out = out.Elem()
- }
- d.unmarshal(node, out)
- if len(d.terrors) > 0 {
- return &TypeError{d.terrors}
- }
- return nil
-}
-
-// Decode decodes the node and stores its data into the value pointed to by v.
-//
-// See the documentation for Unmarshal for details about the
-// conversion of YAML into a Go value.
-func (n *Node) Decode(v interface{}) (err error) {
- d := newDecoder()
- defer handleErr(&err)
- out := reflect.ValueOf(v)
- if out.Kind() == reflect.Ptr && !out.IsNil() {
- out = out.Elem()
- }
- d.unmarshal(n, out)
- if len(d.terrors) > 0 {
- return &TypeError{d.terrors}
- }
- return nil
-}
-
-func unmarshal(in []byte, out interface{}, strict bool) (err error) {
- defer handleErr(&err)
- d := newDecoder()
- p := newParser(in)
- defer p.destroy()
- node := p.parse()
- if node != nil {
- v := reflect.ValueOf(out)
- if v.Kind() == reflect.Ptr && !v.IsNil() {
- v = v.Elem()
- }
- d.unmarshal(node, v)
- }
- if len(d.terrors) > 0 {
- return &TypeError{d.terrors}
- }
- return nil
-}
-
-// Marshal serializes the value provided into a YAML document. The structure
-// of the generated document will reflect the structure of the value itself.
-// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
-//
-// Struct fields are only marshalled if they are exported (have an upper case
-// first letter), and are marshalled using the field name lowercased as the
-// default key. Custom keys may be defined via the "yaml" name in the field
-// tag: the content preceding the first comma is used as the key, and the
-// following comma-separated options are used to tweak the marshalling process.
-// Conflicting names result in a runtime error.
-//
-// The field tag format accepted is:
-//
-// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
-//
-// The following flags are currently supported:
-//
-// omitempty Only include the field if it's not set to the zero
-// value for the type or to empty slices or maps.
-// Zero valued structs will be omitted if all their public
-// fields are zero, unless they implement an IsZero
-// method (see the IsZeroer interface type), in which
-// case the field will be excluded if IsZero returns true.
-//
-// flow Marshal using a flow style (useful for structs,
-// sequences and maps).
-//
-// inline Inline the field, which must be a struct or a map,
-// causing all of its fields or keys to be processed as if
-// they were part of the outer struct. For maps, keys must
-// not conflict with the yaml keys of other struct fields.
-//
-// In addition, if the key is "-", the field is ignored.
-//
-// For example:
-//
-// type T struct {
-// F int `yaml:"a,omitempty"`
-// B int
-// }
-// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
-// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
-func Marshal(in interface{}) (out []byte, err error) {
- defer handleErr(&err)
- e := newEncoder()
- defer e.destroy()
- e.marshalDoc("", reflect.ValueOf(in))
- e.finish()
- out = e.out
- return
-}
-
-// An Encoder writes YAML values to an output stream.
-type Encoder struct {
- encoder *encoder
-}
-
-// NewEncoder returns a new encoder that writes to w.
-// The Encoder should be closed after use to flush all data
-// to w.
-func NewEncoder(w io.Writer) *Encoder {
- return &Encoder{
- encoder: newEncoderWithWriter(w),
- }
-}
-
-// Encode writes the YAML encoding of v to the stream.
-// If multiple items are encoded to the stream, the
-// second and subsequent document will be preceded
-// with a "---" document separator, but the first will not.
-//
-// See the documentation for Marshal for details about the conversion of Go
-// values to YAML.
-func (e *Encoder) Encode(v interface{}) (err error) {
- defer handleErr(&err)
- e.encoder.marshalDoc("", reflect.ValueOf(v))
- return nil
-}
-
-// Encode encodes value v and stores its representation in n.
-//
-// See the documentation for Marshal for details about the
-// conversion of Go values into YAML.
-func (n *Node) Encode(v interface{}) (err error) {
- defer handleErr(&err)
- e := newEncoder()
- defer e.destroy()
- e.marshalDoc("", reflect.ValueOf(v))
- e.finish()
- p := newParser(e.out)
- p.textless = true
- defer p.destroy()
- doc := p.parse()
- *n = *doc.Content[0]
- return nil
-}
-
-// SetIndent changes the used indentation used when encoding.
-func (e *Encoder) SetIndent(spaces int) {
- if spaces < 0 {
- panic("yaml: cannot indent to a negative number of spaces")
- }
- e.encoder.indent = spaces
-}
-
-// Close closes the encoder by writing any remaining data.
-// It does not write a stream terminating string "...".
-func (e *Encoder) Close() (err error) {
- defer handleErr(&err)
- e.encoder.finish()
- return nil
-}
-
-func handleErr(err *error) {
- if v := recover(); v != nil {
- if e, ok := v.(yamlError); ok {
- *err = e.err
- } else {
- panic(v)
- }
- }
-}
-
-type yamlError struct {
- err error
-}
-
-func fail(err error) {
- panic(yamlError{err})
-}
-
-func failf(format string, args ...interface{}) {
- panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
-}
-
-// A TypeError is returned by Unmarshal when one or more fields in
-// the YAML document cannot be properly decoded into the requested
-// types. When this error is returned, the value is still
-// unmarshaled partially.
-type TypeError struct {
- Errors []string
-}
-
-func (e *TypeError) Error() string {
- return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
-}
-
-type Kind uint32
-
-const (
- DocumentNode Kind = 1 << iota
- SequenceNode
- MappingNode
- ScalarNode
- AliasNode
-)
-
-type Style uint32
-
-const (
- TaggedStyle Style = 1 << iota
- DoubleQuotedStyle
- SingleQuotedStyle
- LiteralStyle
- FoldedStyle
- FlowStyle
-)
-
-// Node represents an element in the YAML document hierarchy. While documents
-// are typically encoded and decoded into higher level types, such as structs
-// and maps, Node is an intermediate representation that allows detailed
-// control over the content being decoded or encoded.
-//
-// It's worth noting that although Node offers access into details such as
-// line numbers, colums, and comments, the content when re-encoded will not
-// have its original textual representation preserved. An effort is made to
-// render the data plesantly, and to preserve comments near the data they
-// describe, though.
-//
-// Values that make use of the Node type interact with the yaml package in the
-// same way any other type would do, by encoding and decoding yaml data
-// directly or indirectly into them.
-//
-// For example:
-//
-// var person struct {
-// Name string
-// Address yaml.Node
-// }
-// err := yaml.Unmarshal(data, &person)
-//
-// Or by itself:
-//
-// var person Node
-// err := yaml.Unmarshal(data, &person)
-type Node struct {
- // Kind defines whether the node is a document, a mapping, a sequence,
- // a scalar value, or an alias to another node. The specific data type of
- // scalar nodes may be obtained via the ShortTag and LongTag methods.
- Kind Kind
-
- // Style allows customizing the apperance of the node in the tree.
- Style Style
-
- // Tag holds the YAML tag defining the data type for the value.
- // When decoding, this field will always be set to the resolved tag,
- // even when it wasn't explicitly provided in the YAML content.
- // When encoding, if this field is unset the value type will be
- // implied from the node properties, and if it is set, it will only
- // be serialized into the representation if TaggedStyle is used or
- // the implicit tag diverges from the provided one.
- Tag string
-
- // Value holds the unescaped and unquoted represenation of the value.
- Value string
-
- // Anchor holds the anchor name for this node, which allows aliases to point to it.
- Anchor string
-
- // Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
- Alias *Node
-
- // Content holds contained nodes for documents, mappings, and sequences.
- Content []*Node
-
- // HeadComment holds any comments in the lines preceding the node and
- // not separated by an empty line.
- HeadComment string
-
- // LineComment holds any comments at the end of the line where the node is in.
- LineComment string
-
- // FootComment holds any comments following the node and before empty lines.
- FootComment string
-
- // Line and Column hold the node position in the decoded YAML text.
- // These fields are not respected when encoding the node.
- Line int
- Column int
-}
-
-// IsZero returns whether the node has all of its fields unset.
-func (n *Node) IsZero() bool {
- return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
- n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
-}
-
-// LongTag returns the long form of the tag that indicates the data type for
-// the node. If the Tag field isn't explicitly defined, one will be computed
-// based on the node properties.
-func (n *Node) LongTag() string {
- return longTag(n.ShortTag())
-}
-
-// ShortTag returns the short form of the YAML tag that indicates data type for
-// the node. If the Tag field isn't explicitly defined, one will be computed
-// based on the node properties.
-func (n *Node) ShortTag() string {
- if n.indicatedString() {
- return strTag
- }
- if n.Tag == "" || n.Tag == "!" {
- switch n.Kind {
- case MappingNode:
- return mapTag
- case SequenceNode:
- return seqTag
- case AliasNode:
- if n.Alias != nil {
- return n.Alias.ShortTag()
- }
- case ScalarNode:
- tag, _ := resolve("", n.Value)
- return tag
- case 0:
- // Special case to make the zero value convenient.
- if n.IsZero() {
- return nullTag
- }
- }
- return ""
- }
- return shortTag(n.Tag)
-}
-
-func (n *Node) indicatedString() bool {
- return n.Kind == ScalarNode &&
- (shortTag(n.Tag) == strTag ||
- (n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
-}
-
-// SetString is a convenience function that sets the node to a string value
-// and defines its style in a pleasant way depending on its content.
-func (n *Node) SetString(s string) {
- n.Kind = ScalarNode
- if utf8.ValidString(s) {
- n.Value = s
- n.Tag = strTag
- } else {
- n.Value = encodeBase64(s)
- n.Tag = binaryTag
- }
- if strings.Contains(n.Value, "\n") {
- n.Style = LiteralStyle
- }
-}
-
-// --------------------------------------------------------------------------
-// Maintain a mapping of keys to structure field indexes
-
-// The code in this section was copied from mgo/bson.
-
-// structInfo holds details for the serialization of fields of
-// a given struct.
-type structInfo struct {
- FieldsMap map[string]fieldInfo
- FieldsList []fieldInfo
-
- // InlineMap is the number of the field in the struct that
- // contains an ,inline map, or -1 if there's none.
- InlineMap int
-
- // InlineUnmarshalers holds indexes to inlined fields that
- // contain unmarshaler values.
- InlineUnmarshalers [][]int
-}
-
-type fieldInfo struct {
- Key string
- Num int
- OmitEmpty bool
- Flow bool
- // Id holds the unique field identifier, so we can cheaply
- // check for field duplicates without maintaining an extra map.
- Id int
-
- // Inline holds the field index if the field is part of an inlined struct.
- Inline []int
-}
-
-var structMap = make(map[reflect.Type]*structInfo)
-var fieldMapMutex sync.RWMutex
-var unmarshalerType reflect.Type
-
-func init() {
- var v Unmarshaler
- unmarshalerType = reflect.ValueOf(&v).Elem().Type()
-}
-
-func getStructInfo(st reflect.Type) (*structInfo, error) {
- fieldMapMutex.RLock()
- sinfo, found := structMap[st]
- fieldMapMutex.RUnlock()
- if found {
- return sinfo, nil
- }
-
- n := st.NumField()
- fieldsMap := make(map[string]fieldInfo)
- fieldsList := make([]fieldInfo, 0, n)
- inlineMap := -1
- inlineUnmarshalers := [][]int(nil)
- for i := 0; i != n; i++ {
- field := st.Field(i)
- if field.PkgPath != "" && !field.Anonymous {
- continue // Private field
- }
-
- info := fieldInfo{Num: i}
-
- tag := field.Tag.Get("yaml")
- if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
- tag = string(field.Tag)
- }
- if tag == "-" {
- continue
- }
-
- inline := false
- fields := strings.Split(tag, ",")
- if len(fields) > 1 {
- for _, flag := range fields[1:] {
- switch flag {
- case "omitempty":
- info.OmitEmpty = true
- case "flow":
- info.Flow = true
- case "inline":
- inline = true
- default:
- return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
- }
- }
- tag = fields[0]
- }
-
- if inline {
- switch field.Type.Kind() {
- case reflect.Map:
- if inlineMap >= 0 {
- return nil, errors.New("multiple ,inline maps in struct " + st.String())
- }
- if field.Type.Key() != reflect.TypeOf("") {
- return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
- }
- inlineMap = info.Num
- case reflect.Struct, reflect.Ptr:
- ftype := field.Type
- for ftype.Kind() == reflect.Ptr {
- ftype = ftype.Elem()
- }
- if ftype.Kind() != reflect.Struct {
- return nil, errors.New("option ,inline may only be used on a struct or map field")
- }
- if reflect.PtrTo(ftype).Implements(unmarshalerType) {
- inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
- } else {
- sinfo, err := getStructInfo(ftype)
- if err != nil {
- return nil, err
- }
- for _, index := range sinfo.InlineUnmarshalers {
- inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
- }
- for _, finfo := range sinfo.FieldsList {
- if _, found := fieldsMap[finfo.Key]; found {
- msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
- return nil, errors.New(msg)
- }
- if finfo.Inline == nil {
- finfo.Inline = []int{i, finfo.Num}
- } else {
- finfo.Inline = append([]int{i}, finfo.Inline...)
- }
- finfo.Id = len(fieldsList)
- fieldsMap[finfo.Key] = finfo
- fieldsList = append(fieldsList, finfo)
- }
- }
- default:
- return nil, errors.New("option ,inline may only be used on a struct or map field")
- }
- continue
- }
-
- if tag != "" {
- info.Key = tag
- } else {
- info.Key = strings.ToLower(field.Name)
- }
-
- if _, found = fieldsMap[info.Key]; found {
- msg := "duplicated key '" + info.Key + "' in struct " + st.String()
- return nil, errors.New(msg)
- }
-
- info.Id = len(fieldsList)
- fieldsList = append(fieldsList, info)
- fieldsMap[info.Key] = info
- }
-
- sinfo = &structInfo{
- FieldsMap: fieldsMap,
- FieldsList: fieldsList,
- InlineMap: inlineMap,
- InlineUnmarshalers: inlineUnmarshalers,
- }
-
- fieldMapMutex.Lock()
- structMap[st] = sinfo
- fieldMapMutex.Unlock()
- return sinfo, nil
-}
-
-// IsZeroer is used to check whether an object is zero to
-// determine whether it should be omitted when marshaling
-// with the omitempty flag. One notable implementation
-// is time.Time.
-type IsZeroer interface {
- IsZero() bool
-}
-
-func isZero(v reflect.Value) bool {
- kind := v.Kind()
- if z, ok := v.Interface().(IsZeroer); ok {
- if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
- return true
- }
- return z.IsZero()
- }
- switch kind {
- case reflect.String:
- return len(v.String()) == 0
- case reflect.Interface, reflect.Ptr:
- return v.IsNil()
- case reflect.Slice:
- return v.Len() == 0
- case reflect.Map:
- return v.Len() == 0
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return v.Int() == 0
- case reflect.Float32, reflect.Float64:
- return v.Float() == 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return v.Uint() == 0
- case reflect.Bool:
- return !v.Bool()
- case reflect.Struct:
- vt := v.Type()
- for i := v.NumField() - 1; i >= 0; i-- {
- if vt.Field(i).PkgPath != "" {
- continue // Private field
- }
- if !isZero(v.Field(i)) {
- return false
- }
- }
- return true
- }
- return false
-}
diff --git a/cli/internal/yaml/yamlh.go b/cli/internal/yaml/yamlh.go
deleted file mode 100644
index ddcd551..0000000
--- a/cli/internal/yaml/yamlh.go
+++ /dev/null
@@ -1,809 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
- "fmt"
- "io"
-)
-
-// The version directive data.
-type yaml_version_directive_t struct {
- major int8 // The major version number.
- minor int8 // The minor version number.
-}
-
-// The tag directive data.
-type yaml_tag_directive_t struct {
- handle []byte // The tag handle.
- prefix []byte // The tag prefix.
-}
-
-type yaml_encoding_t int
-
-// The stream encoding.
-const (
- // Let the parser choose the encoding.
- yaml_ANY_ENCODING yaml_encoding_t = iota
-
- yaml_UTF8_ENCODING // The default UTF-8 encoding.
- yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
- yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
-)
-
-type yaml_break_t int
-
-// Line break types.
-const (
- // Let the parser choose the break type.
- yaml_ANY_BREAK yaml_break_t = iota
-
- yaml_CR_BREAK // Use CR for line breaks (Mac style).
- yaml_LN_BREAK // Use LN for line breaks (Unix style).
- yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
-)
-
-type yaml_error_type_t int
-
-// Many bad things could happen with the parser and emitter.
-const (
- // No error is produced.
- yaml_NO_ERROR yaml_error_type_t = iota
-
- yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory.
- yaml_READER_ERROR // Cannot read or decode the input stream.
- yaml_SCANNER_ERROR // Cannot scan the input stream.
- yaml_PARSER_ERROR // Cannot parse the input stream.
- yaml_COMPOSER_ERROR // Cannot compose a YAML document.
- yaml_WRITER_ERROR // Cannot write to the output stream.
- yaml_EMITTER_ERROR // Cannot emit a YAML stream.
-)
-
-// The pointer position.
-type yaml_mark_t struct {
- index int // The position index.
- line int // The position line.
- column int // The position column.
-}
-
-// Node Styles
-
-type yaml_style_t int8
-
-type yaml_scalar_style_t yaml_style_t
-
-// Scalar styles.
-const (
- // Let the emitter choose the style.
- yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
-
- yaml_PLAIN_SCALAR_STYLE yaml_scalar_style_t = 1 << iota // The plain scalar style.
- yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
- yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
- yaml_LITERAL_SCALAR_STYLE // The literal scalar style.
- yaml_FOLDED_SCALAR_STYLE // The folded scalar style.
-)
-
-type yaml_sequence_style_t yaml_style_t
-
-// Sequence styles.
-const (
- // Let the emitter choose the style.
- yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
-
- yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
- yaml_FLOW_SEQUENCE_STYLE // The flow sequence style.
-)
-
-type yaml_mapping_style_t yaml_style_t
-
-// Mapping styles.
-const (
- // Let the emitter choose the style.
- yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
-
- yaml_BLOCK_MAPPING_STYLE // The block mapping style.
- yaml_FLOW_MAPPING_STYLE // The flow mapping style.
-)
-
-// Tokens
-
-type yaml_token_type_t int
-
-// Token types.
-const (
- // An empty token.
- yaml_NO_TOKEN yaml_token_type_t = iota
-
- yaml_STREAM_START_TOKEN // A STREAM-START token.
- yaml_STREAM_END_TOKEN // A STREAM-END token.
-
- yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
- yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token.
- yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token.
- yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token.
-
- yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
- yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token.
- yaml_BLOCK_END_TOKEN // A BLOCK-END token.
-
- yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
- yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token.
- yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token.
- yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token.
-
- yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
- yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token.
- yaml_KEY_TOKEN // A KEY token.
- yaml_VALUE_TOKEN // A VALUE token.
-
- yaml_ALIAS_TOKEN // An ALIAS token.
- yaml_ANCHOR_TOKEN // An ANCHOR token.
- yaml_TAG_TOKEN // A TAG token.
- yaml_SCALAR_TOKEN // A SCALAR token.
-)
-
-func (tt yaml_token_type_t) String() string {
- switch tt {
- case yaml_NO_TOKEN:
- return "yaml_NO_TOKEN"
- case yaml_STREAM_START_TOKEN:
- return "yaml_STREAM_START_TOKEN"
- case yaml_STREAM_END_TOKEN:
- return "yaml_STREAM_END_TOKEN"
- case yaml_VERSION_DIRECTIVE_TOKEN:
- return "yaml_VERSION_DIRECTIVE_TOKEN"
- case yaml_TAG_DIRECTIVE_TOKEN:
- return "yaml_TAG_DIRECTIVE_TOKEN"
- case yaml_DOCUMENT_START_TOKEN:
- return "yaml_DOCUMENT_START_TOKEN"
- case yaml_DOCUMENT_END_TOKEN:
- return "yaml_DOCUMENT_END_TOKEN"
- case yaml_BLOCK_SEQUENCE_START_TOKEN:
- return "yaml_BLOCK_SEQUENCE_START_TOKEN"
- case yaml_BLOCK_MAPPING_START_TOKEN:
- return "yaml_BLOCK_MAPPING_START_TOKEN"
- case yaml_BLOCK_END_TOKEN:
- return "yaml_BLOCK_END_TOKEN"
- case yaml_FLOW_SEQUENCE_START_TOKEN:
- return "yaml_FLOW_SEQUENCE_START_TOKEN"
- case yaml_FLOW_SEQUENCE_END_TOKEN:
- return "yaml_FLOW_SEQUENCE_END_TOKEN"
- case yaml_FLOW_MAPPING_START_TOKEN:
- return "yaml_FLOW_MAPPING_START_TOKEN"
- case yaml_FLOW_MAPPING_END_TOKEN:
- return "yaml_FLOW_MAPPING_END_TOKEN"
- case yaml_BLOCK_ENTRY_TOKEN:
- return "yaml_BLOCK_ENTRY_TOKEN"
- case yaml_FLOW_ENTRY_TOKEN:
- return "yaml_FLOW_ENTRY_TOKEN"
- case yaml_KEY_TOKEN:
- return "yaml_KEY_TOKEN"
- case yaml_VALUE_TOKEN:
- return "yaml_VALUE_TOKEN"
- case yaml_ALIAS_TOKEN:
- return "yaml_ALIAS_TOKEN"
- case yaml_ANCHOR_TOKEN:
- return "yaml_ANCHOR_TOKEN"
- case yaml_TAG_TOKEN:
- return "yaml_TAG_TOKEN"
- case yaml_SCALAR_TOKEN:
- return "yaml_SCALAR_TOKEN"
- }
- return "<unknown token>"
-}
-
-// The token structure.
-type yaml_token_t struct {
- // The token type.
- typ yaml_token_type_t
-
- // The start/end of the token.
- start_mark, end_mark yaml_mark_t
-
- // The stream encoding (for yaml_STREAM_START_TOKEN).
- encoding yaml_encoding_t
-
- // The alias/anchor/scalar value or tag/tag directive handle
- // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
- value []byte
-
- // The tag suffix (for yaml_TAG_TOKEN).
- suffix []byte
-
- // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
- prefix []byte
-
- // The scalar style (for yaml_SCALAR_TOKEN).
- style yaml_scalar_style_t
-
- // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
- major, minor int8
-}
-
-// Events
-
-type yaml_event_type_t int8
-
-// Event types.
-const (
- // An empty event.
- yaml_NO_EVENT yaml_event_type_t = iota
-
- yaml_STREAM_START_EVENT // A STREAM-START event.
- yaml_STREAM_END_EVENT // A STREAM-END event.
- yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
- yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event.
- yaml_ALIAS_EVENT // An ALIAS event.
- yaml_SCALAR_EVENT // A SCALAR event.
- yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
- yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event.
- yaml_MAPPING_START_EVENT // A MAPPING-START event.
- yaml_MAPPING_END_EVENT // A MAPPING-END event.
- yaml_TAIL_COMMENT_EVENT
-)
-
-var eventStrings = []string{
- yaml_NO_EVENT: "none",
- yaml_STREAM_START_EVENT: "stream start",
- yaml_STREAM_END_EVENT: "stream end",
- yaml_DOCUMENT_START_EVENT: "document start",
- yaml_DOCUMENT_END_EVENT: "document end",
- yaml_ALIAS_EVENT: "alias",
- yaml_SCALAR_EVENT: "scalar",
- yaml_SEQUENCE_START_EVENT: "sequence start",
- yaml_SEQUENCE_END_EVENT: "sequence end",
- yaml_MAPPING_START_EVENT: "mapping start",
- yaml_MAPPING_END_EVENT: "mapping end",
- yaml_TAIL_COMMENT_EVENT: "tail comment",
-}
-
-func (e yaml_event_type_t) String() string {
- if e < 0 || int(e) >= len(eventStrings) {
- return fmt.Sprintf("unknown event %d", e)
- }
- return eventStrings[e]
-}
-
-// The event structure.
-type yaml_event_t struct {
-
- // The event type.
- typ yaml_event_type_t
-
- // The start and end of the event.
- start_mark, end_mark yaml_mark_t
-
- // The document encoding (for yaml_STREAM_START_EVENT).
- encoding yaml_encoding_t
-
- // The version directive (for yaml_DOCUMENT_START_EVENT).
- version_directive *yaml_version_directive_t
-
- // The list of tag directives (for yaml_DOCUMENT_START_EVENT).
- tag_directives []yaml_tag_directive_t
-
- // The comments
- head_comment []byte
- line_comment []byte
- foot_comment []byte
- tail_comment []byte
-
- // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
- anchor []byte
-
- // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
- tag []byte
-
- // The scalar value (for yaml_SCALAR_EVENT).
- value []byte
-
- // Is the document start/end indicator implicit, or the tag optional?
- // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
- implicit bool
-
- // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
- quoted_implicit bool
-
- // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
- style yaml_style_t
-}
-
-func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) }
-func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
-func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) }
-
-// Nodes
-
-const (
- yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null.
- yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false.
- yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values.
- yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values.
- yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values.
- yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
-
- yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
- yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
-
- // Not in original libyaml.
- yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
- yaml_MERGE_TAG = "tag:yaml.org,2002:merge"
-
- yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str.
- yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
- yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map.
-)
-
-type yaml_node_type_t int
-
-// Node types.
-const (
- // An empty node.
- yaml_NO_NODE yaml_node_type_t = iota
-
- yaml_SCALAR_NODE // A scalar node.
- yaml_SEQUENCE_NODE // A sequence node.
- yaml_MAPPING_NODE // A mapping node.
-)
-
-// An element of a sequence node.
-type yaml_node_item_t int
-
-// An element of a mapping node.
-type yaml_node_pair_t struct {
- key int // The key of the element.
- value int // The value of the element.
-}
-
-// The node structure.
-type yaml_node_t struct {
- typ yaml_node_type_t // The node type.
- tag []byte // The node tag.
-
- // The node data.
-
- // The scalar parameters (for yaml_SCALAR_NODE).
- scalar struct {
- value []byte // The scalar value.
- length int // The length of the scalar value.
- style yaml_scalar_style_t // The scalar style.
- }
-
- // The sequence parameters (for YAML_SEQUENCE_NODE).
- sequence struct {
- items_data []yaml_node_item_t // The stack of sequence items.
- style yaml_sequence_style_t // The sequence style.
- }
-
- // The mapping parameters (for yaml_MAPPING_NODE).
- mapping struct {
- pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value).
- pairs_start *yaml_node_pair_t // The beginning of the stack.
- pairs_end *yaml_node_pair_t // The end of the stack.
- pairs_top *yaml_node_pair_t // The top of the stack.
- style yaml_mapping_style_t // The mapping style.
- }
-
- start_mark yaml_mark_t // The beginning of the node.
- end_mark yaml_mark_t // The end of the node.
-
-}
-
-// The document structure.
-type yaml_document_t struct {
-
- // The document nodes.
- nodes []yaml_node_t
-
- // The version directive.
- version_directive *yaml_version_directive_t
-
- // The list of tag directives.
- tag_directives_data []yaml_tag_directive_t
- tag_directives_start int // The beginning of the tag directives list.
- tag_directives_end int // The end of the tag directives list.
-
- start_implicit int // Is the document start indicator implicit?
- end_implicit int // Is the document end indicator implicit?
-
- // The start/end of the document.
- start_mark, end_mark yaml_mark_t
-}
-
-// The prototype of a read handler.
-//
-// The read handler is called when the parser needs to read more bytes from the
-// source. The handler should write not more than size bytes to the buffer.
-// The number of written bytes should be set to the size_read variable.
-//
-// [in,out] data A pointer to an application data specified by
-//
-// yaml_parser_set_input().
-//
-// [out] buffer The buffer to write the data from the source.
-// [in] size The size of the buffer.
-// [out] size_read The actual number of bytes read from the source.
-//
-// On success, the handler should return 1. If the handler failed,
-// the returned value should be 0. On EOF, the handler should set the
-// size_read to 0 and return 1.
-type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
-
-// This structure holds information about a potential simple key.
-type yaml_simple_key_t struct {
- possible bool // Is a simple key possible?
- required bool // Is a simple key required?
- token_number int // The number of the token.
- mark yaml_mark_t // The position mark.
-}
-
-// The states of the parser.
-type yaml_parser_state_t int
-
-const (
- yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
-
- yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document.
- yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START.
- yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document.
- yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END.
- yaml_PARSE_BLOCK_NODE_STATE // Expect a block node.
- yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
- yaml_PARSE_FLOW_NODE_STATE // Expect a flow node.
- yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence.
- yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence.
- yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence.
- yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
- yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key.
- yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value.
- yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry.
- yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
- yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
- yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
- yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping.
- yaml_PARSE_END_STATE // Expect nothing.
-)
-
-func (ps yaml_parser_state_t) String() string {
- switch ps {
- case yaml_PARSE_STREAM_START_STATE:
- return "yaml_PARSE_STREAM_START_STATE"
- case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
- return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
- case yaml_PARSE_DOCUMENT_START_STATE:
- return "yaml_PARSE_DOCUMENT_START_STATE"
- case yaml_PARSE_DOCUMENT_CONTENT_STATE:
- return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
- case yaml_PARSE_DOCUMENT_END_STATE:
- return "yaml_PARSE_DOCUMENT_END_STATE"
- case yaml_PARSE_BLOCK_NODE_STATE:
- return "yaml_PARSE_BLOCK_NODE_STATE"
- case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
- return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
- case yaml_PARSE_FLOW_NODE_STATE:
- return "yaml_PARSE_FLOW_NODE_STATE"
- case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
- return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
- case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
- return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
- case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
- return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
- case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
- return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
- case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
- return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
- case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
- return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
- case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
- return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
- case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
- return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
- case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
- return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
- case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
- return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
- case yaml_PARSE_END_STATE:
- return "yaml_PARSE_END_STATE"
- }
- return "<unknown parser state>"
-}
-
-// This structure holds aliases data.
-type yaml_alias_data_t struct {
- anchor []byte // The anchor.
- index int // The node id.
- mark yaml_mark_t // The anchor mark.
-}
-
-// The parser structure.
-//
-// All members are internal. Manage the structure using the
-// yaml_parser_ family of functions.
-type yaml_parser_t struct {
-
- // Error handling
-
- error yaml_error_type_t // Error type.
-
- problem string // Error description.
-
- // The byte about which the problem occurred.
- problem_offset int
- problem_value int
- problem_mark yaml_mark_t
-
- // The error context.
- context string
- context_mark yaml_mark_t
-
- // Reader stuff
-
- read_handler yaml_read_handler_t // Read handler.
-
- input_reader io.Reader // File input data.
- input []byte // String input data.
- input_pos int
-
- eof bool // EOF flag
-
- buffer []byte // The working buffer.
- buffer_pos int // The current position of the buffer.
-
- unread int // The number of unread characters in the buffer.
-
- newlines int // The number of line breaks since last non-break/non-blank character
-
- raw_buffer []byte // The raw buffer.
- raw_buffer_pos int // The current position of the buffer.
-
- encoding yaml_encoding_t // The input encoding.
-
- offset int // The offset of the current position (in bytes).
- mark yaml_mark_t // The mark of the current position.
-
- // Comments
-
- head_comment []byte // The current head comments
- line_comment []byte // The current line comments
- foot_comment []byte // The current foot comments
- tail_comment []byte // Foot comment that happens at the end of a block.
- stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc)
-
- comments []yaml_comment_t // The folded comments for all parsed tokens
- comments_head int
-
- // Scanner stuff
-
- stream_start_produced bool // Have we started to scan the input stream?
- stream_end_produced bool // Have we reached the end of the input stream?
-
- flow_level int // The number of unclosed '[' and '{' indicators.
-
- tokens []yaml_token_t // The tokens queue.
- tokens_head int // The head of the tokens queue.
- tokens_parsed int // The number of tokens fetched from the queue.
- token_available bool // Does the tokens queue contain a token ready for dequeueing.
-
- indent int // The current indentation level.
- indents []int // The indentation levels stack.
-
- simple_key_allowed bool // May a simple key occur at the current position?
- simple_keys []yaml_simple_key_t // The stack of simple keys.
- simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
-
- // Parser stuff
-
- state yaml_parser_state_t // The current parser state.
- states []yaml_parser_state_t // The parser states stack.
- marks []yaml_mark_t // The stack of marks.
- tag_directives []yaml_tag_directive_t // The list of TAG directives.
-
- // Dumper stuff
-
- aliases []yaml_alias_data_t // The alias data.
-
- document *yaml_document_t // The currently parsed document.
-}
-
-type yaml_comment_t struct {
- scan_mark yaml_mark_t // Position where scanning for comments started
- token_mark yaml_mark_t // Position after which tokens will be associated with this comment
- start_mark yaml_mark_t // Position of '#' comment mark
- end_mark yaml_mark_t // Position where comment terminated
-
- head []byte
- line []byte
- foot []byte
-}
-
-// Emitter Definitions
-
-// The prototype of a write handler.
-//
-// The write handler is called when the emitter needs to flush the accumulated
-// characters to the output. The handler should write @a size bytes of the
-// @a buffer to the output.
-//
-// @param[in,out] data A pointer to an application data specified by
-//
-// yaml_emitter_set_output().
-//
-// @param[in] buffer The buffer with bytes to be written.
-// @param[in] size The size of the buffer.
-//
-// @returns On success, the handler should return @c 1. If the handler failed,
-// the returned value should be @c 0.
-type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
-
-type yaml_emitter_state_t int
-
-// The emitter states.
-const (
- // Expect STREAM-START.
- yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
-
- yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END.
- yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END.
- yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document.
- yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END.
- yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence.
- yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE // Expect the next item of a flow sequence, with the comma already written out
- yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence.
- yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
- yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE // Expect the next key of a flow mapping, with the comma already written out
- yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
- yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping.
- yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
- yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence.
- yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence.
- yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
- yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping.
- yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
- yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping.
- yaml_EMIT_END_STATE // Expect nothing.
-)
-
-// The emitter structure.
-//
-// All members are internal. Manage the structure using the @c yaml_emitter_
-// family of functions.
-type yaml_emitter_t struct {
-
- // Error handling
-
- error yaml_error_type_t // Error type.
- problem string // Error description.
-
- // Writer stuff
-
- write_handler yaml_write_handler_t // Write handler.
-
- output_buffer *[]byte // String output data.
- output_writer io.Writer // File output data.
-
- buffer []byte // The working buffer.
- buffer_pos int // The current position of the buffer.
-
- raw_buffer []byte // The raw buffer.
- raw_buffer_pos int // The current position of the buffer.
-
- encoding yaml_encoding_t // The stream encoding.
-
- // Emitter stuff
-
- canonical bool // If the output is in the canonical style?
- best_indent int // The number of indentation spaces.
- best_width int // The preferred width of the output lines.
- unicode bool // Allow unescaped non-ASCII characters?
- line_break yaml_break_t // The preferred line break.
-
- state yaml_emitter_state_t // The current emitter state.
- states []yaml_emitter_state_t // The stack of states.
-
- events []yaml_event_t // The event queue.
- events_head int // The head of the event queue.
-
- indents []int // The stack of indentation levels.
-
- tag_directives []yaml_tag_directive_t // The list of tag directives.
-
- indent int // The current indentation level.
-
- flow_level int // The current flow level.
-
- root_context bool // Is it the document root context?
- sequence_context bool // Is it a sequence context?
- mapping_context bool // Is it a mapping context?
- simple_key_context bool // Is it a simple mapping key context?
-
- line int // The current line.
- column int // The current column.
- whitespace bool // If the last character was a whitespace?
- indention bool // If the last character was an indentation character (' ', '-', '?', ':')?
- open_ended bool // If an explicit document end is required?
-
- space_above bool // Is there's an empty line above?
- foot_indent int // The indent used to write the foot comment above, or -1 if none.
-
- // Anchor analysis.
- anchor_data struct {
- anchor []byte // The anchor value.
- alias bool // Is it an alias?
- }
-
- // Tag analysis.
- tag_data struct {
- handle []byte // The tag handle.
- suffix []byte // The tag suffix.
- }
-
- // Scalar analysis.
- scalar_data struct {
- value []byte // The scalar value.
- multiline bool // Does the scalar contain line breaks?
- flow_plain_allowed bool // Can the scalar be expessed in the flow plain style?
- block_plain_allowed bool // Can the scalar be expressed in the block plain style?
- single_quoted_allowed bool // Can the scalar be expressed in the single quoted style?
- block_allowed bool // Can the scalar be expressed in the literal or folded styles?
- style yaml_scalar_style_t // The output style.
- }
-
- // Comments
- head_comment []byte
- line_comment []byte
- foot_comment []byte
- tail_comment []byte
-
- key_line_comment []byte
-
- // Dumper stuff
-
- opened bool // If the stream was already opened?
- closed bool // If the stream was already closed?
-
- // The information associated with the document nodes.
- anchors *struct {
- references int // The number of references.
- anchor int // The anchor id.
- serialized bool // If the node has been emitted?
- }
-
- last_anchor_id int // The last assigned anchor id.
-
- document *yaml_document_t // The currently emitted document.
-}
diff --git a/cli/internal/yaml/yamlprivateh.go b/cli/internal/yaml/yamlprivateh.go
deleted file mode 100644
index dea1ba9..0000000
--- a/cli/internal/yaml/yamlprivateh.go
+++ /dev/null
@@ -1,198 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-const (
- // The size of the input raw buffer.
- input_raw_buffer_size = 512
-
- // The size of the input buffer.
- // It should be possible to decode the whole raw buffer.
- input_buffer_size = input_raw_buffer_size * 3
-
- // The size of the output buffer.
- output_buffer_size = 128
-
- // The size of the output raw buffer.
- // It should be possible to encode the whole output buffer.
- output_raw_buffer_size = (output_buffer_size*2 + 2)
-
- // The size of other stacks and queues.
- initial_stack_size = 16
- initial_queue_size = 16
- initial_string_size = 16
-)
-
-// Check if the character at the specified position is an alphabetical
-// character, a digit, '_', or '-'.
-func is_alpha(b []byte, i int) bool {
- return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
-}
-
-// Check if the character at the specified position is a digit.
-func is_digit(b []byte, i int) bool {
- return b[i] >= '0' && b[i] <= '9'
-}
-
-// Get the value of a digit.
-func as_digit(b []byte, i int) int {
- return int(b[i]) - '0'
-}
-
-// Check if the character at the specified position is a hex-digit.
-func is_hex(b []byte, i int) bool {
- return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
-}
-
-// Get the value of a hex-digit.
-func as_hex(b []byte, i int) int {
- bi := b[i]
- if bi >= 'A' && bi <= 'F' {
- return int(bi) - 'A' + 10
- }
- if bi >= 'a' && bi <= 'f' {
- return int(bi) - 'a' + 10
- }
- return int(bi) - '0'
-}
-
-// Check if the character is ASCII.
-func is_ascii(b []byte, i int) bool {
- return b[i] <= 0x7F
-}
-
-// Check if the character at the start of the buffer can be printed unescaped.
-func is_printable(b []byte, i int) bool {
- return ((b[i] == 0x0A) || // . == #x0A
- (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
- (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
- (b[i] > 0xC2 && b[i] < 0xED) ||
- (b[i] == 0xED && b[i+1] < 0xA0) ||
- (b[i] == 0xEE) ||
- (b[i] == 0xEF && // #xE000 <= . <= #xFFFD
- !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
- !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
-}
-
-// Check if the character at the specified position is NUL.
-func is_z(b []byte, i int) bool {
- return b[i] == 0x00
-}
-
-// Check if the beginning of the buffer is a BOM.
-func is_bom(b []byte, i int) bool {
- return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
-}
-
-// Check if the character at the specified position is space.
-func is_space(b []byte, i int) bool {
- return b[i] == ' '
-}
-
-// Check if the character at the specified position is tab.
-func is_tab(b []byte, i int) bool {
- return b[i] == '\t'
-}
-
-// Check if the character at the specified position is blank (space or tab).
-func is_blank(b []byte, i int) bool {
- //return is_space(b, i) || is_tab(b, i)
- return b[i] == ' ' || b[i] == '\t'
-}
-
-// Check if the character at the specified position is a line break.
-func is_break(b []byte, i int) bool {
- return (b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
-}
-
-func is_crlf(b []byte, i int) bool {
- return b[i] == '\r' && b[i+1] == '\n'
-}
-
-// Check if the character is a line break or NUL.
-func is_breakz(b []byte, i int) bool {
- //return is_break(b, i) || is_z(b, i)
- return (
- // is_break:
- b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
- // is_z:
- b[i] == 0)
-}
-
-// Check if the character is a line break, space, or NUL.
-func is_spacez(b []byte, i int) bool {
- //return is_space(b, i) || is_breakz(b, i)
- return (
- // is_space:
- b[i] == ' ' ||
- // is_breakz:
- b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
- b[i] == 0)
-}
-
-// Check if the character is a line break, space, tab, or NUL.
-func is_blankz(b []byte, i int) bool {
- //return is_blank(b, i) || is_breakz(b, i)
- return (
- // is_blank:
- b[i] == ' ' || b[i] == '\t' ||
- // is_breakz:
- b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
- b[i] == 0)
-}
-
-// Determine the width of the character.
-func width(b byte) int {
- // Don't replace these by a switch without first
- // confirming that it is being inlined.
- if b&0x80 == 0x00 {
- return 1
- }
- if b&0xE0 == 0xC0 {
- return 2
- }
- if b&0xF0 == 0xE0 {
- return 3
- }
- if b&0xF8 == 0xF0 {
- return 4
- }
- return 0
-
-}
diff --git a/cli/package.json b/cli/package.json
deleted file mode 100644
index 971eaca..0000000
--- a/cli/package.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "cli",
- "private": true,
- "version": "0.0.0",
- "scripts": {
- "clean": "make clean",
- "build": "make",
- "test": "make test-go",
- "format": "make fmt-go",
- "lint": "make lint-go"
- },
- "devDependencies": {
- "copy-template-dir": "^1.4.0",
- "faker": "^5.1.0",
- "ngraph.generators": "^19.3.0",
- "shelljs": "^0.8.4"
- }
-}
diff --git a/cli/scripts/generate.mjs b/cli/scripts/generate.mjs
deleted file mode 100644
index 1b9cbec..0000000
--- a/cli/scripts/generate.mjs
+++ /dev/null
@@ -1,297 +0,0 @@
-#!/usr/bin/env node
-import shelljs from "shelljs";
-import path from "path";
-import fs from "fs-extra";
-import faker from "faker";
-import graphGenerator from "ngraph.generators";
-import copy from "copy-template-dir";
-import { fileURLToPath } from "url";
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-faker.seed(123);
-
-const scope = `@${faker.hacker
- .noun()
- .toLowerCase()
- .replace(/\s/g, "-")
- .replace("1080p-", "rando")}`;
-
-const type = process.argv[2];
-
-// TODO: algo should be customizable along with the size
-const packageGraph = graphGenerator.complete(5);
-
-// Generate the package name & versions
-packageGraph.forEachNode((node) => {
- node.data = {
- name: `${scope}/${faker.hacker.adjective()}-${faker.hacker.noun()}`
- .toLocaleLowerCase()
- .replace(/\s/g, "-"),
- version: faker.system.semver(),
- };
-});
-
-// Generate package dependencies
-packageGraph.forEachNode((node) => {
- const links = packageGraph.getLinks(node.id);
-
- if (links) {
- for (const link of links) {
- if (link.fromId === node.id) {
- const depNode = packageGraph.getNode(link.toId);
- node.data.dependencies = node.data.dependencies || {};
- node.data.dependencies[depNode.data.name] = `^${depNode.data.version}`;
- node.data.implicitDependencies = node.data.implicitDependencies || [];
- node.data.implicitDependencies.push(
- depNode.data.name.replace(/^@[^/]+\//, "")
- );
- }
- }
- }
-});
-
-// Generate the monorepo
-// 1. the root package.json
-// 2. create packages/
-// 3. create package directories
-const root = path.join(__dirname, "../demo", type);
-
-function generate(root, skipInstall) {
- fs.mkdirSync(root, { recursive: true });
- if (type !== "nx") {
- fs.writeFileSync(
- path.join(root, ".gitignore"),
- `node_modules
-dist
-.turbo
-out
-turbo
-turbo-linux
-.yalc`
- );
- if (fs.existsSync(root)) {
- try {
- fs.rmSync(root + "/packages", { recursive: true });
- } catch (error) {}
- }
-
- let deps =
- type !== "turbo"
- ? {
- devDependencies: {
- [type]: "*",
- },
- }
- : {};
-
- fs.writeFileSync(
- path.join(root, "package.json"),
- JSON.stringify(
- {
- name: "monorepo",
- version: "0.0.0",
- private: true,
- workspaces: ["packages/*"],
- ...deps,
- packageManager: "yarn@1.22.17",
- },
- null,
- 2
- )
- );
-
- fs.writeFileSync(
- path.join(root, "tsconfig.json"),
- JSON.stringify(
- {
- compilerOptions: {
- composite: false,
- declaration: true,
- declarationMap: true,
- esModuleInterop: true,
- forceConsistentCasingInFileNames: true,
- inlineSourceMap: true,
- inlineSources: false,
- isolatedModules: true,
- moduleResolution: "node",
- noUnusedLocals: false,
- noUnusedParameters: false,
- preserveWatchOutput: true,
- skipLibCheck: true,
- strict: true,
- lib: ["es2020"],
- module: "commonjs",
- target: "es2020",
- },
- },
- null,
- 2
- )
- );
- }
-
- if (type === "turbo") {
- fs.writeFileSync(
- path.join(root, "turbo.json"),
- JSON.stringify(
- {
- npmClient: "yarn",
- cacheStorageConfig: {
- provider: "local",
- cacheUrl: "https://1a77600385dd.ngrok.io",
- },
- pipeline: {
- build: {
- outputs: ["dist/**/*"],
- dependsOn: ["^build"],
- },
- test: {
- dependsOn: ["build"],
- },
- dev: {
- cache: false,
- },
- },
- },
- null,
- 2
- )
- );
- }
-
- if (type === "lerna") {
- fs.writeFileSync(
- path.join(root, "lerna.json"),
- JSON.stringify(
- {
- packages: ["packages/*"],
- version: "0.0.0",
- },
- null,
- 2
- )
- );
- }
-
- if (type === "lage") {
- fs.writeFileSync(
- path.join(root, "lage.config.js"),
- `
-module.exports = {
- pipeline: {
- build: ['^build'],
- test: ['build'],
- lint: [],
- },
- npmClient: 'yarn',
- cacheOptions: {
- cacheStorageConfig: {
- provider: 'local',
- },
- outputGlob: ['dist/**'],
- },
-};
- `
- );
- }
-
- if (type !== "nx") {
- fs.mkdirSync(path.join(root, "packages"));
- } else {
- shelljs.exec(
- `cd ${path.join(
- __dirname,
- "../demo"
- )} && yarn create nx-workspace nx --preset=empty --nx-cloud=false --packageManager=yarn --cli=nx --linter=eslint`
- );
- shelljs.exec(`cd ${root} && yarn add @nrwl/node`);
- }
-
- if (type !== "nx") {
- packageGraph.forEachNode((node) => {
- const packageRoot = path.join(
- root,
- "packages",
- node.data.name.replace(/^@[^/]+\//, "")
- );
- fs.mkdirSync(packageRoot, { recursive: true });
- copy(
- path.join(__dirname, "templates"),
- path.join(packageRoot),
- {
- name: node.data.name.replace(/^@[^/]+\//, ""),
- },
- () => {}
- );
-
- fs.writeFileSync(
- path.join(packageRoot, "package.json"),
- JSON.stringify(
- {
- name: node.data.name,
- version: node.data.version,
- dependencies: node.data.dependencies,
- files: ["dist/**"],
- main: "dist/index.js",
- types: "dist/index.d.ts",
- devDependencies: {
- typescript: "^4.6.3",
- jest: "^27.0.0",
- "ts-jest": "^27.0.0",
- "@types/jest": "^27.0.0",
- },
- scripts: {
- build: "tsc",
- dev: "tsc -w",
- test: "jest",
- },
- },
- null,
- 2
- )
- );
- });
- }
-
- if (type === "nx") {
- packageGraph.forEachNode((node) => {
- shelljs.exec(
- `cd ${root} && yarn nx g @nrwl/node:library --buildable --publishable --name="${node.data.name.replace(
- /^@[^/]+\//,
- ""
- )}" --importPath="${node.data.name.replace(/^@[^/]+\//, "")}"`
- );
- // instead of dealing with actual code, just list as implicitDependencies
- const safeName = node.data.name.replace(/^@[^/]+\//, "");
- const workspace = fs.readJSONSync(path.join(root, "workspace.json"));
- workspace.projects[safeName] = {
- ...workspace.projects[safeName],
- implicitDependencies: node.data.implicitDependencies || [],
- };
- fs.writeFileSync(
- path.join(root, "nx.json"),
- JSON.stringify(workspace, null, 2)
- );
- });
- }
- if (!skipInstall) {
- shelljs.exec(`cd ${root} && yarn install`);
- }
- fs.ensureDirSync(path.join(root, ".git"));
- fs.writeFileSync(
- path.join(root, ".git", "config"),
- `
-[user]
- name = GitHub Actions
- email = actions@users.noreply.github.com
-`
- );
- shelljs.exec(
- `cd ${root} && git init -q && git add . && git commit -m "init"`
- );
-}
-
-generate(root);
-if (type === "turbo") {
- generate(root + "-installed", true);
-}
diff --git a/cli/scripts/nginx/.dockerignore b/cli/scripts/nginx/.dockerignore
deleted file mode 100644
index 4c8fbef..0000000
--- a/cli/scripts/nginx/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-cacher_root
diff --git a/cli/scripts/nginx/Dockerfile.cacher b/cli/scripts/nginx/Dockerfile.cacher
deleted file mode 100644
index aedf629..0000000
--- a/cli/scripts/nginx/Dockerfile.cacher
+++ /dev/null
@@ -1,11 +0,0 @@
-FROM ubuntu:xenial
-
-RUN apt-get update \
- && apt-get install -y --no-install-recommends \
- nginx \
- nginx-extras \
- && rm -rf /var/lib/apt/lists/*
-
-COPY nginx.conf /etc/nginx/nginx.conf
-
-CMD nginx -g "daemon off;"
diff --git a/cli/scripts/nginx/docker-compose.yml b/cli/scripts/nginx/docker-compose.yml
deleted file mode 100644
index d93ef16..0000000
--- a/cli/scripts/nginx/docker-compose.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-services:
- cacher:
- build:
- context: .
- dockerfile: Dockerfile.cacher
- volumes:
- - ./cacher_root:/var/www/cache
- ports:
- - "7070:7070"
diff --git a/cli/scripts/nginx/nginx.conf b/cli/scripts/nginx/nginx.conf
deleted file mode 100644
index d56b5c0..0000000
--- a/cli/scripts/nginx/nginx.conf
+++ /dev/null
@@ -1,39 +0,0 @@
-user root;
-worker_processes auto;
-pid /run/nginx.pid;
-
-events {
- worker_connections 768;
- # multi_accept on;
-}
-
-http {
- sendfile on;
- tcp_nopush on;
- tcp_nodelay on;
- keepalive_timeout 65;
- types_hash_max_size 2048;
- # server_tokens off;
-
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
-
- access_log /dev/stdout;
- error_log /dev/stderr;
-
- gzip on;
- gzip_disable "msie6";
-
- server {
- listen 7070 default_server;
-
- root /var/www;
-
- location /v8/artifacts {
- dav_methods PUT;
- autoindex on;
- allow all;
- client_max_body_size 512M;
- }
- }
-}
diff --git a/cli/scripts/npm-native-packages/.gitignore b/cli/scripts/npm-native-packages/.gitignore
deleted file mode 100644
index 84c048a..0000000
--- a/cli/scripts/npm-native-packages/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build/
diff --git a/cli/scripts/npm-native-packages/npm-native-packages.js b/cli/scripts/npm-native-packages/npm-native-packages.js
deleted file mode 100644
index 06ab67f..0000000
--- a/cli/scripts/npm-native-packages/npm-native-packages.js
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env node
-
-const fs = require("fs");
-const path = require("path");
-
-// Map to node os and arch names.
-const nodeOsLookup = {
- darwin: "darwin",
- linux: "linux",
- windows: "win32",
-};
-
-const nodeArchLookup = {
- amd64: "x64",
- arm64: "arm64",
-};
-
-const humanizedArchLookup = {
- amd64: "64",
- arm64: "arm64",
-};
-
-const template = require("./template/template.package.json");
-const os = process.argv[2];
-const arch = process.argv[3];
-const version = process.argv[4];
-
-template.name = `turbo-${os}-${humanizedArchLookup[arch]}`;
-template.description = `The ${os}-${humanizedArchLookup[arch]} binary for turbo, a monorepo build system.`;
-template.os = [nodeOsLookup[os]];
-template.cpu = [nodeArchLookup[arch]];
-template.version = version;
-
-const outputPath = path.join(__dirname, "build", template.name);
-fs.rmSync(outputPath, { recursive: true, force: true });
-fs.mkdirSync(path.join(outputPath, "bin"), { recursive: true });
-
-if (os === "windows") {
- fs.copyFileSync(
- path.join(__dirname, "template", "bin", "turbo"),
- path.join(outputPath, "bin", "turbo")
- );
-}
-fs.copyFileSync(
- path.join(__dirname, "template", "README.md"),
- path.join(outputPath, "README.md")
-);
-fs.writeFileSync(
- path.join(outputPath, "package.json"),
- JSON.stringify(template, null, 2)
-);
-
-const goBin = os === "windows" ? "go-turbo.exe" : "go-turbo";
-fs.copyFileSync(
- path.join(__dirname, "..", "..", `dist-${os}-${arch}`, goBin),
- path.join(outputPath, "bin", goBin)
-);
diff --git a/cli/scripts/npm-native-packages/template/README.md b/cli/scripts/npm-native-packages/template/README.md
deleted file mode 100644
index fcbd4c0..0000000
--- a/cli/scripts/npm-native-packages/template/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# `turbo`
-
-This is a platform-specific binary for Turborepo, a monorepo build system. See https://github.com/vercel/turbo for details.
diff --git a/cli/scripts/npm-native-packages/template/bin/turbo b/cli/scripts/npm-native-packages/template/bin/turbo
deleted file mode 100644
index 4557a07..0000000
--- a/cli/scripts/npm-native-packages/template/bin/turbo
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env node
-
-// Unfortunately even though npm shims "bin" commands on Windows with auto-
-// generated forwarding scripts, it doesn't strip the ".exe" from the file name
-// first. So it's possible to publish executables via npm on all platforms
-// except Windows. I consider this a npm bug.
-//
-// My workaround is to add this script as another layer of indirection. It'll
-// be slower because node has to boot up just to shell out to the actual exe,
-// but Windows is somewhat of a second-class platform to npm so it's the best
-// I can do I think.
-const path = require('path');
-const turbo_exe = path.join(__dirname, 'turbo.exe');
-const child_process = require('child_process');
-child_process.spawnSync(turbo_exe, process.argv.slice(2), { stdio: 'inherit' });
diff --git a/cli/scripts/npm-native-packages/template/template.package.json b/cli/scripts/npm-native-packages/template/template.package.json
deleted file mode 100644
index fdc72c0..0000000
--- a/cli/scripts/npm-native-packages/template/template.package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "turbo-{{Os}}-{{Arch}}",
- "version": "{{Version}",
- "description": "The {{Os}}-{{Arch}} binary for turbo, a monorepo build system.",
- "repository": "https://github.com/vercel/turbo",
- "bugs": "https://github.com/vercel/turbo/issues",
- "homepage": "https://turbo.build/repo",
- "license": "MPL-2.0",
- "os": ["{{Os}}"],
- "cpu": ["{{Arch}}"],
- "preferUnplugged": true
-}
diff --git a/cli/scripts/templates/jest.config.js b/cli/scripts/templates/jest.config.js
deleted file mode 100644
index 0548306..0000000
--- a/cli/scripts/templates/jest.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-module.exports = {
- roots: ["<rootDir>/src"],
- transform: {
- "^.+\\.tsx?$": "ts-jest",
- },
- // testRegex: '(/__tests__/.*(\\.|/)(test|spec))\\.tsx?$',
- moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
- modulePathIgnorePatterns: ["<rootDir>/src/__fixtures__"],
- preset: "ts-jest",
-};
diff --git a/cli/scripts/templates/src/__tests__/index.test.ts b/cli/scripts/templates/src/__tests__/index.test.ts
deleted file mode 100644
index 9a4831a..0000000
--- a/cli/scripts/templates/src/__tests__/index.test.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { sum } from "../.";
-
-describe("Hello", () => {
- it("renders without crashing", () => {
- expect(sum(1, 2)).toEqual(3);
- });
-});
diff --git a/cli/scripts/templates/src/__tests__/tsconfig.json b/cli/scripts/templates/src/__tests__/tsconfig.json
deleted file mode 100644
index bf65be6..0000000
--- a/cli/scripts/templates/src/__tests__/tsconfig.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "extends": "../../tsconfig.json",
- "include": [".", "../."]
-}
diff --git a/cli/scripts/templates/src/index.ts b/cli/scripts/templates/src/index.ts
deleted file mode 100644
index 715e93e..0000000
--- a/cli/scripts/templates/src/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const sum = (a: number, b: number) => {
- return a + b;
-};
diff --git a/cli/scripts/templates/tsconfig.json b/cli/scripts/templates/tsconfig.json
deleted file mode 100644
index 76ae392..0000000
--- a/cli/scripts/templates/tsconfig.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "extends": "../../tsconfig.json",
- "compilerOptions": {
- "rootDir": "src",
- "outDir": "dist"
- },
- "include": ["src"],
- "exclude": ["node_modules"]
-}
diff --git a/cli/turbo.json b/cli/turbo.json
deleted file mode 100644
index b8567ca..0000000
--- a/cli/turbo.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "$schema": "../docs/public/schema.json",
- "extends": ["//"],
- "pipeline": {
- "build": {
- "outputs": ["turbo", "turbo.exe"]
- },
-
- "e2e": {
- "outputs": [],
- "inputs": ["**/*.go", "go.mod", "go.sum", "scripts/e2e/e2e.ts"]
- },
- "e2e-prebuilt": {
- "inputs": ["**/*.go", "go.mod", "go.sum", "scripts/e2e/e2e.ts"]
- }
- }
-}